1

I want to instantiate a module multiple times in a TLA specification, e.g., in a communication network consisting of multiple but identical nodes, executing the same protocol.

My problem is that I haven't found a way to do this without having to adapt the composition model (the network in the example above) for each change in the number of nodes.

The following example shows the problem from above on a more abstract level:

This model encapsulates a single variable v which is initialized to 1 and allows to change that variable from 0 to 1.

---- MODULE single ----
VARIABLE v

Init == v = 0

Next == v = 0 /\ v' = 1

Spec == Init /\ [][Next]_v
====

The following model instantiates this module two times:

---- MODULE concurrent_a ----
VARIABLES
    a, b

A == INSTANCE single WITH v <- a
B == INSTANCE single WITH v <- b

Init == A!Init /\ B!Init
 
Next == [A!Next]_a /\ [B!Next]_b 

Spec == Init /\ [][Next]_<<a, b>>
====

This is working as expected, both a and b can now be changed from 0 to 1 independently.

However, I want to generalize this to be able to instantiate multiple times without having to adapt the actions every time I change something. I tried the following:

---- MODULE concurrent ----
VARIABLES
    a, b, c, d

vars == <<a, b, c, d>> \* For usage in the next-state relation

N(v) == INSTANCE single

Init == 
    /\ N(a)!Init
    /\ N(b)!Init
    /\ N(c)!Init
    /\ N(d)!Init
 
Next == 
    /\ [N(a)!Next]_a 
    /\ [N(b)!Next]_b 
    /\ [N(c)!Next]_c 
    /\ [N(d)!Next]_d 

Spec == Init /\ [][Next]_vars
====

This is still working, but shows my problem. With each new instance, I have to change the overall specification, i.e., the Init and Next actions.

I want to express this in a way similar to this module:

---- MODULE concurrent_err ----
VARIABLES
    a, b, c, d

vars == <<a, b, c, d>> \* For usage in the next-state relation
Vars == {a, b, c, d} \* For quantification

N(v) == INSTANCE single

Init == \A v \in Vars: N(v)!Init
 
Next == \A v \in Vars: [N(v)!Next]_v 

Spec == Init /\ [][Next]_Vars
====

TLC throws an error trying to compute the initial states:

[...]
Computing initial states...
Error: In evaluation, the identifier a is either undefined or not an operator.
line 6, col 10 to line 6, col 10 of module concurrent
Error: The error occurred when TLC was evaluating the nested
expressions at the following positions:
0. Line 10, column 9 to line 10, column 32 in concurrent
1. Line 10, column 18 to line 10, column 21 in concurrent
2. Line 6, column 9 to line 6, column 20 in concurrent
3. Line 6, column 10 to line 6, column 10 in concurrent


0 states generated, 0 distinct states found, 0 states left on queue.

This relates to the evaluation of v \in Vars in the Init (and corresponding Next) Action. However, a similar evaluation(?) takes place in the definition of [Next]_vars. I suppose this corresponds to a syntactical replacement rather than an actual evaluation, and I expected the same to be true for the first case, but this doesn't seem to be true.

Is there a way to express the semantics of module concurrent in a form similar to concurrent_err?

naumb
  • 11
  • 3
  • Maybe a simple error, can you actually quantify over sequences or do they have to be finite sets instead? Try Vars == {a,b,c,d}. You do have to use sequences for variable subscripts though. I think the finite set form might end up being the value of the variables rather than their symbolic form perhaps though. – ahelwer Apr 27 '23 at 13:17
  • You are correct - Sequences don't seem to be enumerable. I tried defining `Vars` as a set as you suggested, but the error remains. However, it is thrown already at the definition of the set. Additionally, as you already pointed out, TLC throws warnings stating that the subscript of the next-state relation doesn't contain the variables. I updated the question accordingly. – naumb Apr 28 '23 at 06:05
  • From talking to a friend about this apparently a solution is possible but is very complicated and would take many pages to explain. It might be easier to just have each subsystem use their variable as a function indexed by some kind of node ID. – ahelwer Apr 28 '23 at 16:33
  • Would have to get an exact solution later, but the way I'd do it is to 1) replace the vars with a constant `V`, 2) add the variable `v` of type `[V -> 0..1]`, and then 3) prefix `Next` with `v' \in [V -> 0..1]`. This might be too dependent on your abstract version though. – Hovercouch May 01 '23 at 18:28

0 Answers0