alloydeclarative-programming

Changing service code for object inside a system in Alloy


I want to change the service code of an object whenever there has been any service operated upon it. Suppose, I have a operation whenever that applies to an object, the service code of that object will be 1 and again when another operation executes then the service code will be 2. I want to save the latest service code to each object. Unfortunately, I am not able design my predicate well, that's why getting predicate inconsistent message from alloy.

I have tried some code for assigning service code to each object. The complete code shown below-

open util/ordering[Environment]

abstract sig Object{
    name: String,
    serviceCode: Int,
}{

    serviceCode >= 0 and serviceCode <= 3
}

// Events
enum Event {Event1, Event2, Event3}

abstract sig Condition{
    name: Event,
    object: Object
}


abstract sig BaseOperation{
    name: Event,
    object: Object
// it will have more attributes than Condition later
}

abstract sig Connector{
    condition:  Condition,
    baseOperation:  BaseOperation,
}


sig Environment{
    ev : set Event
}

pred execute [u:Environment, u':Environment, r:Connector] {
          some e: u.ev | {
          e = r.condition.name =>    
              u'.ev = u.ev + r.baseOperation.name
          else
              u'.ev = u.ev
      }
}

fact {
     all u:Environment-last, u':u.next, r:Connector {
         execute [u, u', r]
     }
}


sig Object1 extends Object{
}{
    name = "Object1 Object"
}

sig Object2 extends Object{
}{
    name = "Object2 Object"
}

sig Condition1 extends Condition{
}{
    name = Event1
    object = Object2
    object.serviceCode = 1
}

sig Operation1 extends BaseOperation{
}{
    name = Event2
    object = Object1
    object.serviceCode = 1
}


sig Operation2 extends BaseOperation{
}{
    name = Event3
    object = Object1
    object.serviceCode = 0
}

one sig Connector1 extends Connector{
}{
    condition = Condition1
    baseOperation = Operation1

}

one sig Connector2  extends Connector{
}{
    condition = Condition1
    baseOperation = Operation2
}

fact {
     Event3 !in first.ev &&
    Event2 !in first.ev
}

run {Event1 in last.ev} for 10

The above code works fine when I have only one operation link to one object. I have attached the diagram for it here . Whenever there is more than one operation, then alloy fails to find an instance. Need help on designing alloy code for achieving my goal.

Another possible approach might be- instead of one service code, we may have a list of service code. Considering timestamp along with each service code. Then when need to find out the latest service code. We can take the service code of max timestamp. But I am not sure how to design this in alloy.


Solution

  • I think you should take a look at Daniel Jackson's book. Alloy is not a programming language with mutable assignments. It is basically a rule engine over relations that can generate an instance, a set of relations matching those rules. This means that if you need mutable assignments then you need a way to represent the mutable state over time in a relation. There are two ways:

    The key problem is that your problem description is almost completely disconnected from the specification. You talk about Service and then later Operation, are they the same? Where do Event and Connector come in? They are never mentioned in your problem description?

    Let's take it one by one:

    I want to change the service code of an object

       open util/ordering[Environment]
    
       sig Object {}
       enum ServiceCode { _1, _2 }
    
       sig Environment {
          object    : Object -> ServiceCode
       }
    
    

    In general, you do not want to use Ints for things like Service Code since they tend to blow up the state space.

    The Environment is our state. We want to execute one Service per Environment atom.

    ... whenever there has been any service operated upon it.

       sig Service {
        serviceCode : ServiceCode
       }
    
       pred execute[ e, e' : Environment, o : Object, s : Service ] {
        e'.object = e.object ++ o -> s.serviceCode       
       }
    

    Suppose, I have an Operation whenever that applies to an Object,

    It is not clear what you mean with Operation, I assume this is the earlier Service?

    ... the Service Code of that Object will be 1 and again when another Operation executes then the ServiceCode will be 2. I want to save the latest service code to each object. Unfortunately,

      pred trace {
        no first.object
        all t : Environment-last, t':t.next {
               some o: Object, s : Service {
               execute[t,t', o, s]
            }
        }
      }
    
      run trace
    

    In the table view this gives you:

    ┌────────────────┐
    │this/ServiceCode│
    ├────────────────┤
    │_1⁰             │
    ├────────────────┤
    │_2⁰             │
    └────────────────┘
    
    ┌───────────┐
    │this/Object│
    ├───────────┤
    │Object⁰    │
    ├───────────┤
    │Object¹    │
    └───────────┘
    
    ┌────────────┬───────────┐
    │this/Service│serviceCode│
    ├────────────┼───────────┤
    │Service⁰    │_2⁰        │
    ├────────────┼───────────┤
    │Service¹    │_2⁰        │
    ├────────────┼───────────┤
    │Service²    │_1⁰        │
    └────────────┴───────────┘
    
    ┌────────────────┬───────────┐
    │this/Environment│object     │
    ├────────────────┼───────────┤
    │Environment⁰    │           │
    ├────────────────┼───────┬───┤
    │Environment¹    │Object¹│_2⁰│
    ├────────────────┼───────┼───┤
    │Environment²    │Object⁰│_1⁰│
    │                ├───────┼───┤
    │                │Object¹│_2⁰│
    └────────────────┴───────┴───┘
    

    When you use Alloy the first thing you should do is define the problem you want to specify in plain English. You then translate the concepts in this text to Alloy constructs. The goal of an Alloy spec is to make it read like prose.