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
auto make_nullable_automaton(const Context &ctx)
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)
container_filter_range< Cont, Pred > make_container_filter_range(const Cont &cont, Pred pred)
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
std::shared_ptr< detail::mutable_automaton_impl< Context >> mutable_automaton
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().
mutable_automaton< Context > make_mutable_automaton(const Context &ctx)
An input/output format for valuesets.
Provide a variadic mul on top of a binary mul(), and one().
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.
const labelset_ptr & labelset() const
tr_cont_t succ
Outgoing transitions.
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)
boost::flyweight< std::string, boost::flyweights::no_tracking, boost::flyweights::intermodule_holder > symbol
An internalized string.
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.
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
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)
typename detail::transition_t_of_impl< base_t< ValueSet >>::type transition_t_of
Lightweight transition handle (or index).
Lightweight state handle (or index).
std::ostream & print_state_name(state_t s, std::ostream &o=std::cout, format={}, bool=false) const
typename detail::weightset_t_of_impl< base_t< ValueSet >>::type weightset_t_of
An exponent, or range of exponents.
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.
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.
nullableset_context_t< context< LabelSet, WeightSet > > make_nullableset_context(const context< LabelSet, WeightSet > &ctx)
The nullableset context of a context.
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
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].
Aut transpose(const transpose_automaton< Aut > &aut)
The transpose of a transpose automaton is the original automaton.