Commit da391492 authored by Alexandre Duret-Lutz's avatar Alexandre Duret-Lutz

twa: store property bits as trivals

* spot/twa/twa.hh: Store property bits as trivals.
* NEWS: Mention the change.
* spot/parseaut/parseaut.yy, spot/twaalgos/are_isomorphic.cc,
spot/twaalgos/complete.cc, spot/twaalgos/dot.cc, spot/twaalgos/hoa.cc,
spot/twaalgos/isdet.cc, spot/twaalgos/isunamb.cc, spot/twaalgos/lbtt.cc,
spot/twaalgos/ltl2tgba_fm.cc, spot/twaalgos/postproc.cc,
spot/twaalgos/remfin.cc, spot/twaalgos/strength.cc,
spot/twaalgos/stutter.cc, spot/twaalgos/stutter.hh,
spot/twaalgos/totgba.cc, tests/core/ikwiad.cc,
tests/python/product.ipynb, tests/python/remfin.py: Adjust.
* doc/org/hoa.org, doc/org/tut21.org: Update documentation.
parent 1aeb260a
......@@ -74,6 +74,15 @@ New in spot 1.99.6a (not yet released)
acc_cond::is_ff() -> acc_cond::is_f()
parse_acc_code() -> acc_cond::acc_code(...)
* Automata property bits (those that tell whether the automaton is
deterministic, weak, stutter-invariant, etc.) are now stored using
three-valued logic: in addition to "maybe"/"yes" they can now also
represent "no". This is some preparation for the upcomming
support of the HOA v1.1 format, but it also saves some time in
some algorithms (e.g, is_deterministic() can now return
immediately on automata marked as not deterministic).
Python:
* Iterating over the transitions leaving a state (the
......
......@@ -186,15 +186,15 @@ rm -f stvstracc.hoa
Even if an input HOA file uses only state-based acceptance, Spot
internally stores it using transition-based acceptance. However in
that case the TωA will have a property bit indicating that it actually
that case the TωA will have a property flag indicating that it actually
represents an automaton with the "state-based acceptance" property:
this implies that transitions leaving one state all belong to the same
acceptance sets. A couple of algorithms in Spot checks for this
property, and enable specialized treatments of state-based automata.
Furthermore, even if an automaton does not have the "state-based
acceptance" property bit set, the HOA output routine may detect that
the automaton satisfies this property. In that case, it output the
acceptance" property flag set, the HOA output routine may detect that
the automaton satisfies this property. In that case, it outputs the
automaton with state-based acceptance.
For instance in the following automaton, the outgoing transitions of
......@@ -583,7 +583,7 @@ labels whenever that is possible. The option is named =k= (i.e., use
=-Hk= with command-line tools) because it is useful when the HOA file
is used to describe a Kripke structure.
** Property bits
** Property flags
:PROPERTIES:
:CUSTOM_ID: property-bits
:END:
......@@ -593,7 +593,7 @@ These properties can be useful to speedup certain algorithms: for
instance it is easier to complement a deterministic automaton that is
known to be inherently weak.
Spot stores this properties that matters to its algorithms as
Spot stores the properties that matters to its algorithms as
additional bits attached to each automaton. Currently the HOA parser
ignores all the properties that are unused by Spot.
......@@ -603,22 +603,22 @@ is parsed; this is for instance the case of =deterministic=,
body of the file, and then return and error if what has been declared
does not correspond to the reality.
Some supported properties (like =weak=, =unambiguous=, or
=stutter-invariant=) are not double-checked, because that would
require too much additional operations. Command-line tools that read
HOA files all take a =--trust-hoa=no= option to ignore properties that
are not double-checked by the parser.
Some supported properties (like =weak=, =inherently-weak=,
=unambiguous=, or =stutter-invariant=) are not double-checked, because
that would require more operations. Command-line tools that
read HOA files all take a =--trust-hoa=no= option to ignore properties
that are not double-checked by the parser.
It should be noted that these bits are only implications. When such a
bit is false, it only means that it is unknown whether the property is
true. For instance if in some algorithm you want to know whether an
automaton is deterministic (the equivalent of calling =autfilt -q
It should be noted that each property can take three values: true,
false, or maybe. So actually two bits are used per property. For
instance if in some algorithm you want to know whether an automaton is
deterministic (the equivalent of calling =autfilt -q
--is-deterministic aut.hoa= from the command-line), you should not
call the method =aut->prop_deterministic()= because that only checks
the property bit, and it might be false even if the =aut= is
the property bits, and it might return =maybe= even if =aut= is
deterministic. Instead, call the function =is_deterministic(aut)=.
This function will first test the property bit, and do the actual
check if it has to.
This function will first test the property bits, and do the actual
check in case it is unknown.
Algorithms that update a TωA should call the method =prop_keep()= and
use the argument to specify which of the properties they preserve.
......@@ -632,7 +632,7 @@ take a new argument).
The =HOA= printer also tries to not bloat the output with many
redundant and useless properties. For instance =deterministic=
automata are necessarily =unambiguous=, and people interested in
unambiguous automata know that, so Spot only output the =unambiguous=
unambiguous automata know that, so Spot only outputs the =unambiguous=
property if an unambiguous automaton is non-deterministic. Similarly,
while Spot only outputs non-alternating automata, it does not output
the =no-univ-branch= property because we cannot think of a situation
......@@ -666,7 +666,7 @@ particular:
| =complete= | checked | no | checked | |
| =unambiguous= | trusted | yes | as stored if (=-Hv= or not =deterministic=) | can be checked with =--check=unambiguous= |
| =stutter-invariant= | trusted | yes | as stored | can be checked with =--check=stuttering= |
| =stutter-sensitive= | trusted | yes | as stored | can be checked with =--check=stuttering= |
| =stutter-sensitive= | trusted | yes | as stored (opposite of =stutter-invariant=) | can be checked with =--check=stuttering= |
| =terminal= | trusted | yes | as stored | can be checked with =--check=strength= |
| =weak= | trusted | yes | as stored if (=-Hv= or not =terminal=) | can be checked with =--check=strength= |
| =inherently-weak= | trusted | yes | as stored if (=-Hv= or not =weak=) | can be checked with =--check=strength= |
......
......@@ -37,8 +37,7 @@ Start: 0
AP: 3 "a" "b" "c"
acc-name: generalized-Buchi 2
Acceptance: 2 Inf(0)&Inf(1)
properties: trans-labels explicit-labels trans-acc unambiguous
properties: stutter-invariant
properties: trans-labels explicit-labels trans-acc stutter-invariant
--BODY--
State: 0
[0] 1
......@@ -121,29 +120,22 @@ corresponding BDD variable number, and then use for instance
if (auto name = aut->get_named_prop<std::string>("automaton-name"))
out << "Name: " << *name << '\n';
// For the following prop_*() methods, true means "it's sure", false
// means "I don't know". These properties correspond to bits stored
// in the automaton, so they can be queried in constant time. They
// are only set whenever they can be determined at a cheap cost: for
// instance any algorithm that always produce deterministic automata
// would set the deterministic bit on its output. In this example,
// the properties that are set come from the "properties:" line of
// the input file.
out << "Deterministic: "
<< (aut->prop_deterministic() ? "yes\n" : "maybe\n");
out << "Unambiguous: "
<< (aut->prop_unambiguous() ? "yes\n" : "maybe\n");
out << "State-Based Acc: "
<< (aut->prop_state_acc() ? "yes\n" : "maybe\n");
out << "Terminal: "
<< (aut->prop_terminal() ? "yes\n" : "maybe\n");
out << "Weak: "
<< (aut->prop_weak() ? "yes\n" : "maybe\n");
out << "Inherently Weak: "
<< (aut->prop_inherently_weak() ? "yes\n" : "maybe\n");
out << "Stutter Invariant: "
<< (aut->prop_stutter_invariant() ? "yes\n" :
aut->prop_stutter_sensitive() ? "no\n" : "maybe\n");
// For the following prop_*() methods, the return value is an
// instance of the spot::trival class that can represent
// yes/maybe/no. These properties correspond to bits stored in the
// automaton, so they can be queried in constant time. They are
// only set whenever they can be determined at a cheap cost: for
// instance an algorithm that always produces deterministic automata
// would set the deterministic property on its output. In this
// example, the properties that are set come from the "properties:"
// line of the input file.
out << "Deterministic: " << aut->prop_deterministic() << '\n';
out << "Unambiguous: " << aut->prop_unambiguous() << '\n';
out << "State-Based Acc: " << aut->prop_state_acc() << '\n';
out << "Terminal: " << aut->prop_terminal() << '\n';
out << "Weak: " << aut->prop_weak() << '\n';
out << "Inherently Weak: " << aut->prop_inherently_weak() << '\n';
out << "Stutter Invariant: " << aut->prop_stutter_invariant() << '\n';
// States are numbered from 0 to n-1
unsigned n = aut->num_states();
......@@ -175,8 +167,8 @@ Number of edges: 10
Initial state: 0
Atomic propositions: a (=0) b (=1) c (=2)
Name: Fa | G(Fb & Fc)
Deterministic: maybe
Unambiguous: yes
Deterministic: no
Unambiguous: maybe
State-Based Acc: maybe
Terminal: maybe
Weak: maybe
......@@ -226,12 +218,6 @@ Here is the very same example, but written in Python:
import spot
def maybe_yes(pos, neg=False):
if neg:
return "no"
return "yes" if pos else "maybe"
def custom_print(aut):
bdict = aut.get_dict()
print("Acceptance:", aut.get_acceptance())
......@@ -249,14 +235,13 @@ Here is the very same example, but written in Python:
name = aut.get_name()
if name:
print("Name: ", name)
print("Deterministic:", maybe_yes(aut.prop_deterministic()))
print("Unambiguous:", maybe_yes(aut.prop_unambiguous()))
print("State-Based Acc:", maybe_yes(aut.prop_state_acc()))
print("Terminal:", maybe_yes(aut.prop_terminal()))
print("Weak:", maybe_yes(aut.prop_weak()))
print("Inherently Weak:", maybe_yes(aut.prop_inherently_weak()))
print("Stutter Invariant:", maybe_yes(aut.prop_stutter_invariant(),
aut.prop_stutter_sensitive()))
print("Deterministic:", aut.prop_deterministic())
print("Unambiguous:", aut.prop_unambiguous())
print("State-Based Acc:", aut.prop_state_acc())
print("Terminal:", aut.prop_terminal())
print("Weak:", aut.prop_weak())
print("Inherently Weak:", aut.prop_inherently_weak())
print("Stutter Invariant:", aut.prop_stutter_invariant())
for s in range(0, aut.num_states()):
print("State {}:".format(s))
......@@ -280,8 +265,8 @@ Number of states: 4
Initial states: 0
Atomic propositions: a (=0) b (=1) c (=2)
Name: Fa | G(Fb & Fc)
Deterministic: maybe
Unambiguous: yes
Deterministic: no
Unambiguous: maybe
State-Based Acc: maybe
Terminal: maybe
Weak: maybe
......
/* -*- coding: utf-8 -*-
** Copyright (C) 2014, 2015 Laboratoire de Recherche et Développement
** de l'Epita (LRDE).
** Copyright (C) 2014, 2015, 2016 Laboratoire de Recherche et
** Développement de l'Epita (LRDE).
**
** This file is part of Spot, a model checking library.
**
......@@ -132,7 +132,7 @@ extern "C" int strverscmp(const char *s1, const char *s2);
bool accept_all_seen = false;
bool aliased_states = false;
bool deterministic = false;
spot::trival deterministic = spot::trival::maybe();
bool complete = false;
bool trans_acc_seen = false;
......@@ -457,12 +457,25 @@ header: format-version header-items
auto& a = res.aut_or_ks;
auto& p = res.props;
auto e = p.end();
a->prop_stutter_invariant(p.find("stutter-invariant") != e);
a->prop_stutter_sensitive(p.find("stutter-sensitive") != e);
a->prop_inherently_weak(p.find("inherently-weak") != e);
a->prop_weak(p.find("weak") != e);
a->prop_terminal(p.find("terminal") != e);
a->prop_unambiguous(p.find("unambiguous") != e);
if (p.find("stutter-invariant") != e)
{
a->prop_stutter_invariant(true);
auto i = p.find("stutter-sensitive");
if (i != e)
error(i->second,
"automaton cannot be both stutter-invariant"
"and stutter-sensitive");
}
if (p.find("stutter-sensitive") != e)
a->prop_stutter_invariant(false);
if (p.find("inherently-weak") != e)
a->prop_inherently_weak(true);
if (p.find("weak") != e)
a->prop_weak(true);
if (p.find("terminal") != e)
a->prop_terminal(true);
if (p.find("unambiguous") != e)
a->prop_unambiguous(true);
}
}
......@@ -952,8 +965,9 @@ state: state-name labeled-edges
}
| error
{
// Assume the worse.
res.deterministic = false;
// Assume the worse. This skips the tests about determinism
// we might perform on the state.
res.deterministic = spot::trival::maybe();
res.complete = false;
}
......@@ -1242,8 +1256,8 @@ dstar_header: dstar_sizes
res.h->aut->new_states(res.states);;
res.info_states.resize(res.states);
}
res.h->aut->prop_state_acc(true);
res.h->aut->prop_deterministic(true);
res.acc_style = State_Acc;
res.deterministic = true;
// res.h->aut->prop_complete();
fill_guards(res);
res.cur_guard = res.guards.end();
......@@ -1394,8 +1408,7 @@ never: "never"
}
res.namer = res.h->aut->create_namer<std::string>();
res.h->aut->set_buchi();
res.h->aut->prop_state_acc(true);
res.acc_state = State_Acc;
res.acc_style = State_Acc;
res.pos_acc_sets = res.h->aut->acc().all_sets();
}
'{' nc-states '}'
......@@ -1658,8 +1671,7 @@ lbtt-header-states: LBTT
lbtt-header: lbtt-header-states INT_S
{
res.acc_mapper = new spot::acc_mapper_int(res.h->aut, $2);
res.h->aut->prop_state_acc(true);
res.acc_state = State_Acc;
res.acc_style = State_Acc;
}
| lbtt-header-states INT
{
......
// -*- coding: utf-8 -*-
// Copyright (C) 2009, 2011, 2013, 2014, 2015 Laboratoire de Recherche
// et Développement de l'Epita (LRDE).
// Copyright (C) 2009, 2011, 2013, 2014, 2015, 2016 Laboratoire de
// Recherche et Développement de l'Epita (LRDE).
// Copyright (C) 2003, 2004, 2005 Laboratoire d'Informatique de
// Paris 6 (LIP6), département Systèmes Répartis Coopératifs (SRC),
// Université Pierre et Marie Curie.
......@@ -34,6 +34,7 @@
#include <spot/misc/casts.hh>
#include <spot/misc/hash.hh>
#include <spot/tl/formula.hh>
#include <spot/misc/trival.hh>
namespace spot
{
......@@ -757,14 +758,13 @@ namespace spot
// holds, but false means the property is unknown.
struct bprop
{
bool state_based_acc:1; // State-based acceptance.
bool inherently_weak:1; // Inherently Weak automaton.
bool weak:1; // Weak automaton.
bool terminal:1; // Terminal automaton.
bool deterministic:1; // Deterministic automaton.
bool unambiguous:1; // Unambiguous automaton.
bool stutter_invariant:1; // Stutter invariant language.
bool stutter_sensitive:1; // Stutter sensitive language.
trival::repr_t state_based_acc:2; // State-based acceptance.
trival::repr_t inherently_weak:2; // Inherently Weak automaton.
trival::repr_t weak:2; // Weak automaton.
trival::repr_t terminal:2; // Terminal automaton.
trival::repr_t deterministic:2; // Deterministic automaton.
trival::repr_t unambiguous:2; // Unambiguous automaton.
trival::repr_t stutter_invariant:2; // Stutter invariant language.
};
union
{
......@@ -810,104 +810,92 @@ namespace spot
named_prop_.clear();
}
bool prop_state_acc() const
trival prop_state_acc() const
{
return is.state_based_acc;
}
void prop_state_acc(bool val)
void prop_state_acc(trival val)
{
is.state_based_acc = val;
is.state_based_acc = val.val();
}
bool is_sba() const
trival is_sba() const
{
return prop_state_acc() && acc().is_buchi();
}
bool prop_inherently_weak() const
trival prop_inherently_weak() const
{
return is.inherently_weak;
}
void prop_inherently_weak(bool val)
void prop_inherently_weak(trival val)
{
is.inherently_weak = val;
is.inherently_weak = val.val();
if (!val)
is.terminal = is.weak = val.val();
}
bool prop_terminal() const
trival prop_terminal() const
{
return is.terminal;
}
void prop_terminal(bool val)
void prop_terminal(trival val)
{
is.terminal = val.val();
if (val)
is.inherently_weak = is.weak = is.terminal = true;
else
is.terminal = false;
is.inherently_weak = is.weak = val.val();
}
bool prop_weak() const
trival prop_weak() const
{
return is.weak;
}
void prop_weak(bool val)
void prop_weak(trival val)
{
is.weak = val.val();
if (val)
is.inherently_weak = is.weak = true;
else
is.weak = false;
is.inherently_weak = val.val();
if (!val)
is.terminal = val.val();
}
bool prop_deterministic() const
trival prop_deterministic() const
{
return is.deterministic;
}
void prop_deterministic(bool val)
void prop_deterministic(trival val)
{
is.deterministic = val.val();
if (val)
{
// deterministic implies unambiguous
is.deterministic = true;
is.unambiguous = true;
}
else
{
is.deterministic = false;
}
// deterministic implies unambiguous
is.unambiguous = val.val();
}
bool prop_unambiguous() const
trival prop_unambiguous() const
{
return is.unambiguous;
}
void prop_unambiguous(bool val)
void prop_unambiguous(trival val)
{
is.unambiguous = val;
is.unambiguous = val.val();
if (!val)
is.deterministic = val.val();
}
bool prop_stutter_invariant() const
trival prop_stutter_invariant() const
{
return is.stutter_invariant;
}
bool prop_stutter_sensitive() const
void prop_stutter_invariant(trival val)
{
return is.stutter_sensitive;
}
void prop_stutter_invariant(bool val)
{
is.stutter_invariant = val;
}
void prop_stutter_sensitive(bool val)
{
is.stutter_sensitive = val;
is.stutter_invariant = val.val();
}
struct prop_set
......@@ -941,32 +929,26 @@ namespace spot
prop_unambiguous(other->prop_unambiguous());
}
if (p.stutter_inv)
{
prop_stutter_invariant(other->prop_stutter_invariant());
prop_stutter_sensitive(other->prop_stutter_sensitive());
}
prop_stutter_invariant(other->prop_stutter_invariant());
}
void prop_keep(prop_set p)
{
if (!p.state_based)
prop_state_acc(false);
prop_state_acc(trival::maybe());
if (!p.inherently_weak)
{
prop_terminal(false);
prop_weak(false);
prop_inherently_weak(false);
prop_terminal(trival::maybe());
prop_weak(trival::maybe());
prop_inherently_weak(trival::maybe());
}
if (!p.deterministic)
{
prop_deterministic(false);
prop_unambiguous(false);
prop_deterministic(trival::maybe());
prop_unambiguous(trival::maybe());
}
if (!p.stutter_inv)
{
prop_stutter_invariant(false);
prop_stutter_sensitive(false);
}
prop_stutter_invariant(trival::maybe());
}
};
......
// -*- coding: utf-8 -*-
// Copyright (C) 2014, 2015 Laboratoire de Recherche et
// Copyright (C) 2014, 2015, 2016 Laboratoire de Recherche et
// Développement de l'Epita (LRDE).
// Copyright (C) 2004, 2005 Laboratoire d'Informatique de Paris 6 (LIP6),
// département Systèmes Répartis Coopératifs (SRC), Université Pierre
......@@ -113,9 +113,16 @@ namespace spot
isomorphism_checker::isomorphism_checker(const const_twa_graph_ptr ref)
{
ref_ = make_twa_graph(ref, twa::prop_set::all());
ref_deterministic_ = ref_->prop_deterministic();
if (!ref_deterministic_)
trival prop_det = ref_->prop_deterministic();
if (prop_det)
{
ref_deterministic_ = true;
}
else
{
// Count the number of state even if we know that the
// automaton is non-deterministic, as this can be used to
// decide if two automata are non-isomorphic.
nondet_states_ = spot::count_nondet_states(ref_);
ref_deterministic_ = (nondet_states_ == 0);
}
......@@ -125,10 +132,10 @@ namespace spot
bool
isomorphism_checker::is_isomorphic_(const const_twa_graph_ptr aut)
{
bool autdet = aut->prop_deterministic();
trival autdet = aut->prop_deterministic();
if (ref_deterministic_)
{
if (autdet || spot::is_deterministic(aut))
if (autdet || (!autdet && spot::is_deterministic(aut)))
return are_isomorphic_det(ref_, aut);
}
else
......
// -*- coding: utf-8 -*-
// Copyright (C) 2013, 2014, 2015 Laboratoire de Recherche et
// Copyright (C) 2013, 2014, 2015, 2016 Laboratoire de Recherche et
// Développement de l'Epita.
//
// This file is part of Spot, a model checking library.
......@@ -114,7 +114,7 @@ namespace spot
}
// In case the automaton use state-based acceptance, propagate
// the acceptance of the first edge to the one we add.
if (!aut->prop_state_acc())
if (aut->prop_state_acc() != true)
acc = 0U;
aut->new_edge(i, sink, missingcond, acc);
}
......
// -*- coding: utf-8 -*-
// Copyright (C) 2011, 2012, 2014, 2015 Laboratoire de Recherche et
// Developpement de l'Epita (LRDE).
// Copyright (C) 2011, 2012, 2014, 2015, 2016 Laboratoire de Recherche
// et Developpement de l'Epita (LRDE).
// Copyright (C) 2003, 2004 Laboratoire d'Informatique de Paris 6 (LIP6),
// département Systèmes Répartis Coopératifs (SRC), Université Pierre
// et Marie Curie.
......@@ -499,7 +499,8 @@ namespace spot
}
if (opt_name_)
name_ = aut_->get_named_prop<std::string>("automaton-name");
mark_states_ = !opt_force_acc_trans_ && aut_->prop_state_acc();
mark_states_ = (!opt_force_acc_trans_
&& aut_->prop_state_acc().is_true());
if (opt_shape_ == ShapeAuto)
{
if (sn_ || sprod_ || aut->num_states() > 100)
......
// -*- coding: utf-8 -*-
// Copyright (C) 2011, 2012, 2014, 2015 Laboratoire de Recherche et
// Copyright (C) 2011, 2012, 2014, 2015, 2016 Laboratoire de Recherche et
// Developpement de l'Epita (LRDE).
// Copyright (C) 2003, 2004 Laboratoire d'Informatique de Paris 6 (LIP6),
// département Systèmes Répartis Coopératifs (SRC), Université Pierre
......@@ -159,8 +159,8 @@ namespace spot
is_colored = colored && (!has_state_acc || nodeadend);
// If the automaton declares that it is deterministic or
// state-based, make sure that it really is.
assert(!aut->prop_deterministic() || deterministic);
assert(!aut->prop_state_acc() || state_acc);
assert(deterministic || aut->prop_deterministic() != true);
assert(state_acc || aut->prop_state_acc() != true);
}
void number_all_ap()
......@@ -433,16 +433,15 @@ namespace spot
// in the case of deterministic automata.
if (aut->prop_unambiguous() && (verbose || !md.is_deterministic))
prop(" unambiguous");
assert(!(aut->prop_stutter_invariant() && aut->prop_stutter_sensitive()));
if (aut->prop_stutter_invariant())
prop(" stutter-invariant");
if (aut->prop_stutter_sensitive())
if (!aut->prop_stutter_invariant())
prop(" stutter-sensitive");
if (aut->prop_terminal())
prop(" terminal");
if (aut->prop_weak() && (verbose || !aut->prop_terminal()))
if (aut->prop_weak() && (verbose || aut->prop_terminal() != true))
prop(" weak");
if (aut->prop_inherently_weak() && (verbose || !aut->prop_weak()))
if (aut->prop_inherently_weak() && (verbose || aut->prop_weak() != true))
prop(" inherently-weak");
os << nl;
......
// -*- coding: utf-8 -*-
// Copyright (C) 2012, 2013, 2014, 2015 Laboratoire de Recherche et
// Développement de l'Epita (LRDE).
// Copyright (C) 2012, 2013, 2014, 2015, 2016 Laboratoire de Recherche
// et Développement de l'Epita (LRDE).
//
// This file is part of Spot, a model checking library.
//
......@@ -63,8 +63,9 @@ namespace spot
bool
is_deterministic(const const_twa_graph_ptr& aut)
{
if (aut->prop_deterministic())
return true;
trival d = aut->prop_deterministic();
if (d.is_known())
return d.is_true();
return !count_nondet_states_aux<false>(aut);
}
......
// -*- coding: utf-8 -*-
// Copyright (C) 2013, 2015 Laboratoire de Recherche et Developpement
// Copyright (C) 2013, 2015, 2016 Laboratoire de Recherche et Developpement
// de l'Epita (LRDE).
//
// This file is part of Spot, a model checking library.
......@@ -27,20 +27,23 @@ namespace spot
{