Awali
Another Weighted Automata library
c.hh
Go to the documentation of this file.
1 // This file is part of Awali.
2 // Copyright 2016-2022 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  static bool is_special(const value_t) // C++11: cannot be constexpr.
117  {
118  return false;
119  }
120 
121  static bool is_zero(const value_t v)
122  {
123  return v.real() == 0 && v.imag() == 0;
124  }
125 
126  static bool is_one(const value_t v)
127  {
128  // All values are normalized.
129  return v.real() == 1 && v.imag() == 0;
130  }
131 
132  static bool equals(const value_t l, const value_t r)
133  {
134  return l==r;
135  }
136 
138  static bool less_than(value_t lhs, value_t rhs)
139  {
140  if(std::norm(lhs) == std::norm(rhs))
141  return std::arg(lhs) < std::arg(rhs);
142  return std::norm(lhs) < std::norm(rhs);
143  }
144 
145  static constexpr bool is_commutative_semiring() { return true; }
146 
147  static constexpr bool show_one() { return false; }
148  static constexpr star_status_t star_status() { return star_status_t::ABSVAL; }
149 
150  static value_t
151  abs(const value_t v)
152  {
153  return std::abs(v);
154  }
155 
156  static value_t
158  {
159  return v;
160  }
161 
162  static size_t hash(value_t v)
163  {
164  size_t res = 0;
165  std::hash_combine(res, utils::hash_value(v.real()));
166  std::hash_combine(res, utils::hash_value(v.imag()));
167  return res;
168  }
169 
170  static value_t
172  {
173  return v;
174  }
175 
176  static value_t
178  {
179  return {v};
180  }
181 
182  static value_t
184  {
185  return {double(v.num) / double(v.den)};
186  }
187 
188  static value_t
190  {
191  return {(double)v};
192  }
193 
194  static value_t
196  {
197  return {(double)v};
198  }
199 
200  static value_t
202  {
203  return v?one():zero();
204  }
205 
206  static double greedy(std::istream& i) {
207  std::ostringstream os;
208  char maybe, sig=0;
209  if (i.peek()=='+' || i.peek()=='-')
210  i>> sig;
211  while((maybe = i.peek()) == '.' || (maybe >='0' && maybe <='9')) {
212  i >> maybe;
213  os << maybe;
214  }
215  if(os.str().empty()) {
216  if(sig=='+')
217  return 1;
218  if(sig=='-')
219  return -1;
220  throw std::runtime_error(sname() + " : invalid real");
221  }
222  double r;
223  std::istringstream is(os.str());
224  is >> r;
225  if(sig=='-')
226  return -r;
227  return r;
228  }
229 
230  static value_t
231  conv(std::istream& i)
232  {
233  double re,im;
234  char maybe;
235  if ((maybe = i.peek()) == 'i') { //no real part
236  sttc::eat(i, 'i');
237  return value_t{0,1};
238  }
239  re = greedy(i);
240  if ((maybe = i.peek()) == 'i') { //no real part
241  sttc::eat(i, 'i');
242  return value_t{0,re};
243  }
244  if ((maybe = i.peek()) == '+' || maybe == '-'){ // imaginary part
245  im=greedy(i);
246  if (i.peek()!='i')
247  sttc::fail_reading(i, sname() + ": invalid imaginary complex part");
248  sttc::eat(i, 'i');
249  return value_t{re, im};
250  }
251  return value_t{re}; // no imaginary part
252  }
253 
254 // static double parse_simple_real(const std::string & s, size_t& p, double def=0) {
255 // size_t i=p;
256 // for(; i>0 && ((s[i-1]>='0' && s[i-1]<='9') || s[i-1]=='.'); --i)
257 // ;
258 // double r=def;
259 // if(p>i) {
260 // std::istringstream st(s.substr(i, p-i));
261 // st >> r;
262 // }
263 // if(s[i-1]=='-') {
264 // --i;
265 // r=-r;
266 // }
267 // if(s[i-1]=='+')
268 // --i;
269 // p=i;
270 // return r;
271 // }
272 
273 
274  static value_t
275  parse(const std::string & s, size_t& p) {
276  return internal::lr_parse_complex(s,p);
277  }
278 
279 
280  static std::ostream&
281  print(const value_t v, std::ostream& o,
282  const std::string& format = "text")
283  {
284  if (format == "json") {
285  o<< '{';
286  if(v.real()!=0 || v.imag()==0) {
287  o << "\"re\":" << v.real();
288  if(v.imag()!=0)
289  o<< ", \"im\":" << v.imag();
290  }
291  else
292  o<< "\"im\":" << v.imag();
293  o <<'}';
294  return o;
295  }
296  if(v.real()!=0) {
297  o << v.real();
298  if(v.imag()>0)
299  o << '+';
300  }
301  if(v.imag()!=0) {
302  double im = v.imag();
303  if(im==1)
304  o << 'i';
305  else if(im==-1)
306  o << "-i";
307  else
308  o << im << 'i';
309  }
310  if(v.real()==0 && v.imag()==0)
311  o << 0.0;
312  return o;
313  }
314 
315  std::ostream&
316  print_set(std::ostream& o, const std::string& format = "text") const
317  {
318  if (format == "latex")
319  o << "\\mathbb{C}";
320  else if (format == "text")
321  o << "C";
322  else
323  raise("invalid format: ", format);
324  return o;
325  }
326 
327  template<unsigned version = version::fsm_json>
328  json::node_t*
329  to_json() const
330  {
331  version::check_fsmjson<version>();
332  switch (version) {
333  case 0: /* Never occurs due to above check. */
334  case 1:
335  default:
336  return new json::object_t("semiring", new json::string_t("C"));
337  }
338  }
339 
340 
341  template<unsigned version = version::fsm_json>
342  json::node_t*
344  const
345  {
346  version::check_fsmjson<version>();
347  switch (version) {
348  case 0: /* Never occurs due to above check. */
349  case 1:
350  default:
351  json::object_t* l = new json::object_t();
352  if (v.imag () == 0.)
353  l->push_back("real",new json::float_t(v.real()));
354  else if (v.real() == 0.)
355  l->push_back("imag",new json::float_t(v.imag()));
356  else {
357  l->push_back("real",new json::float_t(v.real()));
358  l->push_back("imag",new json::float_t(v.imag()));
359  }
360  return l;
361  }
362  }
363 
364  template<unsigned version = version::fsm_json>
365  value_t
367  const
368  {
369  version::check_fsmjson<version>();
370  switch (version) {
371  case 0: /* Never occurs due to above check. */
372  case 1:
373  default:
374  try { return value_t{p->to_double(),0}; }
375  catch (json::exception const&){}
376  switch(p->kind) {
377  case json::ARRAY: {
378  std::vector<json::node_t*> const& v = p->array()->values;
379  if (p->arity() !=2)
380  throw json::coercion_exception("This ARRAY node should have exactly two elements.","c",p);
381  double a[2];
382  for(int i=0;i<2;i++)
383  a[i]=v[i]->to_double();
384  return value_t{a[0],a[1]};
385  }
386  case json::OBJECT: {
387  if( !p->has_child("real") && !p->has_child("imag")
388  && !p->has_child("re") && !p->has_child("im"))
389  throw json::coercion_exception("Should have either a field \"real\" or \"imag\".","c",p);
390  double a[2] = {0,0};
391  if(p->has_child("real"))
392  a[0]=p->at("real")->to_double();
393  else if(p->has_child("re"))
394  a[0]=p->at("re")->to_double();
395  if(p->has_child("imag"))
396  a[1]=p->at("imag")->to_double();
397  if(p->has_child("im"))
398  a[1]=p->at("im")->to_double();
399  return value_t{a[0],a[1]};
400  }
401  case json::STRING: {
402  std::string const& str = p->string()->value;
403  size_t pos = str.length();
404  value_t v = parse(str, pos);
405  if (pos != 0)
406  break;
407  return v;
408  }
409  default : {}
410  }
411  throw json::coercion_exception("Unable to coerce this "
412  + json::string_of(p->kind)
413  + " node to a complex number.",
414  "c",p);
415  }
416  }
417 
418  };
419 
420  inline c join(const c&, const c&) { return {}; }
421 
422  inline c join(const r&, const c&) { return {}; }
423  inline c join(const c&, const r&) { return {}; }
424 
425  inline c join(const q&, const c&) { return {}; }
426  inline c join(const c&, const q&) { return {}; }
427 
428  inline c join(const z&, const c&) { return {}; }
429  inline c join(const c&, const z&) { return {}; }
430 
431  inline c join(const n&, const c&) { return {}; }
432  inline c join(const c&, const n&) { return {}; }
433 
434  inline c join(const b&, const c&) { return {}; }
435  inline c join(const c&, const b&) { return {}; }
436 
437  }
438 }//end of ns awali::stc
439 
440 
441 
442 
443 #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:116
static bool equals(const value_t l, const value_t r)
Definition: c.hh:132
static value_t conv(q, q::value_t v)
Definition: c.hh:183
std::string vname(bool=true) const
Definition: c.hh:53
json::node_t * to_json() const
Definition: c.hh:329
static double greedy(std::istream &i)
Definition: c.hh:206
value_t value_from_json(json::node_t const *p) const
Definition: c.hh:366
static value_t abs(const value_t v)
Definition: c.hh:151
std::complex< double > value_t
Definition: c.hh:65
json::node_t * value_to_json(value_t v) const
Definition: c.hh:343
static value_t conv(b, b::value_t v)
Definition: c.hh:201
static bool less_than(value_t lhs, value_t rhs)
Whether lhs < rhs.
Definition: c.hh:138
static value_t conv(self_type, value_t v)
Definition: c.hh:171
static std::ostream & print(const value_t v, std::ostream &o, const std::string &format="text")
Definition: c.hh:281
static value_t transpose(const value_t v)
Definition: c.hh:157
static constexpr bool show_one()
Definition: c.hh:147
static value_t conv(std::istream &i)
Definition: c.hh:231
static value_t parse(const std::string &s, size_t &p)
Definition: c.hh:275
static value_t one()
Definition: c.hh:73
std::ostream & print_set(std::ostream &o, const std::string &format="text") const
Definition: c.hh:316
static size_t hash(value_t v)
Definition: c.hh:162
static bool is_one(const value_t v)
Definition: c.hh:126
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:121
static constexpr bool is_commutative_semiring()
Definition: c.hh:145
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:195
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:177
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:148
static value_t conv(z, z::value_t v)
Definition: c.hh:189
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:445
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