--------------------------- MODULE Apalache ----------------------------------- (* * This is a standard module for use with the Apalache model checker. * The meaning of the operators is explained in the comments. * Many of the operators serve as additional annotations of their arguments. * As we like to preserve compatibility with TLC and TLAPS, we define the * operator bodies by erasure. The actual interpretation of the operators is * encoded inside Apalache. For the moment, these operators are mirrored in * the class at.forsyte.apalache.tla.lir.oper.ApalacheOper. * * Igor Konnov, Jure Kukovec, Informal Systems 2020-2021 *) (** * An assignment of an expression e to a state variable x. Typically, one * uses the non-primed version of x in the initializing predicate Init and * the primed version of x (that is, x') in the transition predicate Next. * Although TLA+ does not have a concept of a variable assignment, we find * this concept extremely useful for symbolic model checking. In pure TLA+, * one would simply write x = e, or x \in {e}. * * Apalache automatically converts some expressions of the form * x = e or x \in {e} into assignments. However, if you like to annotate * assignments by hand, you can use this operator. * * For a further discussion on that matter, see: * https://github.com/informalsystems/apalache/blob/ik/idiomatic-tla/docs/idiomatic/assignments.md *) x := e == x = e (** * A generator of a data structure. Given a positive integer `bound`, and * assuming that the type of the operator application is known, we * recursively generate a TLA+ data structure as a tree, whose width is * bound by the number `bound`. * * The body of this operator is redefined by Apalache. *) Gen(size) == {} (** * Convert a set of pairs S to a function F. Note that if S contains at least * two pairs <> and <> such that x = u and y /= v, * then F is not uniquely defined. We use CHOOSE to resolve this ambiguity. * Apalache implements a more efficient encoding of this operator * than the default one. * * @type: Set(<>) => (a -> b); *) SetAsFun(S) == LET Dom == { x: <> \in S } Rng == { y: <> \in S } IN [ x \in Dom |-> CHOOSE y \in Rng: <> \in S ] (** * As TLA+ is untyped, one can use function- and sequence-specific operators * interchangeably. However, to maintain correctness w.r.t. our type-system, * an explicit cast is needed when using functions as sequences. *) LOCAL INSTANCE Sequences FunAsSeq(fn, maxSeqLen) == SubSeq(fn, 1, maxSeqLen) (** * Annotating an expression \E x \in S: P as Skolemizable. That is, it can * be replaced with an expression c \in S /\ P(c) for a fresh constant c. * Not every exisential can be replaced with a constant, this should be done * with care. Apalache detects Skolemizable expressions by static analysis. *) Skolem(e) == e (** * A hint to the model checker to expand a set S, instead of dealing * with it symbolically. Apalache finds out which sets have to be expanded * by static analysis. *) Expand(S) == S (** * A hint to the model checker to replace its argument Cardinality(S) >= k * with a series of existential quantifiers for a constant k. * Similar to Skolem, this has to be done carefully. Apalache automatically * places this hint by static analysis. *) ConstCardinality(cardExpr) == cardExpr (** * The folding operator, used to implement computation over a set. * Apalache implements a more efficient encoding than the one below. * (from the community modules). *) RECURSIVE FoldSet(_,_,_) FoldSet( Op(_,_), v, S ) == IF S = {} THEN v ELSE LET w == CHOOSE x \in S: TRUE IN LET T == S \ {w} IN FoldSet( Op, Op(v,w), T ) (** * The folding operator, used to implement computation over a sequence. * Apalache implements a more efficient encoding than the one below. * (from the community modules). *) RECURSIVE FoldSeq(_,_,_) FoldSeq( Op(_,_), v, seq ) == IF seq = <<>> THEN v ELSE FoldSeq( Op, Op(v,Head(seq)), Tail(seq) ) ===============================================================================