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