Skip to content

CPP API

Till Hofmann edited this page Oct 10, 2022 · 2 revisions

Creation of timed automata

A timed automaton (TA) in TACOS is a templated six-tuple consisting of

  • a set of locations,
  • an alphabet (a set of actions),
  • a single initial location,
  • a set of final locations,
  • a set of clocks, and
  • a set of transitions.

We use two template types to define the set of actions on transitions and atomic propositions (APs), which label locations. See here for a full example.

Locations

As clocks in timed automata are always running and the set of clocks is global (i.e., all locations consider the same set of clocks), only a set of APs is required to create a location. A location labeled with "INITIAL" (using std::string as the type for APs) is created by

auto loc1 = tacos::automata::ta::Location{"INITIAL"};

Currently, locations do not allow invariant constraints.

Alphabet

The alphabet given as a set of (templated) actions contains all actions that can be used on discrete transitions for synchronization or validation of specifications.

Initial location

The initial location represents the initial configuration. Implicitly, all clocks are initialized with the valuation 0.

Final locations

All locations marked as being final.

Clocks

Clocks are identified by strings and represent variables which evolve continuously with slope one.

Transitions

Transitions allow switching the mode from one location to another (from source to target location) using an action action (which may be used for synchronization). Transitions may be guarded, i.e., a transition can only be taken if the clock valuations in the source location satisfy the set of clock constraints associated with the transition. Additionally, clocks may be reset to zero when taking a transition. A transition can be specified as

auto t = tacos::automata::ta::Transition{source, action, target, guard, reset};

where source and target are locations, action is an action-type, guard is a set of clock constraints, and reset is a set of clocks (a set of std::string).

Clock constraints

A clock constraint can be for instance to define a guarding condition for a discrete transition. A clock constraint always compares a clock to a valuation using the relation symbols <,<=,=,>=,> represented by the c++-types std::less, std::less_equal, std::equal, std::greater_equal, and std::greater. Clock constraints may only use integer values (even though the type is double for technical reasons). A clock constraint comparing a clock x to the valuation 3 can for instance be defined as

using namespace tacos::automata;
auto cc = ClockConstraint{"x",AtomicClockConstraintT<std::equal_to<Time>>(3)};

TA example

We want to create a TA with two locations, where the second one is final and only reachable after two or more time units. Furthermore, the only clock x can be reset in the first location only after exactly one time unit. To be able to distinguish locations we use the APs of type integer "0" (first location) and "1" (second location) and appropriate actions on ("restart" and "turn_off") of type string on the transitions. The resulting automaton can be created by

using TA         = tacos::automata::ta::TimedAutomaton<int, std::string>;
using Location   = automata::ta::Location<int>;
using Transition = automata::ta::Transition<int, std::string>;
using tacos::automata::Time;
using tacos::automata::AtomicClockConstraintT;

auto automaton = TA{{Location{0}, Location{1}},
		     {"restart", "turn_off"},
		     Location{0},
		     {Location{1}},
		     {"x"},
		     {
		       Transition(Location{0}, 
                                  "restart", 
                                  Location{0}, 
                                  {{"x", AtomicClockConstraintT<std::equal<Time>>(1)}}, 
                                  {"x"}),
		       Transition(Location{0},
		                  "turn_off",
		                  Location{1},
		                  {{"x", AtomicClockConstraintT<std::greater_equal<Time>>(2)}},
		                  {})
                      }
                     };

MTL Formulas

Formulas in metric temporal logic (MTL) in TACoS are used as a specification for controller synthesis. MTL formulas over atomic propositions (APs, template type) are composed recursively using negation, conjunction, disjunction, until, and dual until operators.

We use the usual c++-operators as much as possible with the usual semantics (see here for examples).

Examples

The single terms (assuming std::string as a type for APs) can be created (from the namespace tacos::logic) as follows (we assume the atomic propositions a and b have been created before):

  • atomic propositions: auto ap = AtomicProposition<std::string>("a");
  • negation: auto not_a = !a;
  • conjunction: auto a_and_b = a && b;
  • disjunction: auto a_or_b = a || b;
  • until: auto a_until_b = a.until(b);
  • bounded until (satisfied in [1,2]): auto a_until_b = a.until(b,{1,2});
  • bounded dual until (satisfied in [3,4]): auto a_until_b = a.dual_until(b,[3,4]);

We use the constant MTLFormula::TRUE() to derive syntactic sugar, e.g., tacos::logic::finally(a,bound) and tacos::logic::globally(a,bound) where a is an MTL-Formula and bound is a time interval (tacos::utilities::arithmetic::Interval).

Utility

We can validate timed words (sequences of tuples of atomic propositions and time points) against MTL-specifications:

tacos::logic::AtomicProposition<std::string> a{"a"};
tacos::logic::AtomicProposition<std::string> b{"b"};
tacos::logic::MTLWord<std::string> word = {{{a}, 1},{{b}, 2},{{a}, 3}};

bool a_true_at_one = word.satisfies(tacos::logic::finally(a, tacos::logic::TimeInterval{1,1}));

MTL-formulas can be brought to positive normal form using the member-function to_positive_normal_form(), which recursively moves all negations inside the subformulas using standard transformations.

Synthesizing a controller

To synthesize a controller, given a plant and an MTL-specification, TACOS employs the approach presented by Bouyer et al.. The method operates in several stages. We assume spec to be a MTL-formula over the set of atomic propositions actions and plant to be a timed automaton. The set of actions can be partitioned in uncontrollable environment actions and controllable controller actions.

  1. The MTL-specification is transformed into an alternating timed automaton (ATA)
[...]
auto spec_ata = tacos::mtl_ata_translation::translate(spec, actions);
  1. An exhaustive search is performed on the product automaton of the TA and the ATA (created internally), nodes in the resulting search tree are labelled throughout the process (whether the specification is satisfied in the respective subtree, or not)
[...]
auto spec_ata = tacos::mtl_ata_translation::translate(spec, actions);
// determines the largest constant used in the TA and in the ATA
std::size_t K = std::max(plant.get_largest_constant(), spec.get_largest_constant());
// the last parameter enables incremental labeling during search, 
// otherwise searcher.label() needs to be called
auto searcher = tacos::TreeSearch{plant,spec_ata,controller_actions,environment_actions,K,true};
// build search tree, label directly. The passed flag enables multithreading if set to true.
searcher.build_tree(false);
  1. The resulting search tree is traversed to create a controller in case the specification can be satisfied in the root node.
[...]
// build search tree, label directly. The passed flag enables multithreading if set to true.
searcher.build_tree(false);
// construct controller from resulting search tree
auto controller = controller_synthesis::create_controller(searcher.get_root(),
	                                                          controller_actions,
	                                                          environment_actions,
	                                                          K);