infinity.cpp
1 #include <symengine/complex.h>
2 #include <symengine/complex_double.h>
3 #include <symengine/constants.h>
4 #include <symengine/infinity.h>
5 #include <symengine/functions.h>
6 #include <symengine/symengine_exception.h>
7 #include <symengine/complex_mpc.h>
8 
10 
11 namespace SymEngine
12 {
13 
14 Infty::Infty(const RCP<const Number> &direction)
15 {
16  SYMENGINE_ASSIGN_TYPEID()
17  _direction = direction;
18  SYMENGINE_ASSERT(is_canonical(_direction));
19 }
20 
21 Infty::Infty(const Infty &inf)
22 {
23  SYMENGINE_ASSIGN_TYPEID()
24  _direction = inf.get_direction();
25  SYMENGINE_ASSERT(is_canonical(_direction))
26 }
27 
28 RCP<const Infty> Infty::from_direction(const RCP<const Number> &direction)
29 {
30  return make_rcp<Infty>(direction);
31 }
32 
33 RCP<const Infty> Infty::from_int(const int val)
34 {
35  SYMENGINE_ASSERT(val >= -1 && val <= 1)
36  return make_rcp<Infty>(integer(val));
37 }
38 
40 bool Infty::is_canonical(const RCP<const Number> &num) const
41 {
42  if (is_a<Complex>(*num) || is_a<ComplexDouble>(*num))
43  throw NotImplementedError("Not implemented for all directions");
44 
45  if (num->is_one() || num->is_zero() || num->is_minus_one())
46  return true;
47 
48  return false;
49 }
50 
51 hash_t Infty::__hash__() const
52 {
53  hash_t seed = SYMENGINE_INFTY;
54  hash_combine<Basic>(seed, *_direction);
55  return seed;
56 }
57 
58 bool Infty::__eq__(const Basic &o) const
59 {
60  if (is_a<Infty>(o)) {
61  const Infty &s = down_cast<const Infty &>(o);
62  return eq(*_direction, *(s.get_direction()));
63  }
64 
65  return false;
66 }
67 
68 int Infty::compare(const Basic &o) const
69 {
70  SYMENGINE_ASSERT(is_a<Infty>(o))
71  const Infty &s = down_cast<const Infty &>(o);
72  return _direction->compare(*(s.get_direction()));
73 }
74 
75 bool Infty::is_unsigned_infinity() const
76 {
77  return _direction->is_zero();
78 }
79 
80 bool Infty::is_positive_infinity() const
81 {
82  return _direction->is_positive();
83 }
84 
85 bool Infty::is_negative_infinity() const
86 {
87  return _direction->is_negative();
88 }
89 
90 RCP<const Basic> Infty::conjugate() const
91 {
92  if (is_positive_infinity() or is_negative_infinity()) {
93  return infty(_direction);
94  }
95  return make_rcp<const Conjugate>(ComplexInf);
96 }
97 
98 RCP<const Number> Infty::add(const Number &other) const
99 {
100  if (not is_a<Infty>(other))
101  return rcp_from_this_cast<Number>();
102 
103  const Infty &s = down_cast<const Infty &>(other);
104 
105  if (not eq(*s.get_direction(), *_direction))
106  return Nan;
107  else if (is_unsigned_infinity())
108  return Nan;
109  else
110  return rcp_from_this_cast<Number>();
111 }
112 
113 RCP<const Number> Infty::mul(const Number &other) const
114 {
115  if (is_a<Complex>(other))
116  throw NotImplementedError(
117  "Multiplication with Complex not implemented");
118 
119  if (is_a<Infty>(other)) {
120  const Infty &s = down_cast<const Infty &>(other);
121  return make_rcp<const Infty>(this->_direction->mul(*(s._direction)));
122  } else {
123  if (other.is_positive())
124  return rcp_from_this_cast<Number>();
125  else if (other.is_negative())
126  return make_rcp<const Infty>(this->_direction->mul(*minus_one));
127  else
128  return Nan;
129  }
130 }
131 
132 RCP<const Number> Infty::div(const Number &other) const
133 {
134  if (is_a<Infty>(other)) {
135  return Nan;
136  } else {
137  if (other.is_positive())
138  return rcp_from_this_cast<Number>();
139  else if (other.is_zero())
140  return infty(0);
141  else
142  return infty(this->_direction->mul(*minus_one));
143  }
144 }
145 
146 RCP<const Number> Infty::pow(const Number &other) const
147 {
148  if (is_a<Infty>(other)) {
149  if (is_positive_infinity()) {
150  if (other.is_negative()) {
151  return zero;
152  } else if (other.is_positive()) {
153  return rcp_from_this_cast<Number>();
154  } else {
155  return Nan;
156  }
157  } else if (is_negative_infinity()) {
158  return Nan;
159  } else {
160  if (other.is_positive()) {
161  return infty(0);
162  } else if (other.is_negative()) {
163  return zero;
164  } else {
165  return Nan;
166  }
167  }
168  } else if (is_a<Complex>(other)) {
169  throw NotImplementedError(
170  "Raising to the Complex powers not yet implemented");
171  } else {
172  if (other.is_negative()) {
173  return zero;
174  } else if (other.is_zero()) {
175  return one;
176  } else {
177  if (is_positive_infinity()) {
178  return rcp_from_this_cast<Number>();
179  } else if (is_negative_infinity()) {
180  throw NotImplementedError("Raising Negative Infty to the "
181  "Positive Real powers not yet "
182  "implemented");
183  } else {
184  return infty(0);
185  }
186  }
187  }
188 }
189 
190 RCP<const Number> Infty::rpow(const Number &other) const
191 {
192  if (is_a_Complex(other)) {
193  throw NotImplementedError(
194  "Raising Complex powers to Infty not yet implemented");
195  } else {
196  if (other.is_negative()) {
197  throw NotImplementedError("Raising Negative numbers to infinite "
198  "powers not yet implemented");
199  } else if (other.is_zero()) {
200  throw SymEngineException("Indeterminate Expression: `0 ** +- "
201  "unsigned Infty` encountered");
202  } else {
203  const Number &s = down_cast<const Number &>(other);
204  if (s.is_one()) {
205  return Nan;
206  } else if (is_positive_infinity()) {
207  if (s.sub(*one)->is_negative()) {
208  return zero;
209  } else {
210  return rcp_from_this_cast<Number>();
211  }
212  } else if (is_negative_infinity()) {
213  if (s.sub(*one)->is_negative()) {
214  return infty(0);
215  } else {
216  return zero;
217  }
218  } else {
219  throw SymEngineException("Indeterminate Expression: `Positive "
220  "Real Number ** unsigned Infty` "
221  "encountered");
222  }
223  }
224  }
225 }
226 
227 inline RCP<const Infty> infty(const RCP<const Number> &direction)
228 {
229  return make_rcp<Infty>(direction);
230 }
231 
232 class EvaluateInfty : public Evaluate
233 {
234  virtual RCP<const Basic> sin(const Basic &x) const override
235  {
236  SYMENGINE_ASSERT(is_a<Infty>(x))
237  throw DomainError("sin is not defined for infinite values");
238  }
239  virtual RCP<const Basic> cos(const Basic &x) const override
240  {
241  SYMENGINE_ASSERT(is_a<Infty>(x))
242  throw DomainError("cos is not defined for infinite values");
243  }
244  virtual RCP<const Basic> tan(const Basic &x) const override
245  {
246  SYMENGINE_ASSERT(is_a<Infty>(x))
247  throw DomainError("tan is not defined for infinite values");
248  }
249  virtual RCP<const Basic> cot(const Basic &x) const override
250  {
251  SYMENGINE_ASSERT(is_a<Infty>(x))
252  throw DomainError("cot is not defined for infinite values");
253  }
254  virtual RCP<const Basic> sec(const Basic &x) const override
255  {
256  SYMENGINE_ASSERT(is_a<Infty>(x))
257  throw DomainError("sec is not defined for infinite values");
258  }
259  virtual RCP<const Basic> csc(const Basic &x) const override
260  {
261  SYMENGINE_ASSERT(is_a<Infty>(x))
262  throw DomainError("csc is not defined for infinite values");
263  }
264  virtual RCP<const Basic> asin(const Basic &x) const override
265  {
266  SYMENGINE_ASSERT(is_a<Infty>(x))
267  throw DomainError("asin is not defined for infinite values");
268  }
269  virtual RCP<const Basic> acos(const Basic &x) const override
270  {
271  SYMENGINE_ASSERT(is_a<Infty>(x))
272  throw DomainError("acos is not defined for infinite values");
273  }
274  virtual RCP<const Basic> acsc(const Basic &x) const override
275  {
276  SYMENGINE_ASSERT(is_a<Infty>(x))
277  throw DomainError("acsc is not defined for infinite values");
278  }
279  virtual RCP<const Basic> asec(const Basic &x) const override
280  {
281  SYMENGINE_ASSERT(is_a<Infty>(x))
282  throw DomainError("asec is not defined for infinite values");
283  }
284  virtual RCP<const Basic> atan(const Basic &x) const override
285  {
286  SYMENGINE_ASSERT(is_a<Infty>(x))
287  const Infty &s = down_cast<const Infty &>(x);
288  if (s.is_positive()) {
289  return div(pi, integer(2));
290  } else if (s.is_negative()) {
291  return mul(minus_one, (div(pi, integer(2))));
292  } else {
293  throw DomainError("atan is not defined for Complex Infinity");
294  }
295  }
296  virtual RCP<const Basic> acot(const Basic &x) const override
297  {
298  SYMENGINE_ASSERT(is_a<Infty>(x))
299  const Infty &s = down_cast<const Infty &>(x);
300  if (s.is_positive() or s.is_negative()) {
301  return zero;
302  } else {
303  throw DomainError("acot is not defined for Complex Infinity");
304  }
305  }
306  virtual RCP<const Basic> sinh(const Basic &x) const override
307  {
308  SYMENGINE_ASSERT(is_a<Infty>(x))
309  const Infty &s = down_cast<const Infty &>(x);
310  if (s.is_positive() or s.is_negative()) {
311  return infty(s.get_direction());
312  } else {
313  throw DomainError("sinh is not defined for Complex Infinity");
314  }
315  }
316  virtual RCP<const Basic> csch(const Basic &x) const override
317  {
318  SYMENGINE_ASSERT(is_a<Infty>(x))
319  const Infty &s = down_cast<const Infty &>(x);
320  if (s.is_positive() or s.is_negative()) {
321  return zero;
322  } else {
323  throw DomainError("csch is not defined for Complex Infinity");
324  }
325  }
326  virtual RCP<const Basic> cosh(const Basic &x) const override
327  {
328  SYMENGINE_ASSERT(is_a<Infty>(x))
329  const Infty &s = down_cast<const Infty &>(x);
330  if (s.is_positive() or s.is_negative()) {
331  return Inf;
332  } else {
333  throw DomainError("cosh is not defined for Complex Infinity");
334  }
335  }
336  virtual RCP<const Basic> sech(const Basic &x) const override
337  {
338  SYMENGINE_ASSERT(is_a<Infty>(x))
339  const Infty &s = down_cast<const Infty &>(x);
340  if (s.is_positive() or s.is_negative()) {
341  return zero;
342  } else {
343  throw DomainError("sech is not defined for Complex Infinity");
344  }
345  }
346  virtual RCP<const Basic> tanh(const Basic &x) const override
347  {
348  SYMENGINE_ASSERT(is_a<Infty>(x))
349  const Infty &s = down_cast<const Infty &>(x);
350  if (s.is_positive()) {
351  return one;
352  } else if (s.is_negative()) {
353  return minus_one;
354  } else {
355  throw DomainError("tanh is not defined for Complex Infinity");
356  }
357  }
358  virtual RCP<const Basic> coth(const Basic &x) const override
359  {
360  SYMENGINE_ASSERT(is_a<Infty>(x))
361  const Infty &s = down_cast<const Infty &>(x);
362  if (s.is_positive()) {
363  return one;
364  } else if (s.is_negative()) {
365  return minus_one;
366  } else {
367  throw DomainError("coth is not defined for Complex Infinity");
368  }
369  }
370  virtual RCP<const Basic> asinh(const Basic &x) const override
371  {
372  SYMENGINE_ASSERT(is_a<Infty>(x))
373  const Infty &s = down_cast<const Infty &>(x);
374  if (s.is_positive() or s.is_negative()) {
375  return infty(s.get_direction());
376  } else {
377  throw DomainError("asinh is not defined for Complex Infinity");
378  }
379  }
380  virtual RCP<const Basic> acosh(const Basic &x) const override
381  {
382  SYMENGINE_ASSERT(is_a<Infty>(x))
383  const Infty &s = down_cast<const Infty &>(x);
384  if (s.is_positive() or s.is_negative()) {
385  return Inf;
386  } else {
387  throw DomainError("acosh is not defined for Complex Infinity");
388  }
389  }
390  virtual RCP<const Basic> acsch(const Basic &x) const override
391  {
392  SYMENGINE_ASSERT(is_a<Infty>(x))
393  const Infty &s = down_cast<const Infty &>(x);
394  if (s.is_positive() or s.is_negative()) {
395  return zero;
396  } else {
397  throw DomainError("acsch is not defined for Complex Infinity");
398  }
399  }
400  virtual RCP<const Basic> asech(const Basic &x) const override
401  {
402  SYMENGINE_ASSERT(is_a<Infty>(x))
403  const Infty &s = down_cast<const Infty &>(x);
404  if (s.is_positive() or s.is_negative()) {
405  return mul(mul(I, pi), div(one, integer(2)));
406  } else {
407  throw DomainError("asech is not defined for Complex Infinity");
408  }
409  }
410  virtual RCP<const Basic> atanh(const Basic &x) const override
411  {
412  SYMENGINE_ASSERT(is_a<Infty>(x))
413  const Infty &s = down_cast<const Infty &>(x);
414  if (s.is_positive()) {
415  return mul(minus_one, div(mul(pi, I), integer(2)));
416  } else if (s.is_negative()) {
417  return div(mul(pi, I), integer(2));
418  } else {
419  throw DomainError("atanh is not defined for Complex Infinity");
420  }
421  }
422  virtual RCP<const Basic> acoth(const Basic &x) const override
423  {
424  SYMENGINE_ASSERT(is_a<Infty>(x))
425  const Infty &s = down_cast<const Infty &>(x);
426  if (s.is_positive() or s.is_negative()) {
427  return zero;
428  } else {
429  throw DomainError("acoth is not defined for Complex Infinity");
430  }
431  }
432  virtual RCP<const Basic> abs(const Basic &x) const override
433  {
434  SYMENGINE_ASSERT(is_a<Infty>(x))
435  return Inf;
436  }
437  virtual RCP<const Basic> log(const Basic &x) const override
438  {
439  SYMENGINE_ASSERT(is_a<Infty>(x))
440  const Infty &s = down_cast<const Infty &>(x);
441  if (s.is_positive() or s.is_negative()) {
442  return Inf;
443  } else {
444  return ComplexInf;
445  }
446  }
447  virtual RCP<const Basic> gamma(const Basic &x) const override
448  {
449  SYMENGINE_ASSERT(is_a<Infty>(x))
450  const Infty &s = down_cast<const Infty &>(x);
451  if (s.is_positive()) {
452  return Inf;
453  } else {
454  return ComplexInf;
455  }
456  }
457  virtual RCP<const Basic> exp(const Basic &x) const override
458  {
459  SYMENGINE_ASSERT(is_a<Infty>(x))
460  const Infty &s = down_cast<const Infty &>(x);
461  if (s.is_positive()) {
462  return Inf;
463  } else if (s.is_negative()) {
464  return zero;
465  } else {
466  throw DomainError("exp is not defined for Complex Infinity");
467  }
468  }
469  virtual RCP<const Basic> floor(const Basic &x) const override
470  {
471  SYMENGINE_ASSERT(is_a<Infty>(x))
472  const Infty &s = down_cast<const Infty &>(x);
473  if (s.is_positive()) {
474  return Inf;
475  } else if (s.is_negative()) {
476  return NegInf;
477  } else {
478  throw DomainError("floor is not defined for Complex Infinity");
479  }
480  }
481  virtual RCP<const Basic> ceiling(const Basic &x) const override
482  {
483  SYMENGINE_ASSERT(is_a<Infty>(x))
484  const Infty &s = down_cast<const Infty &>(x);
485  if (s.is_positive()) {
486  return Inf;
487  } else if (s.is_negative()) {
488  return NegInf;
489  } else {
490  throw DomainError("ceiling is not defined for Complex Infinity");
491  }
492  }
493  virtual RCP<const Basic> truncate(const Basic &x) const override
494  {
495  SYMENGINE_ASSERT(is_a<Infty>(x))
496  const Infty &s = down_cast<const Infty &>(x);
497  if (s.is_positive()) {
498  return Inf;
499  } else if (s.is_negative()) {
500  return NegInf;
501  } else {
502  throw DomainError("truncate is not defined for Complex Infinity");
503  }
504  }
505  virtual RCP<const Basic> erf(const Basic &x) const override
506  {
507  SYMENGINE_ASSERT(is_a<Infty>(x))
508  const Infty &s = down_cast<const Infty &>(x);
509  if (s.is_positive()) {
510  return one;
511  } else if (s.is_negative()) {
512  return minus_one;
513  } else {
514  throw DomainError("erf is not defined for Complex Infinity");
515  }
516  }
517  virtual RCP<const Basic> erfc(const Basic &x) const override
518  {
519  SYMENGINE_ASSERT(is_a<Infty>(x))
520  const Infty &s = down_cast<const Infty &>(x);
521  if (s.is_positive()) {
522  return zero;
523  } else if (s.is_negative()) {
524  return integer(2);
525  } else {
526  throw DomainError("erfc is not defined for Complex Infinity");
527  }
528  }
529 };
530 
532 {
533  static EvaluateInfty evaluate_infty;
534  return evaluate_infty;
535 }
536 
537 } // namespace SymEngine
The lowest unit of symbolic representation.
Definition: basic.h:95
A class that will evaluate functions numerically.
Definition: number.h:193
RCP< const Number > div(const Number &other) const
Division.
Definition: infinity.cpp:132
bool is_canonical(const RCP< const Number > &num) const
Canonical when the direction is -1, 0 or 1.
Definition: infinity.cpp:40
bool __eq__(const Basic &o) const
Definition: infinity.cpp:58
virtual RCP< const Basic > conjugate() const
Definition: infinity.cpp:90
bool is_negative() const
Definition: infinity.h:90
static RCP< const Infty > from_int(const int val)
Constructs Infty using sign of val
Definition: infinity.cpp:33
RCP< const Number > pow(const Number &other) const
Power.
Definition: infinity.cpp:146
bool is_positive() const
Definition: infinity.h:85
Infty(const RCP< const Number > &direction)
Constructs Infty using the sign of _direction
Definition: infinity.cpp:14
RCP< const Number > add(const Number &other) const
Addition.
Definition: infinity.cpp:98
hash_t __hash__() const
Definition: infinity.cpp:51
int compare(const Basic &o) const
Definition: infinity.cpp:68
virtual Evaluate & get_eval() const
Get Evaluate singleton to evaluate numerically.
Definition: infinity.cpp:531
RCP< const Number > mul(const Number &other) const
Multiplication.
Definition: infinity.cpp:113
virtual bool is_negative() const =0
virtual bool is_positive() const =0
virtual bool is_zero() const =0
Main namespace for SymEngine package.
Definition: add.cpp:19
RCP< const Basic > div(const RCP< const Basic > &a, const RCP< const Basic > &b)
Division.
Definition: mul.cpp:426
std::enable_if< std::is_integral< T >::value, RCP< const Integer > >::type integer(T i)
Definition: integer.h:200
bool eq(const Basic &a, const Basic &b)
Checks equality for a and b
Definition: basic-inl.h:21
RCP< const Basic > mul(const RCP< const Basic > &a, const RCP< const Basic > &b)
Multiplication.
Definition: mul.cpp:347
bool is_a_Complex(const Basic &b)
Definition: complex.h:24