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  return;
476  }
477 }
478 
479 tribool RealVisitor::apply(const Basic &b)
480 {
481  b.accept(*this);
482  return is_real_;
483 }
484 
485 tribool is_real(const Basic &b, const Assumptions *assumptions)
486 {
487  RealVisitor visitor(assumptions);
488  return visitor.apply(b);
489 }
490 
491 void ComplexVisitor::bvisit(const Symbol &x)
492 {
493  if (assumptions_) {
494  is_complex_ = assumptions_->is_complex(x.rcp_from_this());
495  } else {
496  is_complex_ = tribool::indeterminate;
497  }
498 }
499 
500 void ComplexVisitor::bvisit(const Number &x)
501 {
502  if (is_a<Infty>(x) or is_a<NaN>(x)) {
503  is_complex_ = tribool::trifalse;
504  } else {
505  is_complex_ = tribool::tritrue;
506  }
507 }
508 
509 void ComplexVisitor::bvisit(const Add &x)
510 {
511  tribool b = tribool::tritrue;
512  for (const auto &arg : x.get_args()) {
513  arg->accept(*this);
514  b = andwk_tribool(b, is_complex_);
515  if (is_indeterminate(b) or is_false(b))
516  return;
517  }
518 }
519 
520 void ComplexVisitor::bvisit(const Mul &x)
521 {
522  tribool b = tribool::tritrue;
523  for (const auto &p : x.get_dict()) {
524  this->check_power(*p.first, *p.second);
525  b = andwk_tribool(b, is_complex_);
526  if (is_indeterminate(b) or is_false(b))
527  return;
528  }
529 }
530 
531 void ComplexVisitor::check_power(const Basic &base, const Basic &exp)
532 {
533  base.accept(*this);
534  if (is_true(is_complex_)) {
535  exp.accept(*this);
536  }
537 }
538 
539 void ComplexVisitor::bvisit(const Pow &x)
540 {
541  check_power(*x.get_base(), *x.get_exp());
542 }
543 
544 void ComplexVisitor::bvisit(const Log &x)
545 {
546  complex_arg_not_zero(x, *x.get_arg());
547 }
548 
549 void ComplexVisitor::bvisit(const Tan &x)
550 {
551  complex_arg_not_zero(x, *cos(x.get_arg()));
552 }
553 
554 void ComplexVisitor::complex_arg_not_zero(const OneArgFunction &x,
555  const Basic &not_zero)
556 {
557  // Check if function argument is complex and then if 'not_zero' is not zero
558  x.get_arg()->accept(*this);
559  if (is_true(is_complex_)) {
560  tribool zero = is_zero(not_zero);
561  if (not is_false(zero)) {
562  is_complex_ = not_tribool(zero);
563  }
564  }
565 }
566 
567 void ComplexVisitor::complex_arg_not_pm(const OneArgFunction &x, bool one)
568 {
569  // Check if function argument is complex but not plus/minus 1 (one=True) or
570  // i (one=False)
571  x.get_arg()->accept(*this);
572  if (not is_true(is_complex_))
573  return;
574  RCP<const Number> i1;
575  if (one)
576  i1 = integer(1);
577  else
578  i1 = Complex::from_two_nums(*integer(0), *integer(1));
579  tribool zi1 = is_zero(*sub(x.get_arg(), i1));
580  if (not is_false(zi1)) {
581  is_complex_ = not_tribool(zi1);
582  return;
583  }
584  RCP<const Number> mi1;
585  if (one)
586  mi1 = integer(-1);
587  else
588  mi1 = Complex::from_two_nums(*integer(0), *integer(-1));
589  tribool zmi1 = is_zero(*sub(x.get_arg(), mi1));
590  is_complex_ = not_tribool(zmi1);
591 }
592 
593 void ComplexVisitor::bvisit(const ATan &x)
594 {
595  complex_arg_not_pm(x, false);
596 }
597 
598 void ComplexVisitor::bvisit(const ATanh &x)
599 {
600  complex_arg_not_pm(x, true);
601 }
602 
603 void ComplexVisitor::bvisit(const ACot &x)
604 {
605  complex_arg_not_pm(x, false);
606 }
607 
608 void ComplexVisitor::bvisit(const ACoth &x)
609 {
610  complex_arg_not_pm(x, true);
611 }
612 
613 void ComplexVisitor::bvisit(const Cot &x)
614 {
615  complex_arg_not_zero(x, *sin(x.get_arg()));
616 }
617 
618 void ComplexVisitor::bvisit(const Sec &x)
619 {
620  complex_arg_not_zero(x, *cos(x.get_arg()));
621 }
622 
623 void ComplexVisitor::bvisit(const ASec &x)
624 {
625  complex_arg_not_zero(x, *x.get_arg());
626 }
627 
628 void ComplexVisitor::bvisit(const ASech &x)
629 {
630  complex_arg_not_zero(x, *x.get_arg());
631 }
632 
633 void ComplexVisitor::bvisit(const Csc &x)
634 {
635  complex_arg_not_zero(x, *sin(x.get_arg()));
636 }
637 
638 void ComplexVisitor::bvisit(const ACsc &x)
639 {
640  complex_arg_not_zero(x, *x.get_arg());
641 }
642 
643 void ComplexVisitor::bvisit(const ACsch &x)
644 {
645  complex_arg_not_zero(x, *x.get_arg());
646 }
647 
648 tribool ComplexVisitor::apply(const Basic &b)
649 {
650  b.accept(*this);
651  return is_complex_;
652 }
653 
654 tribool is_complex(const Basic &b, const Assumptions *assumptions)
655 {
656  ComplexVisitor visitor(assumptions);
657  return visitor.apply(b);
658 }
659 
660 void PolynomialVisitor::bvisit(const Basic &x)
661 {
662  auto old_allowed = variables_allowed_;
663  variables_allowed_ = false;
664  for (const auto &p : x.get_args()) {
665  p->accept(*this);
666  if (!is_polynomial_) {
667  variables_allowed_ = old_allowed;
668  return;
669  }
670  }
671  variables_allowed_ = old_allowed;
672 }
673 
674 void PolynomialVisitor::bvisit(const Add &x)
675 {
676  for (const auto &arg : x.get_args()) {
677  arg->accept(*this);
678  if (!is_polynomial_)
679  return;
680  }
681 }
682 
683 void PolynomialVisitor::bvisit(const Mul &x)
684 {
685  for (const auto &p : x.get_dict()) {
686  this->check_power(*p.first, *p.second);
687  if (!is_polynomial_)
688  return;
689  }
690 }
691 
692 void PolynomialVisitor::check_power(const Basic &base, const Basic &exp)
693 {
694  if (variables_allowed_) {
695  variables_allowed_ = false;
696  exp.accept(*this);
697  if (!is_polynomial_) {
698  variables_allowed_ = true;
699  return;
700  }
701  base.accept(*this);
702  variables_allowed_ = true;
703  if (!is_polynomial_) {
704  is_polynomial_ = true;
705  base.accept(*this);
706  is_polynomial_ = is_polynomial_ and is_a<Integer>(exp)
707  and down_cast<const Integer &>(exp).is_positive();
708  }
709  } else {
710  base.accept(*this);
711  if (!is_polynomial_)
712  return;
713  exp.accept(*this);
714  }
715 }
716 
717 void PolynomialVisitor::bvisit(const Pow &x)
718 {
719  check_power(*x.get_base(), *x.get_exp());
720 }
721 
722 void PolynomialVisitor::bvisit(const Symbol &x)
723 {
724  if (variables_allowed_)
725  return;
726 
727  if (variables_.empty()) { // All symbols are variables
728  is_polynomial_ = false;
729  } else {
730  for (const auto &elem : variables_) {
731  if (x.__eq__(*elem)) {
732  is_polynomial_ = false;
733  return;
734  }
735  }
736  }
737 }
738 
739 bool PolynomialVisitor::apply(const Basic &b)
740 {
741  b.accept(*this);
742  return is_polynomial_;
743 }
744 
745 bool is_polynomial(const Basic &b, const set_basic &variables)
746 {
747  PolynomialVisitor visitor(variables);
748  return visitor.apply(b);
749 }
750 
751 void RationalVisitor::bvisit(const Number &x)
752 {
753  is_rational_ = tribool::trifalse;
754  if (is_a_Complex(x) or is_a<Infty>(x) or is_a<NaN>(x)) {
755  neither_ = true;
756  }
757 }
758 
759 void RationalVisitor::bvisit(const Constant &x)
760 {
761  if (eq(x, *pi) or eq(x, *E) or eq(x, *GoldenRatio)) {
762  // It is currently (2021) not known whether Catalan's constant
763  // or Euler's constant are rational or irrational
764  is_rational_ = tribool::trifalse;
765  } else {
766  is_rational_ = tribool::indeterminate;
767  }
768 }
769 
770 void RationalVisitor::bvisit(const Add &x)
771 {
772  tribool b = tribool::tritrue;
773  for (const auto &arg : x.get_args()) {
774  arg->accept(*this);
775  b = andwk_tribool(b, is_rational_);
776  if (is_indeterminate(b))
777  return;
778  }
779 }
780 
781 tribool RationalVisitor::apply(const Basic &b)
782 {
783  b.accept(*this);
784  tribool result = is_rational_;
785  if (not rational_ and not neither_) {
786  result = not_tribool(result);
787  }
788  return result;
789 }
790 
791 tribool is_rational(const Basic &b)
792 {
793  RationalVisitor visitor(true);
794  return visitor.apply(b);
795 }
796 
797 tribool is_irrational(const Basic &b)
798 {
799  RationalVisitor visitor(false);
800  return visitor.apply(b);
801 }
802 
803 void FiniteVisitor::error()
804 {
805  throw SymEngineException(
806  "Only numeric types allowed for is_finite/is_infinite");
807 }
808 
809 void FiniteVisitor::bvisit(const Basic &x)
810 {
811  is_finite_ = tribool::indeterminate;
812 }
813 
814 void FiniteVisitor::bvisit(const Symbol &x)
815 {
816  if (assumptions_) {
817  is_finite_ = assumptions_->is_complex(x.rcp_from_this());
818  } else {
819  is_finite_ = tribool::indeterminate;
820  }
821 }
822 
823 void FiniteVisitor::bvisit(const Number &x)
824 {
825  is_finite_ = tribool::tritrue;
826 }
827 
828 void FiniteVisitor::bvisit(const Infty &x)
829 {
830  is_finite_ = tribool::trifalse;
831 }
832 
833 void FiniteVisitor::bvisit(const NaN &x)
834 {
835  error();
836 }
837 
838 void FiniteVisitor::bvisit(const Set &x)
839 {
840  error();
841 }
842 
843 void FiniteVisitor::bvisit(const Relational &x)
844 {
845  error();
846 }
847 
848 void FiniteVisitor::bvisit(const Boolean &x)
849 {
850  error();
851 }
852 
853 void FiniteVisitor::bvisit(const Constant &x)
854 {
855  is_finite_ = tribool::tritrue;
856 }
857 
858 tribool FiniteVisitor::apply(const Basic &b)
859 {
860  b.accept(*this);
861  return is_finite_;
862 }
863 
864 tribool is_finite(const Basic &b, const Assumptions *assumptions)
865 {
866  FiniteVisitor visitor(assumptions);
867  return visitor.apply(b);
868 }
869 
870 tribool is_infinite(const Basic &b, const Assumptions *assumptions)
871 {
872  FiniteVisitor visitor(assumptions);
873  return not_tribool(visitor.apply(b));
874 }
875 
876 tribool is_even(const Basic &b, const Assumptions *assumptions)
877 {
878  return is_integer(*div(b.rcp_from_this(), integer(2)), assumptions);
879 }
880 
881 tribool is_odd(const Basic &b, const Assumptions *assumptions)
882 {
883  return is_integer(*div(add(b.rcp_from_this(), integer(1)), integer(2)),
884  assumptions);
885 }
886 
887 void AlgebraicVisitor::error()
888 {
889  throw SymEngineException(
890  "Only numeric types allowed for is_algebraic/is_transcendental");
891 }
892 
893 void AlgebraicVisitor::bvisit(const Basic &x)
894 {
895  is_algebraic_ = tribool::indeterminate;
896 }
897 
898 void AlgebraicVisitor::bvisit(const Set &x)
899 {
900  error();
901 }
902 
903 void AlgebraicVisitor::bvisit(const Relational &x)
904 {
905  error();
906 }
907 
908 void AlgebraicVisitor::bvisit(const Boolean &x)
909 {
910  error();
911 }
912 
913 void AlgebraicVisitor::bvisit(const Add &x)
914 {
915  // algebraic + algebraic = algebraic
916  // algebraic + transcendental = transcendental
917  // algebraic + transcendental + transcendental = indeterminate
918  tribool current = tribool::tritrue;
919  for (const auto &arg : x.get_args()) {
920  arg->accept(*this);
921  if (is_false(current) and is_false(is_algebraic_)) {
922  is_algebraic_ = tribool::indeterminate;
923  return;
924  }
925  current = andwk_tribool(current, is_algebraic_);
926  if (is_indeterminate(current)) {
927  is_algebraic_ = current;
928  return;
929  }
930  }
931  is_algebraic_ = current;
932 }
933 
934 void AlgebraicVisitor::bvisit(const Symbol &x)
935 {
936  if (assumptions_) {
937  is_algebraic_ = assumptions_->is_rational(x.rcp_from_this());
938  if (is_false(is_algebraic_)) {
939  is_algebraic_ = tribool::indeterminate;
940  }
941  } else {
942  is_algebraic_ = tribool::indeterminate;
943  }
944 }
945 
946 void AlgebraicVisitor::bvisit(const Constant &x)
947 {
948  if (eq(x, *pi) or eq(x, *E)) {
949  is_algebraic_ = tribool::trifalse;
950  } else if (eq(x, *GoldenRatio)) {
951  is_algebraic_ = tribool::tritrue;
952  } else {
953  // It is unknown (2021) whether EulerGamma or Catalan are algebraic or
954  // transcendental
955  is_algebraic_ = tribool::indeterminate;
956  }
957 }
958 
959 void AlgebraicVisitor::bvisit(const Integer &x)
960 {
961  is_algebraic_ = tribool::tritrue;
962 }
963 
964 void AlgebraicVisitor::bvisit(const Rational &x)
965 {
966  is_algebraic_ = tribool::tritrue;
967 }
968 
969 void AlgebraicVisitor::trans_nonzero_and_algebraic(const Basic &b)
970 {
971  // transcendental if b is algebraic and nonzero
972  b.accept(*this);
973  if (is_true(is_algebraic_) and is_nonzero(b)) {
974  is_algebraic_ = tribool::trifalse;
975  } else {
976  is_algebraic_ = tribool::indeterminate;
977  }
978 }
979 
980 void AlgebraicVisitor::bvisit(const TrigFunction &x)
981 {
982  // x algebraic and not 0 => sin(x) transcendental
983  trans_nonzero_and_algebraic(*x.get_arg());
984 }
985 
986 void AlgebraicVisitor::bvisit(const HyperbolicFunction &x)
987 {
988  // x algebraic and not 0 => sinh(x) transcendental
989  trans_nonzero_and_algebraic(*x.get_arg());
990 }
991 
992 void AlgebraicVisitor::bvisit(const LambertW &x)
993 {
994  // x algebraic and not 0 => W(x) transcendental
995  trans_nonzero_and_algebraic(*x.get_arg());
996 }
997 
998 tribool AlgebraicVisitor::apply(const Basic &b)
999 {
1000  b.accept(*this);
1001  return is_algebraic_;
1002 }
1003 
1004 tribool is_algebraic(const Basic &b, const Assumptions *assumptions)
1005 {
1006  AlgebraicVisitor visitor(assumptions);
1007  return visitor.apply(b);
1008 }
1009 
1010 tribool is_transcendental(const Basic &b, const Assumptions *assumptions)
1011 {
1012  AlgebraicVisitor visitor(assumptions);
1013  return not_tribool(visitor.apply(b));
1014 }
1015 
1016 } // namespace SymEngine
The lowest unit of symbolic representation.
Definition: basic.h:95
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:437
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 > 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:270
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
tribool is_zero(const Basic &b, const Assumptions *assumptions=nullptr)
Check if a number is zero.
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