A TLA+ specification is a mathematical formula. "Evaluation' is not a
meaningful concept in mathematics. TLC is a program, one of its tasks
being to compute the set of possible next states of an action for a
given state. Since this involves trying to solve an unsolvable
problem, TLC uses certain heuristics. For example, it will do this
for the action formula (x' = 1) /\ (y' = x') but not for the
equivalent action formula (y' = x') /\ (x' = 1).
TLC's heuristics are insensitive to the use of definitions. In your
example, it handles Foo(x)' exactly the way it handles (x \cup y)',
which is exactly the way it handles (x' \cup y').
In almost all cases that arise in practice, it is easy to rewrite a
sensible action formula in a form that TLC can handle--for example by
rewriting (y' = x') /\ (x' = 1) as (x' = 1) /\ (y' = x'). Thus, if
you can't find such a rewriting, the odds are that your formula is not
sensible because it doesn't mean what you think it should. It may
therefore be instructive if you would post an action formula (that is
as simple as possible) that you would like TLC to evaluate but that
it doesn't.
Leslie
A TLA+ specification is a mathematical formula. "Evaluation' is not a
meaningful concept in mathematics.
In almost all cases that arise in practice, it is easy to rewrite a
sensible action formula in a form that TLC can handle
Basically I'm looking for a "lowering" operator where:
Lower(x) == the level-0 expression (constant value) which
is equal to x in this state
I can't think of any way to define such an operator, but it may help
to observe that if Foo is defined by
Foo(a, b) == a' = e1 /\ b' = e2
Then \E t : (t=x) /\ Foo(t,y)' is equivalent to Foo(x, y').
TLC's requirement that x' be determined in a single expression means
that I can't write:
\A t \in DOMAIN x : x'[t] = e \* e is some expression
This is not a problem when only one variable is involved, as you can
do:
x' = [t \in DOMAIN x |-> e]
/\ x' = [t \in DOMAIN x |-> x'[t]]
/\ \A t \in DOMAIN x : x'[t] = e
but it's hardly simper than the second one.
it's not easy to realize that if x is a variable, then f[2] is not
equal to the illegal expression (x')'.
Leslie
it may help
to observe that if Foo is defined by
Foo(a, b) == a' = e1 /\ b' = e2
Then \E t : (t=x) /\ Foo(t,y)' is equivalent to Foo(x, y').
Those
two formulas are not equivalent. The second determines the value of
x'. The first tells you very little about the value of x'. All it tells
you are the values of x'[t] for t \in DOMAIN x. It tells you nothing
about the domain of x'. It doesn't even tell you if x' is a function.
Hence, it's not a sensible formula--at least, not by itself. The following
formula is equivalent to the second one:/\ x' = [t \in DOMAIN x |-> x'[t]]
/\ \A t \in DOMAIN x : x'[t] = e
but it's hardly simper than the second one.
So, as I wrote before, when TLC doesn't allow you to write something
you think it should, then it's often the case that what you wrote
isn't what you meant to write. You should learn to read what a
formula says rather than what you want it to say. This requires that
you stop thinking of TLA+ formula as a program and start thinking of
it as a mathematical assertion.
Occasionally, this is difficult. For
example, if you writef[n \in Nat] == IF n = 0 THEN x ELSE f[n-1]'it's not easy to realize that if x is a variable, then f[2] is not
equal to the illegal expression (x')'.
Capture(var, Action(_)) == \E t \in S : t = var /\ Action(t) \* S is a constant set known to contain the variable var
and it does the capture/lowering I want.
Then I tried:
Capture(var, Action(_)) == \E t \in {var} : t = var /\ Action(t)
and that works too! I guess that's because the quantification happens outside the priming, and so t is a fresh, bound symbol rather than an expression involving a variable.
Thanks again!
I'm not sure what "works quite well". To clarify things, if
Action(t) == t = y
Capture(var, Action(_)) == \E t \in {var} : t = var /\ Action(t)
Then
Capture(x, Action)' = (\E t \in {x} : t = x /\ (t=y))'
= (\E t \in {x'} : t' = x' /\ (t'=y'))
= (\E t \in {x'} : t = x' /\ (t=y'))
The last equality holds because t' = t, since \E t introduces t as a constant.
Leslie
So, the Capture operator works well, except that it introduces a very significant performance hit when model-checking, so I can’t use it…
I’d like to pursue this point just a bit further, and explain the motivation. One of my specs is for a reliable multicast protocol (similar to Skeen’s algorithm) in a virtual synchrony environment. My variables include communication queues, the set of live machines, the state of the replicated state machine `st[m]` (where m is the machine), and each machine’s view, `view[m]` which is the set of machines m believes to be alive.
I have the concept of a node, which is an abstract machine, which at any point in time is mapped to a single physical machine. Also, I have an operator, let’s call it Address(m, n), which given a machine and a node, is equal to the address (i.e. physical machine) that machine m believes to be that of node n according to view[m]. I could explicitly pass view[m] to Address, but that would make things less convenient.
Now, a step may install a new view, view’, in machine m, in which case the protocol dictates that some messages be re-sent. Therefore, I tried to use Address(m, n)', so that the newly installed view be used. That didn’t work because it turns out that the node n in this case is computed from one of the state’s (`st`) fields, and st' has not yet been computed (as TLC requires).
I can’t set st' yet because of the problem I mentioned in an earlier email in this conversation, which is that in order to make things composable, the operator handling the change of view works on one message at a time (it is possible that multiple messages are being multicast concurrently), and so my `HandleNewView` operator returns a tuple containing the new value of st for that particular machine and that particular messages, as well as a sequence of messages to be sent (all because I can’t set a variable’s next value one domain point at a time).
So, perhaps there should be an operator, CAPTURE e, which would be a level-0 value equal to the value of expression e in the current state, so that I could write:
Address(m, CAPTURE n)'
I thought that having such an operator wouldn’t make much sense because semantically it would be a constant, yet its value would change with the state; now I think it’s just a matter of interpretation. (CAPTURE e) can be interpreted as a syntactic construct that simply says "this subexpression is protected from priming".
Ron
If you can precisely specify the meaning of Capture, we might consider it. That is, for any expression e, define the meaning of Capture(e) in terms of the meaning of e. The meaning of an action-level expression e is a mapping from pairs of states to values. I have no idea how to do that.
--
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 post to this group, send email to tla...@googlegroups.com.
Visit this group at https://groups.google.com/group/tlaplus.
For more options, visit https://groups.google.com/d/optout.
Sorry for being late to this discussion. I think that basically what you want isCapture(e) == CHOOSE x : x = e
with the additional effect that the expression Capture(e) is considered as a level-0 expression by SANY. (If you try writing Capture(x')' for the above definition where x is a state variable, SANY will complain about level-incorrectness.)
It seems to me that this wouldn't cause problems semantically. In fact, the more general solution would be to consider any expressionCHOOSE x : Pto be of level 0, whatever the level of P (currently, P must be of level <= 2, but even an extension to CHOOSE expressions for temporal formulas should be acceptable).
> That was my original intuition. I don't know what TLA+'s policy on backwards compatibility is, but changing the action semantics of CHOOSE now may break existing specs in possibly subtle ways.
No, it shouldn't. A CHOOSE expression returns a value, i.e., a constant. So the proposed change doesn't break the semantics but only the level-checking algorithm, which we know to be an approximation.
Capture(e) == CHOOSE k \in {e} : k = e
Next == /\ x' = x + 1
/\ PrintT(x) \* => 1
/\ PrintT(x') \* => 2
/\ PrintT(Capture(x)) \* => 1
/\ PrintT(Capture(x)') \* => 2
Spec == (x = 1) /\ [][Next]_<<x>>
So Capture(x)' /= Capture(x), and this seems to be more than just level-checking.
If the difference is due to my writing `CHOOSE k \in {e} : k = e` instead of `CHOOSE k : k = e`, then the latter is currently unsupported by TLC anyway.
VARIABLE xCapture(e) == CHOOSE k \in {e} : k = e
Next == /\ x' = x + 1
/\ PrintT(x) \* => 1
/\ PrintT(x') \* => 2
/\ PrintT(Capture(x)) \* => 1
/\ PrintT(Capture(x)') \* => 2
Spec == (x = 1) /\ [][Next]_<<x>>
So Capture(x)' /= Capture(x), and this seems to be more than just level-checking.
Hi Ron,
First of all, you are proposing to add a fundamentally new kind of
operator to TLA (and not just to TLA+). In 25 years, no one to my
knowledge has seen any need for such an operator. So, I'm not about
to add it because one user finds that it makes writing his specs more
convenient.
For example, suppose x is a vatiable s.t. s[[x]] = 1 and t[[x]] = 2, then
The last equality, s[[CAPTURE e']] = 2, makes no sense. How can the
value of a formula that doesn't mention t depend on the value of x in
state t? Is it because "t" is the next letter in the alphabet after "s",
so t[[CAPTURE e']] will equal the value of x in whatever state I decide
to name "u"?
Leslie
Hi Ron,
I should point out another problematic part of what you wrote--namely:
<<s, t>>[[(CAPTURE e)']] = 1
The semantics of prime is that
<<s, t>>[[exp']] = t[[exp]].
Therefore, your equality implies that t[[CAPTURE e]] = 1. Why does
t[[x]] = 2 imply that t[[CAPTURE x]] = 1?
Leslie
Hi Ron,
First of all, you are proposing to add a fundamentally new kind of
operator to TLA (and not just to TLA+). In 25 years, no one to my
knowledge has seen any need for such an operator. So, I'm not about
to add it because one user finds that it makes writing his specs more
convenient.
Also, I still don't understand the semantics of CAPTURE. Your writeFor example, suppose x is a vatiable s.t. s[[x]] = 1 and t[[x]] = 2, then
e == x |- s[[e]] = 1, <<s, t>>[[e']] = 2, s[[CAPTURE e]] = 1,<<s, t>>[[(CAPTURE e)']] = 1, s[[CAPTURE e']] = 2
The last equality, s[[CAPTURE e']] = 2, makes no sense. How can the
value of a formula that doesn't mention t depend on the value of x in
state t? Is it because "t" is the next letter in the alphabet after "s",
so t[[CAPTURE e']] will equal the value of x in whatever state I decide
to name "u"?