Awali
Another Weighted Automata library
c.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_C_HH
18 #define AWALI_WEIGHTSET_C_HH
19 
20 #include <string>
21 #include <ostream>
22 #include <sstream>
23 
24 #include <awali/utils/arith.hh>
25 
26 #include <complex>
27 #include <awali/common/enums.hh>
28 
30 #include <awali/utils/hash.hh>
31 
32 #include <awali/sttc/misc/raise.hh>
33 #include <awali/sttc/misc/stream.hh> // eat
36 
37 namespace awali {
38  namespace sttc {
43  class c
44  {
45  public:
46  using self_type = c;
47 
48  static std::string sname()
49  {
50  return "c";
51  }
52 
53  std::string vname(bool = true) const
54  {
55  return sname();
56  }
57 
59  static c make(std::istream& is)
60  {
61  eat(is, sname());
62  return {};
63  }
64 
65  using value_t = std::complex<double>;
66 
67 
68  static value_t zero()
69  {
70  return value_t();
71  }
72 
73  static value_t one()
74  {
75  return value_t(1);
76  }
77 
78  static value_t add(const value_t l, const value_t r)
79  {
80  return l+r;
81  }
82 
83  static value_t sub(const value_t l, const value_t r)
84  {
85  return l-r;
86  }
87 
88  static value_t mul(const value_t l, const value_t r)
89  {
90  return l*r;
91  }
92 
93  static value_t
94  rdiv(const value_t l, const value_t r)
95  {
96  require(!is_zero(r), "div: division by zero");
97  return l/r;
98  }
99 
100  static value_t
101  ldiv(const value_t l, const value_t r)
102  {
103  return rdiv(r, l);
104  }
105 
106  value_t star(const value_t v) const
107  {
108  // Bad casting when v.den is too big
109  if (std::norm(v) < 1)
110  // No need to reduce: numerator and denominators are primes.
111  return value_t(1)/(value_t(1)-v);
112  else
113  raise(sname(), ": star: invalid value: ", format(*this, v));
114  }
115 
116  value_t plus(const value_t v) const
117  {
118  // Bad casting when v.den is too big
119  if (std::norm(v) < 1)
120  // No need to reduce: numerator and denominators are primes.
121  return value_t(v)/(value_t(1)-v);
122  else
123  raise(sname(), ": star: invalid value: ", format(*this, v));
124  }
125 
126  static bool is_special(const value_t) // C++11: cannot be constexpr.
127  {
128  return false;
129  }
130 
131  static bool is_zero(const value_t v)
132  {
133  return v.real() == 0 && v.imag() == 0;
134  }
135 
136  static bool is_one(const value_t v)
137  {
138  // All values are normalized.
139  return v.real() == 1 && v.imag() == 0;
140  }
141 
142  static bool equals(const value_t l, const value_t r)
143  {
144  return l==r;
145  }
146 
148  static bool less_than(value_t lhs, value_t rhs)
149  {
150  if(std::norm(lhs) == std::norm(rhs))
151  return std::arg(lhs) < std::arg(rhs);
152  return std::norm(lhs) < std::norm(rhs);
153  }
154 
155  static constexpr bool is_commutative_semiring() { return true; }
156 
157  static constexpr bool show_one() { return false; }
158  static constexpr star_status_t star_status() { return star_status_t::ABSVAL; }
159 
160  static value_t
161  abs(const value_t v)
162  {
163  return std::abs(v);
164  }
165 
166  static value_t
168  {
169  return v;
170  }
171 
172  static size_t hash(value_t v)
173  {
174  size_t res = 0;
175  std::hash_combine(res, utils::hash_value(v.real()));
176  std::hash_combine(res, utils::hash_value(v.imag()));
177  return res;
178  }
179 
180  static value_t
182  {
183  return v;
184  }
185 
186  static value_t
188  {
189  return {v};
190  }
191 
192  static value_t
194  {
195  return {double(v.num) / double(v.den)};
196  }
197 
198  static value_t
200  {
201  return {(double)v};
202  }
203 
204  static value_t
206  {
207  return {(double)v};
208  }
209 
210  static value_t
212  {
213  return v?one():zero();
214  }
215 
216  static double greedy(std::istream& i) {
217  std::ostringstream os;
218  char maybe, sig=0;
219  if (i.peek()=='+' || i.peek()=='-')
220  i>> sig;
221  while((maybe = i.peek()) == '.' || (maybe >='0' && maybe <='9')) {
222  i >> maybe;
223  os << maybe;
224  }
225  if(os.str().empty()) {
226  if(sig=='+')
227  return 1;
228  if(sig=='-')
229  return -1;
230  throw std::runtime_error(sname() + " : invalid real");
231  }
232  double r;
233  std::istringstream is(os.str());
234  is >> r;
235  if(sig=='-')
236  return -r;
237  return r;
238  }
239 
240  static value_t
241  conv(std::istream& i)
242  {
243  double re,im;
244  char maybe;
245  if ((maybe = i.peek()) == 'i') { //no real part
246  sttc::eat(i, 'i');
247  return value_t{0,1};
248  }
249  re = greedy(i);
250  if ((maybe = i.peek()) == 'i') { //no real part
251  sttc::eat(i, 'i');
252  return value_t{0,re};
253  }
254  if ((maybe = i.peek()) == '+' || maybe == '-'){ // imaginary part
255  im=greedy(i);
256  if (i.peek()!='i')
257  sttc::fail_reading(i, sname() + ": invalid imaginary complex part");
258  sttc::eat(i, 'i');
259  return value_t{re, im};
260  }
261  return value_t{re}; // no imaginary part
262  }
263 
264 // static double parse_simple_real(const std::string & s, size_t& p, double def=0) {
265 // size_t i=p;
266 // for(; i>0 && ((s[i-1]>='0' && s[i-1]<='9') || s[i-1]=='.'); --i)
267 // ;
268 // double r=def;
269 // if(p>i) {
270 // std::istringstream st(s.substr(i, p-i));
271 // st >> r;
272 // }
273 // if(s[i-1]=='-') {
274 // --i;
275 // r=-r;
276 // }
277 // if(s[i-1]=='+')
278 // --i;
279 // p=i;
280 // return r;
281 // }
282 
283 
284  static value_t
285  parse(const std::string & s, size_t& p) {
286  return internal::lr_parse_complex(s,p);
287  }
288 
289 
290  static std::ostream&
291  print(const value_t v, std::ostream& o,
292  const std::string& format = "text")
293  {
294  if (format == "json") {
295  o<< '{';
296  if(v.real()!=0 || v.imag()==0) {
297  o << "\"re\":" << v.real();
298  if(v.imag()!=0)
299  o<< ", \"im\":" << v.imag();
300  }
301  else
302  o<< "\"im\":" << v.imag();
303  o <<'}';
304  return o;
305  }
306  if(v.real()!=0) {
307  o << v.real();
308  if(v.imag()>0)
309  o << '+';
310  }
311  if(v.imag()!=0) {
312  double im = v.imag();
313  if(im==1)
314  o << 'i';
315  else if(im==-1)
316  o << "-i";
317  else
318  o << im << 'i';
319  }
320  if(v.real()==0 && v.imag()==0)
321  o << 0.0;
322  return o;
323  }
324 
325  std::ostream&
326  print_set(std::ostream& o, const std::string& format = "text") const
327  {
328  if (format == "latex")
329  o << "\\mathbb{C}";
330  else if (format == "text")
331  o << "C";
332  else
333  raise("invalid format: ", format);
334  return o;
335  }
336 
337  template<unsigned version = version::fsm_json>
338  json::node_t*
339  to_json() const
340  {
341  version::check_fsmjson<version>();
342  switch (version) {
343  case 0: /* Never occurs due to above check. */
344  case 1:
345  default:
346  return new json::object_t("semiring", new json::string_t("C"));
347  }
348  }
349 
350 
351  template<unsigned version = version::fsm_json>
352  json::node_t*
354  const
355  {
356  version::check_fsmjson<version>();
357  switch (version) {
358  case 0: /* Never occurs due to above check. */
359  case 1:
360  default:
361  json::object_t* l = new json::object_t();
362  if (v.imag () == 0.)
363  l->push_back("real",new json::float_t(v.real()));
364  else if (v.real() == 0.)
365  l->push_back("imag",new json::float_t(v.imag()));
366  else {
367  l->push_back("real",new json::float_t(v.real()));
368  l->push_back("imag",new json::float_t(v.imag()));
369  }
370  return l;
371  }
372  }
373 
374  template<unsigned version = version::fsm_json>
375  value_t
377  const
378  {
379  version::check_fsmjson<version>();
380  switch (version) {
381  case 0: /* Never occurs due to above check. */
382  case 1:
383  default:
384  try { return value_t{p->to_double(),0}; }
385  catch (json::exception const&){}
386  switch(p->kind) {
387  case json::ARRAY: {
388  std::vector<json::node_t*> const& v = p->array()->values;
389  if (p->arity() !=2)
390  throw json::coercion_exception("This ARRAY node should have exactly two elements.","c",p);
391  double a[2];
392  for(int i=0;i<2;i++)
393  a[i]=v[i]->to_double();
394  return value_t{a[0],a[1]};
395  }
396  case json::OBJECT: {
397  if( !p->has_child("real") && !p->has_child("imag")
398  && !p->has_child("re") && !p->has_child("im"))
399  throw json::coercion_exception("Should have either a field \"real\" or \"imag\".","c",p);
400  double a[2] = {0,0};
401  if(p->has_child("real"))
402  a[0]=p->at("real")->to_double();
403  else if(p->has_child("re"))
404  a[0]=p->at("re")->to_double();
405  if(p->has_child("imag"))
406  a[1]=p->at("imag")->to_double();
407  if(p->has_child("im"))
408  a[1]=p->at("im")->to_double();
409  return value_t{a[0],a[1]};
410  }
411  case json::STRING: {
412  std::string const& str = p->string()->value;
413  size_t pos = str.length();
414  value_t v = parse(str, pos);
415  if (pos != 0)
416  break;
417  return v;
418  }
419  default : {}
420  }
421  throw json::coercion_exception("Unable to coerce this "
422  + json::string_of(p->kind)
423  + " node to a complex number.",
424  "c",p);
425  }
426  }
427 
428  };
429 
430  inline c join(const c&, const c&) { return {}; }
431 
432  inline c join(const r&, const c&) { return {}; }
433  inline c join(const c&, const r&) { return {}; }
434 
435  inline c join(const q&, const c&) { return {}; }
436  inline c join(const c&, const q&) { return {}; }
437 
438  inline c join(const z&, const c&) { return {}; }
439  inline c join(const c&, const z&) { return {}; }
440 
441  inline c join(const n&, const c&) { return {}; }
442  inline c join(const c&, const n&) { return {}; }
443 
444  inline c join(const b&, const c&) { return {}; }
445  inline c join(const c&, const b&) { return {}; }
446 
447  }
448 }//end of ns awali::stc
449 
450 
451 
452 
453 #endif // !AWALI_WEIGHTSET_C_HH
std::vector< node_t * > const & values
Definition: node.hh:436
Exception used when trying to coerce a node to a given type.
Definition: node.hh:143
Definition: node.hh:110
Definition: node.hh:508
Definition: node.hh:193
virtual node_t * at(std::string const &key)
virtual double to_double() const
Coerces this node_t to a double
Definition: node.hh:343
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
virtual array_t const * array() const
Casts this node to array_t.
Definition: node.hh:207
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
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 complex numbers.
Definition: c.hh:44
static value_t zero()
Definition: c.hh:68
static c make(std::istream &is)
Build from the description in is.
Definition: c.hh:59
static bool is_special(const value_t)
Definition: c.hh:126
static bool equals(const value_t l, const value_t r)
Definition: c.hh:142
static value_t conv(q, q::value_t v)
Definition: c.hh:193
std::string vname(bool=true) const
Definition: c.hh:53
json::node_t * to_json() const
Definition: c.hh:339
static double greedy(std::istream &i)
Definition: c.hh:216
value_t value_from_json(json::node_t const *p) const
Definition: c.hh:376
static value_t abs(const value_t v)
Definition: c.hh:161
std::complex< double > value_t
Definition: c.hh:65
json::node_t * value_to_json(value_t v) const
Definition: c.hh:353
static value_t conv(b, b::value_t v)
Definition: c.hh:211
static bool less_than(value_t lhs, value_t rhs)
Whether lhs < rhs.
Definition: c.hh:148
static value_t conv(self_type, value_t v)
Definition: c.hh:181
static std::ostream & print(const value_t v, std::ostream &o, const std::string &format="text")
Definition: c.hh:291
static value_t transpose(const value_t v)
Definition: c.hh:167
static constexpr bool show_one()
Definition: c.hh:157
static value_t conv(std::istream &i)
Definition: c.hh:241
static value_t parse(const std::string &s, size_t &p)
Definition: c.hh:285
static value_t one()
Definition: c.hh:73
std::ostream & print_set(std::ostream &o, const std::string &format="text") const
Definition: c.hh:326
static size_t hash(value_t v)
Definition: c.hh:172
static bool is_one(const value_t v)
Definition: c.hh:136
value_t star(const value_t v) const
Definition: c.hh:106
static std::string sname()
Definition: c.hh:48
static value_t ldiv(const value_t l, const value_t r)
Definition: c.hh:101
static bool is_zero(const value_t v)
Definition: c.hh:131
static constexpr bool is_commutative_semiring()
Definition: c.hh:155
static value_t sub(const value_t l, const value_t r)
Definition: c.hh:83
static value_t mul(const value_t l, const value_t r)
Definition: c.hh:88
static value_t conv(n, n::value_t v)
Definition: c.hh:205
static value_t rdiv(const value_t l, const value_t r)
Definition: c.hh:94
static value_t conv(r, r::value_t v)
Definition: c.hh:187
static value_t add(const value_t l, const value_t r)
Definition: c.hh:78
static constexpr star_status_t star_status()
Definition: c.hh:158
value_t plus(const value_t v) const
Definition: c.hh:116
static value_t conv(z, z::value_t v)
Definition: c.hh:199
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
The semiring of floating Numbers.
Definition: r.hh:35
double value_t
Definition: r.hh:56
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
std::string const & string_of(node_kind_t kind)
@ OBJECT
Definition: node.hh:93
@ ARRAY
Definition: node.hh:94
@ STRING
Definition: node.hh:97
std::complex< double > lr_parse_complex(std::string const &s, size_t &p, bool allow_empty=false, std::complex< double > value_if_empty={0, 0})
Reads a complex number left of position p in string, by using as many characters as possible.
Definition: lr_parse_number.hh:458
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
Main namespace of Awali.
Definition: ato.hh:22