Vcsn  2.1
Be Rational
q.hh
Go to the documentation of this file.
1 #pragma once
2 
3 #include <string>
4 #include <ostream>
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 symbol res("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 int den;
59  };
60 
61  static unsigned int abs(int a)
62  {
63  return a < 0 ? -a : a;
64  }
65 
66  static value_t zero()
67  {
68  return value_t{0, 1};
69  }
70 
71  static value_t one()
72  {
73  return value_t{1, 1};
74  }
75 
76  static value_t add(const value_t l, const value_t r)
77  {
78  unsigned int cm = lcm(l.den, abs(r.den));
79  return value_t{l.num * int (cm / l.den) + r.num * int (cm / r.den),
80  cm}.reduce();
81  }
82 
83  static value_t sub(const value_t l, const value_t r)
84  {
85  unsigned int cm = lcm(l.den, abs(r.den));
86  return value_t{l.num * int (cm / l.den) - r.num * int (cm / r.den),
87  cm}.reduce();
88  }
89 
90  static value_t mul(const value_t l, const value_t r)
91  {
92  return value_t{l.num * r.num, l.den * r.den}.reduce();
93  }
94 
96  static value_t
97  lgcd(const value_t l, const value_t r)
98  {
99  require(!is_zero(l), sname(), ": lgcd: invalid lhs: zero");
100  require(!is_zero(r), sname(), ": lgcd: invalid rhs: zero");
101  return l;
102  }
103 
104  static value_t
105  rgcd(const value_t l, const value_t r)
106  {
107  return lgcd(l, r);
108  }
109 
110  static value_t
111  rdiv(const value_t l, const value_t r)
112  {
113  require(!is_zero(r), "div: division by zero");
114  if (0 < r.num)
115  return value_t{l.num * int(r.den), l.den * r.num}.reduce();
116  else
117  return value_t{-l.num * int(r.den), l.den * -r.num}.reduce();
118  }
119 
120  static value_t
121  ldiv(const value_t l, const value_t r)
122  {
123  return rdiv(r, l);
124  }
125 
126  value_t star(const value_t v) const
127  {
128  if (abs(v.num) < v.den)
129  // No need to reduce: numerator and denominator are coprime.
130  return {int(v.den), v.den - v.num};
131  else
132  raise(sname(), ": star: invalid value: ", to_string(*this, v));
133  }
134 
135  static bool is_special(const value_t) // C++11: cannot be constexpr.
136  {
137  return false;
138  }
139 
140  static bool is_zero(const value_t v)
141  {
142  return v.num == 0;
143  }
144 
145  static bool is_one(const value_t v)
146  {
147  // All values are normalized.
148  return v.num == 1 && v.den == 1;
149  }
150 
151  static bool equal(const value_t l, const value_t r)
152  {
153  return l.num == r.num && l.den == r.den;
154  }
155 
157  static bool less(const value_t lhs, const value_t rhs)
158  {
159  return lhs.num * rhs.den < rhs.num * lhs.den;
160  }
161 
162  static constexpr bool is_commutative() { return true; }
163 
164  static constexpr bool show_one() { return false; }
165  static constexpr star_status_t star_status() { return star_status_t::ABSVAL; }
166 
167  static value_t
168  abs(const value_t v)
169  {
170  return v.num < 0 ? (value_t{-v.num, v.den}) : v;
171  }
172 
173  static value_t
175  {
176  return v;
177  }
178 
179  static size_t hash(const value_t v)
180  {
181  size_t res = 0;
182  hash_combine(res, hash_value(v.num));
183  hash_combine(res, hash_value(v.den));
184  return res;
185  }
186 
187  static value_t
189  {
190  return v;
191  }
192 
193  static value_t
194  conv(z, const z::value_t v)
195  {
196  return {v, 1};
197  }
198 
199  static value_t
200  conv(b, const b::value_t v)
201  {
202  return {v, 1};
203  }
204 
205  static value_t
206  conv(std::istream& i, bool = true)
207  {
208  int num;
209  if (!(i >> num))
210  raise(sname(), ": invalid numerator: ", i);
211 
212  // If we have a slash after the numerator then we have a
213  // denominator as well.
214  if (i.peek() == '/')
215  {
216  eat(i, '/');
217 
218  // operator>> with an istream and an unsigned int silently
219  // mangles a negative number into its two's complement
220  // representation as a positive number.
221  if (i.peek() == '-')
222  {
223  num = - num;
224  eat(i, '-');
225  }
226 
227  unsigned int den;
228  if (!(i >> den))
229  raise(sname(), ": invalid denominator: ", i);
230  // Make sure our rational respects our constraints.
231  require(den, sname(), ": null denominator");
232  return value_t{num, den}.reduce();
233  }
234  else
235  return value_t{num, 1};
236  }
237 
238  static std::ostream&
239  print(const value_t v, std::ostream& o,
240  format fmt = {})
241  {
242  if (fmt == format::latex)
243  {
244  if (v.den == 1)
245  o << v.num;
246  else
247  o << "\\frac{" << v.num << "}{" << v.den << '}';
248  }
249  else
250  {
251  o << v.num;
252  if (v.den != 1)
253  o << '/' << v.den;
254  }
255  return o;
256  }
257 
258  std::ostream&
259  print_set(std::ostream& o, format fmt = {}) const
260  {
261  if (fmt == format::latex)
262  o << "\\mathbb{Q}";
263  else if (fmt == format::text)
264  o << sname();
265  else
266  raise("invalid format: ", fmt);
267  return o;
268  }
269  };
270 
271  /*-------.
272  | join. |
273  `-------*/
274 
275  VCSN_JOIN_SIMPLE(b, q);
276  VCSN_JOIN_SIMPLE(z, q);
277  VCSN_JOIN_SIMPLE(q, q);
278  }
279 }
static value_t sub(const value_t l, const value_t r)
Definition: q.hh:83
ATTRIBUTE_PURE unsigned int gcd(unsigned int a, unsigned int b)
Greatest common divisor.
Definition: math.hh:13
static constexpr bool is_commutative()
Definition: q.hh:162
std::ostream & print_set(std::ostream &o, format fmt={}) const
Definition: q.hh:259
static value_t lgcd(const value_t l, const value_t r)
GCD: arbitrarily the first argument.
Definition: q.hh:97
static value_t rdiv(const value_t l, const value_t r)
Definition: q.hh:111
value_t(int n=0, unsigned d=1)
Definition: q.hh:43
std::istringstream is
The input stream: the specification to translate.
Definition: translate.cc:372
unsigned int den
Definition: q.hh:58
static value_t rgcd(const value_t l, const value_t r)
Definition: q.hh:105
weightset_mixin< detail::b_impl > b
Definition: fwd.hh:48
char eat(std::istream &is, char c)
Check lookahead character and advance.
Definition: stream.cc:37
static value_t ldiv(const value_t l, const value_t r)
Definition: q.hh:121
static value_t mul(const value_t l, const value_t r)
Definition: q.hh:90
static bool is_one(const value_t v)
Definition: q.hh:145
static bool is_zero(const value_t v)
Definition: q.hh:140
static value_t add(const value_t l, const value_t r)
Definition: q.hh:76
auto hash_value(const T &v) -> decltype(std::hash< T >
Following the naming convention of Boost.
Definition: functional.hh:63
static value_t one()
Definition: q.hh:71
value_t & reduce()
Put it in normal form.
Definition: q.hh:49
void hash_combine(std::size_t &seed, const T &v)
Definition: functional.hh:32
static q make(std::istream &is)
Build from the description in is.
Definition: q.hh:35
static size_t hash(const value_t v)
Definition: q.hh:179
An input/output format.
Definition: format.hh:11
static value_t transpose(const value_t v)
Definition: q.hh:174
Provide a variadic mul on top of a binary mul(), and one().
Definition: fwd.hh:46
static value_t conv(std::istream &i, bool=true)
Definition: q.hh:206
static bool is_special(const value_t)
Definition: q.hh:135
weightset_mixin< detail::q_impl > q
Definition: fwd.hh:52
void require(bool b, Args &&...args)
If b is not verified, raise an error with args as message.
Definition: raise.hh:75
static bool less(const value_t lhs, const value_t rhs)
Whether lhs < rhs.
Definition: q.hh:157
std::string to_string(direction d)
Conversion to string.
Definition: direction.cc:7
static value_t conv(b, const b::value_t v)
Definition: q.hh:200
valid iff proper succeeds on the "absolute value" of the automaton
Definition: star-status.hh:9
static constexpr bool show_one()
Definition: q.hh:164
boost::flyweight< std::string, boost::flyweights::no_tracking, boost::flyweights::intermodule_holder > symbol
An internalized string.
Definition: symbol.hh:23
static unsigned int abs(int a)
Definition: q.hh:61
static bool equal(const value_t l, const value_t r)
Definition: q.hh:151
star_status_t
Definition: star-status.hh:5
static value_t abs(const value_t v)
Definition: q.hh:168
static constexpr star_status_t star_status()
Definition: q.hh:165
static value_t conv(self_t, const value_t v)
Definition: q.hh:188
VCSN_JOIN_SIMPLE(b, b)
static value_t zero()
Definition: q.hh:66
ATTRIBUTE_PURE unsigned int lcm(unsigned int a, unsigned int b)
Lowest common multiple.
Definition: math.hh:28
static value_t conv(z, const z::value_t v)
Definition: q.hh:194
value_t star(const value_t v) const
Definition: q.hh:126
weightset_mixin< detail::z_impl > z
Definition: fwd.hh:56
static std::ostream & print(const value_t v, std::ostream &o, format fmt={})
Definition: q.hh:239
static symbol sname()
Definition: q.hh:28