org: several typos

* doc/org/tut01.org, doc/org/tut02.org, doc/org/tut03.org,
doc/org/tut04.org, doc/org/tut10.org, doc/org/tut20.org,
doc/org/tut21.org, doc/org/tut50.org: Fix some typos and reword some
sentences.
This commit is contained in:
Alexandre Duret-Lutz 2016-08-05 11:13:15 +02:00
parent 14bee1ae7f
commit 06d5aa5ea2
8 changed files with 116 additions and 100 deletions

View file

@ -31,8 +31,9 @@ ltlfilt --lbt-input -f "$formula" --spin -p
The reason the LBT parser has to be explicitly enabled is because of The reason the LBT parser has to be explicitly enabled is because of
some corner cases that have different meanings in the two syntaxes. some corner cases that have different meanings in the two syntaxes.
(For instance =t= and =f= are the true constant in LBT's syntax, but (For instance =t= and =f= are the true and false constants in LBT's
they are considered as atomic propositions in all the other syntaxes.) syntax, but they are considered as atomic propositions in all the
other syntaxes.)
* Python bindings * Python bindings
@ -94,17 +95,18 @@ After [[file:compile.org][compiling and executing]] we get:
: (p1) && (p2) && ([](p0)) : (p1) && (p2) && ([](p0))
Notice that, except for the =<<= operator, the different output Notice that, except for the =<<= operator, the different output
routines specify in their name the syntax the output, and the type of routines specify in their name the syntax to use for output, and the
formula they can output. Here we are only using LTL formulas for type of formula they can output. Here we are only using LTL formulas
demonstration, so those three functions are OK with that. The for demonstration, and PSL is a superset of LTL, so those three output
routine used by =<<= is =print_psl()=. functions are all OK with that. The routine used by =<<= is
=print_psl()=, the default syntax used by Spot.
We do not recommend using the =parse_formula()= interface because of We do not recommend using the =parse_formula()= interface because of
the potential formulas (like =f= or =t=) that have different meanings the potential formulas (like =f= or =t=) that have different meanings
in the two parsers that are tried. in the two parsers that are tried.
Instead, depending on whether you want to parse formulas with infix Instead, depending on whether you want to parse formulas with infix
syntax, or formulas with prefix syntax, you should call the specific syntax, or formulas with prefix syntax, you should call the appropriate
parser. Additionally, this give you control over how to print errors. parser. Additionally, this give you control over how to print errors.
** Calling the infix parser explicitly ** Calling the infix parser explicitly
@ -133,7 +135,8 @@ Here is how to call the infix parser explicitly:
Note that as its name implies, this parser can read more than LTL Note that as its name implies, this parser can read more than LTL
formulas: the fragment of PSL we support is basically LTL extended formulas: the fragment of PSL we support is basically LTL extended
with regular expressions. with regular expressions. (Refer to the [[https://spot.lrde.epita.fr/tl.pdf][temporal logic specifications]]
for the syntax and semantics.)
The =parse_infix_psl()= function processes =input=, and returns a The =parse_infix_psl()= function processes =input=, and returns a
=spot::parsed_formula= object. In addition to the =spot::formula= we =spot::parsed_formula= object. In addition to the =spot::formula= we
@ -141,16 +144,17 @@ desire (stored as the =spot::parsed_formula::f= attribute), the
=spot::parsed_formula= also stores any diagnostic collected during the =spot::parsed_formula= also stores any diagnostic collected during the
parsing. Those diagnostics are stored in the parsing. Those diagnostics are stored in the
=spot::parsed_formula::errors= attribute, but they can conveniently be =spot::parsed_formula::errors= attribute, but they can conveniently be
printed by calling the =spot::parsed::format_errors()= method: this printed by calling the =spot::parsed_formula::format_errors()= method:
method returns true if and only if a diagnostic was output, so this is this method returns =true= if and only if a diagnostic was output, so
usually used to abort the program with an error status as above. this is usually used to abort the program with an error status as
above.
The parser usually tries to do some error recovery, so the =f= The parser usually tries to do some error recovery, so the =f=
attribute can be non-null even if some parsing errors where returned. attribute can be non-null even if some parsing errors were returned.
For instance if you have input =(a U b))= the parser will complain For instance if you have input =(a U b))= the parser will complain
about the extra parenthesis, but it will still return a formula that about the extra parenthesis, but it will still return a formula that
is equivalent to =a U b=. So you could decide to continue with the is equivalent to =a U b=. You could decide to continue with the
"fixed" formula if you wish. Here is an example: "fixed" formula if you wish. Here is an example:
#+BEGIN_SRC C++ :results verbatim :exports both #+BEGIN_SRC C++ :results verbatim :exports both
@ -231,7 +235,7 @@ you can simply use =parse_infix_psl()= to parse LTL formulas.
There is a potential problem if you design a tool that only works with There is a potential problem if you design a tool that only works with
LTL formulas, but call =parse_infix_psl()= to parse user input. In LTL formulas, but call =parse_infix_psl()= to parse user input. In
that case, the user might well input a PSL formula and cause problem that case, the user might input a PSL formula and cause problem
down the line. down the line.
For instance, let's see what happens if a PSL formulas is passed to For instance, let's see what happens if a PSL formulas is passed to
@ -290,7 +294,7 @@ The first is to simply diagnose non-LTL formulas.
#+END_SRC #+END_SRC
A second (but slightly weird) idea would be to try to simplify the PSL A second (but slightly weird) idea would be to try to simplify the PSL
formula, and hope that the PSL simplify is able to come up with an formula, and hope that the simplifier is able to come up with an
equivalent LTL formula. This does not always work, so you need to be equivalent LTL formula. This does not always work, so you need to be
prepared to reject the formula anyway. In our example, we are lucky prepared to reject the formula anyway. In our example, we are lucky
(maybe because it was carefully chosen...): (maybe because it was carefully chosen...):
@ -411,7 +415,7 @@ specifiers after the second =:= (if any) are the usual [[https://docs.python.org
specifiers]] (typically alignment choices) and are applied on the string specifiers]] (typically alignment choices) and are applied on the string
produced from the formula. produced from the formula.
The complete list of specified that apply to formulas can always be The complete list of specifier that apply to formulas can always be
printed with =help(spot.formula.__format__)=: printed with =help(spot.formula.__format__)=:
#+BEGIN_SRC python :results output :exports results #+BEGIN_SRC python :results output :exports results

View file

@ -4,9 +4,9 @@
#+SETUPFILE: setup.org #+SETUPFILE: setup.org
#+HTML_LINK_UP: tut.html #+HTML_LINK_UP: tut.html
The task is to read an LTL formula, relabel all (possibly complex) The task is to read an LTL formula, relabel all (possibly
atomic propositions, and provide =#define= statements for each of double-quoted) atomic propositions, and provide =#define= statements
these renamings, writing everything in Spin's syntax. for each of these renamings, writing everything in Spin's syntax.
* Shell * Shell
@ -49,6 +49,11 @@ accept_all:
} }
#+end_example #+end_example
Aside: another way to work around syntax limitations of tools is to
use [[file:ltldo.org][=ltldo=]]. On the above example, =ltldo ltl2ba -f '"Proc@Here" U
("var > 10" | "var < 4")' -s= would produce a never clam with the
correct atomic proposition, even though =ltl2ba= cannot parse them.
* Python * Python
The =spot.relabel= function takes an optional third parameter that The =spot.relabel= function takes an optional third parameter that
@ -73,8 +78,7 @@ print(g.to_str('spin', True))
* C++ * C++
The =spot::relabeling_map= is just a =std::map= with a custom The =spot::relabeling_map= is just implemented as a =std::map=.
destructor.
#+BEGIN_SRC C++ :results verbatim :exports both #+BEGIN_SRC C++ :results verbatim :exports both
#include <string> #include <string>

View file

@ -7,11 +7,11 @@
This page explains how to build formulas and how to iterate over their This page explains how to build formulas and how to iterate over their
syntax trees. syntax trees.
We'll first describe how to build a formula from scratch, by using the We will first describe how to build a formula from scratch, by using
constructor functions associated to each operators, and show that the constructors associated to each operators, and show the basic
basic accessor methods for formulas. We will do that for C++ first, accessor methods for formulas. We will do that for C++ first, and
and then Python. Once these basics are covered, we will show examples then Python. Once these basics are covered, we will show examples for
for traversing and transforming formulas (again in C++ then Python). traversing and transforming formulas (again in C++ then Python).
* Constructing formulas * Constructing formulas
@ -86,7 +86,7 @@ memoization.
Building a formula using these operators is quite straightforward. Building a formula using these operators is quite straightforward.
The second part of the following example shows how to print some The second part of the following example shows how to print some
detail of the top-level oeprator in the formula. detail of the top-level operator in the formula.
#+BEGIN_SRC C++ :results verbatim :exports both #+BEGIN_SRC C++ :results verbatim :exports both
#include <iostream> #include <iostream>
@ -176,25 +176,26 @@ The Python equivalent is similar:
** C++ ** C++
In Spot, Formula objects are immutable: this allows identical subtrees In Spot, Formula objects are immutable: this allows identical subtrees
to be shared among multiple formulas. Algorithm that "transform" to be shared among multiple formulas. Algorithms that "transform"
formulas (for instance the [[file:tut02.org][relabeling function]]) actually recursively formulas (for instance the [[file:tut02.org][relabeling function]]) actually recursively
traverses the input formula to construct the output formula. traverse the input formula to construct the output formula.
Using the operators described in the previous section is enough to Using the operators described in the previous section is enough to
write algorithms on formulas. However there are two special methods write algorithms on formulas. However there are two special methods
that makes it a lot easier: =traverse= and =map=. that makes it a lot easier: =traverse= and =map=.
=traverse= takes a function =fun=, and applies it to a subformulas of =traverse= takes a function =fun=, and applies it to each subformulas
a formula, including the formula itself. The formula is explored in a of a given formula, including that starting formula itself. The
DFS fashion (without skipping subformula that appear twice). The formula is explored in a DFS fashion (without skipping subformula that
children of a formula are explored only if =fun= returns =false=. If appear twice). The children of a formula are explored only if =fun=
=fun= returns =true=, that indicates to stop the recursion. returns =false=. If =fun= returns =true=, that indicates to stop the
recursion.
In the following we use a lambda function to count the number of =G= In the following we use a lambda function to count the number of =G=
in the formula. We also print each subformula to show the recursion, in the formula. We also print each subformula to show the recursion,
and stop the recursion as soon as we encounter a subformula without and stop the recursion as soon as we encounter a subformula without
sugar (the =is_sugar_free_ltl()= method is a constant-time operation, sugar (the =is_sugar_free_ltl()= method is a constant-time operation
that tells whether a formulas contains a =F= or =G= operator) to save that tells whether a formula contains a =F= or =G= operator) to save
time time by not exploring further. time time by not exploring further.
@ -241,7 +242,7 @@ b & c & d
The other useful operation is =map=. This also takes a functional The other useful operation is =map=. This also takes a functional
argument, but that function should input a formula and output a argument, but that function should input a formula and output a
replacement formula. =f.map(fun)= applies =fun= to all children of replacement formula. =f.map(fun)= applies =fun= to all children of
=f=, and rebuild a same formula as =f=. =f=, and assemble the result under the same top-level operator as =f=.
Here is a demonstration of how to exchange all =F= and =G= operators Here is a demonstration of how to exchange all =F= and =G= operators
in a formula: in a formula:
@ -258,7 +259,7 @@ in a formula:
return spot::formula::G(xchg_fg(in[0])); return spot::formula::G(xchg_fg(in[0]));
if (in.is(spot::op::G)) if (in.is(spot::op::G))
return spot::formula::F(xchg_fg(in[0])); return spot::formula::F(xchg_fg(in[0]));
// No need to transform Boolean subformulas // No need to transform subformulas without F or G
if (in.is_sugar_free_ltl()) if (in.is_sugar_free_ltl())
return in; return in;
// Apply xchg_fg recursively on any other operator's children // Apply xchg_fg recursively on any other operator's children
@ -327,7 +328,7 @@ Here is the =F= and =G= exchange:
return spot.formula.G(xchg_fg(i[0])); return spot.formula.G(xchg_fg(i[0]));
if i._is(spot.op_G): if i._is(spot.op_G):
return spot.formula.F(xchg_fg(i[0])); return spot.formula.F(xchg_fg(i[0]));
# No need to transform Boolean subformulas # No need to transform subformulas without F or G
if i.is_sugar_free_ltl(): if i.is_sugar_free_ltl():
return i; return i;
# Apply xchg_fg recursively on any other operator's children # Apply xchg_fg recursively on any other operator's children

View file

@ -28,6 +28,11 @@ ltlfilt -c -f '(a U b) U a' --equivalent-to 'b U a'
#+RESULTS: #+RESULTS:
: 1 : 1
Or use =-q= if you only care about the exit status of =ltlfilt=: the
exist status is =0= if some formula matched, and =1= if no formula
matched. (The effect of these =-c= and =-q= options should be
familiar to =grep= users.)
* Python * Python
In Python, we can test this via a =language_containment_checker= In Python, we can test this via a =language_containment_checker=
@ -38,10 +43,10 @@ import spot
f = spot.formula("(a U b) U a") f = spot.formula("(a U b) U a")
g = spot.formula("b U a") g = spot.formula("b U a")
c = spot.language_containment_checker() c = spot.language_containment_checker()
print(c.equal(f, g)) print("Equivalent" if c.equal(f, g) else "Not equivalent")
#+END_SRC #+END_SRC
#+RESULTS: #+RESULTS:
: True : Equivalent
The equivalence check is done by converting the formulas $f$ and $g$ The equivalence check is done by converting the formulas $f$ and $g$
and their negation into four automata $A_f$, $A_{\lnot f}$, $A_g$, and and their negation into four automata $A_f$, $A_{\lnot f}$, $A_g$, and
@ -64,15 +69,15 @@ def equiv(f, g):
f = spot.formula("(a U b) U a") f = spot.formula("(a U b) U a")
g = spot.formula("b U a") g = spot.formula("b U a")
print(equiv(f, g)) print("Equivalent" if equiv(f, g) else "Not equivalent")
#+END_SRC #+END_SRC
#+RESULTS: #+RESULTS:
: True : Equivalent
The =language_containment_checker= object essentially performs the The =language_containment_checker= object essentially performs the
same work, but it also implements a cache to avoid translating the same work, but it also implements a cache to avoid translating the
same formulas multiple times when it is used to test multiple same formulas multiple times when it is used to test multiple
equivalence. equivalences.
* C++ * C++

View file

@ -119,13 +119,13 @@ T0_S3:
All the translation pipeline (this include simplifying the formula, All the translation pipeline (this include simplifying the formula,
translating the simplified formula into an automaton, and simplifying translating the simplified formula into an automaton, and simplifying
the resulting automaton) is handled by the =spot::translator= object. the resulting automaton) is handled by the =spot::translator= class.
This object can configured by calling =set_type()= to chose the type An instance of this class can configured by calling =set_type()= to
of automaton to output, =set_level()= to set the level of optimization chose the type of automaton to output, =set_level()= to set the level
(it's high by default), and =set_pref()= to set various preferences of optimization (it's high by default), and =set_pref()= to set
(like small or deterministic) or characteristic (complete, various preferences (like small or deterministic) or characteristic
unambiguous) for the resulting automaton. Finally, the output as a (complete, unambiguous) for the resulting automaton. Finally, the
never claim is done via the =print_never_claim= function. output as a never claim is done via the =print_never_claim= function.
#+BEGIN_SRC C++ :results verbatim :exports both #+BEGIN_SRC C++ :results verbatim :exports both
#include <string> #include <string>

View file

@ -45,7 +45,7 @@ Note that the automaton parser of Spot can read automata written
either as never claims, in LBTT's format, in ltl2dstar's format or in either as never claims, in LBTT's format, in ltl2dstar's format or in
the HOA format, and there is no need to specify which format you the HOA format, and there is no need to specify which format you
expect. Even if our example uses a never claim as input, the code we expect. Even if our example uses a never claim as input, the code we
write will work with any of those formats. write will read any of those formats.
* Shell * Shell
@ -185,18 +185,18 @@ State: 4
--END-- --END--
#+END_SRC #+END_SRC
In automata, transitions guards are represented by BDDs. The role of In the Spot representation of automata, transitions guards are
=bdd_dict= object is to keep track of the correspondence between BDD represented by BDDs. The role of the =bdd_dict= object is to keep
variables and atomic propositions such as =foo= and =bar= in the above track of the correspondence between BDD variables and atomic
example. So each automaton has a shared pointer to some =bdd_dict= propositions such as =foo= and =bar= in the above example. So each
(this shared pointer is what the =bdd_dict_ptr= type is), and automaton has a shared pointer to some =bdd_dict= (this shared pointer
operations between automata (like a product) can only work on automata is what the =bdd_dict_ptr= type is), and operations between automata
that share the same pointer. Here, when we call the automaton parser, (like a product) can only work on automata that share the same
we supply the =bdd_dict_ptr= that should be used to do the mapping pointer. Here, when we call the automaton parser, we supply the
between atomic propositions and BDD variables. Atomic propositions =bdd_dict_ptr= that should be used to do the mapping between atomic
that were not already registered will get a new BDD variable number, propositions and BDD variables. Atomic propositions that were not
and while existing atomic propositions will reuse the existing already registered will get a new BDD variable number, and while
variable. existing atomic propositions will reuse the existing variable.
In the example for [[file:tut10.org][translating LTL into BA]], we did not specify any In the example for [[file:tut10.org][translating LTL into BA]], we did not specify any
=bdd_dict=, because the =translator= object will create a new one by =bdd_dict=, because the =translator= object will create a new one by
@ -211,11 +211,12 @@ There are actually different C++ interfaces to the automaton parser,
depending on your use case. For instance the parser is able to read a depending on your use case. For instance the parser is able to read a
stream of automata stored in the same file, so that they could be stream of automata stored in the same file, so that they could be
processed in a loop. For this, you would instanciate a processed in a loop. For this, you would instanciate a
=automaton_stream_parser= object and call its =parse()= method in a =spot::automaton_stream_parser= object and call its =parse()= method
loop. Each call to this method will either return one automaton, or in a loop. Each call to this method will either return one
=nullptr= if there is no more automaton to read. The =parse_aut()= =spot::parsed_aut_ptr=, or =nullptr= if there is no more automaton to
function is actually a simple convenience wrapper that instantiates read. The =parse_aut()= function is actually a simple convenience
an =automaton_stream_parser= and calls its =parse()= method once. wrapper that instantiates an =automaton_stream_parser= and calls its
=parse()= method once.
In Python, you can easily iterate over a file containing multiple In Python, you can easily iterate over a file containing multiple

View file

@ -6,11 +6,11 @@
This example demonstrates how to iterate over an automaton in C++ and This example demonstrates how to iterate over an automaton in C++ and
Python. This case uses automata stored entirely in memory as a graph: Python. This case uses automata stored entirely in memory as a graph:
states are numbered by integers, and transitions can be seen as tuple states are numbered by integers, and transitions can be seen as tuples
of the form of the form
$(\mathit{src},\mathit{dst},\mathit{cond},\mathit{accsets})$ where $(\mathit{src},\mathit{dst},\mathit{cond},\mathit{accsets})$ where
$\mathit{src}$ and $\mathit{dst}$ are integer denoting the extremities $\mathit{src}$ and $\mathit{dst}$ are integers denoting the source and
of the transition, $\mathit{cond}$ is a BDD representing the label destination states, $\mathit{cond}$ is a BDD representing the label
(a.k.a. guard), and $\mathit{accsets}$ is an object of type (a.k.a. guard), and $\mathit{accsets}$ is an object of type
=acc_cond::mark_t= encoding the membership to each acceptance sets =acc_cond::mark_t= encoding the membership to each acceptance sets
(=acc_cond::mark_t= is basically a bit vector). (=acc_cond::mark_t= is basically a bit vector).
@ -18,9 +18,9 @@ of the transition, $\mathit{cond}$ is a BDD representing the label
The interface available for those graph-based automata allows random The interface available for those graph-based automata allows random
access to any state of the graph, hence the code given bellow can do a access to any state of the graph, hence the code given bellow can do a
simple loop over all states of the automaton. Spot also supports a simple loop over all states of the automaton. Spot also supports a
different kind of interface (not demonstrated here) to iterate over different kind of interface (not demonstrated here) to
automata that are constructed on-the-fly and where such a loop would [[file:tut50.org][iterate over automata that are constructed
be impossible. on-the-fly]] and where such a loop would be impossible.
First let's create an example automaton in HOA format. We use =-U= to First let's create an example automaton in HOA format. We use =-U= to
request unambiguous automata, as this allows us to demonstrate how request unambiguous automata, as this allows us to demonstrate how
@ -38,7 +38,8 @@ Start: 0
AP: 3 "a" "b" "c" AP: 3 "a" "b" "c"
acc-name: generalized-Buchi 2 acc-name: generalized-Buchi 2
Acceptance: 2 Inf(0)&Inf(1) Acceptance: 2 Inf(0)&Inf(1)
properties: trans-labels explicit-labels trans-acc stutter-invariant properties: trans-labels explicit-labels trans-acc unambiguous
properties: stutter-invariant
--BODY-- --BODY--
State: 0 State: 0
[0] 1 [0] 1
@ -102,7 +103,7 @@ corresponding BDD variable number, and then use for instance
void custom_print(std::ostream& out, spot::twa_graph_ptr& aut) void custom_print(std::ostream& out, spot::twa_graph_ptr& aut)
{ {
// We need the dictionary to print the BDDs that label the edges // We need the dictionary to print the BDDs that label the edges
const auto& dict = aut->get_dict(); const spot::bdd_dict_ptr& dict = aut->get_dict();
// Some meta-data... // Some meta-data...
out << "Acceptance: " << aut->get_acceptance() << '\n'; out << "Acceptance: " << aut->get_acceptance() << '\n';
@ -146,7 +147,7 @@ corresponding BDD variable number, and then use for instance
// The out(s) method returns a fake container that can be // The out(s) method returns a fake container that can be
// iterated over as if the contents was the edges going // iterated over as if the contents was the edges going
// out of s. Each of these edge is a quadruplet // out of s. Each of these edges is a quadruplet
// (src,dst,cond,acc). Note that because this returns // (src,dst,cond,acc). Note that because this returns
// a reference, the edge can also be modified. // a reference, the edge can also be modified.
for (auto& t: aut->out(s)) for (auto& t: aut->out(s))
@ -169,7 +170,7 @@ Initial state: 0
Atomic propositions: a (=0) b (=1) c (=2) Atomic propositions: a (=0) b (=1) c (=2)
Name: Fa | G(Fb & Fc) Name: Fa | G(Fb & Fc)
Deterministic: no Deterministic: no
Unambiguous: maybe Unambiguous: yes
State-Based Acc: maybe State-Based Acc: maybe
Terminal: maybe Terminal: maybe
Weak: maybe Weak: maybe

View file

@ -211,10 +211,10 @@ syntax of C++ works exactly as if we had typed
#+END_SRC #+END_SRC
In the above =example()= function, the iterators =i= and =end= are In the above =example()= function, the iterators =i= and =end= are
instance of the =internal::edge_iterator<spot::twa_graph::graph_t>= instances of the =internal::edge_iterator<spot::twa_graph::graph_t>=
class, which redefines enough operators to act like an STL Foward class, which redefines enough operators to act like an STL Foward
Iterator over all outgoing edges of =s=. Note that the =tmp= and =i= Iterator over all outgoing edges of =s=. Note that the =tmp= and =i=
objects hold a pointer to the graph, but it does not really matters objects hold a pointer to the graph, but it does not really matter
because the compiler will optimize this away. because the compiler will optimize this away.
In fact after operators are inlined and useless temporary variables In fact after operators are inlined and useless temporary variables
@ -441,9 +441,9 @@ exploration of an automaton. Subclasses of =twa= need not represent
the entire automaton in memory; if they prefer, they can compute it as the entire automaton in memory; if they prefer, they can compute it as
it is explored. it is explored.
Naturally =twa_graph=, even if they store the automaton graph Naturally =twa_graph=, even if it stores the automaton graph
explicitly, are subclasses of =twa=, so they also implement the explicitly, is a subclasse of =twa=, so it also implements the
on-the-fly interface, even if they do not have to compute anything. on-the-fly interface but without computing anything.
** How this interface works ** How this interface works
@ -548,23 +548,23 @@ subclass.
The interface puts few requirement on memory management: we want to be The interface puts few requirement on memory management: we want to be
able to write automata that can forget about their states (and able to write automata that can forget about their states (and
recompute them), so there is no guarantee that reaching twice the same recompute them), so there is no guarantee that reaching the same state
state will give return the same pointer. Even calling twice will return the same pointer twice. Even calling
=get_init_state()= twice could return different pointers. The only =get_init_state()= twice could return two different pointers. The
way to decide whether two =state*= =s1= and =s2= represent the same only way to decide whether two =state*= =s1= and =s2= represent the
state is to check that ~s1->compare(s2) == 0~. same state is to check that ~s1->compare(s2) == 0~.
As far as memory management goes, there are roughly two types of =twa= As far as memory management goes, there are roughly two types of =twa=
subclasses: those that always create new =state= instances, and those subclasses: those that always create new =state= instances, and those
that reuse =state= instances (either because they have a cache, or that reuse =state= instances (either because they have a cache, or
because, as in the case of =twa_graph=, they know the entire graph). because, as in the case of =twa_graph=, they know the entire graph).
From the user's perspective, =state= should never be passed to =delete= From the user's perspective, =state= should never be passed to
(their protected destructor will prevent that). Instead, we should =delete= (their protected destructor will prevent that). Instead, we
call =state::destroy()=. Doing so allows each subclass to override should call =state::destroy()=. Doing so allows each subclass to
the default behavior of =destroy()= (which is to call =delete=). States override the default behavior of =destroy()= (which is to call
can be cloned using the =state::clone()= methode, in which case each =delete=). States can be cloned using the =state::clone()= method, in
copy has to be destroyed. which case each copy has to be destroyed.
=twa_succ_iterator= instances are allocated and should be deleted once =twa_succ_iterator= instances are allocated and should be deleted once
done, but to save some work, they can also be returned to the done, but to save some work, they can also be returned to the
@ -620,7 +620,7 @@ state, it is /usually/ known.
Let us improve the above loop. In the previous example, each of Let us improve the above loop. In the previous example, each of
=first()=, =done()=, =next()= is a virtual method call. So if there =first()=, =done()=, =next()= is a virtual method call. So if there
are $n$ successors, there will be $1$ call to =first()=, $n$ calls to are $n$ successors, there will be $1$ call to =first()=, $n$ calls to
=next()=, and $n+1$ call to =done()=, so a total of $2n$ virtual =next()=, and $n+1$ calls to =done()=, so a total of $2n+2$ virtual
method calls. method calls.
However =first()= and =next()= also return a Boolean stating whether However =first()= and =next()= also return a Boolean stating whether
@ -647,7 +647,7 @@ follows:
#+END_SRC #+END_SRC
Now we have only $1$ call to =first()= and $n$ calls to =next()=, Now we have only $1$ call to =first()= and $n$ calls to =next()=,
so we almost halved to number of virtual calls. so we halved to number of virtual calls.
Using C++11's ranged =for= loop, this example can be reduced to the Using C++11's ranged =for= loop, this example can be reduced to the
following equivalent code: following equivalent code:
@ -698,7 +698,7 @@ passes the iterator back to =aut->release_iter()= for recycling.
** Recursive DFS (v1) ** Recursive DFS (v1)
We can now write a recursive DFS easily. The only pain is to keep We can now write a recursive DFS easily. The only pain is to keep
track of the state to =destroy()= them only after we do not need them track of the states to =destroy()= them only after we do not need them
anymore. This tracking can be done using the data structure we use to anymore. This tracking can be done using the data structure we use to
remember what states we have already seen. remember what states we have already seen.
@ -769,7 +769,7 @@ previously (in that case the passed state is destroyed). The
=spot::state_unicity_table::is_new()= behaves similarly, but returns =spot::state_unicity_table::is_new()= behaves similarly, but returns
=nullptr= for states that already exist. =nullptr= for states that already exist.
With this class, the recursive code can be simplified to this: With this class, the recursive code can be simplified down to this:
#+BEGIN_SRC C++ :results verbatim :exports both #+BEGIN_SRC C++ :results verbatim :exports both
#include <iostream> #include <iostream>