Create the cosimulation.

* src/tgbaalgos/simulation.cc: Add the cosimulation:
(acc_compl_automaton) Add a template parameter.
(acc_compl_automaton::process_link) Add a swap source destination.
(direct_simulation) Add a template parameter.
(direct_simulation::compute_sig) Add a flag in the signature to
know if the state is initial.
(direct_simulation::build_result) Remove the flag before reading
the signature.
Swap source and destination when building the new automaton.
* src/tgbaalgos/simulation.hh: Declare and document the
Cosimulation.
* src/tgbatest/ltl2tgba.cc: Associate the cosimulation with the -RRS
option.
* src/tgbatest/spotlbtt.test: Add a test on the cosimulation.
This commit is contained in:
Thomas Badie 2012-08-06 18:57:26 +02:00 committed by Alexandre Duret-Lutz
parent aa230d1f8b
commit 387bace98b
4 changed files with 137 additions and 38 deletions

View file

@ -78,6 +78,13 @@
// bdd_support(sig(X)) - allacc - allclassvar // bdd_support(sig(X)) - allacc - allclassvar
// We have had the Cosimulation by changing the acc_compl_automaton by
// adding a template parameter. If this parameter is set to true, we
// record the transition in the opposite direction (we just swap
// sources and destination). In the build result we are making the
// same thing to rebuild the automaton.
// In the signature,
namespace spot namespace spot
{ {
namespace namespace
@ -93,7 +100,6 @@ namespace spot
state_ptr_hash, state_ptr_hash,
state_ptr_equal> map_state_unsigned; state_ptr_equal> map_state_unsigned;
// Get the list of state for each class. // Get the list of state for each class.
typedef std::map<bdd, std::list<const state*>, typedef std::map<bdd, std::list<const state*>,
bdd_less_than> map_bdd_lstate; bdd_less_than> map_bdd_lstate;
@ -101,6 +107,7 @@ namespace spot
// This class takes an automaton and creates a copy with all // This class takes an automaton and creates a copy with all
// acceptance conditions complemented. // acceptance conditions complemented.
template <bool Cosimulation>
class acc_compl_automaton: class acc_compl_automaton:
public tgba_reachable_iterator_depth_first public tgba_reachable_iterator_depth_first
{ {
@ -139,6 +146,15 @@ namespace spot
int src = get_state(in_s); int src = get_state(in_s);
int dst = get_state(out_s); int dst = get_state(out_s);
// In the case of the cosimulation, we want to have all the
// ingoing transition, and to keep the rest of the code
// similar, we just create equivalent transition in the other
// direction. Since we do not have to run through the
// automaton to get the signature, this is correct.
if (Cosimulation)
std::swap(src, dst);
bdd acc = ac_.complement(si->current_acceptance_conditions()); bdd acc = ac_.complement(si->current_acceptance_conditions());
tgba_explicit_number::transition* t tgba_explicit_number::transition* t
@ -170,7 +186,7 @@ namespace spot
state* init_; state* init_;
}; };
template <bool Cosimulation>
class direct_simulation class direct_simulation
{ {
// Shortcut used in update_po and go_to_next_it. // Shortcut used in update_po and go_to_next_it.
@ -181,7 +197,7 @@ namespace spot
po_size_(0), po_size_(0),
all_class_var_(bddtrue) all_class_var_(bddtrue)
{ {
acc_compl_automaton acc_compl_automaton<Cosimulation>
acc_compl(t); acc_compl(t);
// We'll start our work by replacing all the acceptance // We'll start our work by replacing all the acceptance
@ -190,6 +206,8 @@ namespace spot
a_ = acc_compl.out_; a_ = acc_compl.out_;
initial_state = a_->get_init_state();
// We use the previous run to know the size of the // We use the previous run to know the size of the
// automaton, and to class all the reachable states in the // automaton, and to class all the reachable states in the
// map previous_class_. // map previous_class_.
@ -199,11 +217,10 @@ namespace spot
// class. We register one bdd by state, because in the worst // class. We register one bdd by state, because in the worst
// case, |Class| == |State|. // case, |Class| == |State|.
unsigned set_num = a_->get_dict() unsigned set_num = a_->get_dict()
->register_anonymous_variables(size_a_, a_); ->register_anonymous_variables(size_a_ + 1, a_);
bdd init = bdd_ithvar(set_num);
// Because we have already take the first element which is init. bdd_initial = bdd_ithvar(set_num++);
++set_num; bdd init = bdd_ithvar(set_num++);
used_var_.push_back(init); used_var_.push_back(init);
all_class_var_ = init; all_class_var_ = init;
@ -258,12 +275,12 @@ namespace spot
it_s != it->second.end(); it_s != it->second.end();
++it_s) ++it_s)
{ {
// If the signature of a state is bddfalse (which is // If the signature of a state is bddfalse (no
// roughly equivalent to no transition) the class of // transitions) the class of this state is bddfalse
// this state is bddfalse instead of an anonymous // instead of an anonymous variable. It allows
// variable. It allows simplifications in the signature // simplifications in the signature by removing a
// by removing a transition which has as a destination a // transition which has as a destination a state with
// state with no outgoing transition. // no outgoing transition.
if (it->first == bddfalse) if (it->first == bddfalse)
previous_class_[*it_s] = bddfalse; previous_class_[*it_s] = bddfalse;
else else
@ -297,10 +314,10 @@ namespace spot
// Take a state and compute its signature. // Take a state and compute its signature.
bdd compute_sig(const state* src) bdd compute_sig(const state* src)
{ {
tgba_succ_iterator* sit = a_->succ_iter(src); tgba_succ_iterator* sit = a_->succ_iter(src);
bdd res = bddfalse; bdd res = bddfalse;
for (sit->first(); !sit->done(); sit->next()) for (sit->first(); !sit->done(); sit->next())
{ {
const state* dst = sit->current_state(); const state* dst = sit->current_state();
bdd acc = sit->current_acceptance_conditions(); bdd acc = sit->current_acceptance_conditions();
@ -315,10 +332,16 @@ namespace spot
dst->destroy(); dst->destroy();
} }
delete sit; // When we Cosimulate, we add a special flag to differentiate
return res; // initial state.
if (Cosimulation && initial_state == src)
res |= bdd_initial;
delete sit;
return res;
} }
void update_sig() void update_sig()
{ {
// At this time, current_class_ must be empty. It implies // At this time, current_class_ must be empty. It implies
@ -402,21 +425,20 @@ namespace spot
++it1) ++it1)
{ {
bdd accu = it1->second; bdd accu = it1->second;
for (map_bdd_bdd::const_iterator it2 = now_to_next.begin(); for (map_bdd_bdd::const_iterator it2 = now_to_next.begin();
it2 != now_to_next.end(); it2 != now_to_next.end();
++it2) ++it2)
{ {
// Skip the case managed by the initialization of accu. // Skip the case managed by the initialization of accu.
if (it1 == it2) if (it1 == it2)
continue; continue;
if (bdd_implies(it1->first, it2->first)) if (bdd_implies(it1->first, it2->first))
{ {
accu &= it2->second; accu &= it2->second;
++po_size_; ++po_size_;
} }
} }
relation_[it1->second] = accu; relation_[it1->second] = accu;
} }
} }
@ -476,6 +498,9 @@ namespace spot
// Get the signature. // Get the signature.
bdd sig = compute_sig(*(it->second.begin())); bdd sig = compute_sig(*(it->second.begin()));
if (Cosimulation)
sig = bdd_compose(sig, bddfalse, bdd_var(bdd_initial));
// Get all the variable in the signature. // Get all the variable in the signature.
bdd sup_sig = bdd_support(sig); bdd sup_sig = bdd_support(sig);
@ -495,7 +520,6 @@ namespace spot
bddtrue); bddtrue);
all_atomic_prop -= one; all_atomic_prop -= one;
// For each possible valuation, iterator over all possible // For each possible valuation, iterator over all possible
// destination classes. We use minato_isop here, because // destination classes. We use minato_isop here, because
// if the same valuation of atomic properties can go // if the same valuation of atomic properties can go
@ -533,6 +557,9 @@ namespace spot
int src = bdd2state[previous_class_[*it->second.begin()]]; int src = bdd2state[previous_class_[*it->second.begin()]];
int dst = bdd2state[dest]; int dst = bdd2state[dest];
if (Cosimulation)
std::swap(src, dst);
// src or dst == 0 means "dest" or "prev..." isn't // src or dst == 0 means "dest" or "prev..." isn't
// in the map. so it is a bug. // in the map. so it is a bug.
assert(src != 0); assert(src != 0);
@ -550,7 +577,9 @@ namespace spot
res->set_init_state(bdd2state[previous_class_ res->set_init_state(bdd2state[previous_class_
[a_->get_init_state()]]); [a_->get_init_state()]]);
res->merge_transitions(); res->merge_transitions();
return res; return res;
} }
@ -629,13 +658,29 @@ namespace spot
// All the class variable: // All the class variable:
bdd all_class_var_; bdd all_class_var_;
// The flag to say if the outgoing state is initial or not
bdd bdd_initial;
// Initial state of the automaton we are working on
state* initial_state;
}; };
} // End namespace anonymous. } // End namespace anonymous.
tgba* tgba*
simulation(const tgba* t) simulation(const tgba* t)
{ {
direct_simulation simul(t); direct_simulation<false> simul(t);
return simul.run();
}
tgba*
cosimulation(const tgba* t)
{
direct_simulation<true> simul(t);
return simul.run(); return simul.run();
} }

View file

@ -30,12 +30,11 @@ namespace spot
/// \addtogroup tgba_reduction /// \addtogroup tgba_reduction
/// @{ /// @{
/// \brief Attempt to reduce the automaton by direct simulation /// \brief Attempt to reduce the automaton by direct simulation When
/// /// the suffixes (letter and acceptance conditions) seen by one
/// When the language recognized by one state is included in the /// state is included in the suffixes seen by another one, the first
/// language recognized by an another one, the first one is merged /// one is merged with the second. The algorithm is based on the
/// with the second. The algorithm is based on the following /// following paper, but generalized to handle TGBA directly.
/// paper, but generalized to handle TGBA directly.
/// ///
/// \verbatim /// \verbatim
/// @InProceedings{ etessami.00.concur, /// @InProceedings{ etessami.00.concur,
@ -58,6 +57,34 @@ namespace spot
/// one /// one
tgba* simulation(const tgba* automaton); tgba* simulation(const tgba* automaton);
/// \brief Attempt to reduce the automaton by direct cosimulation.
/// When the prefixes (letter and acceptance conditions) seen by one
/// state is included in the prefixes seen by another one, the first
/// one is merged with the second. The algorithm is based on the
/// following paper, but generalized to handle TGBA directly.
/// \verbatim
/// @InProceedings{Somenzi:2000:EBA:647769.734097,
/// author = {Somenzi, Fabio and Bloem, Roderick},
/// title = {Efficient {B\"u}chi Automata from LTL Formulae},
/// booktitle = {Proceedings of the 12th International
/// Conference on Computer Aided Verification},
/// series = {CAV '00},
/// year = {2000},
/// isbn = {3-540-67770-4},
/// pages = {248--263},
/// numpages = {16},
/// url = {http://dl.acm.org/citation.cfm?id=647769.734097},
/// acmid = {734097},
/// publisher = {Springer-Verlag},
/// address = {London, UK, UK},
/// }
/// \endverbatim
/// \param automaton the automaton to simulate.
/// \return a new automaton which is at worst a copy of the received
/// one
tgba* cosimulation(const tgba* automaton);
/// @} /// @}
} // End namespace spot. } // End namespace spot.

View file

@ -204,6 +204,8 @@ syntax(char* prog)
<< std::endl << std::endl
<< " -RDS minimize the automaton with direct simulation" << " -RDS minimize the automaton with direct simulation"
<< std::endl << std::endl
<< " -RRS minimize the automaton with reverse simulation"
<< std::endl
<< " -Rm attempt to WDBA-minimize the automata" << std::endl << " -Rm attempt to WDBA-minimize the automata" << std::endl
<< std::endl << std::endl
@ -352,13 +354,14 @@ main(int argc, char** argv)
bool use_timer = false; bool use_timer = false;
bool assume_sba = false; bool assume_sba = false;
bool reduction_dir_sim = false; bool reduction_dir_sim = false;
bool reduction_rev_sim = false;
spot::tgba* temp_dir_sim = 0; spot::tgba* temp_dir_sim = 0;
bool ta_opt = false; bool ta_opt = false;
bool tgta_opt = false; bool tgta_opt = false;
bool opt_with_artificial_initial_state = true; bool opt_with_artificial_initial_state = true;
bool opt_single_pass_emptiness_check = false; bool opt_single_pass_emptiness_check = false;
bool opt_with_artificial_livelock = false; bool opt_with_artificial_livelock = false;
spot::tgba* temp_rev_sim = 0;
for (;;) for (;;)
{ {
@ -631,6 +634,10 @@ main(int argc, char** argv)
// equal to -RDS. // equal to -RDS.
reduction_dir_sim = true; reduction_dir_sim = true;
} }
else if (!strcmp(argv[formula_index], "-RRS"))
{
reduction_rev_sim = true;
}
else if (!strcmp(argv[formula_index], "-R3")) else if (!strcmp(argv[formula_index], "-R3"))
{ {
scc_filter = true; scc_filter = true;
@ -1031,11 +1038,21 @@ main(int argc, char** argv)
a = minimized; a = minimized;
// When the minimization succeed, simulation is useless. // When the minimization succeed, simulation is useless.
reduction_dir_sim = false; reduction_dir_sim = false;
reduction_rev_sim = false;
assume_sba = true; assume_sba = true;
} }
} }
if (reduction_rev_sim)
{
tm.start("Reduction w/ reverse simulation");
temp_rev_sim = spot::cosimulation(a);
a = temp_rev_sim;
tm.stop("Reduction w/ reverse simulation");
assume_sba = false;
}
if (reduction_dir_sim) if (reduction_dir_sim)
{ {
tm.start("Reduction w/ direct simulation"); tm.start("Reduction w/ direct simulation");
@ -1505,6 +1522,7 @@ main(int argc, char** argv)
delete to_free; delete to_free;
delete echeck_inst; delete echeck_inst;
delete temp_dir_sim; delete temp_dir_sim;
delete temp_rev_sim;
} }
else else
{ {

View file

@ -199,6 +199,15 @@ Algorithm
Enabled = yes Enabled = yes
} }
Algorithm
{
Name = "Spot (Couvreur -- FM), cosimulated"
Path = "${LBTT_TRANSLATE}"
Parameters = "--spot '../ltl2tgba -F -f -t -RRS -r4 -R3'"
Enabled = yes
}
Algorithm Algorithm
{ {
Name = "Spot (Couvreur -- LaCim), simulated" Name = "Spot (Couvreur -- LaCim), simulated"