Awali
Another Weighted Automata library
q.hh
Go to the documentation of this file.
1 // This file is part of Awali.
2 // Copyright 2016-2023 Sylvain Lombardy, Victor Marsault, Jacques Sakarovitch
3 //
4 // Awali is a free software: you can redistribute it and/or modify
5 // it under the terms of the GNU General Public License as published by
6 // the Free Software Foundation, either version 3 of the License, or
7 // (at your option) any later version.
8 //
9 // This program is distributed in the hope that it will be useful,
10 // but WITHOUT ANY WARRANTY; without even the implied warranty of
11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 // GNU General Public License for more details.
13 //
14 // You should have received a copy of the GNU General Public License
15 // along with this program. If not, see <http://www.gnu.org/licenses/>.
16 
17 #ifndef AWALI_WEIGHTSET_Q_HH
18 #define AWALI_WEIGHTSET_Q_HH
19 
20 #include <string>
21 #include <ostream>
22 
23 #include <awali/utils/arith.hh>
24 
25 #include <awali/common/qfraction.cc>
26 #include <awali/common/enums.hh>
27 
29 #include <awali/utils/hash.hh>
30 
31 #include <awali/sttc/misc/raise.hh>
32 #include <awali/sttc/misc/stream.hh> // eat
35 
36 namespace awali {
37  namespace sttc {
42  class q {
43  public:
44  using self_type = q;
45 
46  static std::string sname()
47  {
48  return "q";
49  }
50 
51  std::string vname(bool = true) const
52  {
53  return sname();
54  }
55 
57  static q make(std::istream& is)
58  {
59  eat(is, sname());
60  return {};
61  }
62 
64 
65  static unsigned int abs(int a)
66  {
67  return a < 0 ? -a : a;
68  }
69 
70 
71  static value_t zero()
72  {
73  return value_t{0, 1};
74  }
75 
76  static value_t one()
77  {
78  return value_t{1, 1};
79  }
80 
81  static value_t add(const value_t l, const value_t r)
82  {
83  unsigned int cm = utils::lcm(l.den, abs(r.den));
84  return value_t{l.num * int (cm / l.den) + r.num * int (cm / r.den),
85  cm}.reduce();
86  }
87 
88  static value_t sub(const value_t l, const value_t r)
89  {
90  unsigned int cm = utils::lcm(l.den, abs(r.den));
91  return value_t{l.num * int (cm / l.den) - r.num * int (cm / r.den),
92  cm}.reduce();
93  }
94 
95  static value_t mul(const value_t l, const value_t r)
96  {
97  return value_t{l.num * r.num, l.den * r.den}.reduce();
98  }
99 
100  static value_t
101  rdiv(const value_t l, const value_t r)
102  {
103  require(!is_zero(r), "div: division by zero");
104  if (0 < r.num)
105  return value_t{l.num * int(r.den), l.den * r.num}.reduce();
106  else
107  return value_t{-l.num * int(r.den), l.den * -r.num}.reduce();
108  }
109 
110  static value_t
111  ldiv(const value_t l, const value_t r)
112  {
113  return rdiv(r, l);
114  }
115 
116  value_t star(const value_t v) const
117  {
118  // Bad casting when v.den is too big
119  if (abs(v.num) < v.den)
120  // No need to reduce: numerator and denominators are primes.
121  return {int(v.den), v.den - v.num};
122  else
123  raise(sname(), ": star: invalid value: ", format(*this, v));
124  }
125 
126  value_t plus(const value_t v) const
127  {
128  // Bad casting when v.den is too big
129  if (abs(v.num) < v.den)
130  // No need to reduce: numerator and denominators are primes.
131  return {v.num, v.den - v.num};
132  else
133  raise(sname(), ": star: invalid value: ", format(*this, v));
134  }
135 
136  static bool is_special(const value_t) // C++11: cannot be constexpr.
137  {
138  return false;
139  }
140 
141  static bool is_zero(const value_t v)
142  {
143  return v.num == 0;
144  }
145 
146  static bool is_one(const value_t v)
147  {
148  // All values are normalized.
149  return v.num == 1 && v.den == 1;
150  }
151 
152  static bool equals(const value_t l, const value_t r)
153  {
154  return l==r;
155  }
156 
158  static bool less_than(value_t lhs, value_t rhs)
159  {
160  return lhs < rhs;
161  }
162 
163  static constexpr bool is_commutative_semiring() { return true; }
164 
165  static constexpr bool show_one() { return false; }
166  static constexpr star_status_t star_status() { return star_status_t::ABSVAL; }
167 
168  static value_t
169  abs(const value_t v)
170  {
171  return v.num < 0 ? (value_t{-v.num, v.den}) : v;
172  }
173 
174  static value_t
176  {
177  return v;
178  }
179 
180  static size_t hash(value_t v)
181  {
182  size_t res = 0;
183  std::hash_combine(res, utils::hash_value(v.num));
184  std::hash_combine(res, utils::hash_value(v.den));
185  return res;
186  }
187 
188  static value_t
190  {
191  return v;
192  }
193 
194  static value_t
196  {
197  return {v, 1};
198  }
199 
200  static value_t
202  {
203  return {(int)v, 1};
204  }
205 
206  static value_t
208  {
209  return {v, 1};
210  }
211 
212  static value_t
213  conv(std::istream& i)
214  {
215  int num;
216  if (! (i >> num))
217  fail_reading(i, sname() + ": invalid numerator");
218 
219  // If we have a slash after the numerator then we have a
220  // denominator as well.
221  char maybe_slash;
222  if ((maybe_slash = i.peek()) != '/')
223  return value_t{num, 1};
224  eat(i, '/');
225 
226  // operator>> with an istream and an unsigned int silently
227  // mangles a negative number into its two's complement
228  // representation as a positive number.
229  if (i.peek() == '-')
230  {
231  num = - num;
232  eat(i, '-');
233  }
234 
235  unsigned int den;
236  if (i >> den)
237  {
238  // Make sure our rational respects our constraints.
239  if (den == 0)
240  throw std::domain_error(sname() + ": zero denominator");
241  return value_t{num, den}.reduce();
242  }
243  else
244  fail_reading(i, sname() + ": invalid denominator");
245  }
246 
247  static value_t
248  parse(const std::string & s, size_t& p) {
249  return internal::lr_parse_qfraction(s,p);
250  }
251 
252 
253  static std::ostream&
254  print(const value_t v, std::ostream& o,
255  const std::string& format = "text")
256  {
257  if (format == "json") {
258  if(v.den ==1u)
259  return o << v.num;
260  o<< "{\"num\":" << v.num << ", \"den\":" << v.den << '}';
261  return o;
262  }
263  if (format == "latex")
264  {
265  if (v.den == 1)
266  o << v.num;
267  else
268  o << "\\frac{" << v.num << "}{" << v.den << '}';
269  }
270  else
271  {
272  o << v.num;
273  if (v.den != 1)
274  o << '/' << v.den;
275  }
276  return o;
277  }
278 
279  std::ostream&
280  print_set(std::ostream& o, const std::string& format = "text") const
281  {
282  if (format == "latex")
283  o << "\\mathbb{Q}";
284  else if (format == "text")
285  o << "Q";
286  else
287  raise("invalid format: ", format);
288  return o;
289  }
290 
291  template<unsigned version = version::fsm_json>
293  to_json() const
294  {
295  version::check_fsmjson<version>();
296  switch (version) {
297  case 0: /* Never occurs due to above check. */
298  case 1:
299  default:
300  return new json::object_t("semiring", new json::string_t("Q"));
301  }
302  }
303 
304  template<unsigned version = version::fsm_json>
306  const
307  {
308  version::check_fsmjson<version>();
309  switch (version) {
310  case 0: /* Never occurs due to above check. */
311  case 1:
312  default:
313  if(v.den ==1u)
314  return new json::int_t(v.num);
315  json::object_t* l = new json::object_t();
316  l->push_back("num",new json::int_t(v.num));
317  l->push_back("den",new json::int_t(v.den));
318  return l;
319  }
320  }
321 
322  template<unsigned version = version::fsm_json>
324  const
325  {
326  version::check_fsmjson<version>();
327  switch (version) {
328  case 0: /* Never occurs due to above check. */
329  case 1:
330  default:
331  switch(p->kind) {
332  case json::FLOATING:
334  "[Q] value_from_json: node is of kind FLOATING and we do "
335  "not support double to qfraction conversion");
336  case json::BOOLEAN:
337  case json::INTEGER:
338  case json::STRING: {
339  try {return value_t{p->to_int(),1u};}
340  catch (json::coercion_exception&) {}
341  std::stringstream ss(p->string()->value);
342  value_t v = conv(ss); // This might be wrong
343  if (ss.eof())
344  return v;
346  "[Q] value_from_json: node is of kind STRING and is not a "
347  "proper qfraction representation.");
348  }
349  case json::ARRAY :{
350  if (p->arity()!=2)
352  "[Q] value_from_json: node is of kind ARRAY and needs to "
353  " have two children to be interpreted as a qfraction.");
354  return value_t(p->at(0)->to_int(),p->at(1)->to_int());
355  }
356  case json::OBJECT :{
357  int n;
358  if(!p->has_child("num")) {
360  "[Q] value_from_json: node is of kind OBJECT and needs to "
361  "have a \"num\" field to be interpreted as a qfraction.");
362  }
363  try {
364  n = p->at("num")->to_int();
365  } catch (json::coercion_exception& e) {
367  "[Q] value_from_json:: node is of kind OBJECT, hence the "
368  "node associated with \"num\" needs to be coercible to "
369  "int. " + std::string(e.what()));
370  }
371  if (p->has_child("den"))
372  return value_t(n, p->at("den")->to_int());
373  else
374  return value_t(n);
375  }
376  case json::_NULL:
378  "[Q] value_from_json: node is of kind NULL and cannot be "
379  "interpreted as a qfraction.");
380  }
381  throw std::runtime_error("json parser Q");
382  }
383  }
384 
385  };
386 
387  inline q join(const q&, const q&) { return {}; }
388 
389  inline q join(const z&, const q&) { return {}; }
390  inline q join(const q&, const z&) { return {}; }
391 
392  inline q join(const n&, const q&) { return {}; }
393  inline q join(const q&, const n&) { return {}; }
394 
395  inline q join(const b&, const q&) { return {}; }
396  inline q join(const q&, const b&) { return {}; }
397 
398  }
399 }//end of ns awali::stc
400 
401 
402 
403 
404 #endif // !AWALI_WEIGHTSET_Q_HH
Exception used when trying to coerce a node to a given type.
Definition: node.hh:143
virtual const char * what() const noexcept override
Definition: node.hh:128
Definition: node.hh:488
Definition: node.hh:193
virtual node_t * at(std::string const &key)
virtual int to_int() const
Coerces this node_t to int.
Definition: node.hh:321
virtual string_t const * string() const
Casts this node to string_t.
Definition: node.hh:215
virtual bool has_child(std::string const &) const
Definition: node.hh:284
node_kind_t const kind
Definition: node.hh:196
virtual unsigned arity() const
Definition: node.hh:355
Definition: node.hh:367
object_t * push_back(std::string key, node_t *node)
Definition: node.hh:529
std::string value
Definition: node.hh:531
Definition: qfraction.hh:26
q_fraction_t & reduce()
den_t den
Definition: qfraction.hh:32
num_t num
Definition: qfraction.hh:31
The Boolean semring.
Definition: b.hh:38
bool value_t
Definition: b.hh:56
The semiring of Natural numbers.
Definition: n.hh:34
unsigned int value_t
Definition: n.hh:55
The semiring of rational numbers.
Definition: q.hh:42
value_t star(const value_t v) const
Definition: q.hh:116
static value_t one()
Definition: q.hh:76
json::node_t * value_to_json(value_t v) const
Definition: q.hh:305
static size_t hash(value_t v)
Definition: q.hh:180
static value_t mul(const value_t l, const value_t r)
Definition: q.hh:95
static value_t parse(const std::string &s, size_t &p)
Definition: q.hh:248
value_t value_from_json(json::node_t const *p) const
Definition: q.hh:323
static value_t conv(z, z::value_t v)
Definition: q.hh:195
static constexpr bool show_one()
Definition: q.hh:165
static value_t add(const value_t l, const value_t r)
Definition: q.hh:81
static bool less_than(value_t lhs, value_t rhs)
Whether lhs < rhs.
Definition: q.hh:158
static value_t abs(const value_t v)
Definition: q.hh:169
static value_t ldiv(const value_t l, const value_t r)
Definition: q.hh:111
static value_t transpose(const value_t v)
Definition: q.hh:175
static value_t conv(b, b::value_t v)
Definition: q.hh:207
static bool is_special(const value_t)
Definition: q.hh:136
static bool is_one(const value_t v)
Definition: q.hh:146
static value_t conv(std::istream &i)
Definition: q.hh:213
static value_t conv(n, n::value_t v)
Definition: q.hh:201
static value_t rdiv(const value_t l, const value_t r)
Definition: q.hh:101
static bool is_zero(const value_t v)
Definition: q.hh:141
static std::string sname()
Definition: q.hh:46
std::ostream & print_set(std::ostream &o, const std::string &format="text") const
Definition: q.hh:280
json::object_t * to_json() const
Definition: q.hh:293
std::string vname(bool=true) const
Definition: q.hh:51
static value_t conv(self_type, value_t v)
Definition: q.hh:189
static q make(std::istream &is)
Build from the description in is.
Definition: q.hh:57
static value_t zero()
Definition: q.hh:71
value_t plus(const value_t v) const
Definition: q.hh:126
static constexpr bool is_commutative_semiring()
Definition: q.hh:163
static std::ostream & print(const value_t v, std::ostream &o, const std::string &format="text")
Definition: q.hh:254
static constexpr star_status_t star_status()
Definition: q.hh:166
static unsigned int abs(int a)
Definition: q.hh:65
static value_t sub(const value_t l, const value_t r)
Definition: q.hh:88
static bool equals(const value_t l, const value_t r)
Definition: q.hh:152
q_fraction_t value_t
Definition: q.hh:63
The semiring of floating Numbers.
Definition: r.hh:35
The semiring of Integers.
Definition: z.hh:35
int value_t
Definition: z.hh:56
star_status_t
The different behaviours a weightset may have with respect to the star.
Definition: enums.hh:163
@ ABSVAL
Definition: enums.hh:168
@ OBJECT
Definition: node.hh:93
@ INTEGER
Definition: node.hh:95
@ ARRAY
Definition: node.hh:94
@ BOOLEAN
Definition: node.hh:98
@ STRING
Definition: node.hh:97
@ FLOATING
Definition: node.hh:96
@ _NULL
Definition: node.hh:99
q_fraction_t lr_parse_qfraction(std::string const &s, size_t &p, bool allow_empty=false, q_fraction_t value_if_empty={1, 1})
Reads a q_fraction_t left of position p in string, by using as many characters as possible.
Definition: lr_parse_number.hh:353
void eat(std::istream &is, char c)
Check lookahead character and advance.
Definition: stream.hh:62
ATTRIBUTE_NORETURN void fail_reading(std::istream &is, std::string explanation)
Throw an exception after failing to read from is.
Definition: stream.hh:93
auto join(const ratexpset< Ctx1 > &a, const ratexpset< Ctx2 > &b) -> ratexpset< join_t< Ctx1, Ctx2 >>
The union of two ratexpsets.
Definition: ratexpset.hh:449
auto format(const ValueSet &vs, const typename ValueSet::value_t &v, Args &&... args) -> std::string
Format v via vs.print.
Definition: stream.hh:109
void require(bool b, Args &&... args)
If b is not verified, raise an error with args as message.
Definition: raise.hh:55
std::size_t hash_value(const T &v)
Definition: hash.hh:76
ATTRIBUTE_CONST unsigned int lcm(unsigned int a, unsigned int b)
Definition: arith.hh:41
Main namespace of Awali.
Definition: ato.hh:22