Vcsn  2.4
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  {
84  auto num = std::numeric_limits<int>::min();
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 
169  static bool equal(const value_t& l, const value_t& r)
170  {
171  return l.num == r.num && l.den == r.den;
172  }
173 
175  static bool less(const value_t& lhs, const value_t& rhs)
176  {
177  return lhs.num * static_cast<long>(rhs.den)
178  < rhs.num * static_cast<long>(lhs.den);
179  }
180 
181  static constexpr bool is_commutative() { return true; }
182  static constexpr bool has_lightening_weights() { return true; }
183 
184  static constexpr bool show_one() { return false; }
185  static constexpr star_status_t star_status() { return star_status_t::ABSVAL; }
186 
187  static value_t
188  abs(const value_t& v)
189  {
190  return v.num < 0 ? (value_t{-v.num, v.den}) : v;
191  }
192 
193  static value_t
195  {
196  return v;
197  }
198 
199  static size_t hash(const value_t& v)
200  {
201  size_t res = 0;
202  hash_combine(res, hash_value(v.num));
203  hash_combine(res, hash_value(v.den));
204  return res;
205  }
206 
207  static value_t
208  conv(self_t, const value_t& v)
209  {
210  return v;
211  }
212 
213  static value_t
214  conv(z, const z::value_t v)
215  {
216  return {v, 1};
217  }
218 
219  static value_t
220  conv(b, const b::value_t v)
221  {
222  return {v, 1};
223  }
224 
225  value_t
226  conv(std::istream& i, bool = true) const
227  {
228  int num;
229  if (!(i >> num))
230  raise(*this, ": invalid numerator: ", i);
231 
232  // If we have a slash after the numerator then we have a
233  // denominator as well.
234  if (i.peek() == '/')
235  {
236  eat(i, '/');
237 
238  // operator>> with an istream and an unsigned silently
239  // mangles a negative number into its two's complement
240  // representation as a positive number.
241  if (i.peek() == '-')
242  {
243  num = - num;
244  eat(i, '-');
245  }
246 
247  unsigned den;
248  if (!(i >> den))
249  raise(*this, ": invalid denominator: ", i);
250  // Make sure our rational respects our constraints.
251  require(den, *this, ": null denominator");
252  return value_t{num, den}.reduce();
253  }
254  else
255  return value_t{num, 1};
256  }
257 
258  static std::ostream&
259  print(const value_t& v, std::ostream& o = std::cout,
260  format fmt = {})
261  {
262  if (fmt == format::latex)
263  {
264  if (v.den == 1)
265  o << v.num;
266  else
267  o << "\\frac{" << v.num << "}{" << v.den << '}';
268  }
269  else
270  {
271  o << v.num;
272  if (v.den != 1)
273  o << '/' << v.den;
274  }
275  return o;
276  }
277 
278  std::ostream&
279  print_set(std::ostream& o, format fmt = {}) const
280  {
281  switch (fmt.kind())
282  {
283  case format::latex:
284  o << "\\mathbb{Q}";
285  break;
286  case format::sname:
287  o << sname();
288  break;
289  case format::text:
290  o << "Q";
291  break;
292  case format::utf8:
293  o << "ℚ";
294  break;
295  case format::raw:
296  assert(0);
297  break;
298  }
299  return o;
300  }
301  };
302 
304  template <typename RandomGenerator>
305  class random_weight<q, RandomGenerator>
306  : public random_weight_base<q, RandomGenerator>
307  {
308  public:
310  using value_t = typename super_t::weight_t;
311 
312  using super_t::super_t;
313 
314  private:
316  {
317  auto dis_num
318  = std::uniform_int_distribution<>(super_t::min_.num,
319  super_t::max_.num);
320  auto dis_den
321  = std::uniform_int_distribution<unsigned>(super_t::min_.den,
322  super_t::max_.num);
323  auto num = dis_num(super_t::gen_);
324  auto den = dis_den(super_t::gen_);
325  return super_t::ws_.value(num, den);
326  }
327  };
328 
329 
330  /*-------.
331  | join. |
332  `-------*/
333 
334  VCSN_JOIN_SIMPLE(b, q);
335  VCSN_JOIN_SIMPLE(z, q);
336  VCSN_JOIN_SIMPLE(q, q);
337  }
338 }
value_t & reduce()
Put it in normal form.
Definition: q.hh:49
Print as is. For instance, don't try to escape labels.
Definition: format.hh:24
char eat(std::istream &is, char c)
Check lookahead character and advance.
Definition: stream.cc:90
static value_t mul(const value_t &l, const value_t &r)
Definition: q.hh:108
Print as a parsable type string.
Definition: format.hh:26
Generic declaration of the class which is specialized in each weightset.
Definition: weightset.hh:205
static value_t conv(z, const z::value_t v)
Definition: q.hh:214
static bool less(const value_t &lhs, const value_t &rhs)
Whether lhs < rhs.
Definition: q.hh:175
return res
Definition: multiply.hh:398
VCSN_JOIN_SIMPLE(b, b)
value_t rgcd(const value_t &l, const value_t &r) const
Definition: q.hh:123
Print for LaTeX.
Definition: format.hh:22
static value_t conv(self_t, const value_t &v)
Definition: q.hh:208
ATTRIBUTE_PURE unsigned int lcm(unsigned int a, unsigned int b)
Lowest common multiple.
Definition: math.hh:28
static unsigned abs(int a)
Definition: q.hh:67
static size_t hash(const value_t &v)
Definition: q.hh:199
ATTRIBUTE_PURE unsigned int gcd(unsigned int a, unsigned int b)
Greatest common divisor.
Definition: math.hh:13
static value_t max()
Definition: q.hh:88
An input/output format for valuesets.
Definition: format.hh:13
Abstract class for random weight generation.
Definition: weightset.hh:112
static value_t conv(b, const b::value_t v)
Definition: q.hh:220
void require(Bool b, Args &&...args)
If b is not verified, raise an error with args as message.
Definition: raise.hh:91
Provide a variadic mul on top of a binary mul(), and one().
Definition: fwd.hh:46
static constexpr bool show_one()
Definition: q.hh:184
boost::flyweight< std::string, boost::flyweights::no_tracking, boost::flyweights::intermodule_holder > symbol
An internalized string.
Definition: symbol.hh:23
static constexpr bool is_commutative()
Definition: q.hh:181
auto hash_value(const T &v) -> decltype(std::hash< T >
Following the naming convention of Boost.
Definition: functional.hh:30
static value_t sub(const value_t &l, const value_t &r)
Definition: q.hh:101
value_t star(const value_t &v) const
Definition: q.hh:144
value_t(int n=0, unsigned d=1)
Definition: q.hh:43
static bool is_special(const value_t &)
Definition: q.hh:153
return exp min
Definition: multiply.hh:361
Definition: a-star.hh:8
static bool equal(const value_t &l, const value_t &r)
Definition: q.hh:169
typename super_t::weight_t value_t
Definition: q.hh:310
Print as rich UTF-8 text, escaped.
Definition: format.hh:30
static value_t abs(const value_t &v)
Definition: q.hh:188
static value_t value(int num, unsigned den)
Create rational weight from num and den.
Definition: q.hh:62
Print as plain (ASCII) text, escaped.
Definition: format.hh:28
static std::ostream & print(const value_t &v, std::ostream &o=std::cout, format fmt={})
Definition: q.hh:259
weightset_mixin< detail::q_impl > q
Definition: fwd.hh:52
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
valid iff proper succeeds on the "absolute value" of the automaton
Definition: star-status.hh:9
star_status_t
Definition: star-status.hh:5
static value_t one()
Definition: q.hh:77
std::ostream & print_set(std::ostream &o, format fmt={}) const
Definition: q.hh:279
ATTRIBUTE_NORETURN void raise_not_starrable(const WeightSet &ws, const typename WeightSet::value_t &w)
This value is not starrable.
Definition: raise.hh:100
static value_t add(const value_t &l, const value_t &r)
Definition: q.hh:94
value_t conv(std::istream &i, bool=true) const
Definition: q.hh:226
value_t lgcd(const value_t &l, const value_t &r) const
GCD: arbitrarily the first argument.
Definition: q.hh:115
static symbol sname()
Definition: q.hh:28
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:48
static bool is_zero(const value_t &v)
Definition: q.hh:158
static value_t zero()
Definition: q.hh:72
static constexpr bool has_lightening_weights()
Definition: q.hh:182
static value_t min()
Definition: q.hh:82
static value_t transpose(const value_t &v)
Definition: q.hh:194
static constexpr star_status_t star_status()
Definition: q.hh:185
value_t rdivide(const value_t &l, const value_t &r) const
Definition: q.hh:129