Vcsn  2.1
Be Rational
distance.hh
Go to the documentation of this file.
1 #pragma once
2 
3 #include <algorithm>
4 #include <iostream>
5 #include <limits>
6 #include <queue>
7 #include <unordered_set>
8 #include <unordered_map>
9 #include <vector>
10 
11 #include <boost/range/algorithm/max_element.hpp>
12 
13 #include <vcsn/algos/copy.hh>
14 #include <vcsn/ctx/context.hh>
15 #include <vcsn/dyn/label.hh>
16 #include <vcsn/misc/algorithm.hh> // detail::back
17 #include <vcsn/misc/deque.hh>
18 #include <vcsn/misc/pair.hh>
19 #include <vcsn/weightset/nmin.hh>
20 
21 namespace vcsn
22 {
26  template <typename Aut>
27  std::vector<weight_t_of<Aut>>
29  {
30  using weight_t = weight_t_of<Aut>;
31  using state_t = state_t_of<Aut>;
32 
33  auto ws = *aut->weightset();
34  auto d = std::vector<weight_t>(aut->all_states().back() + 1, ws.zero());
35  d[s0] = ws.one();
36  auto r = d;
37 
38  auto todo = std::deque<state_t>{s0};
39  while (!todo.empty())
40  {
41  auto s = todo.front();
42  todo.pop_front();
43  auto r1 = r[s];
44  r[s] = ws.zero();
45  for (auto t : aut->all_out(s))
46  {
47  auto dst = aut->dst_of(t);
48  auto w1 = ws.mul(r1, aut->weight_of(t));
49  auto w = ws.add(d[dst], w1);
50  if (!ws.equal(d[dst], w))
51  {
52  d[dst] = w;
53  r[dst] = ws.add(r[dst], w1);
54  if (!has(todo, dst))
55  todo.emplace_back(dst);
56  }
57  }
58  }
59  return d;
60  }
61 
63  template <typename Aut, typename WeightSet>
65  {
66  state_distancer(const Aut& aut)
67  : aut_(aut)
68  {}
69 
70  using automaton_t = Aut;
73  using pair_t = std::pair<state_t, weight_t>;
74 
80  weight_t
81  operator() (state_t s0, state_t s1) const
82  {
83  auto& ws = *aut_->weightset();
84 
85  // States to visit.
86  auto stack = std::vector<pair_t>{{s0, ws.one()}};
87 
88  // Result weight
89  weight_t res = ws.zero();
90 
91  while (!stack.empty())
92  {
93  pair_t p = stack.back();
94  stack.pop_back();
95  state_t src = p.first;
96  weight_t w = p.second;
97 
98  // dfs
99  for (auto t : aut_->all_out(src))
100  {
101  state_t dst = aut_->dst_of(t);
102  weight_t new_weight(ws.mul(w, aut_->weight_of(t)));
103  if (dst == s1)
104  // Found a path, add it
105  res = ws.add(res, new_weight);
106  else
107  {
108  pair_t np(dst, new_weight);
109  stack.emplace_back(dst, new_weight);
110  }
111  }
112  }
113  return res;
114  }
115 
116  private:
118  };
119 
121  template <typename Aut>
122  struct state_distancer<Aut, nmin>
123  {
124  state_distancer(const Aut& aut)
125  : aut_(aut)
126  {}
127 
128  using automaton_t = Aut;
131  using pair_t = std::pair<state_t, weight_t>;
132 
133 
138  weight_t
140  {
141  auto& ws = *aut_->weightset();
142  // stack of the states to visit
143  auto stack = std::vector<pair_t>{{s0, ws.one()}};
144 
145  // map of the minimum distance found to get to the node
146  // Initially, +inf for everyone
147  auto min_weight
148  = std::vector<weight_t>(detail::back(aut_->all_states()) + 1, ws.zero());
149 
150  while (!stack.empty())
151  {
152  pair_t p = stack.back();
153  stack.pop_back();
154  state_t src = p.first;
155  weight_t w = p.second;
156 
157  // The state was not already seen with a smaller weight
158  if (w < min_weight[src])
159  {
160  min_weight[src] = w;
161  if (src != s1)
162  for (auto t : aut_->all_out(src))
163  {
164  state_t dst = aut_->dst_of(t);
165  weight_t new_weight(ws.mul(w, aut_->weight_of(t)));
166  // Otherwise, useless since we have already seen a shorter path
167  if (new_weight < min_weight[dst] &&
168  new_weight < min_weight[s1])
169  stack.emplace_back(dst, new_weight);
170  }
171  }
172  }
173  return min_weight[s1];
174  }
175 
176  private:
178  };
179 
186  template<typename Aut>
187  std::unordered_map<state_t_of<Aut>,
188  std::pair<unsigned,
190  paths_ibfs(const Aut& aut, const std::vector<state_t_of<Aut>>& start)
191  {
192  using context_t = context_t_of<Aut>;
193  using automaton_t = mutable_automaton<context_t>;
194  using state_t = state_t_of<automaton_t>;
195  using transition_t = transition_t_of<automaton_t>;
196 
197  std::queue<state_t> todo;
198  std::unordered_set<state_t> marked;
199  std::unordered_map<state_t, std::pair<unsigned, transition_t>> parent;
200 
201  for (auto s : start)
202  todo.push(s);
203 
204  while (!todo.empty())
205  {
206  state_t p = todo.front();
207  todo.pop();
208  marked.insert(p);
209  for (auto t : aut->all_in(p))
210  {
211  auto s = aut->src_of(t);
212  if (marked.find(s) == marked.end())
213  {
214  todo.push(s);
215  auto cur_p = parent.find(p);
216  unsigned cur_d
217  = cur_p == parent.end() ? 1
218  : cur_p->second.first + 1;
219  parent[s] = {cur_d, t};
220  }
221  }
222  }
223  return parent;
224  }
225 
231  template<typename Aut>
232  std::vector<transition_t_of<Aut>>
233  path_bfs(const Aut& aut,
234  state_t_of<Aut> start, state_t_of<Aut> end)
235  {
236  using context_t = context_t_of<Aut>;
237  using automaton_t = mutable_automaton<context_t>;
238  using state_t = state_t_of<automaton_t>;
239  using transition_t = transition_t_of<automaton_t>;
240 
241  std::queue<state_t> todo;
242  std::unordered_set<state_t> marked;
243  std::unordered_map<state_t, std::pair<state_t, transition_t>> parent;
244 
245  todo.push(start);
246  while (!todo.empty())
247  {
248  state_t p = todo.front();
249  todo.pop();
250  marked.insert(p);
251  if (p == end)
252  {
253  std::vector<transition_t> rpath;
254  state_t bt_curr = end;
255  while (bt_curr != start)
256  {
257  transition_t t;
258  std::tie(bt_curr, t) = parent.find(bt_curr)->second;
259  rpath.push_back(t);
260  }
261  std::reverse(rpath.begin(), rpath.end());
262  return rpath;
263  }
264  else
265  for (auto t : aut->all_out(p))
266  {
267  auto s = aut->dst_of(t);
268  if (marked.find(s) == marked.end())
269  {
270  todo.push(s);
271  parent[s] = {p, t};
272  }
273  }
274  }
275  // FIXME: why don't we raise here?
276  return std::vector<transition_t>();
277  }
278 
279  template <typename Aut>
280  std::vector<std::vector<weight_t_of<Aut>>>
281  all_distances(const Aut& aut)
282  {
283  using automaton_t = Aut;
284  using weight_t = weight_t_of<automaton_t>;
285 
286  auto ws = aut->weightset();
287  auto n = aut->all_states().back() + 1;
288  std::vector<std::vector<weight_t>> res(
289  n, std::vector<weight_t>(n, ws->zero()));
290 
291  for (auto t : aut->all_transitions())
292  res[aut->src_of(t)][aut->dst_of(t)] = aut->weight_of(t);
293  for (auto k : aut->all_states())
294  for (auto i : aut->all_states())
295  for (auto j : aut->all_states())
296  res[i][j] = ws->add(res[i][j], ws->mul(res[i][k], res[k][j]));
297  return res;
298  }
299 }
value_t mul(const Ts &...ts) const
A variadic multiplication.
Definition: weightset.hh:36
std::vector< std::vector< weight_t_of< Aut > > > all_distances(const Aut &aut)
Definition: distance.hh:281
std::vector< transition_t_of< Aut > > path_bfs(const Aut &aut, state_t_of< Aut > start, state_t_of< Aut > end)
A shortest path between two states.
Definition: distance.hh:233
Container::value_type back(const Container &container)
The last member of this Container.
Definition: algorithm.hh:26
weight_t_of< automaton_t > weight_t
Definition: distance.hh:129
std::pair< state_t, weight_t > pair_t
Definition: distance.hh:131
typename detail::context_t_of_impl< base_t< ValueSet >>::type context_t_of
Definition: traits.hh:45
typename detail::state_t_of_impl< base_t< ValueSet >>::type state_t_of
Definition: traits.hh:48
weight_t_of< automaton_t > weight_t
Definition: distance.hh:71
std::unordered_map< state_t_of< Aut >, std::pair< unsigned, transition_t_of< Aut > > > paths_ibfs(const Aut &aut, const std::vector< state_t_of< Aut >> &start)
Find the shortest paths from some states to all the states.
Definition: distance.hh:190
state_t_of< automaton_t > state_t
Definition: distance.hh:130
Provide a variadic mul on top of a binary mul(), and one().
Definition: fwd.hh:46
std::pair< state_t, weight_t > pair_t
Definition: distance.hh:73
std::vector< weight_t_of< Aut > > ss_shortest_distance(const Aut &aut, state_t_of< Aut > s0)
Single source shortest distance.
Definition: distance.hh:28
weight_t operator()(state_t s0, state_t s1) const
State distance Find weighted distance between state s0 and state s1 using a dfs.
Definition: distance.hh:81
typename detail::transition_t_of_impl< base_t< ValueSet >>::type transition_t_of
Definition: traits.hh:49
state_t_of< automaton_t > state_t
Definition: distance.hh:72
pair_automaton< Aut > pair(const Aut &aut, bool keep_initials=false)
Definition: pair.hh:243
ATTRIBUTE_PURE bool has(const std::deque< T, Allocator > &s, const T &e)
Whether e is member of s.
Definition: deque.hh:13
state_distancer(const Aut &aut)
Definition: distance.hh:66
Wrapper struct to provide the state distance function.
Definition: distance.hh:64
automaton_t aut_
Definition: distance.hh:117
std::shared_ptr< detail::mutable_automaton_impl< Context >> mutable_automaton
Definition: fwd.hh:24
typename detail::weight_t_of_impl< base_t< ValueSet >>::type weight_t_of
Definition: traits.hh:50