// -*- coding: utf-8 -*- // Copyright (C) 2015, 2016, 2020 Laboratoire de Recherche // et Développement 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 . #pragma once #include #include #include #include #include #include #include namespace spot { /// \brief Class for thread-safe states. class SPOT_API cstate { public: cstate() = default; cstate(const cstate& s) = delete; cstate(cstate&& s) noexcept; cstate(unsigned id); ~cstate() = default; unsigned label(); private: unsigned id_; }; /// \brief Class for representing a transition. class SPOT_API transition { public: transition() = default; transition(const transition& t) = delete; transition(transition&& t) noexcept; transition(const cube& cube, acc_cond::mark_t acc); ~transition() = default; cube cube_; acc_cond::mark_t acc_; }; /// \brief Class for iterators over transitions class SPOT_API trans_index final: public std::enable_shared_from_this { public: typedef digraph graph_t; typedef graph_t::edge_storage_t edge_storage_t; trans_index(trans_index& ci) = delete; trans_index(unsigned state, const graph_t& g): st_(g.state_storage(state)) { reset(); } trans_index(trans_index&& ci): idx_(ci.idx_), st_(ci.st_) { } /// Reset the iterator on the first element. inline void reset() { idx_ = st_.succ; } /// \brief Iterate over the next transition. inline void next() { ++idx_; } /// \brief Returns a boolean indicating wether all the transitions /// have been iterated. inline bool done() const { return !idx_ || idx_ > st_.succ_tail; } /// \brief Returns the current transition according to a specific /// \a seed. The \a seed is traditionnally the thread identifier. inline unsigned current(unsigned seed = 0) const { // no-swarming : since twacube are dedicated for parallelism, i.e. // swarming, we expect swarming is activated. if (SPOT_UNLIKELY(!seed)) return idx_; // Here swarming performs a technique called "primitive // root modulo n", i. e. for i in [1..n]: i*seed (mod n). We // also must have seed prime with n: to solve this, we use // precomputed primes and seed access one of this primes. Note // that the chosen prime must be greater than n. SPOT_ASSERT(primes[seed] > (st_.succ_tail-st_.succ+1)); unsigned long long c = (idx_-st_.succ) + 1; unsigned long long p = primes[seed]; unsigned long long s = (st_.succ_tail-st_.succ+1); return (unsigned) (((c*p) % s)+st_.succ); } private: unsigned idx_; ///< The current transition const graph_t::state_storage_t& st_; ///< The underlying states }; /// \brief Class for representing a thread-safe twa. class SPOT_API twacube final: public std::enable_shared_from_this { public: twacube() = delete; /// \brief Build a new automaton from a list of atomic propositions. twacube(const std::vector aps); virtual ~twacube(); /// \brief Returns the acceptance condition associated to the automaton. const acc_cond& acc() const; acc_cond& acc(); /// \brief Returns the names of the atomic properties. std::vector ap() const; /// \brief This method creates a new state. unsigned new_state(); /// \brief Updates the initial state to \a init void set_initial(unsigned init); /// \brief Returns the id of the initial state in the automaton. unsigned get_initial() const; /// \brief Accessor for a state from its id. cstate* state_from_int(unsigned i); /// \brief create a transition between state \a src and state \a dst, /// using \a cube as the labelling cube and \a mark as the acceptance mark. void create_transition(unsigned src, const cube& cube, const acc_cond::mark_t& mark, unsigned dst); /// \brief Accessor the cube's manipulator. const cubeset& get_cubeset() const; /// \brief Check if all the successors of a state are located contigously /// in memory. This is mandatory for swarming techniques. bool succ_contiguous() const; unsigned num_states() const { return theg_.num_states(); } unsigned num_edges() const { return theg_.num_edges(); } typedef digraph graph_t; /// \brief Returns the underlying graph for this automaton. const graph_t& get_graph() { return theg_; } typedef graph_t::edge_storage_t edge_storage_t; /// \brief Returns the storage associated to a transition. const graph_t::edge_storage_t& trans_storage(std::shared_ptr ci, unsigned seed = 0) const { return theg_.edge_storage(ci->current(seed)); } /// \brief Returns the data associated to a transition. const transition& trans_data(std::shared_ptr ci, unsigned seed = 0) const { return theg_.edge_data(ci->current(seed)); } ///< \brief Returns the successor of state \a i. std::shared_ptr succ(unsigned i) const { return std::make_shared(i, theg_); } friend SPOT_API std::ostream& operator<<(std::ostream& os, const twacube& twa); private: unsigned init_; ///< The Id of the initial state acc_cond acc_; ///< The acceptance contidion const std::vector aps_; ///< The name of atomic propositions graph_t theg_; ///< The underlying graph cubeset cubeset_; ///< Ease the cube manipulation }; inline twacube_ptr make_twacube(const std::vector aps) { return std::make_shared(aps); } }