Loading...
Searching...
No Matches
test_visitors.cpp
1#include <symengine/test_visitors.h>
2
3namespace SymEngine
4{
5
6void ZeroVisitor::error()
7{
8 throw SymEngineException(
9 "Only numeric types allowed for is_zero/is_nonzero");
10}
11
12void ZeroVisitor::bvisit(const Basic &x)
13{
14 is_zero_ = tribool::indeterminate;
15}
16
17void ZeroVisitor::bvisit(const Set &x)
18{
19 error();
20}
21
22void ZeroVisitor::bvisit(const Relational &x)
23{
24 error();
25}
26
27void ZeroVisitor::bvisit(const Boolean &x)
28{
29 error();
30}
31
32void ZeroVisitor::bvisit(const Constant &x)
33{
34 is_zero_ = tribool::trifalse;
35}
36
37void ZeroVisitor::bvisit(const Abs &x)
38{
39 x.get_arg()->accept(*this);
40}
41
42void ZeroVisitor::bvisit(const Conjugate &x)
43{
44 x.get_arg()->accept(*this);
45}
46
47void ZeroVisitor::bvisit(const Sign &x)
48{
49 x.get_arg()->accept(*this);
50}
51
52void 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
58void 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
67void 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
76tribool ZeroVisitor::apply(const Basic &b)
77{
78 b.accept(*this);
79 return is_zero_;
80}
81
82tribool is_zero(const Basic &b, const Assumptions *assumptions)
83{
84 ZeroVisitor visitor(assumptions);
85 return visitor.apply(b);
86}
87
88tribool is_nonzero(const Basic &b, const Assumptions *assumptions)
89{
90 ZeroVisitor visitor(assumptions);
91 return not_tribool(visitor.apply(b));
92}
93
94void PositiveVisitor::error()
95{
96 throw SymEngineException("Only numeric types allowed for is_positive");
97}
98
99void PositiveVisitor::bvisit(const Constant &x)
100{
101 is_positive_ = tribool::tritrue;
102}
103
104void PositiveVisitor::bvisit(const Basic &x)
105{
106 is_positive_ = tribool::indeterminate;
107}
108
109void PositiveVisitor::bvisit(const Set &x)
110{
111 error();
112}
113
114void PositiveVisitor::bvisit(const Relational &x)
115{
116 error();
117}
118
119void PositiveVisitor::bvisit(const Boolean &x)
120{
121 error();
122}
123
124void 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
133void 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
144void 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
189tribool PositiveVisitor::apply(const Basic &b)
190{
191 b.accept(*this);
192 return is_positive_;
193}
194
195tribool is_positive(const Basic &b, const Assumptions *assumptions)
196{
197 PositiveVisitor visitor(assumptions);
198 return visitor.apply(b);
199}
200
201void NonPositiveVisitor::error()
202{
203 throw SymEngineException("Only numeric types allowed for is_negative");
204}
205
206void NonPositiveVisitor::bvisit(const Constant &x)
207{
208 is_nonpositive_ = tribool::trifalse;
209}
210
211void NonPositiveVisitor::bvisit(const Basic &x)
212{
213 is_nonpositive_ = tribool::indeterminate;
214}
215
216void NonPositiveVisitor::bvisit(const Set &x)
217{
218 error();
219}
220
221void NonPositiveVisitor::bvisit(const Relational &x)
222{
223 error();
224}
225
226void NonPositiveVisitor::bvisit(const Boolean &x)
227{
228 error();
229}
230
231void 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
240void 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
251tribool NonPositiveVisitor::apply(const Basic &b)
252{
253 b.accept(*this);
254 return is_nonpositive_;
255}
256
257tribool is_nonpositive(const Basic &b, const Assumptions *assumptions)
258{
259 NonPositiveVisitor visitor(assumptions);
260 return visitor.apply(b);
261}
262
263void NegativeVisitor::error()
264{
265 throw SymEngineException("Only numeric types allowed for is_negative");
266}
267
268void NegativeVisitor::bvisit(const Basic &x)
269{
270 is_negative_ = tribool::indeterminate;
271}
272
273void NegativeVisitor::bvisit(const Set &x)
274{
275 error();
276}
277
278void NegativeVisitor::bvisit(const Relational &x)
279{
280 error();
281}
282
283void NegativeVisitor::bvisit(const Boolean &x)
284{
285 error();
286}
287
288void NegativeVisitor::bvisit(const Constant &x)
289{
290 is_negative_ = tribool::trifalse;
291}
292
293void 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
302void 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
313tribool NegativeVisitor::apply(const Basic &b)
314{
315 b.accept(*this);
316 return is_negative_;
317}
318
319tribool is_negative(const Basic &b, const Assumptions *assumptions)
320{
321 NegativeVisitor visitor(assumptions);
322 return visitor.apply(b);
323}
324
325void NonNegativeVisitor::error()
326{
327 throw SymEngineException("Only numeric types allowed for is_nonnegative");
328}
329
330void NonNegativeVisitor::bvisit(const Basic &x)
331{
332 is_nonnegative_ = tribool::indeterminate;
333}
334
335void NonNegativeVisitor::bvisit(const Set &x)
336{
337 error();
338}
339
340void NonNegativeVisitor::bvisit(const Relational &x)
341{
342 error();
343}
344
345void NonNegativeVisitor::bvisit(const Boolean &x)
346{
347 error();
348}
349
350void NonNegativeVisitor::bvisit(const Constant &x)
351{
352 is_nonnegative_ = tribool::tritrue;
353}
354
355void 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
364void 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
375tribool NonNegativeVisitor::apply(const Basic &b)
376{
377 b.accept(*this);
378 return is_nonnegative_;
379}
380
381tribool is_nonnegative(const Basic &b, const Assumptions *assumptions)
382{
383 NonNegativeVisitor visitor(assumptions);
384 return visitor.apply(b);
385}
386
387void 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
396void 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
406void 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
417void 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
428tribool IntegerVisitor::apply(const Basic &b)
429{
430 b.accept(*this);
431 return is_integer_;
432}
433
434tribool is_integer(const Basic &b, const Assumptions *assumptions)
435{
436 IntegerVisitor visitor(assumptions);
437 return visitor.apply(b);
438}
439
440void 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
449void 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
458void 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
468void 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
481void 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
512void 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
541void RealVisitor::bvisit(const Pow &x)
542{
543 this->check_power(x.get_base(), x.get_exp());
544}
545
546tribool RealVisitor::apply(const Basic &b)
547{
548 b.accept(*this);
549 return is_real_;
550}
551
552tribool is_real(const Basic &b, const Assumptions *assumptions)
553{
554 RealVisitor visitor(assumptions);
555 return visitor.apply(b);
556}
557
558void 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
567void 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
576void 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
587void 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
598void 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
606void ComplexVisitor::bvisit(const Pow &x)
607{
608 check_power(*x.get_base(), *x.get_exp());
609}
610
611void ComplexVisitor::bvisit(const Log &x)
612{
613 complex_arg_not_zero(x, *x.get_arg());
614}
615
616void ComplexVisitor::bvisit(const Tan &x)
617{
618 complex_arg_not_zero(x, *cos(x.get_arg()));
619}
620
621void 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
634void 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
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
660void ComplexVisitor::bvisit(const ATan &x)
661{
662 complex_arg_not_pm(x, false);
663}
664
665void ComplexVisitor::bvisit(const ATanh &x)
666{
667 complex_arg_not_pm(x, true);
668}
669
670void ComplexVisitor::bvisit(const ACot &x)
671{
672 complex_arg_not_pm(x, false);
673}
674
675void ComplexVisitor::bvisit(const ACoth &x)
676{
677 complex_arg_not_pm(x, true);
678}
679
680void ComplexVisitor::bvisit(const Cot &x)
681{
682 complex_arg_not_zero(x, *sin(x.get_arg()));
683}
684
685void ComplexVisitor::bvisit(const Sec &x)
686{
687 complex_arg_not_zero(x, *cos(x.get_arg()));
688}
689
690void ComplexVisitor::bvisit(const ASec &x)
691{
692 complex_arg_not_zero(x, *x.get_arg());
693}
694
695void ComplexVisitor::bvisit(const ASech &x)
696{
697 complex_arg_not_zero(x, *x.get_arg());
698}
699
700void ComplexVisitor::bvisit(const Csc &x)
701{
702 complex_arg_not_zero(x, *sin(x.get_arg()));
703}
704
705void ComplexVisitor::bvisit(const ACsc &x)
706{
707 complex_arg_not_zero(x, *x.get_arg());
708}
709
710void ComplexVisitor::bvisit(const ACsch &x)
711{
712 complex_arg_not_zero(x, *x.get_arg());
713}
714
715tribool ComplexVisitor::apply(const Basic &b)
716{
717 b.accept(*this);
718 return is_complex_;
719}
720
721tribool is_complex(const Basic &b, const Assumptions *assumptions)
722{
723 ComplexVisitor visitor(assumptions);
724 return visitor.apply(b);
725}
726
727void 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
741void 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
750void 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
759void 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
784void PolynomialVisitor::bvisit(const Pow &x)
785{
786 check_power(*x.get_base(), *x.get_exp());
787}
788
789void 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
806bool PolynomialVisitor::apply(const Basic &b)
807{
808 b.accept(*this);
809 return is_polynomial_;
810}
811
812bool is_polynomial(const Basic &b, const set_basic &variables)
813{
814 PolynomialVisitor visitor(variables);
815 return visitor.apply(b);
816}
817
818void 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
826void 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
837void 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
848tribool 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
858tribool is_rational(const Basic &b)
859{
860 RationalVisitor visitor(true);
861 return visitor.apply(b);
862}
863
864tribool is_irrational(const Basic &b)
865{
866 RationalVisitor visitor(false);
867 return visitor.apply(b);
868}
869
870void FiniteVisitor::error()
871{
872 throw SymEngineException(
873 "Only numeric types allowed for is_finite/is_infinite");
874}
875
876void FiniteVisitor::bvisit(const Basic &x)
877{
878 is_finite_ = tribool::indeterminate;
879}
880
881void 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
890void FiniteVisitor::bvisit(const Number &x)
891{
892 is_finite_ = tribool::tritrue;
893}
894
895void FiniteVisitor::bvisit(const Infty &x)
896{
897 is_finite_ = tribool::trifalse;
898}
899
900void FiniteVisitor::bvisit(const NaN &x)
901{
902 error();
903}
904
905void FiniteVisitor::bvisit(const Set &x)
906{
907 error();
908}
909
910void FiniteVisitor::bvisit(const Relational &x)
911{
912 error();
913}
914
915void FiniteVisitor::bvisit(const Boolean &x)
916{
917 error();
918}
919
920void FiniteVisitor::bvisit(const Constant &x)
921{
922 is_finite_ = tribool::tritrue;
923}
924
925tribool FiniteVisitor::apply(const Basic &b)
926{
927 b.accept(*this);
928 return is_finite_;
929}
930
931tribool is_finite(const Basic &b, const Assumptions *assumptions)
932{
933 FiniteVisitor visitor(assumptions);
934 return visitor.apply(b);
935}
936
937tribool is_infinite(const Basic &b, const Assumptions *assumptions)
938{
939 FiniteVisitor visitor(assumptions);
940 return not_tribool(visitor.apply(b));
941}
942
943tribool is_even(const Basic &b, const Assumptions *assumptions)
944{
945 return is_integer(*div(b.rcp_from_this(), integer(2)), assumptions);
946}
947
948tribool 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
954void AlgebraicVisitor::error()
955{
956 throw SymEngineException(
957 "Only numeric types allowed for is_algebraic/is_transcendental");
958}
959
960void AlgebraicVisitor::bvisit(const Basic &x)
961{
962 is_algebraic_ = tribool::indeterminate;
963}
964
965void AlgebraicVisitor::bvisit(const Set &x)
966{
967 error();
968}
969
970void AlgebraicVisitor::bvisit(const Relational &x)
971{
972 error();
973}
974
975void AlgebraicVisitor::bvisit(const Boolean &x)
976{
977 error();
978}
979
980void 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
1001void 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
1013void 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
1026void AlgebraicVisitor::bvisit(const Integer &x)
1027{
1028 is_algebraic_ = tribool::tritrue;
1029}
1030
1031void AlgebraicVisitor::bvisit(const Rational &x)
1032{
1033 is_algebraic_ = tribool::tritrue;
1034}
1035
1036void 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_nonzero(b)) {
1041 is_algebraic_ = tribool::trifalse;
1042 } else {
1043 is_algebraic_ = tribool::indeterminate;
1044 }
1045}
1046
1047void 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
1053void 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
1059void 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
1065tribool AlgebraicVisitor::apply(const Basic &b)
1066{
1067 b.accept(*this);
1068 return is_algebraic_;
1069}
1070
1071tribool is_algebraic(const Basic &b, const Assumptions *assumptions)
1072{
1073 AlgebraicVisitor visitor(assumptions);
1074 return visitor.apply(b);
1075}
1076
1077tribool 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
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
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
std::enable_if< std::is_integral< T >::value, RCP< constInteger > >::type integer(T i)
Definition: integer.h:200
RCP< const Basic > sin(const RCP< const Basic > &arg)
Canonicalize Sin:
Definition: functions.cpp:874