// -*- coding: utf-8 -*- // Copyright (C) 2009, 2011, 2013, 2014 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. // // 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 . #ifndef SPOT_TGBA_TGBA_HH # define SPOT_TGBA_TGBA_HH #include "state.hh" #include "bdddict.hh" #include "succiter.hh" namespace spot { class tgba_succ_iterator; /// \defgroup tgba TGBA (Transition-based Generalized Büchi Automata) /// /// Spot is centered around the spot::tgba type. This type and its /// cousins are listed \ref tgba_essentials "here". This is an /// abstract interface. Its implementations are either \ref /// tgba_representation "concrete representations", or \ref /// tgba_on_the_fly_algorithms "on-the-fly algorithms". Other /// algorithms that work on spot::tgba are \ref tgba_algorithms /// "listed separately". /// \addtogroup tgba_essentials Essential TGBA types /// \ingroup tgba /// \ingroup tgba_essentials /// \brief A Transition-based Generalized Büchi Automaton. /// /// The acronym TGBA (Transition-based Generalized Büchi Automaton) /// was coined by Dimitra Giannakopoulou and Flavio Lerda /// in "From States to Transitions: Improving Translation of LTL /// Formulae to Büchi Automata". (FORTE'02) /// /// TGBAs are transition-based, meanings their labels are put /// on arcs, not on nodes. They use Generalized Büchi acceptance /// conditions: there are several acceptance sets (of /// transitions), and a path can be accepted only if it traverses /// at least one transition of each set infinitely often. /// /// Browsing such automaton can be achieved using two functions: /// \c get_init_state, and \c succ_iter. The former returns /// the initial state while the latter lists the /// successor states of any state. /// /// Note that although this is a transition-based automata, /// we never represent transitions! Transition informations are /// obtained by querying the iterator over the successors of /// a state. class SPOT_API tgba { protected: tgba(); // Any iterator returned via release_iter. mutable tgba_succ_iterator* iter_cache_; public: #ifndef SWIG class succ_iterable { protected: const tgba* aut_; tgba_succ_iterator* it_; public: succ_iterable(const tgba* aut, tgba_succ_iterator* it) : aut_(aut), it_(it) { } succ_iterable(succ_iterable&& other) : aut_(other.aut_), it_(other.it_) { other.it_ = nullptr; } ~succ_iterable() { if (it_) aut_->release_iter(it_); } internal::succ_iterator begin() { return it_->first() ? it_ : nullptr; } internal::succ_iterator end() { return nullptr; } }; #endif virtual ~tgba(); /// \brief Get the initial state of the automaton. /// /// The state has been allocated with \c new. It is the /// responsability of the caller to \c destroy it when no /// longer needed. virtual state* get_init_state() const = 0; /// \brief Get an iterator over the successors of \a local_state. /// /// The iterator has been allocated with \c new. It is the /// responsability of the caller to \c delete it when no /// longer needed. virtual tgba_succ_iterator* succ_iter(const state* local_state) const = 0; #ifndef SWIG /// \brief Build an iterable over the successors of \a s. /// /// This is meant to be used as /// for (auto i: aut->out(s)) { /* i->current_state() */ }. succ_iterable succ(const state* s) const { return {this, succ_iter(s)}; } #endif /// \brief Release an iterator after usage. /// /// This iterator can then be reused by succ_iter() to avoid /// memory allocation. void release_iter(tgba_succ_iterator* i) const { if (iter_cache_) delete i; else iter_cache_ = i; } /// \brief Get a formula that must hold whatever successor is taken. /// /// \return A formula which must be verified for all successors /// of \a state. /// /// This can be as simple as \c bddtrue, or more completely /// the disjunction of the condition of all successors. This /// is used as an hint by \c succ_iter() to reduce the number /// of successor to compute in a product. /// /// Sub classes should implement compute_support_conditions(), /// this function is just a wrapper that will cache the /// last return value for efficiency. bdd support_conditions(const state* state) const; /// \brief Get the dictionary associated to the automaton. /// /// Atomic propositions and acceptance conditions are represented /// as BDDs. The dictionary allows to map BDD variables back to /// formulae, and vice versa. This is useful when dealing with /// several automata (which may use the same BDD variable for /// different formula), or simply when printing. virtual bdd_dict* get_dict() const = 0; /// \brief Format the state as a string for printing. /// /// This formating is the responsability of the automata /// that owns the state. virtual std::string format_state(const state* state) const = 0; /// \brief Return a possible annotation for the transition /// pointed to by the iterator. /// /// You may decide to use annotations when building a tgba class /// that represents the state space of a model, for instance to /// indicate how the tgba transitions relate to the original model /// (e.g. the annotation could be the name of a PetriNet /// transition, or the line number of some textual formalism). /// /// Implementing this method is optional; the default annotation /// is the empty string. /// /// This method is used for instance in dotty_reachable(), /// and replay_tgba_run(). /// /// \param t a non-done tgba_succ_iterator for this automaton virtual std::string transition_annotation(const tgba_succ_iterator* t) const; /// \brief Project a state on an automaton. /// /// This converts \a s, into that corresponding spot::state for \a /// t. This is useful when you have the state of a product, and /// want restrict this state to a specific automata occuring in /// the product. /// /// It goes without saying that \a s and \a t should be compatible /// (i.e., \a s is a state of \a t). /// /// \return 0 if the projection fails (\a s is unrelated to \a t), /// or a new \c state* (the projected state) that must be /// destroyed by the caller. virtual state* project_state(const state* s, const tgba* t) const; /// \brief Return the set of all acceptance conditions used /// by this automaton. /// /// The goal of the emptiness check is to ensure that /// a strongly connected component walks through each /// of these acceptiong conditions. I.e., the union /// of the acceptiong conditions of all transition in /// the SCC should be equal to the result of this function. virtual bdd all_acceptance_conditions() const = 0; /// The number of acceptance conditions. virtual unsigned int number_of_acceptance_conditions() const; /// \brief Return the conjuction of all negated acceptance /// variables. /// /// For instance if the automaton uses variables Acc[a], /// Acc[b] and Acc[c] to describe acceptance sets, /// this function should return !Acc[a]\&!Acc[b]\&!Acc[c]. /// /// This is useful when making products: each operand's condition /// set should be augmented with the neg_acceptance_conditions() of /// the other operand. virtual bdd neg_acceptance_conditions() const = 0; protected: /// Do the actual computation of tgba::support_conditions(). virtual bdd compute_support_conditions(const state* state) const = 0; mutable const state* last_support_conditions_input_; private: mutable bdd last_support_conditions_output_; mutable int num_acc_; }; /// \addtogroup tgba_representation TGBA representations /// \ingroup tgba /// \addtogroup tgba_algorithms TGBA algorithms /// \ingroup tgba /// \addtogroup tgba_on_the_fly_algorithms TGBA on-the-fly algorithms /// \ingroup tgba_algorithms /// \addtogroup tgba_io Input/Output of TGBA /// \ingroup tgba_algorithms /// \addtogroup tgba_ltl Translating LTL formulae into TGBA /// \ingroup tgba_algorithms /// \addtogroup tgba_generic Algorithm patterns /// \ingroup tgba_algorithms /// \addtogroup tgba_reduction TGBA simplifications /// \ingroup tgba_algorithms /// \addtogroup tgba_misc Miscellaneous algorithms on TGBA /// \ingroup tgba_algorithms } #endif // SPOT_TGBA_TGBA_HH