Vcsn  2.0
Be Rational
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros
minimize-moore.hh
Go to the documentation of this file.
1 #ifndef VCSN_ALGOS_MINIMIZE_MOORE_HH
2 # define VCSN_ALGOS_MINIMIZE_MOORE_HH
3 
4 # include <unordered_map>
5 # include <vector>
6 
7 # include <vcsn/algos/accessible.hh>
9 # 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 
32  const automaton_t &a_;
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 
58  std::ostream& print_(const set_t& ss, std::ostream& o) const
59  {
60  o << '{';
61  const char* sep = "";
62  for (auto s : ss)
63  {
64  o << sep << s;
65  sep = ", ";
66  }
67  return o << '}';
68  }
69  std::ostream& print_(const class_to_set_t& c2ss, std::ostream& o) const
70  {
71  const char* sep = "";
72  for (unsigned i = 0; i < c2ss.size(); ++i)
73  {
74  o << sep << '[' << i << "] = ";
75  print_(c2ss[i], o);
76  sep = "\n";
77  }
78  return o;
79  }
80 
88  std::unordered_map<state_t, std::unordered_map<label_t, state_t>>
90 
91  void clear()
92  {
93  class_to_set_.clear();
94  state_to_class_.clear();
95  num_classes_ = 0;
96  class_to_res_state_.clear();
97  out_.clear();
98  }
99 
102  {
103  assert(! set.empty());
104 
105  if (number == class_invalid)
106  number = num_classes_++;
107 
108  for (auto s : set)
109  state_to_class_[s] = number;
110 
111  if (number < class_to_set_.size())
112  class_to_set_[number] = std::move(set);
113  else
114  {
115  assert(number == class_to_set_.size());
116  class_to_set_.emplace_back(std::move(set));
117  }
118 
119  return number;
120  }
121 
125  {
126  auto i = out_.find(s);
127  if (i == out_.end())
128  return class_invalid;
129  auto j = i->second.find(l);
130  if (j == i->second.end())
131  return class_invalid;
132  return state_to_class_[j->second];
133  }
134 
135  public:
136  minimizer(const Aut& a)
137  : a_(a)
138  , gs_(a_->labelset()->genset())
139  {
140  // We _really_ need determinism here. See for instance
141  // minimization of standard(aa+a) (not a+aa).
142  require(is_deterministic(a_), me(), ": input must be deterministic");
143  require(is_trim(a_), me(), ": input must be trim");
144  for (auto t : a_->all_transitions())
145  out_[a_->src_of(t)][a_->label_of(t)] = a_->dst_of(t);
146  }
147 
150  {
151  // Initialization: two classes, partitioning final and non-final states.
152  make_class({a_->pre()});
153  make_class({a_->post()});
154  {
155  set_t nonfinals, finals;
156  for (auto s : a_->states())
157  if (a_->is_final(s))
158  finals.emplace_back(s);
159  else
160  nonfinals.emplace_back(s);
161  if (! nonfinals.empty())
162  make_class(std::move(nonfinals));
163  if (! finals.empty())
164  make_class(std::move(finals));
165  }
166 
167  bool go_on;
168  do
169  {
170  go_on = false;
171  for (class_t c = 0; c < num_classes_; ++c)
172  {
173  const set_t& c_states = class_to_set_[c];
174  for (auto l : gs_)
175  {
176  // See the "alreadyminimal" test comment in
177  // tests/python/minimize.py.
178  target_class_to_states_t target_class_to_c_states;
179  for (auto s : c_states)
180  {
181  auto c2 = out_class(s, l);
182  target_class_to_c_states[c2].emplace_back(s);
183  }
184 
185  // Are there at least two keys?
186  //
187  // std::unordered_map::size is said to be O(1).
188  if (2 <= target_class_to_c_states.size())
189  {
190  go_on = true;
191  class_t num = c;
192  for (auto& p : target_class_to_c_states)
193  {
194  make_class(std::move(p.second), num);
195  num = class_invalid;
196  }
197  // Ignore other labels for this partition
198  break;
199  }
200  } // for on labels
201  } // for on classes
202  }
203  while (go_on);
204  }
205 
208  {
209  build_classes_();
210  return quotient(a_, class_to_set_);
211  }
212  };
213  }
214 
215  template <typename Aut>
216  inline
217  auto
218  minimize_moore(const Aut& a)
220  {
222  return minimize();
223  }
224 
225 
226 } // namespace vcsn
227 
228 #endif // !VCSN_ALGOS_MINIMIZE_MOORE_HH
std::enable_if< std::is_same< weightset_t_of< Aut >, b >::value &&labelset_t_of< Aut >::is_free(), partition_automaton< Aut > >::type minimize(const Aut &a, const std::string &algo)
Definition: minimize.hh:31
bool is_deterministic(const Aut &aut, state_t_of< Aut > s)
Whether state s is deterministic in aut.
class_t make_class(set_t &&set, class_t number=class_invalid)
Make a new class with the given set of states.
typename detail::labelset_t_of_impl< base_t< ValueSet >>::type labelset_t_of
Definition: traits.hh:34
void build_classes_()
Build the initial classes, and split until fix point.
bool is_trim(const Aut &a)
Definition: accessible.hh:151
std::vector< set_t > class_to_set_t
std::unordered_map< state_t, class_t > state_to_class_t
auto quotient(const Aut &a, typename detail::quotienter< Aut >::class_to_set_t &classes) -> partition_automaton< Aut >
Definition: quotient.hh:143
std::vector< class_t > classes_t
state_to_class_t state_to_class_
const labelset_t_of< Aut >::genset_t gs_
The generators.
state_t_of< automaton_t > state_t
static constexpr const char * me()
std::ostream & print_(const set_t &ss, std::ostream &o) const
std::ostream & print_(const class_to_set_t &c2ss, std::ostream &o) const
typename detail::label_t_of_impl< base_t< ValueSet >>::type label_t_of
Definition: traits.hh:33
typename detail::weightset_t_of_impl< base_t< ValueSet >>::type weightset_t_of
Definition: traits.hh:38
std::vector< state_t > class_to_state_t
const automaton_t & a_
Input automaton, supplied at construction time.
class_to_state_t class_to_res_state_
std::unordered_map< state_t, std::unordered_map< label_t, state_t > > out_
An auxiliary data structure enabling fast access to transitions from a given state and label...
Provide a variadic mul on top of a binary mul(), and one().
Definition: fwd.hh:36
partition_automaton< automaton_t > operator()()
Return the quotient.
auto minimize_moore(const Aut &a) -> partition_automaton< Aut >
label_t_of< automaton_t > label_t
static constexpr class_t class_invalid
An invalid class.
class_t out_class(state_t s, label_t l)
The destination class of s with l in a.
typename detail::state_t_of_impl< base_t< ValueSet >>::type state_t_of
Definition: traits.hh:35
std::shared_ptr< detail::partition_automaton_impl< Aut >> partition_automaton
A partition automaton as a shared pointer.
std::unordered_map< class_t, set_t > target_class_to_states_t
void require(bool b, Args &&...args)
If b is not verified, raise an error with args as message.
Definition: raise.hh:39
std::vector< state_t > set_t