Initialization predicates

Initialization predicates can be used to specify the allowed initial locations of automata, as well as to restrict the allowed initial values of variables.

Initial locations of automata

Initialization predicates can be used to specify the allowed initial locations of automata:

automaton a:
  location loc1:
    initial;

  location loc2:
    initial true;

  location loc3;

  location loc4:
    initial false;
end

Automaton a has four locations. Location loc1 has the initial keyword, and is thus allowed to be the initial location. Location loc2 also uses the initial keyword, but additionally specifies a predicate that indicates under which conditions the location may be the initial location. Since it is true, which always holds, it does not impose any additional restrictions, and can thus always be the initial location. In fact, this is identical to location loc1, which did not specify a predicate, in which case it default to true as well.

Location loc3 does not specify anything about initialization, and thus can never be the initial location. Location loc4 can only be the initial location if false holds. Since false never holds, location loc4 can never be the initial location. In fact, this is identical to location loc3, which did not specify any initialization at all, in which case it default to false as well.

Locations loc1 and loc2 are the potential initial locations, while locations loc3 and loc4 can not be chosen as initial locations of automaton a. Since an automaton can only have one current location, an initial location has to be chosen from the potential initial locations. In other words, the initial location of automaton a is either location loc1 or location loc2.

Consistency between initial locations and initial values

Consider the following CIF specification:

automaton odd_even:
  event inc, dec;
  disc int n = 5;

  location odd:
    initial;
    edge inc do n := n + 1 goto even;
    edge dec do n := n - 1 goto even;

  location even:
    edge inc do n := n + 1 goto odd;
    edge dec do n := n - 1 goto odd;
end

Automaton odd_even keeps track of a value (n) that can constantly be incremented (event inc) and decremented (event dec) by one. It has two locations, that keep track of the odd/even status of value n. Currently, the initial value is 5, which is odd. Therefore, the initial keyword is specified in the odd location. However, if we change the initial value of variable n to 6, we have to change the initial location as well, to ensure consistent initialization. To automatically keep the initial location consistent with the initial value of variable n, we can change the specification to the following:

automaton odd_even:
  event inc, dec;
  disc int n = 5;

  location odd:
    initial n mod 2 = 1; // Initial location if 'n' is odd.
    edge inc do n := n + 1 goto even;
    edge dec do n := n - 1 goto even;

  location even:
    initial n mod 2 = 0; // Initial location if 'n' is even.
    edge inc do n := n + 1 goto odd;
    edge dec do n := n - 1 goto odd;
end

In this specification, location odd can only be the initial location if the value is odd (the value modulo two is congruent to one), and location even can only be the initial location if the value is even. Changing the initial value of variable n then also changes the potential initial locations. Since the value is always odd or even, and can’t be both odd and even, automaton odd_even always has exactly one potential initial location.

Restricting initialization

Initialization predicates can also be used to restrict the initial values of variables. Consider the following CIF specification:

automaton a:
  disc int x in any;

  initial x mod 2 = 1;

  location ...
end

In this partial automaton, variable x can be initialized to any integer value, as indicated by its int type and the any keyword. However, the initialization predicate states that initially, the value of x module two must be congruent to one. That is, the value of variable x must initially be odd.

It is allowed to specify initialization predicates inside automata, but it is also allowed to place them outside of them:

automaton a:
  disc int x in any;

  location ...
end

automaton b:
  disc int x in any;

  location ...
end

initial a.x = 2 * b.x;

Here, two automata each declare a variable that can have arbitrary initial values. The initialization predicate specifies that the initial value of variable x from automaton b must be twice the initial value of variable x from automaton a.

It is generally recommended to place an initialization predicate inside an automaton if the condition only applies to declarations from that automaton, and to place it outside of the automata if the condition applies to declarations of multiple automata.