Vcsn  2.8
Be Rational
lightest.hh
Go to the documentation of this file.
1 #pragma once
2 
3 #include <algorithm>
4 #include <deque>
5 #include <fstream>
6 
7 #include <boost/heap/binomial_heap.hpp>
8 
10 #include <vcsn/algos/eppstein.hh>
13 #include <vcsn/ctx/context.hh>
14 #include <vcsn/dyn/automaton.hh>
15 #include <vcsn/dyn/fwd.hh>
16 #include <vcsn/dyn/value.hh>
18 
19 namespace vcsn
20 {
21 
22  /*----------------------.
23  | lightest(automaton). |
24  `----------------------*/
25 
26  namespace detail
27  {
28 
37  template <Automaton Aut>
39  {
40  public:
41  using automaton_t = Aut;
43 
47  using monomial_t = typename polynomialset_t::monomial_t;
48 
52 
56 
57  using profile_t = std::tuple<state_t, word_t, weight_t>;
58  struct profile_less
59  {
70  bool operator()(const profile_t& r, const profile_t& l) const
71  {
72  if (weightset_t::less(std::get<2>(l), std::get<2>(r)))
73  return true;
74  else if (weightset_t::less(std::get<2>(r), std::get<2>(l)))
75  return false;
76  else if (labelset_t::less(std::get<1>(l), std::get<1>(r)))
77  return true;
78  else if (labelset_t::less(std::get<1>(r), std::get<1>(l)))
79  return false;
80  else if (std::get<0>(r) == automaton_t::element_type::post())
81  return true;
82  else if (std::get<0>(l) == automaton_t::element_type::post())
83  return false;
84  else
85  return std::get<0>(l) < std::get<0>(r);
86  }
87  };
88  using queue_t =
89  boost::heap::binomial_heap<profile_t,
90  boost::heap::compare<profile_less>>;
91 
96  : aut_(aut)
97  {}
98 
101  polynomial_t operator()(unsigned num)
102  {
104  "lightest(n > 1): requires automaton without lightening cycles");
105  return lightest_(num);
106  }
107 
108  private:
109  polynomial_t lightest_(unsigned num)
110  {
111  auto queue = queue_t{};
112  queue.emplace(aut_->pre(), ls_.one(), ws_.one());
113 
114  // The approximated behavior: the first orders to post's past.
115  auto res = ps_.zero();
116  while (!queue.empty() && num != res.size())
117  {
118  state_t s; word_t l; weight_t w;
119  std::tie(s, l, w) = queue.top();
120 
121  queue.pop();
122 
125  if (!queue.empty()
126  && std::get<0>(queue.top()) == s
127  && ls_.equal(std::get<1>(queue.top()), l))
128  {
129  while (!queue.empty()
130  && std::get<0>(queue.top()) == s
131  && ls_.equal(std::get<1>(queue.top()), l))
132  {
133  w = ws_.add(w, std::get<2>(queue.top()));
134  queue.pop();
135  }
136  queue.emplace(s, l, w);
137  continue;
138  }
139 
140  if (s == aut_->post())
141  ps_.add_here(res, std::move(l), std::move(w));
142 
143  for (const auto t: all_out(aut_, s))
144  {
145  auto dst = aut_->dst_of(t);
146  auto nw = ws_.mul(w, aut_->weight_of(t));
147  if (aut_->src_of(t) == aut_->pre() || dst == aut_->post())
148  queue.emplace(dst, l, std::move(nw));
149  else
150  {
151  auto nl = ls_.mul(l, aut_->label_of(t));
152  queue.emplace(dst, std::move(nl), std::move(nw));
153  }
154  }
155  }
156 
157  return res;
158  }
159 
161  void show_heap_(const queue_t& q, std::ostream& os = std::cerr)
162  {
163  const char* sep = "";
164  for (auto i = q.ordered_begin(), end = q.ordered_end();
165  i != end; ++i)
166  {
167  os << sep;
168  sep = " , ";
169  aut_->print_state_name(std::get<0>(*i), os) << ":<";
170  ws_.print(std::get<2>(*i), os);
171  os << ">:";
172  ls_.print(std::get<1>(*i), os);
173  }
174  os << '\n';
175  }
176 
179  const weightset_t& ws_ = *aut_->weightset();
180  const polynomialset_t ps_ = make_word_polynomialset(aut_->context());
181  const labelset_t& ls_ = *ps_.labelset();
182  };
183  }
184 
190  template <Automaton Aut>
192  lightest(const Aut& aut, unsigned num = 1, const std::string& algo = "auto")
193  {
194  if (algo == "yen")
195  {
196  const auto ps = make_word_polynomialset(aut->context());
197  auto res = ps.zero();
198  auto paths = k_lightest_path(aut, aut->pre(), aut->post(), num);
199  for (const auto& path : paths)
200  if (auto m = path_monomial(aut, format_lightest(aut, path)))
201  ps.add_here(res, *m);
202  return res;
203  }
204  else if (algo == "eppstein")
205  {
207  "lightest: eppstein: invalid weightset: ",
208  *aut->weightset());
209  const auto ps = make_word_polynomialset(aut->context());
210  auto res = ps.zero();
211  auto computed = compute_eppstein(aut, aut->pre(), aut->post(), num);
212  for (const auto& path : computed)
213  ps.add_here(res, path.make_monomial(ps));
214  return res;
215  }
216  else if ((algo == "auto" && num != 1) || algo == "breadth-first")
217  {
219  return lightest(num);
220  }
221  else if (num == 1)
222  {
223  if (auto res = path_monomial(aut, lightest_path(aut, algo)))
224  return {*res};
225  else
226  return {};
227  }
228  else
229  raise("lightest: invalid algorithm: ", algo);
230  }
231 
232 
233  namespace dyn
234  {
235  namespace detail
236  {
238  template <Automaton Aut, typename Num, typename String>
239  polynomial
240  lightest(const automaton& aut, unsigned num, const std::string& algo)
241  {
242  const auto& a = aut->as<Aut>();
243  auto ps = vcsn::detail::make_word_polynomialset(a->context());
244  return {ps, lightest(a, num, algo)};
245  }
246  }
247  }
248 }
A dyn automaton.
Definition: automaton.hh:17
weight_t_of< automaton_t > weight_t
Definition: lightest.hh:54
typename detail::weightset_t_of_impl< base_t< ValueSet > >::type weightset_t_of
Definition: traits.hh:67
void show_heap_(const queue_t &q, std::ostream &os=std::cerr)
Show the heap, for debugging.
Definition: lightest.hh:161
The lightest algorithm computes the paths between pre and post with the smallest weight possible...
Definition: lightest.hh:38
bool operator()(const profile_t &r, const profile_t &l) const
Whether l < r (as this is a max heap).
Definition: lightest.hh:70
context_t_of< Aut > context_t
Definition: lightest.hh:42
word_t_of< automaton_t > word_t
Definition: lightest.hh:51
typename detail::state_t_of_impl< base_t< ValueSet > >::type state_t_of
Definition: traits.hh:64
typename polynomialset_t::monomial_t monomial_t
Definition: lightest.hh:47
std::vector< detail::path< Aut > > compute_eppstein(const Aut &aut, state_t_of< Aut > src, state_t_of< Aut > dst, unsigned num)
Compute the num lightest paths in the automaton aut from src to dst.
Definition: eppstein.hh:129
boost::heap::binomial_heap< profile_t, boost::heap::compare< profile_less > > queue_t
Definition: lightest.hh:90
const labelset_t & ls_
Definition: lightest.hh:181
typename polynomialset_t::value_t polynomial_t
Definition: lightest.hh:46
value_impl< detail::polynomial_tag > polynomial
Definition: fwd.hh:33
std::vector< path_t_of< Aut > > k_lightest_path(const Aut &aut, state_t_of< Aut > src, state_t_of< Aut > dst, unsigned k)
auto all_out(const Aut &aut, state_t_of< Aut > s)
Indexes of transitions leaving state s.
Definition: automaton.hh:67
const polynomialset_t ps_
Definition: lightest.hh:180
typename detail::context_t_of_impl< base_t< ValueSet > >::type context_t_of
Definition: traits.hh:61
std::enable_if_t< weightset_t_of< Aut >::has_lightening_weights(), bool > has_lightening_cycle(const Aut &aut)
Provide a variadic mul on top of a binary mul(), and one().
Definition: fwd.hh:46
std::tuple< state_t, word_t, weight_t > profile_t
Definition: lightest.hh:57
state_t_of< automaton_t > state_t
Definition: lightest.hh:55
std::vector< transition_t_of< Aut > > lightest_path(const Aut &aut, state_t_of< Aut > source, state_t_of< Aut > dest, a_star_tag)
Definition: a-star.hh:151
std::ostringstream os
The output stream: the corresponding C++ snippet to compile.
Definition: translate.cc:404
weightset_t_of< automaton_t > weightset_t
Definition: lightest.hh:53
typename detail::labelset_t_of_impl< base_t< ValueSet > >::type labelset_t_of
Definition: traits.hh:63
Definition: a-star.hh:8
const weightset_t & ws_
Definition: lightest.hh:179
predecessors_t_of< Aut > format_lightest(const Aut &aut, const std::vector< transition_t_of< Aut >> &path)
A state-indexed vector of predecessor transitions from the path path.
detail::word_polynomialset_t< context_t_of< Aut > >::value_t lightest(const Aut &aut, unsigned num=1, const std::string &algo="auto")
The approximated behavior of an automaton.
Definition: lightest.hh:192
lightest_impl(const automaton_t &aut)
Prepare to compute an approximation of the behavior.
Definition: lightest.hh:95
labelset_t_of< polynomialset_t > labelset_t
Wordset.
Definition: lightest.hh:50
auto & as()
Extract wrapped typed automaton.
Definition: automaton.hh:37
auto make_word_polynomialset(const Ctx &ctx) -> word_polynomialset_t< Ctx >
The polynomialset of words of a labelset (not necessarily on words itself).
typename labelset_t_of< base_t< ValueSet > >::word_t word_t_of
Definition: traits.hh:90
polynomial_t lightest_(unsigned num)
Definition: lightest.hh:109
auto path_monomial(const Aut &aut, const predecessors_t_of< Aut > &path, state_t_of< Aut > src=Aut::element_type::pre(), state_t_of< Aut > dst=Aut::element_type::post()) -> boost::optional< typename detail::word_polynomialset_t< context_t_of< Aut >>::monomial_t >
Given a path (typically computed by lightest_path), the corresponding monomial (label, weight).
void require(Bool b, Args &&... args)
If b is not verified, raise an error with args as message.
Definition: raise.hh:87
typename detail::weight_t_of_impl< base_t< ValueSet > >::type weight_t_of
Definition: traits.hh:66
automaton_t aut_
The automaton whose behavior to approximate.
Definition: lightest.hh:178
return res
Definition: multiply.hh:399
polynomial_t operator()(unsigned num)
The approximated behavior of the automaton.
Definition: lightest.hh:101