Lecture Notes

Synchronous observers

Software systems are often required to satisfy one or more safety properties. With synchronous reactive systems, a safety property is, essentially, one that is true of the system at all instants. When developing such systems in a language like Lustre, a convenient way to specify safety properties is to use synchronous observers.

These are programs that observe the input and output streams of the program S to be verified, and have a Boolean output stream for each safety property specified for S. The observers are defined so that, for each output stream, the output value is true at any point in the stream if, and only if, the corresponding safety property holds for S at that point.

Note that synchronous observers are not limited to safety properties. For instance, they can be used to check more complex properties such as the equivalence of two programs. They are explained nicely in the first 2 sections of [Halb99].

In class we have seen a few examples of synchronous observer programs:

Temporal Combinators

When writing synchronous observers the following temporal operators, defined in temporal.lus, are often useful.

  • Sofar(X) indicates if X has been true from the beginning of time or not. (simulate)

  • First(X) is a constant stream which has the value that X had in the first point in time. (simulate)

  • Since(X,Y) is true precisely when X has been true at some point, and Y has been true since then. There is an overlapping variant of Since that is called SinceIncl(X,Y) (simulate Since, simulate SinceIncl).

The following additional examples make use of those combinators:

Typical usage patterns are:
  • We use "Sofar( Env ) => A" if we want to state that A should be true if Env has been always true until then. Very often, Env states a condition that we assume about the environment that is guaranteed never to be broken.

  • We use "Since( X, Y ) => A" if we want to state that A holds whenever condition Y has been true since the last time X has been true. In other words, whenever X happens, and Y is true from that point on, then A should be true too.

  • We can define an arbitrary but constant stream a, by saying "a = First( A )", and letting A be an extra input to our observer. This allows us to relate values of two different streams in different points in time. (We use the convention that stream-names starting with a lower-case letter denote constant streams.)

  • From natural language to propositional logic to Lustre

    When formalizing a safety property, the following table may be helpful in translating from natural language.

    English Logic Lustre
    A and B
    A but B
    A ∧ B A and B
    A if B
    A when B
    A whenever B
    B ⇒ A B => A
    if A, then B
    A implies B
    A forces B
    A ⇒ B A => B
    only if A, B
    B only if A
    B ⇒ A B => A
    A precisely when B
    A if and only if B
    B ⇔ A
    A ⇔ B
    B = A
    A = B
    A or B
    either A or B
    A ⊕ B
    ("exclusive or", "xor")
    A or B
    A unless B
    A ∨ B
    ("logical or")
    A or B

    Copyright: Cesare Tinelli, The University of Iowa, 2014   Credits