Vcsn  2.8
Be Rational
q.hh
Go to the documentation of this file.
1 #pragma once
2 
3 #include <ostream>
4 #include <string>
5 
6 #include <vcsn/core/join.hh>
7 #include <vcsn/misc/format.hh>
8 #include <vcsn/misc/functional.hh> // hash_combine
9 #include <vcsn/misc/math.hh>
10 #include <vcsn/misc/raise.hh>
11 #include <vcsn/misc/star-status.hh>
12 #include <vcsn/misc/stream.hh> // eat
13 #include <vcsn/misc/symbol.hh>
14 #include <vcsn/weightset/b.hh>
15 #include <vcsn/weightset/fwd.hh>
17 #include <vcsn/weightset/z.hh>
18 
19 namespace vcsn
20 {
21  namespace detail
22  {
23  class q_impl
24  {
25  public:
26  using self_t = q;
27 
28  static symbol sname()
29  {
30  static auto res = symbol{"q"};
31  return res;
32  }
33 
35  static q make(std::istream& is)
36  {
37  eat(is, sname());
38  return {};
39  }
40 
41  struct value_t
42  {
43  value_t(int n = 0, unsigned d = 1)
44  : num(n)
45  , den(d)
46  {}
47 
50  {
51  int gc = gcd(abs(num), den);
52  num /= gc;
53  den /= gc;
54  return *this;
55  }
56 
57  int num;
58  unsigned den;
59  };
60 
62  static value_t value(int num, unsigned den)
63  {
64  return value_t{num, den}.reduce();
65  }
66 
67  static unsigned abs(int a)
68  {
69  return a < 0 ? -a : a;
70  }
71 
72  static value_t zero()
73  {
74  return value_t{0, 1};
75  }
76 
77  static value_t one()
78  {
79  return value_t{1, 1};
80  }
81 
82  static value_t min()
83  {
85  return value_t{num, 1};
86  }
87 
88  static value_t max()
89  {
90  auto num = std::numeric_limits<int>::max();
91  return value_t{num, 1};
92  }
93 
94  static value_t add(const value_t& l, const value_t& r)
95  {
96  unsigned cm = lcm(l.den, abs(r.den));
97  return value_t{l.num * int (cm / l.den) + r.num * int (cm / r.den),
98  cm}.reduce();
99  }
100 
101  static value_t sub(const value_t& l, const value_t& r)
102  {
103  unsigned cm = lcm(l.den, abs(r.den));
104  return value_t{l.num * int (cm / l.den) - r.num * int (cm / r.den),
105  cm}.reduce();
106  }
107 
108  static value_t mul(const value_t& l, const value_t& r)
109  {
110  return value_t{l.num * r.num, l.den * r.den}.reduce();
111  }
112 
114  value_t
115  lgcd(const value_t& l, const value_t& r) const
116  {
117  require(!is_zero(l), *this, ": lgcd: invalid lhs: zero");
118  require(!is_zero(r), *this, ": lgcd: invalid rhs: zero");
119  return l;
120  }
121 
122  value_t
123  rgcd(const value_t& l, const value_t& r) const
124  {
125  return lgcd(l, r);
126  }
127 
128  value_t
129  rdivide(const value_t& l, const value_t& r) const
130  {
131  require(!is_zero(r), *this, ": div: division by zero");
132  if (0 < r.num)
133  return value_t{l.num * int(r.den), l.den * r.num}.reduce();
134  else
135  return value_t{-l.num * int(r.den), l.den * -r.num}.reduce();
136  }
137 
138  value_t
139  ldivide(const value_t& l, const value_t& r) const
140  {
141  return rdivide(r, l);
142  }
143 
144  value_t star(const value_t& v) const
145  {
146  if (abs(v.num) < v.den)
147  // No need to reduce: numerator and denominator are coprime.
148  return {int(v.den), v.den - v.num};
149  else
150  raise_not_starrable(*this, v);
151  }
152 
153  static bool is_special(const value_t&) // C++11: cannot be constexpr.
154  {
155  return false;
156  }
157 
158  static bool is_zero(const value_t& v)
159  {
160  return v.num == 0;
161  }
162 
163  static bool is_one(const value_t& v)
164  {
165  // All values are normalized.
166  return v.num == 1 && v.den == 1;
167  }
168 
170  static int compare(const value_t& l, const value_t& r)
171  {
172  return l.num * long(r.den) - r.num * long(l.den);
173  }
174 
176  static bool equal(const value_t& l, const value_t& r)
177  {
178  return l.num == r.num && l.den == r.den;
179  }
180 
182  static bool less(const value_t& l, const value_t& r)
183  {
184  return l.num * long(r.den) < r.num * long(l.den);
185  }
186 
187  static constexpr bool is_commutative() { return true; }
188  static constexpr bool has_lightening_weights() { return true; }
189 
190  static constexpr bool show_one() { return false; }
191  static constexpr star_status_t star_status() { return star_status_t::ABSVAL; }
192 
193  static value_t
194  abs(const value_t& v)
195  {
196  return v.num < 0 ? (value_t{-v.num, v.den}) : v;
197  }
198 
199  static value_t
201  {
202  return v;
203  }
204 
205  static size_t hash(const value_t& v)
206  {
207  size_t res = 0;
208  hash_combine(res, hash_value(v.num));
209  hash_combine(res, hash_value(v.den));
210  return res;
211  }
212 
213  static value_t
214  conv(self_t, const value_t& v)
215  {
216  return v;
217  }
218 
219  static value_t
220  conv(z, const z::value_t v)
221  {
222  return {v, 1};
223  }
224 
225  static value_t
226  conv(b, const b::value_t v)
227  {
228  return {v, 1};
229  }
230 
231  value_t
232  conv(std::istream& i, bool = true) const
233  {
234  int num;
235  if (!(i >> num))
236  raise(*this, ": invalid numerator: ", i);
237 
238  // If we have a slash after the numerator then we have a
239  // denominator as well.
240  if (i.peek() == '/')
241  {
242  eat(i, '/');
243 
244  // operator>> with an istream and an unsigned silently
245  // mangles a negative number into its two's complement
246  // representation as a positive number.
247  if (i.peek() == '-')
248  {
249  num = - num;
250  eat(i, '-');
251  }
252 
253  unsigned den;
254  if (!(i >> den))
255  raise(*this, ": invalid denominator: ", i);
256  // Make sure our rational respects our constraints.
257  require(den, *this, ": null denominator");
258  return value_t{num, den}.reduce();
259  }
260  else
261  return value_t{num, 1};
262  }
263 
264  static std::ostream&
265  print(const value_t& v, std::ostream& o = std::cout,
266  format fmt = {})
267  {
268  if (fmt == format::latex)
269  {
270  if (v.den == 1)
271  o << v.num;
272  else
273  o << "\\frac{" << v.num << "}{" << v.den << '}';
274  }
275  else
276  {
277  o << v.num;
278  if (v.den != 1)
279  o << '/' << v.den;
280  }
281  return o;
282  }
283 
284  std::ostream&
285  print_set(std::ostream& o, format fmt = {}) const
286  {
287  switch (fmt.kind())
288  {
289  case format::latex:
290  o << "\\mathbb{Q}";
291  break;
292  case format::sname:
293  o << sname();
294  break;
295  case format::text:
296  o << "Q";
297  break;
298  case format::utf8:
299  o << "ℚ";
300  break;
301  case format::raw:
302  assert(0);
303  break;
304  }
305  return o;
306  }
307  };
308 
310  template <typename RandomGenerator>
311  class random_weight<q, RandomGenerator>
312  : public random_weight_base<q, RandomGenerator>
313  {
314  public:
316  using value_t = typename super_t::weight_t;
317 
318  using super_t::super_t;
319 
320  private:
322  {
323  auto dis_num
324  = std::uniform_int_distribution<>(super_t::min_.num,
325  super_t::max_.num);
326  auto dis_den
327  = std::uniform_int_distribution<unsigned>(super_t::min_.den,
328  super_t::max_.num);
329  auto num = dis_num(super_t::gen_);
330  auto den = dis_den(super_t::gen_);
331  return super_t::ws_.value(num, den);
332  }
333  };
334 
335 
336  /*-------.
337  | join. |
338  `-------*/
339 
340  VCSN_JOIN_SIMPLE(b, q);
341  VCSN_JOIN_SIMPLE(z, q);
342  VCSN_JOIN_SIMPLE(q, q);
343  }
344 }
static bool is_special(const value_t &)
Definition: q.hh:153
Print as a parsable type string.
Definition: format.hh:26
static value_t mul(const value_t &l, const value_t &r)
Definition: q.hh:108
static value_t min()
Definition: q.hh:82
static value_t transpose(const value_t &v)
Definition: q.hh:200
static value_t value(int num, unsigned den)
Create rational weight from num and den.
Definition: q.hh:62
static value_t conv(z, const z::value_t v)
Definition: q.hh:220
static std::ostream & print(const value_t &v, std::ostream &o=std::cout, format fmt={})
Definition: q.hh:265
static value_t add(const value_t &l, const value_t &r)
Definition: q.hh:94
char eat(std::istream &is, char c)
Check lookahead character and advance.
Definition: stream.cc:147
return exp min
Definition: multiply.hh:362
ATTRIBUTE_PURE unsigned int lcm(unsigned int a, unsigned int b)
Lowest common multiple.
Definition: math.hh:28
static bool less(const value_t &l, const value_t &r)
Whether l < r.
Definition: q.hh:182
value_t(int n=0, unsigned d=1)
Definition: q.hh:43
static bool is_zero(const value_t &v)
Definition: q.hh:158
weightset_mixin< detail::q_impl > q
Definition: fwd.hh:52
boost::flyweight< std::string, boost::flyweights::no_tracking, boost::flyweights::intermodule_holder > symbol
An internalized string.
Definition: symbol.hh:21
valid iff proper succeeds on the "absolute value" of the automaton
Definition: star-status.hh:9
Print as rich UTF-8 text, escaped.
Definition: format.hh:30
An input/output format for valuesets.
Definition: format.hh:13
Abstract class for random weight generation.
Definition: weightset.hh:118
Provide a variadic mul on top of a binary mul(), and one().
Definition: fwd.hh:46
static bool equal(const value_t &l, const value_t &r)
Whether l == r.
Definition: q.hh:176
static value_t zero()
Definition: q.hh:72
static value_t conv(self_t, const value_t &v)
Definition: q.hh:214
typename super_t::weight_t value_t
Definition: q.hh:316
auto hash_value(const T &v) -> decltype(std::hash< T >
Following the naming convention of Boost.
Definition: functional.hh:45
static value_t one()
Definition: q.hh:77
static unsigned abs(int a)
Definition: q.hh:67
static size_t hash(const value_t &v)
Definition: q.hh:205
value_t star(const value_t &v) const
Definition: q.hh:144
Definition: a-star.hh:8
static symbol sname()
Definition: q.hh:28
value_t lgcd(const value_t &l, const value_t &r) const
GCD: arbitrarily the first argument.
Definition: q.hh:115
star_status_t
Definition: star-status.hh:5
static value_t max()
Definition: q.hh:88
Print as plain (ASCII) text, escaped.
Definition: format.hh:28
static value_t conv(b, const b::value_t v)
Definition: q.hh:226
value_t rdivide(const value_t &l, const value_t &r) const
Definition: q.hh:129
static int compare(const value_t &l, const value_t &r)
Three-way comparison between l and r.
Definition: q.hh:170
value_t conv(std::istream &i, bool=true) const
Definition: q.hh:232
ATTRIBUTE_NORETURN void raise_not_starrable(const WeightSet &ws, const typename WeightSet::value_t &w)
This value is not starrable.
Definition: weightset.hh:235
static constexpr bool show_one()
Definition: q.hh:190
static constexpr bool is_commutative()
Definition: q.hh:187
Print as is. For instance, don&#39;t try to escape labels.
Definition: format.hh:24
Print for LaTeX.
Definition: format.hh:22
ATTRIBUTE_PURE unsigned int gcd(unsigned int a, unsigned int b)
Greatest common divisor.
Definition: math.hh:13
static bool is_one(const value_t &v)
Definition: q.hh:163
void hash_combine(std::size_t &seed, const T &v)
Definition: functional.hh:63
VCSN_JOIN_SIMPLE(b, b)
static value_t abs(const value_t &v)
Definition: q.hh:194
static constexpr star_status_t star_status()
Definition: q.hh:191
Generic declaration of the class which is specialized in each weightset.
Definition: weightset.hh:208
void require(Bool b, Args &&... args)
If b is not verified, raise an error with args as message.
Definition: raise.hh:87
static value_t sub(const value_t &l, const value_t &r)
Definition: q.hh:101
std::ostream & print_set(std::ostream &o, format fmt={}) const
Definition: q.hh:285
return res
Definition: multiply.hh:399
static q make(std::istream &is)
Build from the description in is.
Definition: q.hh:35
value_t ldivide(const value_t &l, const value_t &r) const
Definition: q.hh:139
value_t & reduce()
Put it in normal form.
Definition: q.hh:49
static constexpr bool has_lightening_weights()
Definition: q.hh:188
value_t rgcd(const value_t &l, const value_t &r) const
Definition: q.hh:123