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_);
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 return set_transition(pre(), s, prepost_label_, w); 445 set_initial(state_t s) 447 return 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 return set_transition(s, post(), prepost_label_, w); 495 return 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>
876 return make_shared_ptr<mutable_automaton<Context>>(
ctx);
879 template <
typename Context>
std::shared_ptr< detail::mutable_automaton_impl< Context > > mutable_automaton
Aut transpose(const transpose_automaton< Aut > &aut)
The transpose of a transpose automaton is the original automaton.
Lightweight state/transition handle (or index).
typename context_t::kind_t kind_t
typename detail::weightset_t_of_impl< base_t< ValueSet > >::type weightset_t_of
state_t dst_of(transition_t t) const
static constexpr state_t null_state()
Invalid state.
mutable_automaton< Ctx > fresh_automaton_t
The (shared pointer) type to use if we have to create an automaton of the same (underlying) type...
container_filter_range< Cont, Pred > make_container_filter_range(const Cont &cont, Pred pred)
void del_transition(transition_t t)
auto state_range(state_t b, state_t e, Pred pred) const
The range of index numbers in [b .
typename detail::transition_t_of_impl< base_t< ValueSet > >::type transition_t_of
mutable_automaton_impl & operator=(mutable_automaton_impl &&that)
transition_t set_transition(state_t src, state_t dst, label_t l, weight_t w)
Set a transition between two states.
const labelset_ptr & labelset() const
static constexpr state_t pre()
container_range< const tr_cont_t & > all_out(state_t s) const
Indexes of all transitions leaving state s.
bool has_state(state_t s) const
Whether state s belongs to the automaton.
free_store_t states_fs_
Free indexes in states_.
nullableset_context_t< context< LabelSet, WeightSet > > make_nullableset_context(const context< LabelSet, WeightSet > &ctx)
The nullableset context of a context.
std::ostream & print_state_name(state_t s, std::ostream &o=std::cout, format={}, bool=false) const
free_store_t transitions_fs_
Free indexes in transitions_.
const weightset_ptr & weightset() const
void set_label(label_t &l)
state_t src_of(transition_t t) const
Lightweight transition handle (or index).
boost::flyweight< std::string, boost::flyweights::no_tracking, boost::flyweights::intermodule_holder > symbol
An internalized string.
transition_t add_transition(state_t src, state_t dst, label_t l, weight_t w)
Add a transition between two states.
std::vector< stored_transition_t > tr_store_t
All the automaton's transitions.
transition_t add_transition(state_t src, state_t dst, label_t l)
Same as above, with weight one.
static constexpr transition_t lazy_transition()
Invalid transition that shows that the state's outgoing transitions are unknown.
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.
weight_t lweight(transition_t t, weight_t w)
auto all_transitions() const
All the transition indexes between all states (including pre and post).
typename weightset_t::value_t weight_t
Transition weight.
container_range< const tr_cont_t & > all_in(state_t s) const
Indexes of all transitions arriving to state s.
Restrict the interface of a container to begin/end.
An input/output format for valuesets.
static constexpr state_t post()
Provide a variadic mul on top of a binary mul(), and one().
tr_cont_t succ
Outgoing transitions.
tr_cont_t pred
Incoming transitions.
typename context_t::weightset_ptr weightset_ptr
mutable_automaton_impl(const context_t &ctx)
auto all_states() const
All states including pre()/post().
std::vector< stored_state_t > st_store_t
All the automaton's states.
typename context_t::labelset_ptr labelset_ptr
auto all_states(Pred pred) const
All states including pre()/post() that validate pred.
typename detail::labelset_t_of_impl< base_t< ValueSet > >::type labelset_t_of
context_t ctx_
The algebraic type of this automaton.
mutable_automaton_impl()=delete
weight_t add_weight(transition_t t, weight_t w)
typename labelset_t::value_t label_t
Transition label.
Lightweight state handle (or index).
label_t label_of(transition_t t) const
std::ostream & print_set(std::ostream &o=std::cout, format fmt={}) const
auto make_nullable_automaton(const Context &ctx)
void set_weight(weight_t &k)
static constexpr transition_t null_transition()
Invalid transition.
transition_t set_transition(state_t src, state_t dst, label_t l)
Same as above, with unit weight.
transition_t get_transition(state_t src, state_t dst, label_t l) const
weight_t rweight(transition_t t, weight_t w)
Data stored for each state.
std::ostream & print(std::ostream &o=std::cout) const
Print an automaton, for debugging.
void swap(config::value &first, config::value &second)
Transition with label and non Boolean weight.
mutable_automaton_impl(mutable_automaton_impl &&that)
std::vector< transition_t > tr_cont_t
All the incoming/outgoing transition handles of a state.
const context_t & context() const
std::vector< unsigned > free_store_t
A list of unused indexes in the states/transitions tables.
transition_t new_transition(state_t src, state_t dst, label_t l, weight_t w)
Create a transition between two states.
An exponent, or range of exponents.
labelset_t_of< context_t > labelset_t
mutable_automaton< Context > make_mutable_automaton(const Context &ctx)
weight_t weight_of(transition_t t) const
auto states() const
All states excluding pre()/post().
auto state_range(state_t b, state_t e) const
The range of state numbers in [b .. e].
label_t prepost_label_
Label for initial and final transitions.
weightset_t_of< context_t > weightset_t
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. ...
std::ostream & print(transition_t t, std::ostream &o=std::cout, format fmt={}) const
Print a transition, for debugging.