Converting TLA+ spec to PlusCal

40 views
Skip to first unread message

Deividas Bražėnas

unread,
Dec 18, 2022, 7:24:27 AM12/18/22
to tlaplus
Hello all,
I have a TLA+ spec that I'd like to convert to PlusCal, but I'm facing some issues as I don't know how to convert a few parts of the specification.

1. I want to have this predicate as a process, but I'm not sure how to convert this part "\E n \in CN, p \in BOOLEAN :"

UpdatePredicate ==
\E n \in CN, p \in BOOLEAN :
/\ predicate[n] => p \* Only monotonic updates are make the algorithm to terminate.
/\ predicate' = [predicate EXCEPT ![n] = p]
/\ UNCHANGED <<bcNode, bcValue, output, msgs>>

2. I want to specify global variable bcValue in Init based on the set of bcNode

/\ \/ bcNode \in CN /\ bcValue \in Value
    \/ bcNode \in FN /\ bcValue = NotValue

Thanks a lot!!

Stephan Merz

unread,
Dec 19, 2022, 1:30:20 AM12/19/22
to tla...@googlegroups.com
Hello,

TLA+ is more general than PlusCal, and a systematic conversion to PlusCal is unlikely to yield idiomatic results, if it is possible at all: you will probably end up with a single while loop containing all possible actions. It is a bit like the normal form theorem in computability theory.

On 18 Dec 2022, at 13:24, Deividas Bražėnas <deividas...@trafi.com> wrote:

Hello all,
I have a TLA+ spec that I'd like to convert to PlusCal, but I'm facing some issues as I don't know how to convert a few parts of the specification.

1. I want to have this predicate as a process, but I'm not sure how to convert this part "\E n \in CN, p \in BOOLEAN :"

UpdatePredicate ==
\E n \in CN, p \in BOOLEAN :
/\ predicate[n] => p \* Only monotonic updates are make the algorithm to terminate.
/\ predicate' = [predicate EXCEPT ![n] = p]
/\ UNCHANGED <<bcNode, bcValue, output, msgs>>

In PlusCal you could represent this as

with (n \in CN, p \in BOOLEAN) {
  await (predicate[n] => p);
  predicate[n] := p
}

2. I want to specify global variable bcValue in Init based on the set of bcNode

/\ \/ bcNode \in CN /\ bcValue \in Value
    \/ bcNode \in FN /\ bcValue = NotValue

You could perhaps write

variables
  bcNode \in CN \union FN,
  bcValue \in (CASE bcNode \in CN -> Value [] bcNode \in FN -> {NotValue});

Stephan

Deividas Bražėnas

unread,
Dec 20, 2022, 4:13:27 PM12/20/22
to tlaplus
Thank you, Stephan!!

I'm also wondering how I could write the following in PlusCal.

I have these global variables:

peers = {n_1, n_2, n_3, n_4}
msgs = [node_id \in peers |-> {}]

I want to add [t |-> "PROPOSE"] message for every peer in a process.

I've tried to do it like this, but it does not work as expected. What may I be doing wrong?

        print <<"with">>;
        with peer_id \in peers do
            print <<"peers", peers, "peer", peer_id>>;
            msgs[peer_id] := msgs[peer_id] \union {[t |-> "PROPOSE"]};
        end with;

        print <<"msgs", msgs>>;

I get the following output:

<<"with">>

<<"peers", {n_1, n_2, n_3, n_4}, "peer", n_1>>

<<"msgs", (n_1 :> {[t |-> "PROPOSE"]} @@ n_2 :> {} @@ n_3 :> {} @@ n_4 :> {})>>

<<"peers", {n_1, n_2, n_3, n_4}, "peer", n_2>>

<<"msgs", (n_1 :> {} @@ n_2 :> {[t |-> "PROPOSE"]} @@ n_3 :> {} @@ n_4 :> {})>>

<<"peers", {n_1, n_2, n_3, n_4}, "peer", n_3>>

<<"msgs", (n_1 :> {} @@ n_2 :> {} @@ n_3 :> {[t |-> "PROPOSE"]} @@ n_4 :> {})>>

<<"peers", {n_1, n_2, n_3, n_4}, "peer", n_4>>

<<"msgs", (n_1 :> {} @@ n_2 :> {} @@ n_3 :> {} @@ n_4 :> {[t |-> "PROPOSE"]})>>


Where I would expect:

<<"with">>

<<"peers", {n_1, n_2, n_3, n_4}, "peer", n_1>>

<<"peers", {n_1, n_2, n_3, n_4}, "peer", n_2>>

<<"peers", {n_1, n_2, n_3, n_4}, "peer", n_3>>

<<"peers", {n_1, n_2, n_3, n_4}, "peer", n_4>>

<<"msgs", (n_1 :> {[t |-> "PROPOSE"]} @@ n_2 :>  {[t |-> "PROPOSE"]}   @@ n_3 :>  {[t |-> "PROPOSE"]}   @@ n_4 :>  {[t |-> "PROPOSE"]}  )>>

Stephan Merz

unread,
Dec 21, 2022, 2:38:07 AM12/21/22
to tla...@googlegroups.com
In PlusCal, "with x \in S do ..." expresses non-deterministic choice, not a loop. The body of the "with" instruction is executed for some peer, then TLC backtracks and explores the remaining choices. Remember that TLC is a model checker that explores all runs of an algorithm, not an interpreter that generates one run. Therefore, "print" instructions are often hard to interpret.

I am not sure what exactly you are trying to achieve. The end result can of course be obtained by writing

msgs := [pid \in peers |-> [t |-> "PROPOSE"]]

Stephan


The content of this email, including all attachments, is confidential. If you are not the intended recipient, please notify us immediately and delete this email. Any disclosure, copying, distribution or any other use of its content is strictly prohibited.

-- 
You received this message because you are subscribed to the Google Groups "tlaplus" group.
To unsubscribe from this group and stop receiving emails from it, send an email to tlaplus+u...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/tlaplus/3fb78eb2-9d83-4e1b-b747-29a683469f7an%40googlegroups.com.

Deividas Bražėnas

unread,
Dec 21, 2022, 2:59:30 AM12/21/22
to tlaplus
Hey Stephan, thanks for the clarification and answer.

Sorry for not explaining correctly, but I want to simulate the messages sent for peers. So basically, in the end the variable msgs should look like this
msgs = [n_1 |-> {[t |-> "PROPOSE", v |-> "v_1], [t |-> "ECHO", v |-> "v_1]},
               n_2 |-> {[t |-> "PROPOSE", v |-> "v_1], [t |-> "ECHO", v |-> "v_1]},
               n_2 |-> {[t |-> "PROPOSE", v |-> "v_1], [t |-> "ECHO", v |-> "v_1]}]

And there will be a several processes like SendPropose or SendEcho that would append to set of messages. So sadly your proposed solution will not work :/ 

I've made loop like this work, but I'm wondering whether it would be possible to make it look more pretty

            while index <= Len(SetToSeq(peers)) do
                peer_id := peers[index];
                msgs[peer_id] := msgs[peer_id] \union {[t |-> "PROPOSE",  v |-> input]};
                index := index + 1;
            end while;

Deividas

Stephan Merz

unread,
Dec 21, 2022, 3:32:03 AM12/21/22
to tla...@googlegroups.com
You can rewrite your loop as follows:

while peers # {} do
  with p \in peers do
    msgs[p] := @ \union {...};
    peers := peers \ {p};
  end do;
end while

Note that unlike your version, this loop iterates through peers in a non-deterministic order, and that this will generate more states when you use TLC for model checking.

Stephan

Deividas Bražėnas

unread,
Dec 21, 2022, 3:37:01 AM12/21/22
to tla...@googlegroups.com
Thanks for the answer, Stephan!

You received this message because you are subscribed to a topic in the Google Groups "tlaplus" group.
To unsubscribe from this topic, visit https://groups.google.com/d/topic/tlaplus/9Qe7gvU1rqI/unsubscribe.
To unsubscribe from this group and all its topics, send an email to tlaplus+u...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/tlaplus/0BB14F11-2274-45EF-9121-7CBE50F61AA1%40gmail.com.

Deividas Bražėnas

unread,
Dec 21, 2022, 3:40:20 AM12/21/22
to tlaplus
I'm also wondering, maybe it would be possible to do that in a more simpler way? e.g. something like this:

msgs := [peer_id \in peers |-> msgs[peer_id] \cup {[t |-> "PROPOSE", v |-> input]}];

But this one gives me a syntax error at first "|->" operator when generated to following TLA+:
msgs' = [peer_id[self] \in peers[self] |-> msgs[peer_id[self]] \cup {[t |-> "PROPOSE", , v |-> input[self]]}]

Stephan Merz

unread,
Dec 21, 2022, 3:46:15 AM12/21/22
to tla...@googlegroups.com
The two commas look wrong: this could be an error in the PlusCal translator. If you can confirm this, could you open a GitHub issue? Could you share the entire TLA+ module?

What happens if you write something like

with m = [t |-> "PROPOSE", v |-> input] do
  msgs := [p \in peers |-> @ \cup {m}]
end with

Stephan


Deividas Bražėnas

unread,
Dec 21, 2022, 6:58:01 AM12/21/22
to tlaplus
Sorry, that was my typo, PlusCal translation seems to be alright.

Talking about your proposed solution, what does "@" means here? I get the following error during TLC "@ used where its meaning is not defined."

Deividas

Stephan Merz

unread,
Dec 21, 2022, 7:34:54 AM12/21/22
to tla...@googlegroups.com
Within a form [f EXCEPT ![x] = g(@)] (to which a PlusCal assignment f[x] := ... translates), `@' designates f[x]. `@' has no meaning in the right-hand side of an expression [x \in S |-> ...], sorry for the syntax error.

Stephan

Deividas Bražėnas

unread,
Dec 21, 2022, 4:07:06 PM12/21/22
to tlaplus
Hey Stephan,
I'm a bit confused after your previous answer - what would be the correct way to write that with statement in my case?

Sorry if that is a dumb question 🤦‍♂️.

Deividas

Stephan Merz

unread,
Dec 22, 2022, 2:56:24 AM12/22/22
to tla...@googlegroups.com
with m = [t |-> "PROPOSE", v |-> input] do
  msgs := [p \in peers |-> msgs[p] \cup {m}]
end with

Apologies for the confusion!

Stephan

Reply all
Reply to author
Forward
0 new messages