17 #ifndef AWALI_ALGOS_SYNCHRONIZING_WORD_HH
18 # define AWALI_ALGOS_SYNCHRONIZING_WORD_HH
26 # include <unordered_set>
48 template <
typename Aut>
54 std::unordered_set<state_t> todo;
56 for (
auto s : aut->states())
59 for (
auto l : aut->labelset()->letters_of(w))
61 std::unordered_set<state_t> new_todo;
64 auto ntf = aut->out(s, l);
65 auto size = ntf.size();
66 require(0 < size,
"automaton must be complete");
67 require(size < 2,
"automaton must be deterministic");
68 new_todo.insert(aut->dst_of(*ntf.begin()));
70 todo = std::move(new_todo);
73 return todo.size() == 1;
82 template <
typename Aut>
93 using weight_t =
typename weightset_t::value_t;
99 using pair_t = std::pair<state_t, state_t>;
100 using origins_t = std::map<state_t, pair_t>;
106 , transition_map_(aut)
107 , keep_initials_(keep_initials)
109 auto ctx = input_->context();
110 auto ws = ctx.weightset();
115 for (
auto l : input_->labelset()->genset())
119 for (
auto s : input_->states())
120 pair_states_.emplace(std::make_pair(s, s), this->
add_state());
124 auto states = input_->states();
125 auto end = std::end(
states);
126 for (
auto i1 = std::begin(
states); i1 != end; ++i1)
132 for (++i2; i2 != end; ++i2)
134 pair_states_.emplace(std::make_pair(*i1, *i2),
139 for (
auto ps : pair_states_)
141 auto pstates = ps.first;
142 auto cstate = ps.second;
145 transition_map_[pstates.second]))
147 state_(std::get<0>(p.second).dst,
148 std::get<1>(p.second).dst),
152 for (
const auto& p: pair_states_)
153 origins_.emplace(p.second, p.first);
156 for (
auto s : input_->states())
157 singletons_.push_back(state_(s, s));
159 singletons_.push_back(q0_);
164 require(!keep_initials_,
"can't get_q0() on a pairer that "
174 return p.first == p.second;
187 return "pair_automaton<" + automaton_t::element_type::sname() +
">";
192 return "pair_automaton<" + input_->vname(
full) +
">";
215 const std::string& fmt =
"text")
const
222 input_->print_state_name(i->second.first, o, fmt);
224 input_->print_state_name(i->second.second, o, fmt);
237 if (s1 == s2 && !keep_initials_)
246 using transition_map_t
247 = transition_map<automaton_t, weightset_t_of<automaton_t>,
true>;
248 transition_map_t transition_map_;
249 std::unordered_map<pair_t, state_t> pair_states_;
251 std::vector<state_t> singletons_;
253 bool keep_initials_ =
false;
257 template <
typename Aut>
259 = std::shared_ptr<internal::pair_automaton_impl<Aut>>;
265 template <
typename Aut>
268 auto res = make_shared_ptr<pair_automaton<Aut>>(aut, keep_initials);
274 template <
typename Aut>
283 using pair_t = std::pair<state_t, state_t>;
284 using dist_transition_t = std::pair<unsigned, transition_t>;
288 std::unordered_map<state_t, dist_transition_t> paths_;
289 std::unordered_set<state_t> todo_;
298 void init_pair(
bool keep_initials =
false)
300 pair_ =
pair(aut_, keep_initials);
301 paths_ =
paths_ibfs(pair_, pair_->singletons());
304 for (
auto it = paths_.begin(); it != paths_.end(); )
306 if (pair_->is_singleton(it->first))
313 void init_synchro(
bool keep_initials =
false)
315 init_pair(keep_initials);
316 require(pair_->states().size() == paths_.size() +
317 pair_->singletons().size(),
"automaton is not synchronizing");
319 for (
auto s : pair_->states())
320 if (!pair_->is_singleton(s))
324 std::vector<transition_t> recompose_path(
state_t from)
326 std::vector<transition_t> res;
328 while (!pair_->is_singleton(bt_curr))
332 bt_curr = pair_->dst_of(t);
339 if (pair_->is_singleton(s))
341 return paths_.find(s)->second.first;
346 auto ntf = pair_->out(s, l);
347 auto size = ntf.size();
348 require(0 < size,
"automaton must be complete");
349 require(size < 2,
"automaton must be deterministic");
350 return pair_->dst_of(*ntf.begin());
353 void apply_label(
const label_t& label)
355 res_ = aut_->labelset()->concat(res_, label);
356 std::unordered_set<state_t> new_todo;
359 auto add_state = dest_state(s, label);
360 if (!pair_->is_singleton(add_state))
361 new_todo.insert(add_state);
363 todo_ = std::move(new_todo);
368 void apply_path(
const std::vector<transition_t>& path)
371 apply_label(pair_->label_of(t));
384 return paths_.size() == pair_->states().size() - 1;
389 return synchro(&synchronizer::dist);
399 return synchro(&synchronizer::phi_1);
404 return synchro(&synchronizer::phi_2);
409 return fastsynchro_();
415 word_t synchro(heuristic_t heuristic)
418 while (!todo_.empty())
424 int d = (this->*(heuristic))(s);
432 apply_path(recompose_path(s_min));
442 while (!todo_.empty())
448 pair_t o = pair_->get_origin(s);
449 if (!first && o.first != previous && o.second != previous)
459 const auto& path = recompose_path(s_min);
460 pair_t pair_end = pair_->get_origin(
461 pair_->dst_of(path[path.size() - 1]));
462 assert(pair_end.first == pair_end.second);
463 previous = pair_end.first;
477 while (!todo_.empty())
482 for (
const auto& l : pair_->labelset()->genset())
484 int cur_min = phi_3(l);
492 unsigned sq_bound = aut_->states().size();
493 if (
min < 0 && count++ < (sq_bound * sq_bound))
499 size_t t = todo_.size();
500 int bound =
std::min(aut_->states().size(), (t * t - t / 2));
505 if (count++ >= bound)
514 apply_path(recompose_path(s_min));
521 int delta(
state_t p,
const std::vector<transition_t>& w)
525 np = dest_state(np, pair_->label_of(t));
526 return dist(np) - dist(p);
535 auto w = recompose_path(p);
546 return phi_1(p) + dist(p);
555 res += dist(dest_state(s, l)) - dist(s);
566 template <
typename Aut>
577 template <
typename Aut>
582 if (algo ==
"greedy" || algo ==
"eppstein")
584 else if (algo ==
"cycle")
586 else if (algo ==
"synchrop")
588 else if (algo ==
"synchropl")
590 else if (algo ==
"fastsynchro")
593 raise(
"synchronizing_word: invalid algorithm: ",
str_escape(algo));
609 template <
typename Ctx>
610 mutable_automaton<Ctx>
611 cerny(
const Ctx& ctx,
unsigned num_states)
613 require(0 < num_states,
"num_states must be > 0");
616 automaton_t res = make_shared_ptr<automaton_t>(ctx);
618 std::vector<state_t>
states;
619 states.reserve(num_states);
621 for (
unsigned i = 0; i < num_states; ++i)
622 states.push_back(res->add_state());
624 for (
unsigned i = 0; i < num_states; ++i)
627 for (
auto l : ctx.labelset()->genset())
629 auto dest = (la || i == num_states - 1) ? (i + 1) % num_states : i;
631 ctx.weightset()->one());
636 res->set_initial(
states[0]);
637 res->set_final(
states[0]);
carries the algebraic settings of automata
Definition: context.hh:40
Aggregate an automaton, and forward calls to it.
Definition: automaton_decorator.hh:36
auto print_state(Args &&... args) const -> decltype(aut_-> print_state(std::forward< Args >(args)...))
Definition: automaton_decorator.hh:154
auto states(Args &&... args) const -> decltype(aut_-> states(std::forward< Args >(args)...))
Definition: automaton_decorator.hh:157
auto add_state(Args &&... args) -> decltype(aut_-> add_state(std::forward< Args >(args)...))
Definition: automaton_decorator.hh:187
auto add_transition(Args &&... args) -> decltype(aut_-> add_transition(std::forward< Args >(args)...))
Definition: automaton_decorator.hh:181
Definition: synchronizing_word.hh:86
typename weightset_t::value_t weight_t
Definition: synchronizing_word.hh:93
mutable_automaton< context_t_of< Aut > > automaton_nocv_t
Definition: synchronizing_word.hh:89
state_t get_q0() const
Definition: synchronizing_word.hh:162
static std::string sname()
Definition: synchronizing_word.hh:185
const std::unordered_map< pair_t, state_t > & get_map_pair() const
Definition: synchronizing_word.hh:195
Aut automaton_t
Definition: synchronizing_word.hh:88
bool is_singleton(state_t s) const
Definition: synchronizing_word.hh:169
pair_automaton_impl(const automaton_t &aut, bool keep_initials=false)
Definition: synchronizing_word.hh:103
weightset_t_of< automaton_t > weightset_t
Definition: synchronizing_word.hh:92
const std::vector< state_t > & singletons()
Definition: synchronizing_word.hh:180
std::ostream & print_state_name(state_t ss, std::ostream &o, const std::string &fmt="text") const
Definition: synchronizing_word.hh:214
const origins_t & origins() const
A map from result state to tuple of original states.
Definition: synchronizing_word.hh:201
const pair_t get_origin(state_t s) const
Definition: synchronizing_word.hh:206
std::string vname(bool full=true) const
Definition: synchronizing_word.hh:190
context_t_of< automaton_t > context_t
Definition: synchronizing_word.hh:91
std::vector< state_t > states(abstract_automaton_t const *aut, bool all)
any_t word_t
Type for words; it is an alias to any_t since the precise type depends on the context (most of the ti...
Definition: typedefs.hh:67
json_ast_t from(std::istream &i)
Builds a json_ast_t from an input stream.
zipped_maps< Dereference, Maps... > zip_maps(Maps &&... maps)
Definition: zip_maps.hh:274
std::string to_string(identities i)
std::pair< T, T > make_ordered_pair(T e1, T e2)
Definition: pair.hh:52
typename internal::label_t_of_impl< internal::base_t< ValueSet > >::type label_t_of
Helper to retrieve the type of the labels of a value set.
Definition: traits.hh:71
std::shared_ptr< internal::pair_automaton_impl< Aut > > pair_automaton
Definition: synchronizing_word.hh:259
bool is_synchronizing(const Aut &aut)
Definition: synchronizing_word.hh:567
std::ostream & str_escape(std::ostream &os, const int c)
Definition: escape.hh:30
typename internal::context_t_of_impl< internal::base_t< ValueSet > >::type context_t_of
Helper to retrieve the type of the context of a value set.
Definition: traits.hh:66
mutable_automaton< Ctx > cerny(const Ctx &ctx, unsigned num_states)
Cerny automata are automata whose synchronizing word length is always (n - 1)^2, the upper bound of t...
Definition: synchronizing_word.hh:611
typename internal::labelset_t_of_impl< internal::base_t< ValueSet > >::type labelset_t_of
Helper to retrieve the type of the labelset of a value set.
Definition: traits.hh:76
std::unordered_map< state_t, std::pair< unsigned, transition_t > > paths_ibfs(const Aut &aut, std::vector< state_t > start)
Definition: distance.hh:40
std::shared_ptr< internal::mutable_automaton_impl< Context > > mutable_automaton
Definition: mutable_automaton.hh:45
void require(bool b, Args &&... args)
If b is not verified, raise an error with args as message.
Definition: raise.hh:55
pair_automaton< Aut > pair(const Aut &aut, bool keep_initials=false)
Definition: synchronizing_word.hh:266
labelset_t_of< Aut >::word_t synchronizing_word(const Aut &aut, const std::string &algo="greedy")
Definition: synchronizing_word.hh:579
typename internal::weightset_t_of_impl< internal::base_t< ValueSet > >::type weightset_t_of
Helper to retrieve the type of the weightset of a value set.
Definition: traits.hh:86
bool is_synchronized_by(const Aut &aut, const typename labelset_t_of< Aut >::word_t &w)
Definition: synchronizing_word.hh:50
ATTRIBUTE_CONST int max(int a, int b)
Definition: arith.hh:54
ATTRIBUTE_CONST int min(int a, int b)
Definition: arith.hh:48
static const std::string full
Completely version of Awali as a std::string.
Definition: version.hh:42
Main namespace of Awali.
Definition: ato.hh:22
unsigned state_t
Definition: types.hh:21
unsigned transition_t
Definition: types.hh:22
Definition: synchronize.hh:47
word_t cycle()
Definition: synchronizing_word.hh:392
word_t greedy()
Definition: synchronizing_word.hh:387
word_t synchroP()
Definition: synchronizing_word.hh:397
synchronizer(const automaton_t &aut)
Definition: synchronizing_word.hh:293
word_t synchroPL()
Definition: synchronizing_word.hh:402
Aut automaton_t
Definition: synchronizing_word.hh:278
typename labelset_t_of< automaton_t >::word_t word_t
Definition: synchronizing_word.hh:279
bool is_synchronizing()
Definition: synchronizing_word.hh:381
label_t_of< automaton_t > label_t
Definition: synchronizing_word.hh:280
word_t fastsynchro()
Definition: synchronizing_word.hh:407