Vcsn  2.1
Be Rational
minimize-moore.hh
Go to the documentation of this file.
1 #pragma once
2 
3 #include <unordered_map>
4 #include <vector>
5 
6 #include <vcsn/algos/accessible.hh> // is_trim
8 #include <vcsn/algos/quotient.hh>
10 #include <vcsn/misc/raise.hh>
11 #include <vcsn/weightset/fwd.hh> // b
12 
13 namespace vcsn
14 {
15 
16  /*--------------------------------------.
17  | minimization with Moore's algorithm. |
18  `--------------------------------------*/
19  namespace detail_moore
20  {
21  template <typename Aut>
22  class minimizer
23  {
24  static_assert(std::is_same<weightset_t_of<Aut>, b>::value,
25  "minimize: moore: requires Boolean weights");
26  static_assert(labelset_t_of<Aut>::is_free(),
27  "minimize: moore: requires free labelset");
28 
29  using automaton_t = Aut;
30 
33 
36 
39  using class_t = unsigned;
40  using classes_t = std::vector<class_t>;
41  using set_t = std::vector<state_t>;
42  using state_to_class_t = std::unordered_map<state_t, class_t>;
43  using target_class_to_states_t = std::unordered_map<class_t, set_t>;
44  using class_to_set_t = std::vector<set_t>;
45  using class_to_state_t = std::vector<state_t>;
46 
47  constexpr static const char* me() { return "minimize-moore"; }
48 
50  constexpr static class_t class_invalid = -1;
51  unsigned num_classes_ = 0;
52 
53  // First two classes are reserved, and are empty.
57 
60  using transition_map_t
63  /* Deterministic: */ true,
64  /* AllOut: */ true>;
66 
67  void clear()
68  {
69  class_to_set_.clear();
70  state_to_class_.clear();
71  num_classes_ = 0;
72  class_to_res_state_.clear();
73  transition_map_.clear();
74  }
75 
77  class_t make_class(set_t&& set, class_t number = class_invalid)
78  {
79  assert(! set.empty());
80 
81  if (number == class_invalid)
82  number = num_classes_++;
83 
84  for (auto s : set)
85  state_to_class_[s] = number;
86 
87  if (number < class_to_set_.size())
88  class_to_set_[number] = std::move(set);
89  else
90  {
91  assert(number == class_to_set_.size());
92  class_to_set_.emplace_back(std::move(set));
93  }
94 
95  return number;
96  }
97 
101  {
102  const auto& map = transition_map_[s];
103  auto dst = map.find(l);
104  if (dst == std::end(map))
105  return class_invalid;
106  else
107  return state_to_class_[dst->second.dst];
108  }
109 
110  public:
112  minimizer(const Aut& a)
113  : a_(a)
114  , gs_(a_->labelset()->genset())
115  , transition_map_(a)
116  {
117  // We _really_ need determinism here. See for instance
118  // minimization of standard(aa+a) (not a+aa).
119  require(is_deterministic(a_), me(), ": input must be deterministic");
120  require(is_trim(a_), me(), ": input must be trim");
121  }
122 
125  {
126  build_classes_();
127  return class_to_set_;
128  }
129 
130  private:
133  {
134  // Initialization: two classes, partitioning final and
135  // non-final states.
136  make_class({a_->pre()});
137  make_class({a_->post()});
138  {
139  set_t nonfinals, finals;
140  for (auto s : a_->states())
141  if (a_->is_final(s))
142  finals.emplace_back(s);
143  else
144  nonfinals.emplace_back(s);
145  if (! nonfinals.empty())
146  make_class(std::move(nonfinals));
147  if (! finals.empty())
148  make_class(std::move(finals));
149  }
150 
151  bool go_on = true;
152  while (go_on)
153  {
154  go_on = false;
155  for (class_t c = 0; c < num_classes_; ++c)
156  {
157  const set_t& c_states = class_to_set_[c];
158  for (auto l : gs_)
159  {
160  // See the "alreadyminimal" test comment in
161  // tests/python/minimize.py.
162  target_class_to_states_t target_class_to_c_states;
163  for (auto s : c_states)
164  {
165  auto c2 = out_class(s, l);
166  target_class_to_c_states[c2].emplace_back(s);
167  }
168 
169  // Are there at least two keys?
170  //
171  // std::unordered_map::size is said to be O(1).
172  if (2 <= target_class_to_c_states.size())
173  {
174  go_on = true;
175  class_t num = c;
176  for (auto& p : target_class_to_c_states)
177  {
178  make_class(std::move(p.second), num);
179  num = class_invalid;
180  }
181  // Ignore other labels for this partition
182  break;
183  }
184  } // for on labels
185  } // for on classes
186  }
187  }
188  };
189  }
190 
192  template <typename Aut>
193  inline auto
194  minimize_moore(const Aut& a)
195  -> quotient_t<Aut>
196  {
198  return quotient(a, minimize.classes());
199  }
200 
201 } // namespace vcsn
class_t make_class(set_t &&set, class_t number=class_invalid)
Make a new class with the given set of states.
minimizer(const Aut &a)
Build the minimizer. Computes the classes.
typename detail::label_t_of_impl< base_t< ValueSet >>::type label_t_of
Definition: traits.hh:46
partition_automaton_t< Aut > quotient_t
The return type when calling quotient on Aut.
Definition: quotient.hh:119
void build_classes_()
Build the initial classes, and split until fix point.
typename detail::state_t_of_impl< base_t< ValueSet >>::type state_t_of
Definition: traits.hh:48
static constexpr class_t class_invalid
An invalid class.
auto quotient(const Aut &a, typename detail::quotienter< Aut >::class_to_set_t &cs) -> quotient_t< Aut >
Definition: quotient.hh:124
static constexpr const char * me()
typename detail::weightset_t_of_impl< base_t< ValueSet >>::type weightset_t_of
Definition: traits.hh:51
class_to_set_t & classes()
The partition, as a list of classes.
std::unordered_map< state_t, class_t > state_to_class_t
state_to_class_t state_to_class_
std::vector< state_t > set_t
state_t_of< automaton_t > state_t
label_t_of< automaton_t > label_t
const labelset_t_of< Aut >::genset_t gs_
The generators.
vcsn::enable_if_t< std::is_same< weightset_t_of< Aut >, b >::value &&labelset_t_of< Aut >::is_free(), quotient_t< Aut > > minimize(const Aut &a, const std::string &algo="auto")
Definition: minimize.hh:30
std::vector< state_t > class_to_state_t
std::vector< class_t > classes_t
Provide a variadic mul on top of a binary mul(), and one().
Definition: fwd.hh:46
typename detail::labelset_t_of_impl< base_t< ValueSet >>::type labelset_t_of
Definition: traits.hh:47
void require(bool b, Args &&...args)
If b is not verified, raise an error with args as message.
Definition: raise.hh:75
class_t out_class(state_t s, label_t l)
The destination class of s with l in a.
std::unordered_map< class_t, set_t > target_class_to_states_t
automaton_t a_
Input automaton, supplied at construction time.
bool is_trim(const Aut &a)
Whether all its states are useful.
Definition: accessible.hh:161
std::vector< set_t > class_to_set_t
bool is_deterministic(const Aut &aut, state_t_of< Aut > s)
Whether state s is deterministic in aut.
transition_map_t transition_map_
class_to_state_t class_to_res_state_
auto minimize_moore(const Aut &a) -> quotient_t< Aut >
Minimize automaton a using the Moore algorithm.