// Copyright (C) 2012, 2013 Laboratoire de Recherche et Developpement // de l'Epita (LRDE). // // This file is part of Spot, a model checking library. // // Spot is free software; you can redistribute it and/or modify it // under the terms of the GNU General Public License as published by // the Free Software Foundation; either version 3 of the License, or // (at your option) any later version. // // Spot is distributed in the hope that it will be useful, but WITHOUT // ANY WARRANTY; without even the implied warranty of MERCHANTABILITY // or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public // License for more details. // // You should have received a copy of the GNU General Public License // along with this program. If not, see . #include "cycles.hh" #include "tgba/tgbaexplicit.hh" #include "ltlast/formula.hh" #include "isweakscc.hh" namespace spot { namespace { // Look for a non-accepting cycle. class weak_checker: public enumerate_cycles { public: bool result; weak_checker(const scc_map& map) : enumerate_cycles(map), result(true) { } virtual bool cycle_found(const state* start) { dfs_stack::const_reverse_iterator i = dfs_.rbegin(); bdd acc = bddfalse; for (;;) { acc |= i->succ->current_acceptance_conditions(); if (i->ts->first == start) break; ++i; // The const cast is here to please old g++ versions. // At least version 4.0 needs it. assert(i != const_cast(dfs_).rend()); } if (acc != aut_->all_acceptance_conditions()) { // We have found an non-accepting cycle, so the SCC is not // weak. result = false; return false; } return true; } }; } bool is_inherently_weak_scc(scc_map& map, unsigned scc) { // If no cycle is accepting, the SCC is weak. if (!map.accepting(scc)) return true; // If the SCC is accepting, but one cycle is not, the SCC is not // weak. weak_checker w(map); w.run(scc); return w.result; } bool is_weak_scc(scc_map& map, unsigned scc) { // If no cycle is accepting, the SCC is weak. if (!map.accepting(scc)) return true; // If all transitions use all acceptance conditions, the SCC is weak. return (map.useful_acc_of(scc) == bdd_support(map.get_aut()->neg_acceptance_conditions())); } bool is_syntactic_weak_scc(scc_map& map, unsigned scc) { const tgba_explicit_formula* aut = dynamic_cast(map.get_aut()); if (!aut) return false; const std::list states = map.states_of(scc); std::list::const_iterator it; for (it = states.begin(); it != states.end(); ++it) { const state_explicit_formula* s = down_cast(*it); assert(s); if (aut->get_label(s)->is_syntactic_persistence()) return true; } return false; } bool is_syntactic_terminal_scc(scc_map& map, unsigned scc) { const tgba_explicit_formula* aut = dynamic_cast(map.get_aut()); if (!aut) return false; const std::list states = map.states_of(scc); std::list::const_iterator it; for (it = states.begin(); it != states.end(); ++it) { const state_explicit_formula* s = down_cast(*it); assert(s); if (aut->get_label(s)->is_syntactic_guarantee()) return true; } return false; } bool is_complete_scc(scc_map& map, unsigned scc) { const spot::tgba *a = map.get_aut(); const std::list states = map.states_of(scc); std::list::const_iterator it; for (it = states.begin(); it != states.end(); ++it) { const state *s = *it; tgba_succ_iterator* it = a->succ_iter(s); it->first(); // If a state has no successors, the SCC is not complete. if (it->done()) { delete it; return false; } // Sum guards on all outgoing transitions. bdd sumall = bddfalse; do { const state *next = it->current_state(); // check it's the same scc if (map.scc_of_state(next) == scc) sumall |= it->current_condition(); next->destroy(); if (sumall == bddtrue) break; it->next(); } while (!it->done()); delete it; if (sumall != bddtrue) return false; } return true; } bool is_terminal_scc(scc_map& map, unsigned scc) { // If all transitions use all acceptance conditions, the SCC is weak. return ((map.useful_acc_of(scc) == bdd_support(map.get_aut()->neg_acceptance_conditions())) && is_complete_scc(map, scc)); } }