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
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  switch (version) {
332  case 0:
333  throw parse_exception("[c] Unsupported fsm-json version:"
334  + std::to_string(version));
335  case 1:
336  default:
337  return new json::object_t("semiring", new json::string_t("C"));
338  }
339  }
340 
341 
342  template<unsigned version = version::fsm_json>
343  json::node_t*
345  const
346  {
347  switch (version) {
348  case 0:
349  throw parse_exception("[c] Unsupported fsm-json version:"
350  + std::to_string(version));
351  case 1:
352  default:
353  json::object_t* l = new json::object_t();
354  if (v.imag () == 0.)
355  l->push_back("real",new json::float_t(v.real()));
356  else if (v.real() == 0.)
357  l->push_back("imag",new json::float_t(v.imag()));
358  else {
359  l->push_back("real",new json::float_t(v.real()));
360  l->push_back("imag",new json::float_t(v.imag()));
361  }
362  return l;
363  }
364  }
365 
366  template<unsigned version = version::fsm_json>
367  value_t
369  const
370  {
371  switch (version) {
372  case 0:
373  case 1:
374  default:
375  try { return value_t{p->to_double(),0}; }
376  catch (json::exception const&){}
377  switch(p->kind) {
378  case json::ARRAY: {
379  std::vector<json::node_t*> const& v = p->array()->values;
380  if (p->arity() !=2)
381  throw json::coercion_exception("This ARRAY node should have exactly two elements.","c",p);
382  double a[2];
383  for(int i=0;i<2;i++)
384  a[i]=v[i]->to_double();
385  return value_t{a[0],a[1]};
386  }
387  case json::OBJECT: {
388  if( !p->has_child("real") && !p->has_child("imag")
389  && !p->has_child("re") && !p->has_child("im"))
390  throw json::coercion_exception("Should have either a field \"real\" or \"imag\".","c",p);
391  double a[2] = {0,0};
392  if(p->has_child("real"))
393  a[0]=p->at("real")->to_double();
394  else if(p->has_child("re"))
395  a[0]=p->at("re")->to_double();
396  if(p->has_child("imag"))
397  a[1]=p->at("imag")->to_double();
398  if(p->has_child("im"))
399  a[1]=p->at("im")->to_double();
400  return value_t{a[0],a[1]};
401  }
402  case json::STRING: {
403  std::string const& str = p->string()->value;
404  size_t pos = str.length();
405  value_t v = parse(str, pos);
406  if (pos != 0)
407  break;
408  return v;
409  }
410  default : {}
411  }
412  throw json::coercion_exception("Unable to coerce this "
413  + json::string_of(p->kind)
414  + " node to a complex number.",
415  "c",p);
416  }
417  }
418 
419  };
420 
421  inline c join(const c&, const c&) { return {}; }
422 
423  inline c join(const r&, const c&) { return {}; }
424  inline c join(const c&, const r&) { return {}; }
425 
426  inline c join(const q&, const c&) { return {}; }
427  inline c join(const c&, const q&) { return {}; }
428 
429  inline c join(const z&, const c&) { return {}; }
430  inline c join(const c&, const z&) { return {}; }
431 
432  inline c join(const n&, const c&) { return {}; }
433  inline c join(const c&, const n&) { return {}; }
434 
435  inline c join(const b&, const c&) { return {}; }
436  inline c join(const c&, const b&) { return {}; }
437 
438  }
439 }//end of ns awali::stc
440 
441 
442 
443 
444 #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
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:368
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:344
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: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::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
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