UP | HOME

Translating an LTL formula into a monitor

Table of Contents

A monitor is a special type of automaton that is supposed to monitor a running system and move accordingly. A monitor detects an error when it cannot move: i.e., the system as performed some action, or reached some state that is not supposed to happen.

For instance here is a monitor that checks that yellow never occurs immediately after red.

Sorry, your browser does not support SVG.

This monitor stays in the initial state until red becomes true, it can then wait in the second state while red holds and yellow does not,, and will only move back to the initial state when both red and yellow are false. The only way this monitor would not be able to progress is if yellow becomes true while in the second state; in that case a violation should be reported.

Building a deterministic monitor

Shell

To build the above deterministic monitor using ltl2tgba, we simply pass option -M (for monitor) and -D (for deterministic).

ltl2tgba -D -M '!F(red & X(yellow))'
HOA: v1
name: "G(!red | X!yellow)"
States: 2
Start: 0
AP: 2 "red" "yellow"
acc-name: all
Acceptance: 0 t
properties: trans-labels explicit-labels state-acc deterministic weak
--BODY--
State: 0
[!0] 0
[0] 1
State: 1
[!0&!1] 0
[0&!1] 1
--END--

Python

The code is very similar to our previous example of building a never claim except that we explicitly require a deterministic monitor and output in the HOA format.

import spot
print(spot.translate('!F(red & X(yellow))', 'monitor', 'det').to_str('HOA'))
HOA: v1
States: 2
Start: 0
AP: 2 "red" "yellow"
acc-name: all
Acceptance: 0 t
properties: trans-labels explicit-labels state-acc deterministic weak
--BODY--
State: 0
[!0] 0
[0] 1
State: 1
[!0&!1] 0
[0&!1] 1
--END--

C++

The code very similar to the never claim example.

#include <iostream>
#include <spot/tl/parse.hh>
#include <spot/twaalgos/translate.hh>
#include <spot/twaalgos/hoa.hh>

int main()
{
  spot::parsed_formula pf = spot::parse_infix_psl("!F(red & X(yellow))");
  if (pf.format_errors(std::cerr))
    return 1;
  spot::translator trans;
  trans.set_type(spot::postprocessor::Monitor);
  trans.set_pref(spot::postprocessor::Deterministic);
  spot::twa_graph_ptr aut = trans.run(pf.f);
  print_hoa(std::cout, aut) << '\n';
  return 0;
}
HOA: v1
States: 2
Start: 0
AP: 2 "red" "yellow"
acc-name: all
Acceptance: 0 t
properties: trans-labels explicit-labels state-acc deterministic weak
--BODY--
State: 0
[!0] 0
[0] 1
State: 1
[!0&!1] 0
[0&!1] 1
--END--

Non-deterministic monitors

If you drop the -D option from ltl2tgba, or the det argument from spot.translate(), or the set_pref(spot::postprocessor::Deterministic) in C++, then a non-deterministic monitor can be output. By default, Spot will try to build both a deterministic and a non-deterministic monitor, then it will keep the smallest one.

Details

Expressiveness

In the hierarchy of temporal properties, the properties that are monitorable correspond to the class of safety properties. You can check that an LTL formula is a safety by using:

ltlfilt --count --safety -f '!F(red & X(yellow))'
1

(This asks ltlfilt to count the number of safety formulas among those—only one here—that were passed.)

For properties that are not safety properties, the monitors built recognize the smallest safety property that contain the original languages.

For instance if we want to ensure that whenever we press a button, the red light will be on until the green light is on, we would use the following formula: G(press -> red U green). Unfortunately it is not a safety property:

ltlfilt --count --safety -f 'G(press -> red U green)'
0

Nonetheless, we can still build a monitor for it:

Sorry, your browser does not support SVG.

This monitor will report violations if both red and green are off when the button is pressed, and also if red goes off without green going on. However, note that in the original formula, red U green implies that green will eventually become true, and the monitor cannot ensure that: a system where red is continuously on, and green is continuously off would not trigger any violation. The monitor that has been built here actually represents the safety property G(press -> red W green), and accepts a bit more than our original property G(press -> red U green).

Construction & References

The construction of deterministic monitors in Spot follows the construction of M. d'Amorim and G. Roşu (Efficient monitoring of ω-languages. CAV’05) as described by D. Tabakov and M. Y. Vardi (Optimized Temporal Monitors for SystemC. RV’10) with a minor optimization: instead of starting from a Büchi automaton we start from a Transition-based Generalized Büchi automaton.

The construction steps are:

  1. translate the LTL formula into a TGBA
  2. remove SCCs that cannot reach an accepting cycle
  3. strip the acceptance condition
  4. determinize the automaton (using a classical powerset)
  5. minimize the automaton (using standard DFA minimization)

When non-deterministic monitors are required, the last two steps are replaced by a pass of simulation-based reductions.

The following code shows how to implement the above five steps in C++ without using spot::translator. Unless you plan to customize some of these steps, we recommend you use spot::translator instead.

#include <iostream>
#include <spot/tl/parse.hh>
#include <spot/twaalgos/ltl2tgba_fm.hh>
#include <spot/twaalgos/sccfilter.hh>
#include <spot/twaalgos/stripacc.hh>
#include <spot/twaalgos/minimize.hh>
#include <spot/twaalgos/hoa.hh>

int main()
{
  spot::parsed_formula pf = spot::parse_infix_psl("G(press -> red U green)");
  if (pf.format_errors(std::cerr))
    return 1;
  // 1. translate LTL formula into TGBA
  spot::twa_graph_ptr aut = spot::ltl_to_tgba_fm(pf.f, spot::make_bdd_dict());
  // 2. remove "dead" SCCs
  aut = spot::scc_filter(aut);
  // 3. strip the acceptance condition (in place)
  spot::strip_acceptance_here(aut);
  // 4. & 5. determinize and minimize the automaton
  aut = spot::minimize_monitor(aut);
  // output the result.
  print_hoa(std::cout, aut) << '\n';
  return 0;
}
HOA: v1
States: 2
Start: 1
AP: 3 "press" "red" "green"
acc-name: all
Acceptance: 0 t
properties: trans-labels explicit-labels state-acc deterministic
properties: stutter-invariant weak
--BODY--
State: 0
[1&!2] 0
[2] 1
State: 1
[0&1&!2] 0
[!0 | 2] 1
--END--

Further reading

If your application requires monitors, and you plan to build them with Spot, it is very likely that you will want to convert the resulting automata to your own data structure. See how to print an automaton in a custom format to learn all you need to iterate over Spot's automata.