test_visitors.cpp
1 #include <symengine/test_visitors.h>
2 
3 namespace SymEngine
4 {
5 
6 void ZeroVisitor::error()
7 {
8  throw SymEngineException(
9  "Only numeric types allowed for is_zero/is_nonzero");
10 }
11 
12 void ZeroVisitor::bvisit(const Basic &x)
13 {
14  is_zero_ = tribool::indeterminate;
15 }
16 
17 void ZeroVisitor::bvisit(const Set &x)
18 {
19  error();
20 }
21 
22 void ZeroVisitor::bvisit(const Relational &x)
23 {
24  error();
25 }
26 
27 void ZeroVisitor::bvisit(const Boolean &x)
28 {
29  error();
30 }
31 
32 void ZeroVisitor::bvisit(const Constant &x)
33 {
34  is_zero_ = tribool::trifalse;
35 }
36 
37 void ZeroVisitor::bvisit(const Abs &x)
38 {
39  x.get_arg()->accept(*this);
40 }
41 
42 void ZeroVisitor::bvisit(const Conjugate &x)
43 {
44  x.get_arg()->accept(*this);
45 }
46 
47 void ZeroVisitor::bvisit(const Sign &x)
48 {
49  x.get_arg()->accept(*this);
50 }
51 
52 void ZeroVisitor::bvisit(const PrimePi &x)
53 {
54  // First prime is 2 so pi(x) is zero for x < 2
55  is_zero_ = is_negative(*sub(x.get_arg(), integer(2)));
56 }
57 
58 void ZeroVisitor::bvisit(const Number &x)
59 {
60  if (bool(x.is_zero())) {
61  is_zero_ = tribool::tritrue;
62  } else {
63  is_zero_ = tribool::trifalse;
64  }
65 }
66 
67 void ZeroVisitor::bvisit(const Symbol &x)
68 {
69  if (assumptions_) {
70  is_zero_ = assumptions_->is_zero(x.rcp_from_this());
71  } else {
72  is_zero_ = tribool::indeterminate;
73  }
74 }
75 
76 tribool ZeroVisitor::apply(const Basic &b)
77 {
78  b.accept(*this);
79  return is_zero_;
80 }
81 
82 tribool is_zero(const Basic &b, const Assumptions *assumptions)
83 {
84  ZeroVisitor visitor(assumptions);
85  return visitor.apply(b);
86 }
87 
88 tribool is_nonzero(const Basic &b, const Assumptions *assumptions)
89 {
90  ZeroVisitor visitor(assumptions);
91  return not_tribool(visitor.apply(b));
92 }
93 
94 void PositiveVisitor::error()
95 {
96  throw SymEngineException("Only numeric types allowed for is_positive");
97 }
98 
99 void PositiveVisitor::bvisit(const Constant &x)
100 {
101  is_positive_ = tribool::tritrue;
102 }
103 
104 void PositiveVisitor::bvisit(const Basic &x)
105 {
106  is_positive_ = tribool::indeterminate;
107 }
108 
109 void PositiveVisitor::bvisit(const Set &x)
110 {
111  error();
112 }
113 
114 void PositiveVisitor::bvisit(const Relational &x)
115 {
116  error();
117 }
118 
119 void PositiveVisitor::bvisit(const Boolean &x)
120 {
121  error();
122 }
123 
124 void PositiveVisitor::bvisit(const Symbol &x)
125 {
126  if (assumptions_) {
127  is_positive_ = assumptions_->is_positive(x.rcp_from_this());
128  } else {
129  is_positive_ = tribool::indeterminate;
130  }
131 }
132 
133 void PositiveVisitor::bvisit(const Number &x)
134 {
135  if (is_a_Complex(x)) {
136  is_positive_ = tribool::trifalse;
137  } else if (bool(x.is_positive())) {
138  is_positive_ = tribool::tritrue;
139  } else {
140  is_positive_ = tribool::trifalse;
141  }
142 }
143 
144 void PositiveVisitor::bvisit(const Add &x)
145 {
146  // True if all are positive
147  // False if all are negative
148  auto coef = x.get_coef();
149  auto dict = x.get_dict();
150 
151  bool can_be_true = true;
152  bool can_be_false = true;
153  if (coef->is_positive()) {
154  can_be_false = false;
155  } else if (coef->is_negative()) {
156  can_be_true = false;
157  }
158  NegativeVisitor neg_visitor(assumptions_);
159  for (const auto &p : dict) {
160  if (not can_be_true and not can_be_false) {
161  is_positive_ = tribool::indeterminate;
162  return;
163  }
164  p.first->accept(*this);
165  if ((p.second->is_positive() and is_true(is_positive_))
166  or (p.second->is_negative()
167  and is_true(neg_visitor.apply(*p.first)))) {
168  // key * value is positive
169  can_be_false = false;
170  } else if ((p.second->is_negative() and is_true(is_positive_))
171  or (p.second->is_positive()
172  and is_true(neg_visitor.apply(*p.first)))) {
173  // key * value is negative
174  can_be_true = false;
175  } else {
176  can_be_true = false;
177  can_be_false = false;
178  }
179  }
180  if (can_be_true) {
181  is_positive_ = tribool::tritrue;
182  } else if (can_be_false) {
183  is_positive_ = tribool::trifalse;
184  } else {
185  is_positive_ = tribool::indeterminate;
186  }
187 }
188 
189 tribool PositiveVisitor::apply(const Basic &b)
190 {
191  b.accept(*this);
192  return is_positive_;
193 }
194 
195 tribool is_positive(const Basic &b, const Assumptions *assumptions)
196 {
197  PositiveVisitor visitor(assumptions);
198  return visitor.apply(b);
199 }
200 
201 void NonPositiveVisitor::error()
202 {
203  throw SymEngineException("Only numeric types allowed for is_negative");
204 }
205 
206 void NonPositiveVisitor::bvisit(const Constant &x)
207 {
208  is_nonpositive_ = tribool::trifalse;
209 }
210 
211 void NonPositiveVisitor::bvisit(const Basic &x)
212 {
213  is_nonpositive_ = tribool::indeterminate;
214 }
215 
216 void NonPositiveVisitor::bvisit(const Set &x)
217 {
218  error();
219 }
220 
221 void NonPositiveVisitor::bvisit(const Relational &x)
222 {
223  error();
224 }
225 
226 void NonPositiveVisitor::bvisit(const Boolean &x)
227 {
228  error();
229 }
230 
231 void NonPositiveVisitor::bvisit(const Symbol &x)
232 {
233  if (assumptions_) {
234  is_nonpositive_ = assumptions_->is_nonpositive(x.rcp_from_this());
235  } else {
236  is_nonpositive_ = tribool::indeterminate;
237  }
238 }
239 
240 void NonPositiveVisitor::bvisit(const Number &x)
241 {
242  if (is_a_Complex(x)) {
243  is_nonpositive_ = tribool::trifalse;
244  } else if (bool(x.is_positive())) {
245  is_nonpositive_ = tribool::trifalse;
246  } else {
247  is_nonpositive_ = tribool::tritrue;
248  }
249 }
250 
251 tribool NonPositiveVisitor::apply(const Basic &b)
252 {
253  b.accept(*this);
254  return is_nonpositive_;
255 }
256 
257 tribool is_nonpositive(const Basic &b, const Assumptions *assumptions)
258 {
259  NonPositiveVisitor visitor(assumptions);
260  return visitor.apply(b);
261 }
262 
263 void NegativeVisitor::error()
264 {
265  throw SymEngineException("Only numeric types allowed for is_negative");
266 }
267 
268 void NegativeVisitor::bvisit(const Basic &x)
269 {
270  is_negative_ = tribool::indeterminate;
271 }
272 
273 void NegativeVisitor::bvisit(const Set &x)
274 {
275  error();
276 }
277 
278 void NegativeVisitor::bvisit(const Relational &x)
279 {
280  error();
281 }
282 
283 void NegativeVisitor::bvisit(const Boolean &x)
284 {
285  error();
286 }
287 
288 void NegativeVisitor::bvisit(const Constant &x)
289 {
290  is_negative_ = tribool::trifalse;
291 }
292 
293 void NegativeVisitor::bvisit(const Symbol &x)
294 {
295  if (assumptions_) {
296  is_negative_ = assumptions_->is_negative(x.rcp_from_this());
297  } else {
298  is_negative_ = tribool::indeterminate;
299  }
300 }
301 
302 void NegativeVisitor::bvisit(const Number &x)
303 {
304  if (is_a_Complex(x)) {
305  is_negative_ = tribool::trifalse;
306  } else if (bool(x.is_negative())) {
307  is_negative_ = tribool::tritrue;
308  } else {
309  is_negative_ = tribool::trifalse;
310  }
311 }
312 
313 tribool NegativeVisitor::apply(const Basic &b)
314 {
315  b.accept(*this);
316  return is_negative_;
317 }
318 
319 tribool is_negative(const Basic &b, const Assumptions *assumptions)
320 {
321  NegativeVisitor visitor(assumptions);
322  return visitor.apply(b);
323 }
324 
325 void NonNegativeVisitor::error()
326 {
327  throw SymEngineException("Only numeric types allowed for is_nonnegative");
328 }
329 
330 void NonNegativeVisitor::bvisit(const Basic &x)
331 {
332  is_nonnegative_ = tribool::indeterminate;
333 }
334 
335 void NonNegativeVisitor::bvisit(const Set &x)
336 {
337  error();
338 }
339 
340 void NonNegativeVisitor::bvisit(const Relational &x)
341 {
342  error();
343 }
344 
345 void NonNegativeVisitor::bvisit(const Boolean &x)
346 {
347  error();
348 }
349 
350 void NonNegativeVisitor::bvisit(const Constant &x)
351 {
352  is_nonnegative_ = tribool::tritrue;
353 }
354 
355 void NonNegativeVisitor::bvisit(const Symbol &x)
356 {
357  if (assumptions_) {
358  is_nonnegative_ = assumptions_->is_nonnegative(x.rcp_from_this());
359  } else {
360  is_nonnegative_ = tribool::indeterminate;
361  }
362 }
363 
364 void NonNegativeVisitor::bvisit(const Number &x)
365 {
366  if (is_a_Complex(x)) {
367  is_nonnegative_ = tribool::trifalse;
368  } else if (bool(x.is_negative())) {
369  is_nonnegative_ = tribool::trifalse;
370  } else {
371  is_nonnegative_ = tribool::tritrue;
372  }
373 }
374 
375 tribool NonNegativeVisitor::apply(const Basic &b)
376 {
377  b.accept(*this);
378  return is_nonnegative_;
379 }
380 
381 tribool is_nonnegative(const Basic &b, const Assumptions *assumptions)
382 {
383  NonNegativeVisitor visitor(assumptions);
384  return visitor.apply(b);
385 }
386 
387 void IntegerVisitor::bvisit(const Symbol &x)
388 {
389  if (assumptions_) {
390  is_integer_ = assumptions_->is_integer(x.rcp_from_this());
391  } else {
392  is_integer_ = tribool::indeterminate;
393  }
394 }
395 
396 void IntegerVisitor::bvisit(const Constant &x)
397 {
398  if (eq(x, *pi) or eq(x, *E) or eq(x, *EulerGamma) or eq(x, *Catalan)
399  or eq(x, *GoldenRatio)) {
400  is_integer_ = tribool::trifalse;
401  } else {
402  is_integer_ = tribool::indeterminate;
403  }
404 }
405 
406 void IntegerVisitor::bvisit(const Add &x)
407 {
408  for (const auto &arg : x.get_args()) {
409  arg->accept(*this);
410  if (not is_true(is_integer_)) {
411  is_integer_ = tribool::indeterminate;
412  return;
413  }
414  }
415 }
416 
417 void IntegerVisitor::bvisit(const Mul &x)
418 {
419  for (const auto &arg : x.get_args()) {
420  arg->accept(*this);
421  if (not is_true(is_integer_)) {
422  is_integer_ = tribool::indeterminate;
423  return;
424  }
425  }
426 }
427 
428 tribool IntegerVisitor::apply(const Basic &b)
429 {
430  b.accept(*this);
431  return is_integer_;
432 }
433 
434 tribool is_integer(const Basic &b, const Assumptions *assumptions)
435 {
436  IntegerVisitor visitor(assumptions);
437  return visitor.apply(b);
438 }
439 
440 void RealVisitor::bvisit(const Symbol &x)
441 {
442  if (assumptions_) {
443  is_real_ = assumptions_->is_real(x.rcp_from_this());
444  } else {
445  is_real_ = tribool::indeterminate;
446  }
447 }
448 
449 void RealVisitor::bvisit(const Number &x)
450 {
451  if (is_a_Complex(x) or is_a<Infty>(x) or is_a<NaN>(x)) {
452  is_real_ = tribool::trifalse;
453  } else {
454  is_real_ = tribool::tritrue;
455  }
456 }
457 
458 void RealVisitor::bvisit(const Constant &x)
459 {
460  if (eq(x, *pi) or eq(x, *E) or eq(x, *EulerGamma) or eq(x, *Catalan)
461  or eq(x, *GoldenRatio)) {
462  is_real_ = tribool::tritrue;
463  } else {
464  is_real_ = tribool::indeterminate;
465  }
466 }
467 
468 void RealVisitor::bvisit(const Add &x)
469 {
470  tribool b = tribool::tritrue;
471  for (const auto &arg : x.get_args()) {
472  arg->accept(*this);
473  b = andwk_tribool(b, is_real_);
474  if (is_indeterminate(b)) {
475  break;
476  }
477  }
478  is_real_ = b;
479 }
480 
481 void RealVisitor::check_power(const RCP<const Basic> &base,
482  const RCP<const Basic> &exp)
483 {
484  if (is_true(is_zero(*exp, assumptions_))) {
485  // exp == 0 => true
486  is_real_ = tribool::tritrue;
487  return;
488  }
489  base->accept(*this);
490  if (is_true(is_real_)) {
491  if (is_true(is_integer(*exp, assumptions_))) {
492  // base is real and exp is integer => true
493  is_real_ = tribool::tritrue;
494  } else if (is_true(is_nonnegative(*base, assumptions_))) {
495  // base >= 0 and exp is real => true
496  exp->accept(*this);
497  if (is_false(is_real_)) {
498  is_real_ = tribool::indeterminate;
499  }
500  } else {
501  is_real_ = tribool::indeterminate;
502  }
503  } else if (is_false(is_real_) && is_true(is_complex(*base, assumptions_))
504  && is_true(is_zero(*sub(exp, integer(1)), assumptions_))) {
505  // base is not real but complex and exp = 1 => false
506  is_real_ = tribool::trifalse;
507  } else {
508  is_real_ = tribool::indeterminate;
509  }
510 }
511 
512 void RealVisitor::bvisit(const Mul &x)
513 {
514  unsigned non_real = 0;
515  tribool b = tribool_from_bool(!x.get_coef()->is_complex());
516  if (is_false(b)) {
517  non_real++;
518  }
519  for (const auto &p : x.get_dict()) {
520  this->check_power(p.first, p.second);
521  if (is_false(is_real_)) {
522  non_real++;
523  if (non_real > 1) {
524  is_real_ = tribool::indeterminate;
525  return;
526  }
527  }
528  b = andwk_tribool(b, is_real_);
529  if (is_indeterminate(b)) {
530  is_real_ = tribool::indeterminate;
531  return;
532  }
533  }
534  if (non_real == 1) {
535  is_real_ = tribool::trifalse;
536  } else {
537  is_real_ = b;
538  }
539 }
540 
541 void RealVisitor::bvisit(const Pow &x)
542 {
543  this->check_power(x.get_base(), x.get_exp());
544 }
545 
546 tribool RealVisitor::apply(const Basic &b)
547 {
548  b.accept(*this);
549  return is_real_;
550 }
551 
552 tribool is_real(const Basic &b, const Assumptions *assumptions)
553 {
554  RealVisitor visitor(assumptions);
555  return visitor.apply(b);
556 }
557 
558 void ComplexVisitor::bvisit(const Symbol &x)
559 {
560  if (assumptions_) {
561  is_complex_ = assumptions_->is_complex(x.rcp_from_this());
562  } else {
563  is_complex_ = tribool::indeterminate;
564  }
565 }
566 
567 void ComplexVisitor::bvisit(const Number &x)
568 {
569  if (is_a<Infty>(x) or is_a<NaN>(x)) {
570  is_complex_ = tribool::trifalse;
571  } else {
572  is_complex_ = tribool::tritrue;
573  }
574 }
575 
576 void ComplexVisitor::bvisit(const Add &x)
577 {
578  tribool b = tribool::tritrue;
579  for (const auto &arg : x.get_args()) {
580  arg->accept(*this);
581  b = andwk_tribool(b, is_complex_);
582  if (is_indeterminate(b) or is_false(b))
583  return;
584  }
585 }
586 
587 void ComplexVisitor::bvisit(const Mul &x)
588 {
589  tribool b = tribool::tritrue;
590  for (const auto &p : x.get_dict()) {
591  this->check_power(*p.first, *p.second);
592  b = andwk_tribool(b, is_complex_);
593  if (is_indeterminate(b) or is_false(b))
594  return;
595  }
596 }
597 
598 void ComplexVisitor::check_power(const Basic &base, const Basic &exp)
599 {
600  base.accept(*this);
601  if (is_true(is_complex_)) {
602  exp.accept(*this);
603  }
604 }
605 
606 void ComplexVisitor::bvisit(const Pow &x)
607 {
608  check_power(*x.get_base(), *x.get_exp());
609 }
610 
611 void ComplexVisitor::bvisit(const Log &x)
612 {
613  complex_arg_not_zero(x, *x.get_arg());
614 }
615 
616 void ComplexVisitor::bvisit(const Tan &x)
617 {
618  complex_arg_not_zero(x, *cos(x.get_arg()));
619 }
620 
621 void ComplexVisitor::complex_arg_not_zero(const OneArgFunction &x,
622  const Basic &not_zero)
623 {
624  // Check if function argument is complex and then if 'not_zero' is not zero
625  x.get_arg()->accept(*this);
626  if (is_true(is_complex_)) {
627  tribool zero = is_zero(not_zero);
628  if (not is_false(zero)) {
629  is_complex_ = not_tribool(zero);
630  }
631  }
632 }
633 
634 void ComplexVisitor::complex_arg_not_pm(const OneArgFunction &x, bool one)
635 {
636  // Check if function argument is complex but not plus/minus 1 (one=True) or
637  // i (one=False)
638  x.get_arg()->accept(*this);
639  if (not is_true(is_complex_))
640  return;
641  RCP<const Number> i1;
642  if (one)
643  i1 = integer(1);
644  else
645  i1 = Complex::from_two_nums(*integer(0), *integer(1));
646  tribool zi1 = is_zero(*sub(x.get_arg(), i1));
647  if (not is_false(zi1)) {
648  is_complex_ = not_tribool(zi1);
649  return;
650  }
651  RCP<const Number> mi1;
652  if (one)
653  mi1 = integer(-1);
654  else
655  mi1 = Complex::from_two_nums(*integer(0), *integer(-1));
656  tribool zmi1 = is_zero(*sub(x.get_arg(), mi1));
657  is_complex_ = not_tribool(zmi1);
658 }
659 
660 void ComplexVisitor::bvisit(const ATan &x)
661 {
662  complex_arg_not_pm(x, false);
663 }
664 
665 void ComplexVisitor::bvisit(const ATanh &x)
666 {
667  complex_arg_not_pm(x, true);
668 }
669 
670 void ComplexVisitor::bvisit(const ACot &x)
671 {
672  complex_arg_not_pm(x, false);
673 }
674 
675 void ComplexVisitor::bvisit(const ACoth &x)
676 {
677  complex_arg_not_pm(x, true);
678 }
679 
680 void ComplexVisitor::bvisit(const Cot &x)
681 {
682  complex_arg_not_zero(x, *sin(x.get_arg()));
683 }
684 
685 void ComplexVisitor::bvisit(const Sec &x)
686 {
687  complex_arg_not_zero(x, *cos(x.get_arg()));
688 }
689 
690 void ComplexVisitor::bvisit(const ASec &x)
691 {
692  complex_arg_not_zero(x, *x.get_arg());
693 }
694 
695 void ComplexVisitor::bvisit(const ASech &x)
696 {
697  complex_arg_not_zero(x, *x.get_arg());
698 }
699 
700 void ComplexVisitor::bvisit(const Csc &x)
701 {
702  complex_arg_not_zero(x, *sin(x.get_arg()));
703 }
704 
705 void ComplexVisitor::bvisit(const ACsc &x)
706 {
707  complex_arg_not_zero(x, *x.get_arg());
708 }
709 
710 void ComplexVisitor::bvisit(const ACsch &x)
711 {
712  complex_arg_not_zero(x, *x.get_arg());
713 }
714 
715 tribool ComplexVisitor::apply(const Basic &b)
716 {
717  b.accept(*this);
718  return is_complex_;
719 }
720 
721 tribool is_complex(const Basic &b, const Assumptions *assumptions)
722 {
723  ComplexVisitor visitor(assumptions);
724  return visitor.apply(b);
725 }
726 
727 void PolynomialVisitor::bvisit(const Basic &x)
728 {
729  auto old_allowed = variables_allowed_;
730  variables_allowed_ = false;
731  for (const auto &p : x.get_args()) {
732  p->accept(*this);
733  if (!is_polynomial_) {
734  variables_allowed_ = old_allowed;
735  return;
736  }
737  }
738  variables_allowed_ = old_allowed;
739 }
740 
741 void PolynomialVisitor::bvisit(const Add &x)
742 {
743  for (const auto &arg : x.get_args()) {
744  arg->accept(*this);
745  if (!is_polynomial_)
746  return;
747  }
748 }
749 
750 void PolynomialVisitor::bvisit(const Mul &x)
751 {
752  for (const auto &p : x.get_dict()) {
753  this->check_power(*p.first, *p.second);
754  if (!is_polynomial_)
755  return;
756  }
757 }
758 
759 void PolynomialVisitor::check_power(const Basic &base, const Basic &exp)
760 {
761  if (variables_allowed_) {
762  variables_allowed_ = false;
763  exp.accept(*this);
764  if (!is_polynomial_) {
765  variables_allowed_ = true;
766  return;
767  }
768  base.accept(*this);
769  variables_allowed_ = true;
770  if (!is_polynomial_) {
771  is_polynomial_ = true;
772  base.accept(*this);
773  is_polynomial_ = is_polynomial_ and is_a<Integer>(exp)
774  and down_cast<const Integer &>(exp).is_positive();
775  }
776  } else {
777  base.accept(*this);
778  if (!is_polynomial_)
779  return;
780  exp.accept(*this);
781  }
782 }
783 
784 void PolynomialVisitor::bvisit(const Pow &x)
785 {
786  check_power(*x.get_base(), *x.get_exp());
787 }
788 
789 void PolynomialVisitor::bvisit(const Symbol &x)
790 {
791  if (variables_allowed_)
792  return;
793 
794  if (variables_.empty()) { // All symbols are variables
795  is_polynomial_ = false;
796  } else {
797  for (const auto &elem : variables_) {
798  if (x.__eq__(*elem)) {
799  is_polynomial_ = false;
800  return;
801  }
802  }
803  }
804 }
805 
806 bool PolynomialVisitor::apply(const Basic &b)
807 {
808  b.accept(*this);
809  return is_polynomial_;
810 }
811 
812 bool is_polynomial(const Basic &b, const set_basic &variables)
813 {
814  PolynomialVisitor visitor(variables);
815  return visitor.apply(b);
816 }
817 
818 void RationalVisitor::bvisit(const Number &x)
819 {
820  is_rational_ = tribool::trifalse;
821  if (is_a_Complex(x) or is_a<Infty>(x) or is_a<NaN>(x)) {
822  neither_ = true;
823  }
824 }
825 
826 void RationalVisitor::bvisit(const Constant &x)
827 {
828  if (eq(x, *pi) or eq(x, *E) or eq(x, *GoldenRatio)) {
829  // It is currently (2021) not known whether Catalan's constant
830  // or Euler's constant are rational or irrational
831  is_rational_ = tribool::trifalse;
832  } else {
833  is_rational_ = tribool::indeterminate;
834  }
835 }
836 
837 void RationalVisitor::bvisit(const Add &x)
838 {
839  tribool b = tribool::tritrue;
840  for (const auto &arg : x.get_args()) {
841  arg->accept(*this);
842  b = andwk_tribool(b, is_rational_);
843  if (is_indeterminate(b))
844  return;
845  }
846 }
847 
848 tribool RationalVisitor::apply(const Basic &b)
849 {
850  b.accept(*this);
851  tribool result = is_rational_;
852  if (not rational_ and not neither_) {
853  result = not_tribool(result);
854  }
855  return result;
856 }
857 
858 tribool is_rational(const Basic &b)
859 {
860  RationalVisitor visitor(true);
861  return visitor.apply(b);
862 }
863 
864 tribool is_irrational(const Basic &b)
865 {
866  RationalVisitor visitor(false);
867  return visitor.apply(b);
868 }
869 
870 void FiniteVisitor::error()
871 {
872  throw SymEngineException(
873  "Only numeric types allowed for is_finite/is_infinite");
874 }
875 
876 void FiniteVisitor::bvisit(const Basic &x)
877 {
878  is_finite_ = tribool::indeterminate;
879 }
880 
881 void FiniteVisitor::bvisit(const Symbol &x)
882 {
883  if (assumptions_) {
884  is_finite_ = assumptions_->is_complex(x.rcp_from_this());
885  } else {
886  is_finite_ = tribool::indeterminate;
887  }
888 }
889 
890 void FiniteVisitor::bvisit(const Number &x)
891 {
892  is_finite_ = tribool::tritrue;
893 }
894 
895 void FiniteVisitor::bvisit(const Infty &x)
896 {
897  is_finite_ = tribool::trifalse;
898 }
899 
900 void FiniteVisitor::bvisit(const NaN &x)
901 {
902  error();
903 }
904 
905 void FiniteVisitor::bvisit(const Set &x)
906 {
907  error();
908 }
909 
910 void FiniteVisitor::bvisit(const Relational &x)
911 {
912  error();
913 }
914 
915 void FiniteVisitor::bvisit(const Boolean &x)
916 {
917  error();
918 }
919 
920 void FiniteVisitor::bvisit(const Constant &x)
921 {
922  is_finite_ = tribool::tritrue;
923 }
924 
925 tribool FiniteVisitor::apply(const Basic &b)
926 {
927  b.accept(*this);
928  return is_finite_;
929 }
930 
931 tribool is_finite(const Basic &b, const Assumptions *assumptions)
932 {
933  FiniteVisitor visitor(assumptions);
934  return visitor.apply(b);
935 }
936 
937 tribool is_infinite(const Basic &b, const Assumptions *assumptions)
938 {
939  FiniteVisitor visitor(assumptions);
940  return not_tribool(visitor.apply(b));
941 }
942 
943 tribool is_even(const Basic &b, const Assumptions *assumptions)
944 {
945  return is_integer(*div(b.rcp_from_this(), integer(2)), assumptions);
946 }
947 
948 tribool is_odd(const Basic &b, const Assumptions *assumptions)
949 {
950  return is_integer(*div(add(b.rcp_from_this(), integer(1)), integer(2)),
951  assumptions);
952 }
953 
954 void AlgebraicVisitor::error()
955 {
956  throw SymEngineException(
957  "Only numeric types allowed for is_algebraic/is_transcendental");
958 }
959 
960 void AlgebraicVisitor::bvisit(const Basic &x)
961 {
962  is_algebraic_ = tribool::indeterminate;
963 }
964 
965 void AlgebraicVisitor::bvisit(const Set &x)
966 {
967  error();
968 }
969 
970 void AlgebraicVisitor::bvisit(const Relational &x)
971 {
972  error();
973 }
974 
975 void AlgebraicVisitor::bvisit(const Boolean &x)
976 {
977  error();
978 }
979 
980 void AlgebraicVisitor::bvisit(const Add &x)
981 {
982  // algebraic + algebraic = algebraic
983  // algebraic + transcendental = transcendental
984  // algebraic + transcendental + transcendental = indeterminate
985  tribool current = tribool::tritrue;
986  for (const auto &arg : x.get_args()) {
987  arg->accept(*this);
988  if (is_false(current) and is_false(is_algebraic_)) {
989  is_algebraic_ = tribool::indeterminate;
990  return;
991  }
992  current = andwk_tribool(current, is_algebraic_);
993  if (is_indeterminate(current)) {
994  is_algebraic_ = current;
995  return;
996  }
997  }
998  is_algebraic_ = current;
999 }
1000 
1001 void AlgebraicVisitor::bvisit(const Symbol &x)
1002 {
1003  if (assumptions_) {
1004  is_algebraic_ = assumptions_->is_rational(x.rcp_from_this());
1005  if (is_false(is_algebraic_)) {
1006  is_algebraic_ = tribool::indeterminate;
1007  }
1008  } else {
1009  is_algebraic_ = tribool::indeterminate;
1010  }
1011 }
1012 
1013 void AlgebraicVisitor::bvisit(const Constant &x)
1014 {
1015  if (eq(x, *pi) or eq(x, *E)) {
1016  is_algebraic_ = tribool::trifalse;
1017  } else if (eq(x, *GoldenRatio)) {
1018  is_algebraic_ = tribool::tritrue;
1019  } else {
1020  // It is unknown (2021) whether EulerGamma or Catalan are algebraic or
1021  // transcendental
1022  is_algebraic_ = tribool::indeterminate;
1023  }
1024 }
1025 
1026 void AlgebraicVisitor::bvisit(const Integer &x)
1027 {
1028  is_algebraic_ = tribool::tritrue;
1029 }
1030 
1031 void AlgebraicVisitor::bvisit(const Rational &x)
1032 {
1033  is_algebraic_ = tribool::tritrue;
1034 }
1035 
1036 void AlgebraicVisitor::trans_nonzero_and_algebraic(const Basic &b)
1037 {
1038  // transcendental if b is algebraic and nonzero
1039  b.accept(*this);
1040  if (is_true(is_algebraic_) and is_true(is_nonzero(b))) {
1041  is_algebraic_ = tribool::trifalse;
1042  } else {
1043  is_algebraic_ = tribool::indeterminate;
1044  }
1045 }
1046 
1047 void AlgebraicVisitor::bvisit(const TrigFunction &x)
1048 {
1049  // x algebraic and not 0 => sin(x) transcendental
1050  trans_nonzero_and_algebraic(*x.get_arg());
1051 }
1052 
1053 void AlgebraicVisitor::bvisit(const HyperbolicFunction &x)
1054 {
1055  // x algebraic and not 0 => sinh(x) transcendental
1056  trans_nonzero_and_algebraic(*x.get_arg());
1057 }
1058 
1059 void AlgebraicVisitor::bvisit(const LambertW &x)
1060 {
1061  // x algebraic and not 0 => W(x) transcendental
1062  trans_nonzero_and_algebraic(*x.get_arg());
1063 }
1064 
1065 tribool AlgebraicVisitor::apply(const Basic &b)
1066 {
1067  b.accept(*this);
1068  return is_algebraic_;
1069 }
1070 
1071 tribool is_algebraic(const Basic &b, const Assumptions *assumptions)
1072 {
1073  AlgebraicVisitor visitor(assumptions);
1074  return visitor.apply(b);
1075 }
1076 
1077 tribool is_transcendental(const Basic &b, const Assumptions *assumptions)
1078 {
1079  AlgebraicVisitor visitor(assumptions);
1080  return not_tribool(visitor.apply(b));
1081 }
1082 
1083 } // namespace SymEngine
The lowest unit of symbolic representation.
Definition: basic.h:97
static RCP< const Number > from_two_nums(const Number &re, const Number &im)
Definition: complex.cpp:109
T empty(T... args)
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:431
std::enable_if< std::is_integral< T >::value, RCP< const Integer > >::type integer(T i)
Definition: integer.h:197
bool eq(const Basic &a, const Basic &b)
Checks equality for a and b
Definition: basic-inl.h:21
RCP< const Basic > sub(const RCP< const Basic > &a, const RCP< const Basic > &b)
Substracts b from a.
Definition: add.cpp:495
RCP< const Basic > exp(const RCP< const Basic > &x)
Returns the natural exponential function E**x = pow(E, x)
Definition: pow.cpp:271
bool is_polynomial(const Basic &b, const set_basic &variables)
Check if expression is a polynomial.
tribool is_nonzero(const Basic &b, const Assumptions *assumptions=nullptr)
Check if a number is non-zero.
RCP< const Basic > cos(const RCP< const Basic > &arg)
Canonicalize Cos:
Definition: functions.cpp:942
RCP< const Basic > add(const RCP< const Basic > &a, const RCP< const Basic > &b)
Adds two objects (safely).
Definition: add.cpp:425
bool is_a_Complex(const Basic &b)
Definition: complex.h:24
RCP< const Basic > sin(const RCP< const Basic > &arg)
Canonicalize Sin:
Definition: functions.cpp:874