7 #include <boost/range/algorithm/find.hpp> 
    8 #include <boost/range/algorithm/find_if.hpp> 
    9 #include <boost/range/irange.hpp> 
   27   template <
typename Context>
 
   28   class mutable_automaton_impl
 
   35     template <
typename Ctx = Context>
 
   39     using kind_t = 
typename context_t::kind_t;
 
   51     using label_t = 
typename labelset_t::value_t;
 
   53     using weight_t = 
typename weightset_t::value_t;
 
  102       , prepost_label_(that.prepost_label_)
 
  104       *
this = std::move(that);
 
  111           ctx_ = std::move(that.ctx_);
 
  112           prepost_label_ = std::move(that.prepost_label_);
 
  113           std::swap(states_, that.states_);
 
  114           std::swap(states_fs_, that.states_fs_);
 
  115           std::swap(transitions_, that.transitions_);
 
  116           std::swap(transitions_fs_, that.transitions_fs_);
 
  135       o << 
"mutable_automaton<";
 
  140     const context_t& context() const { return ctx_; } 
  141     const weightset_ptr& weightset() const { return ctx_.weightset(); } 
  142     const labelset_ptr& labelset() const { return ctx_.labelset(); } 
  145     /*----------------------------------. 
  146     | Special states and transitions.   | 
  147     `----------------------------------*/ 
  149     // pseudo-initial and final states. 
  150     // The code below assumes that pre() and post() are the first 
  151     // two states of the automaton.  In other words, all other states 
  152     // have greater numbers.  We also assume that pre()<post(). 
  153     static constexpr state_t      pre()  { return 0U; } 
  154     static constexpr state_t      post()  { return 1U; } 
  156     static constexpr state_t      null_state()      { return -1U; } 
  158     static constexpr transition_t null_transition() { return -1U; } 
  161     static constexpr transition_t lazy_transition() { return -2U; } 
  164     label_t prepost_label() const 
  166       return prepost_label_; 
  174     size_t num_all_states() const { return states_.size() - states_fs_.size(); } 
  175     size_t num_states() const { return num_all_states() - 2; } 
  176     size_t num_initials() const { return states_[pre()].succ.size(); } 
  177     size_t num_finals() const { return states_[post()].pred.size(); } 
  178     size_t num_transitions() const 
  180       return (transitions_.size() 
  181               - transitions_fs_.size() - num_initials() - num_finals()); 
  185     /*---------------------. 
  186     | Queries on states.   | 
  187     `---------------------*/ 
  191     has_state(state_t s) const 
  193       // Any number outside our container is not a state. 
  194       // (This includes "null_state()".) 
  195       if (states_.size() <= s) 
  199           const stored_state_t& ss = states_[s]; 
  200           // Erased states have 'invalid
' as their first successor. 
  201           return ss.succ.empty() || ss.succ.front() != null_transition(); 
  208     is_lazy(state_t s) const 
  210       auto ts = all_out(s); 
  211       return !ts.empty() && ts.front() == lazy_transition(); 
  217     is_lazy_in(state_t s) const 
  220       return !ts.empty() && ts.front() == lazy_transition(); 
  225     is_initial(state_t s) const 
  227       return has_transition(pre(), s, prepost_label_); 
  232     is_final(state_t s) const 
  234       return has_transition(s, post(), prepost_label_); 
  240     get_initial_weight(state_t s) const 
  242       transition_t t = get_transition(pre(), s, prepost_label_); 
  243       if (t == null_transition()) 
  244         return weightset()->zero(); 
  252     get_final_weight(state_t s) const 
  254       transition_t t = get_transition(s, post(), prepost_label_); 
  255       if (t == null_transition()) 
  256         return weightset()->zero(); 
  262     /*--------------------------. 
  263     | Queries on transitions.   | 
  264     `--------------------------*/ 
  267     get_transition(state_t src, state_t dst, label_t l) const 
  269       assert(has_state(src)); 
  270       assert(!is_lazy(src)); 
  271       assert(has_state(dst)); 
  272       assert(!is_lazy_in(dst)); 
  273       const tr_cont_t& succ = states_[src].succ; 
  274       const tr_cont_t& pred = states_[dst].pred; 
  275       const auto& ls = *this->labelset(); 
  276       if (succ.size() <= pred.size()) 
  280                            [this,l,ls,dst] (transition_t t) 
  282                              return (dst_of(t) == dst 
  283                                      && ls.equal(label_of(t), l)); 
  292                            [this,l,ls,src] (transition_t t) 
  294                              return (src_of(t) == src 
  295                                      && ls.equal(label_of(t), l)); 
  300       return null_transition(); 
  304     has_transition(state_t src, state_t dst, label_t l) const 
  306       return get_transition(src, dst, l) != null_transition(); 
  310     has_transition(transition_t t) const 
  312       // Any number outside our container is not a transition. 
  313       // (This includes "null_transition()".) 
  314       if (t >= transitions_.size()) 
  317       // Erased transition have invalid source state. 
  318       return transitions_[t].src != null_state(); 
  321     state_t src_of(transition_t t) const   { return transitions_[t].src; } 
  322     state_t dst_of(transition_t t) const   { return transitions_[t].dst; } 
  323     label_t label_of(transition_t t) const 
  325       return transitions_[t].get_label(); 
  328     weight_t weight_of(transition_t t) const 
  330       return transitions_[t].get_weight(); 
  334     /*---------------------. 
  335     | Edition of states.   | 
  336     `---------------------*/ 
  341     del_transition_from_src(transition_t t) 
  343       stored_transition_t& st = transitions_[t]; 
  344       auto& succ = states_[st.src].succ; 
  345       auto tsucc = boost::range::find(succ, t); 
  346       assert(tsucc != succ.end()); 
  347       *tsucc = std::move(succ.back()); 
  353     del_transition_from_dst(transition_t t) 
  355       stored_transition_t& st = transitions_[t]; 
  356       auto& pred = states_[st.dst].pred; 
  357       auto tpred = boost::range::find(pred, t); 
  358       assert(tpred != pred.end()); 
  359       *tpred = std::move(pred.back()); 
  364     del_transition_container(tr_cont_t& tc, bool from_succ) 
  369             del_transition_from_dst(t); 
  371             del_transition_from_src(t); 
  372           transitions_[t].src = null_state(); 
  374       transitions_fs_.insert(transitions_fs_.end(), tc.begin(), tc.end()); 
  384       if (states_fs_.empty()) 
  386           res = states_.size(); 
  387           states_.emplace_back(); 
  391           res = states_fs_.back(); 
  392           states_fs_.pop_back(); 
  393           stored_state_t& ss = states_[res]; 
  394           // De-invalidate this state: remove the invalid transition. 
  401     print_state(state_t s, std::ostream& o = std::cout) const 
  405       else if (s == post()) 
  413     print_state_name(state_t s, std::ostream& o = std::cout, 
  417       return print_state(s, o); 
  420     static constexpr bool 
  421     state_has_name(state_t) 
  429       assert(has_state(s)); 
  430       assert(s > post()); // Cannot erase pre() and post(). 
  431       stored_state_t& ss = states_[s]; 
  432       del_transition_container(ss.pred, false); 
  433       del_transition_container(ss.succ, true); 
  434       ss.succ.emplace_back(null_transition()); // So has_state() can work. 
  435       states_fs_.emplace_back(s); 
  439     set_initial(state_t s, weight_t w) 
  441       set_transition(pre(), s, prepost_label_, w); 
  445     set_initial(state_t s) 
  447       set_initial(s, weightset()->one()); 
  451     set_lazy(state_t s, bool lazy = true) 
  453       assert(has_state(s)); 
  454       stored_state_t& ss = states_[s]; 
  455       assert(ss.succ.empty() 
  456              || ss.succ.front() == lazy_transition()); 
  459         ss.succ.emplace_back(lazy_transition()); 
  463     set_lazy_in(state_t s, bool lazy = true) 
  465       assert(has_state(s)); 
  466       stored_state_t& ss = states_[s]; 
  467       assert(ss.pred.empty() 
  468              || ss.pred.front() == lazy_transition()); 
  471         ss.pred.emplace_back(lazy_transition()); 
  475     add_initial(state_t s, weight_t w) 
  477       return add_transition(pre(), s, prepost_label_, w); 
  481     unset_initial(state_t s) 
  483       set_initial(s, weightset()->zero()); 
  487     set_final(state_t s, weight_t w) 
  489       set_transition(s, post(), prepost_label_, w); 
  495       set_final(s, weightset()->one()); 
  499     add_final(state_t s, weight_t w) 
  501       return add_transition(s, post(), prepost_label_, w); 
  505     unset_final(state_t s) 
  507       set_final(s, weightset()->zero()); 
  511     /*--------------------------. 
  512     | Edition of transitions.   | 
  513     `--------------------------*/ 
  516     del_transition(transition_t t) 
  518       assert(has_transition(t)); 
  519       // Remove transition from source and destination. 
  520       del_transition_from_src(t); 
  521       del_transition_from_dst(t); 
  522       // Actually erase the transition. 
  523       transitions_[t].src = null_state(); 
  524       transitions_fs_.emplace_back(t); 
  529     del_transition(state_t src, state_t dst, label_t l) 
  531       transition_t t = get_transition(src, dst, l); 
  532       if (t != null_transition()) 
  547     new_transition(state_t src, state_t dst, label_t l, weight_t w) 
  549       assert(!has_transition(src, dst, l)); 
  550       if (weightset()->is_zero(w)) 
  551         return null_transition(); 
  554           // FIXME: When src == pre() || dst == post(), label must be empty. 
  556           if (transitions_fs_.empty()) 
  558               t = transitions_.size(); 
  559               transitions_.emplace_back(src, dst, l, w); 
  563               t = transitions_fs_.back(); 
  564               transitions_fs_.pop_back(); 
  565               stored_transition_t& st = transitions_[t]; 
  571           states_[src].succ.emplace_back(t); 
  572           states_[dst].pred.emplace_back(t); 
  589     template <Automaton A> 
  591     new_transition_copy(state_t src, state_t dst, 
  592                         const A& aut, transition_t_of<A> t, 
  593                         bool transpose = false) 
  595       auto l = aut->label_of(t); 
  596       auto w = aut->weight_of(t); 
  599           l = aut->labelset()->transpose(l); 
  600           w = aut->weightset()->transpose(w); 
  602       return new_transition(src, dst, 
  603                             labelset()->conv(*aut->labelset(), l), 
  604                             weightset()->conv(*aut->weightset(), w)); 
  609     new_transition(state_t src, state_t dst, label_t l) 
  611       return new_transition(src, dst, l, weightset()->one()); 
  625     set_transition(state_t src, state_t dst, label_t l, weight_t w) 
  631       assert(src != 
post());
 
  633       assert(dst != 
pre());
 
  698     template <Automaton A>
 
  704       auto l = aut->label_of(t);
 
  705       auto w = aut->weight_of(t);
 
  708           l = aut->labelset()->transpose(l);
 
  709           w = aut->weightset()->transpose(w);
 
  713                             weightset()->conv(*aut->weightset(), w));
 
  721         o << 
"null_transition";
 
  723         o << 
"lazy_transition";
 
  736     std::ostream& 
print(std::ostream& o = std::cout)
 const 
  767         transitions_[t].set_weight(w);
 
  797     template <
typename Pred>
 
  801         (boost::irange<state_t>(b, e),
 
  806            return ((ss.
succ.empty()
 
  828     template <
typename Pred>
 
  845         (boost::irange<transition_t>(0U, transitions_.size()),
 
  858       return states_[s].succ;
 
  867       return states_[s].pred;
 
  872   template <
typename Context>
 
  873   mutable_automaton<Context>
 
  876     return make_shared_ptr<mutable_automaton<Context>>(
ctx);
 
  879   template <
typename Context>
 
const context_t & context() const 
 
index_t_impl< transition_tag > transition_t
 
tr_cont_t pred
Incoming transitions. 
 
transition_t set_weight(transition_t t, weight_t w)
 
transition_t add_transition_copy(state_t src, state_t dst, const A &aut, transition_t_of< A > t, bool transpose=false)
Add a transition between two states, copying the label from the given transition. ...
 
mutable_automaton_impl()=delete
 
mutable_automaton_impl(const context_t &ctx)
 
auto make_nullable_automaton(const Context &ctx)
 
bool has_state(state_t s) const 
Whether state s belongs to the automaton. 
 
std::ostream & print(transition_t t, std::ostream &o=std::cout, format fmt={}) const 
Print a transition, for debugging. 
 
state_t src_of(transition_t t) const 
 
label_t label_of(transition_t t) const 
 
typename weightset_t::value_t weight_t
Transition weight. 
 
labelset_t_of< context_t > labelset_t
 
typename context_t::kind_t kind_t
 
static constexpr state_t null_state()
Invalid state. 
 
container_range< const tr_cont_t & > all_in(state_t s) const 
Indexes of all transitions arriving to state s. 
 
typename context_t::labelset_ptr labelset_ptr
 
weight_t rweight(transition_t t, weight_t w)
 
weight_t lweight(transition_t t, weight_t w)
 
Lightweight state/transition handle (or index). 
 
static constexpr state_t pre()
 
auto all_states() const 
All states including pre()/post(). 
 
An input/output format for valuesets. 
 
Restrict the interface of a container to begin/end. 
 
transition_t new_transition(state_t src, state_t dst, label_t l, weight_t w)
Create a transition between two states. 
 
typename detail::transition_t_of_impl< base_t< ValueSet >>::type transition_t_of
 
const labelset_ptr & labelset() const 
 
tr_cont_t succ
Outgoing transitions. 
 
boost::flyweight< std::string, boost::flyweights::no_tracking, boost::flyweights::intermodule_holder > symbol
An internalized string. 
 
container_range< const tr_cont_t & > all_out(state_t s) const 
Indexes of all transitions leaving state s. 
 
void del_transition(transition_t t)
 
typename detail::labelset_t_of_impl< base_t< ValueSet >>::type labelset_t_of
 
Transition with label and non Boolean weight. 
 
static constexpr transition_t lazy_transition()
Invalid transition that shows that the state's outgoing transitions are unknown. 
 
auto all_states(Pred pred) const 
All states including pre()/post() that validate pred. 
 
mutable_automaton< Ctx > fresh_automaton_t
The (shared pointer) type to use if we have to create an automaton of the same (underlying) type...
 
free_store_t states_fs_
Free indexes in states_. 
 
typename labelset_t::value_t label_t
Transition label. 
 
nullableset_context_t< context< LabelSet, WeightSet > > make_nullableset_context(const context< LabelSet, WeightSet > &ctx)
The nullableset context of a context. 
 
std::vector< stored_transition_t > tr_store_t
All the automaton's transitions. 
 
std::vector< unsigned > free_store_t
A list of unused indexes in the states/transitions tables. 
 
typename context_t::weightset_ptr weightset_ptr
 
typename detail::weightset_t_of_impl< base_t< ValueSet >>::type weightset_t_of
 
weight_t weight_of(transition_t t) const 
 
const weightset_ptr & weightset() const 
 
free_store_t transitions_fs_
Free indexes in transitions_. 
 
context_t ctx_
The algebraic type of this automaton. 
 
auto states() const 
All states excluding pre()/post(). 
 
transition_t set_transition(state_t src, state_t dst, label_t l)
Same as above, with unit weight. 
 
std::ostream & print(std::ostream &o=std::cout) const 
Print an automaton, for debugging. 
 
std::vector< transition_t > tr_cont_t
All the incoming/outgoing transition handles of a state. 
 
transition_t add_transition(state_t src, state_t dst, label_t l, weight_t w)
Add a transition between two states. 
 
transition_t set_transition(state_t src, state_t dst, label_t l, weight_t w)
Set a transition between two states. 
 
auto all_transitions() const 
All the transition indexes between all states (including pre and post). 
 
transition_t add_transition(state_t src, state_t dst, label_t l)
Same as above, with weight one. 
 
weight_t add_weight(transition_t t, weight_t w)
 
Aut transpose(const transpose_automaton< Aut > &aut)
The transpose of a transpose automaton is the original automaton. 
 
mutable_automaton< Context > make_mutable_automaton(const Context &ctx)
 
auto conv(const ValueSet &vs, const std::string &str, Args &&...args) -> decltype(vs.conv(std::declval< std::istream & >(),                                                                                           std::forward< Args >(args)...))
Parse str via vs.conv. 
 
Lightweight transition handle (or index). 
 
Lightweight state handle (or index). 
 
std::shared_ptr< detail::mutable_automaton_impl< Context >> mutable_automaton
 
std::ostream & print_state_name(state_t s, std::ostream &o=std::cout, format={}, bool=false) const 
 
An exponent, or range of exponents. 
 
state_t dst_of(transition_t t) const 
 
mutable_automaton_impl & operator=(mutable_automaton_impl &&that)
 
weightset_t_of< context_t > weightset_t
 
auto state_range(state_t b, state_t e, Pred pred) const 
The range of index numbers in [b . 
 
Data stored for each state. 
 
std::vector< stored_state_t > st_store_t
All the automaton's states. 
 
label_t prepost_label_
Label for initial and final transitions. 
 
transition_tuple< state_t, label_t, weight_t > stored_transition_t
Data stored per transition. 
 
mutable_automaton_impl(mutable_automaton_impl &&that)
 
transition_t get_transition(state_t src, state_t dst, label_t l) const 
 
std::ostream & print_set(std::ostream &o=std::cout, format fmt={}) const 
 
container_filter_range< Cont, Pred > make_container_filter_range(const Cont &cont, Pred pred)
 
static constexpr state_t post()
 
static constexpr transition_t null_transition()
Invalid transition. 
 
auto state_range(state_t b, state_t e) const 
The range of state numbers in [b .. e]. 
 
Provide a variadic mul on top of a binary mul(), and one().