Awali
Another Weighted Automata library
q.hh
Go to the documentation of this file.
1 // This file is part of Awali.
2 // Copyright 2016-2021 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
34 
35 namespace awali {
36  namespace sttc {
41  class q {
42  public:
43  using self_type = q;
44 
45  static std::string sname()
46  {
47  return "q";
48  }
49 
50  std::string vname(bool = true) const
51  {
52  return sname();
53  }
54 
56  static q make(std::istream& is)
57  {
58  eat(is, sname());
59  return {};
60  }
61 
63 
64  static unsigned int abs(int a)
65  {
66  return a < 0 ? -a : a;
67  }
68 
69 
70  static value_t zero()
71  {
72  return value_t{0, 1};
73  }
74 
75  static value_t one()
76  {
77  return value_t{1, 1};
78  }
79 
80  static value_t add(const value_t l, const value_t r)
81  {
82  unsigned int cm = utils::lcm(l.den, abs(r.den));
83  return value_t{l.num * int (cm / l.den) + r.num * int (cm / r.den),
84  cm}.reduce();
85  }
86 
87  static value_t sub(const value_t l, const value_t r)
88  {
89  unsigned int cm = utils::lcm(l.den, abs(r.den));
90  return value_t{l.num * int (cm / l.den) - r.num * int (cm / r.den),
91  cm}.reduce();
92  }
93 
94  static value_t mul(const value_t l, const value_t r)
95  {
96  return value_t{l.num * r.num, l.den * r.den}.reduce();
97  }
98 
99  static value_t
100  rdiv(const value_t l, const value_t r)
101  {
102  require(!is_zero(r), "div: division by zero");
103  if (0 < r.num)
104  return value_t{l.num * int(r.den), l.den * r.num}.reduce();
105  else
106  return value_t{-l.num * int(r.den), l.den * -r.num}.reduce();
107  }
108 
109  static value_t
110  ldiv(const value_t l, const value_t r)
111  {
112  return rdiv(r, l);
113  }
114 
115  value_t star(const value_t v) const
116  {
117  // Bad casting when v.den is too big
118  if (abs(v.num) < v.den)
119  // No need to reduce: numerator and denominators are primes.
120  return {int(v.den), v.den - v.num};
121  else
122  raise(sname(), ": star: invalid value: ", format(*this, v));
123  }
124 
125  static bool is_special(const value_t) // C++11: cannot be constexpr.
126  {
127  return false;
128  }
129 
130  static bool is_zero(const value_t v)
131  {
132  return v.num == 0;
133  }
134 
135  static bool is_one(const value_t v)
136  {
137  // All values are normalized.
138  return v.num == 1 && v.den == 1;
139  }
140 
141  static bool equals(const value_t l, const value_t r)
142  {
143  return l==r;
144  }
145 
147  static bool less_than(value_t lhs, value_t rhs)
148  {
149  return lhs < rhs;
150  }
151 
152  static constexpr bool is_commutative_semiring() { return true; }
153 
154  static constexpr bool show_one() { return false; }
155  static constexpr star_status_t star_status() { return star_status_t::ABSVAL; }
156 
157  static value_t
158  abs(const value_t v)
159  {
160  return v.num < 0 ? (value_t{-v.num, v.den}) : v;
161  }
162 
163  static value_t
165  {
166  return v;
167  }
168 
169  static size_t hash(value_t v)
170  {
171  size_t res = 0;
172  std::hash_combine(res, utils::hash_value(v.num));
173  std::hash_combine(res, utils::hash_value(v.den));
174  return res;
175  }
176 
177  static value_t
179  {
180  return v;
181  }
182 
183  static value_t
185  {
186  return {v, 1};
187  }
188 
189  static value_t
191  {
192  return {(int)v, 1};
193  }
194 
195  static value_t
197  {
198  return {v, 1};
199  }
200 
201  static value_t
202  conv(std::istream& i)
203  {
204  int num;
205  if (! (i >> num))
206  fail_reading(i, sname() + ": invalid numerator");
207 
208  // If we have a slash after the numerator then we have a
209  // denominator as well.
210  char maybe_slash;
211  if ((maybe_slash = i.peek()) != '/')
212  return value_t{num, 1};
213  eat(i, '/');
214 
215  // operator>> with an istream and an unsigned int silently
216  // mangles a negative number into its two's complement
217  // representation as a positive number.
218  if (i.peek() == '-')
219  {
220  num = - num;
221  eat(i, '-');
222  }
223 
224  unsigned int den;
225  if (i >> den)
226  {
227  // Make sure our rational respects our constraints.
228  if (den == 0)
229  throw std::domain_error(sname() + ": zero denominator");
230  return value_t{num, den}.reduce();
231  }
232  else
233  fail_reading(i, sname() + ": invalid denominator");
234  }
235 
236  static value_t
237  parse(const std::string & s, size_t& p) {
238  size_t i;
239 
240  //Compute denominator
241  unsigned int y = 1;
242  for(i=p; i>0 && (s[i-1]>='0' && s[i-1]<='9');--i)
243  ;
244  if(i==p)
245  throw parse_exception("Wrong Q value (right):"+s);
246 
247  if (i>0 && s[i-1] == '/') { //There is a denominator
248  std::istringstream sty(s.substr(i, p-i));
249  sty >> y;
250  p=i-1;
251  }
252 
253  //Compute numerator
254  int x;
255  for(i=p; i>0 && (s[i-1]>='0' && s[i-1]<='9');--i)
256  ;
257 
258  if (i==p)
259  throw parse_exception("Wrong Q value (left):"+s);
260  if(i>0 && (s[i-1]=='-' || s[i-1]=='+'))
261  --i;
262  std::istringstream stx(s.substr(i, p-i));
263  stx >> x;
264  p=i;
265  return value_t{x,y};
266  }
267 
268 
269  static std::ostream&
270  print(const value_t v, std::ostream& o,
271  const std::string& format = "text")
272  {
273  if (format == "json") {
274  if(v.den ==1u)
275  return o << v.num;
276  o<< "{\"num\":" << v.num << ", \"den\":" << v.den << '}';
277  return o;
278  }
279  if (format == "latex")
280  {
281  if (v.den == 1)
282  o << v.num;
283  else
284  o << "\\frac{" << v.num << "}{" << v.den << '}';
285  }
286  else
287  {
288  o << v.num;
289  if (v.den != 1)
290  o << '/' << v.den;
291  }
292  return o;
293  }
294 
295  std::ostream&
296  print_set(std::ostream& o, const std::string& format = "text") const
297  {
298  if (format == "latex")
299  o << "\\mathbb{Q}";
300  else if (format == "text")
301  o << "Q";
302  else
303  raise("invalid format: ", format);
304  return o;
305  }
306 
307  template<unsigned version = version::fsm_json>
309  to_json() const
310  {
311  switch (version) {
312  case 0:
313  throw parse_exception("[q] Unsupported fsm-json version:"
314  + std::to_string(version));
315  case 1:
316  default:
317  return new json::object_t("semiring", new json::string_t("Q"));
318  }
319  }
320 
321  template<unsigned version = version::fsm_json>
323  const
324  {
325  switch (version) {
326  case 0:
327  throw parse_exception("[q] Unsupported fsm-json version:"
328  + std::to_string(version));
329  case 1:
330  default:
331  if(v.den ==1u)
332  return new json::int_t(v.num);
333  json::object_t* l = new json::object_t();
334  l->push_back("num",new json::int_t(v.num));
335  l->push_back("den",new json::int_t(v.den));
336  return l;
337  }
338  }
339 
340  template<unsigned version = version::fsm_json>
342  const
343  {
344  switch (version) {
345  case 0:
346  case 1:
347  default:
348  switch(p->kind) {
349  case json::FLOATING:
351  "[Q] value_from_json: node is of kind FLOATING and we do "
352  "not support double to qfraction conversion");
353  case json::BOOLEAN:
354  case json::INTEGER:
355  case json::STRING: {
356  try {return value_t{p->to_int(),1u};}
357  catch (json::coercion_exception&) {}
358  std::stringstream ss(p->string()->value);
359  value_t v = conv(ss); // This might be wrong
360  if (ss.eof())
361  return v;
363  "[Q] value_from_json: node is of kind STRING and is not a "
364  "proper qfraction representation.");
365  }
366  case json::ARRAY :{
367  std::vector<json::node_t*> const& v = p->array()->values;
368  if (p->arity()!=2)
370  "[Q] value_from_json: node is of kind ARRAY and needs to "
371  " have two children to be interpreted as a qfraction.");
372  return value_t(p->at(0)->to_int(),p->at(1)->to_int());
373  }
374  case json::OBJECT :{
375  int n;
376  if(!p->has_child("num")) {
378  "[Q] value_from_json: node is of kind OBJECT and needs to "
379  "have a \"num\" field to be interpreted as a qfraction.");
380  }
381  try {
382  n = p->at("num")->to_int();
383  } catch (json::coercion_exception& e) {
385  "[Q] value_from_json:: node is of kind OBJECT, hence the "
386  "node associated with \"num\" needs to be coercible to "
387  "int. " + std::string(e.what()));
388  }
389  if (p->has_child("den"))
390  return value_t(n, p->at("den")->to_int());
391  else
392  return value_t(n);
393  }
394  case json::_NULL:
396  "[Q] value_from_json: node is of kind NULL and cannot be "
397  "interpreted as a qfraction.");
398  }
399  throw std::runtime_error("json parser Q");
400  }
401  }
402 
403  };
404 
405  inline q join(const q&, const q&) { return {}; }
406 
407  inline q join(const z&, const q&) { return {}; }
408  inline q join(const q&, const z&) { return {}; }
409 
410  inline q join(const n&, const q&) { return {}; }
411  inline q join(const q&, const n&) { return {}; }
412 
413  inline q join(const b&, const q&) { return {}; }
414  inline q join(const q&, const b&) { return {}; }
415 
416  }
417 }//end of ns awali::stc
418 
419 
420 
421 
422 #endif // !AWALI_WEIGHTSET_Q_HH
std::vector< node_t * > const & values
Definition: node.hh:429
Exception used when trying to coerce a node to a given type.
Definition: exceptions.hh:83
virtual const char * what() const noexcept override
Definition: exceptions.hh:40
Definition: node.hh:483
Definition: node.hh:191
virtual node_t * at(std::string const &key)
virtual int to_int() const
Coerces this node_t to int.
Definition: node.hh:319
virtual string_t const * string() const
Casts this node to string_t.
Definition: node.hh:213
virtual bool has_child(std::string const &) const
Definition: node.hh:282
node_kind_t const kind
Definition: node.hh:194
virtual unsigned arity() const
Definition: node.hh:353
virtual array_t const * array() const
Casts this node to array_t.
Definition: node.hh:205
Definition: node.hh:365
object_t * push_back(std::string key, node_t *node)
Definition: node.hh:526
std::string value
Definition: node.hh:528
The Boolean semring.
Definition: b.hh:38
bool value_t
Definition: b.hh:56
The semiring of Natural numbers.
Definition: n.hh:33
unsigned int value_t
Definition: n.hh:54
The semiring of rational numbers.
Definition: q.hh:41
value_t star(const value_t v) const
Definition: q.hh:115
static value_t one()
Definition: q.hh:75
json::node_t * value_to_json(value_t v) const
Definition: q.hh:322
static size_t hash(value_t v)
Definition: q.hh:169
static value_t mul(const value_t l, const value_t r)
Definition: q.hh:94
static value_t parse(const std::string &s, size_t &p)
Definition: q.hh:237
value_t value_from_json(json::node_t const *p) const
Definition: q.hh:341
static value_t conv(z, z::value_t v)
Definition: q.hh:184
static constexpr bool show_one()
Definition: q.hh:154
static value_t add(const value_t l, const value_t r)
Definition: q.hh:80
static bool less_than(value_t lhs, value_t rhs)
Whether lhs < rhs.
Definition: q.hh:147
static value_t abs(const value_t v)
Definition: q.hh:158
static value_t ldiv(const value_t l, const value_t r)
Definition: q.hh:110
static value_t transpose(const value_t v)
Definition: q.hh:164
static value_t conv(b, b::value_t v)
Definition: q.hh:196
static bool is_special(const value_t)
Definition: q.hh:125
static bool is_one(const value_t v)
Definition: q.hh:135
static value_t conv(std::istream &i)
Definition: q.hh:202
static value_t conv(n, n::value_t v)
Definition: q.hh:190
static value_t rdiv(const value_t l, const value_t r)
Definition: q.hh:100
static bool is_zero(const value_t v)
Definition: q.hh:130
static std::string sname()
Definition: q.hh:45
std::ostream & print_set(std::ostream &o, const std::string &format="text") const
Definition: q.hh:296
json::object_t * to_json() const
Definition: q.hh:309
std::string vname(bool=true) const
Definition: q.hh:50
static value_t conv(self_type, value_t v)
Definition: q.hh:178
static q make(std::istream &is)
Build from the description in is.
Definition: q.hh:56
static value_t zero()
Definition: q.hh:70
static constexpr bool is_commutative_semiring()
Definition: q.hh:152
static std::ostream & print(const value_t v, std::ostream &o, const std::string &format="text")
Definition: q.hh:270
static constexpr star_status_t star_status()
Definition: q.hh:155
static unsigned int abs(int a)
Definition: q.hh:64
static value_t sub(const value_t l, const value_t r)
Definition: q.hh:87
static bool equals(const value_t l, const value_t r)
Definition: q.hh:141
q_fraction_t value_t
Definition: q.hh:62
The semiring of floating Numbers.
Definition: r.hh:34
The semiring of Integers.
Definition: z.hh:34
int value_t
Definition: z.hh:55
star_status_t
The different behaviours a weightset may have with respect to the star.
Definition: enums.hh:161
@ ABSVAL
Definition: enums.hh:166
@ OBJECT
Definition: node.hh:90
@ INTEGER
Definition: node.hh:92
@ ARRAY
Definition: node.hh:91
@ BOOLEAN
Definition: node.hh:95
@ STRING
Definition: node.hh:94
@ FLOATING
Definition: node.hh:93
@ _NULL
Definition: node.hh:96
std::string to_string(identities i)
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:448
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
Exceptions thrown during parsing.
Definition: parse_exception.hh:26
Definition: qfraction.hh:26
q_fraction_t & reduce()
int num
Definition: qfraction.hh:27
unsigned int den
Definition: qfraction.hh:28