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 tribool PositiveVisitor::apply(const Basic &b)
145 {
146  b.accept(*this);
147  return is_positive_;
148 }
149 
150 tribool is_positive(const Basic &b, const Assumptions *assumptions)
151 {
152  PositiveVisitor visitor(assumptions);
153  return visitor.apply(b);
154 }
155 
156 void NonPositiveVisitor::error()
157 {
158  throw SymEngineException("Only numeric types allowed for is_negative");
159 }
160 
161 void NonPositiveVisitor::bvisit(const Constant &x)
162 {
163  is_nonpositive_ = tribool::trifalse;
164 }
165 
166 void NonPositiveVisitor::bvisit(const Basic &x)
167 {
168  is_nonpositive_ = tribool::indeterminate;
169 }
170 
171 void NonPositiveVisitor::bvisit(const Set &x)
172 {
173  error();
174 }
175 
176 void NonPositiveVisitor::bvisit(const Relational &x)
177 {
178  error();
179 }
180 
181 void NonPositiveVisitor::bvisit(const Boolean &x)
182 {
183  error();
184 }
185 
186 void NonPositiveVisitor::bvisit(const Symbol &x)
187 {
188  if (assumptions_) {
189  is_nonpositive_ = assumptions_->is_nonpositive(x.rcp_from_this());
190  } else {
191  is_nonpositive_ = tribool::indeterminate;
192  }
193 }
194 
195 void NonPositiveVisitor::bvisit(const Number &x)
196 {
197  if (is_a_Complex(x)) {
198  is_nonpositive_ = tribool::trifalse;
199  } else if (bool(x.is_positive())) {
200  is_nonpositive_ = tribool::trifalse;
201  } else {
202  is_nonpositive_ = tribool::tritrue;
203  }
204 }
205 
206 tribool NonPositiveVisitor::apply(const Basic &b)
207 {
208  b.accept(*this);
209  return is_nonpositive_;
210 }
211 
212 tribool is_nonpositive(const Basic &b, const Assumptions *assumptions)
213 {
214  NonPositiveVisitor visitor(assumptions);
215  return visitor.apply(b);
216 }
217 
218 void NegativeVisitor::error()
219 {
220  throw SymEngineException("Only numeric types allowed for is_negative");
221 }
222 
223 void NegativeVisitor::bvisit(const Basic &x)
224 {
225  is_negative_ = tribool::indeterminate;
226 }
227 
228 void NegativeVisitor::bvisit(const Set &x)
229 {
230  error();
231 }
232 
233 void NegativeVisitor::bvisit(const Relational &x)
234 {
235  error();
236 }
237 
238 void NegativeVisitor::bvisit(const Boolean &x)
239 {
240  error();
241 }
242 
243 void NegativeVisitor::bvisit(const Constant &x)
244 {
245  is_negative_ = tribool::trifalse;
246 }
247 
248 void NegativeVisitor::bvisit(const Symbol &x)
249 {
250  if (assumptions_) {
251  is_negative_ = assumptions_->is_negative(x.rcp_from_this());
252  } else {
253  is_negative_ = tribool::indeterminate;
254  }
255 }
256 
257 void NegativeVisitor::bvisit(const Number &x)
258 {
259  if (is_a_Complex(x)) {
260  is_negative_ = tribool::trifalse;
261  } else if (bool(x.is_negative())) {
262  is_negative_ = tribool::tritrue;
263  } else {
264  is_negative_ = tribool::trifalse;
265  }
266 }
267 
268 tribool NegativeVisitor::apply(const Basic &b)
269 {
270  b.accept(*this);
271  return is_negative_;
272 }
273 
274 tribool is_negative(const Basic &b, const Assumptions *assumptions)
275 {
276  NegativeVisitor visitor(assumptions);
277  return visitor.apply(b);
278 }
279 
280 void NonNegativeVisitor::error()
281 {
282  throw SymEngineException("Only numeric types allowed for is_nonnegative");
283 }
284 
285 void NonNegativeVisitor::bvisit(const Basic &x)
286 {
287  is_nonnegative_ = tribool::indeterminate;
288 }
289 
290 void NonNegativeVisitor::bvisit(const Set &x)
291 {
292  error();
293 }
294 
295 void NonNegativeVisitor::bvisit(const Relational &x)
296 {
297  error();
298 }
299 
300 void NonNegativeVisitor::bvisit(const Boolean &x)
301 {
302  error();
303 }
304 
305 void NonNegativeVisitor::bvisit(const Constant &x)
306 {
307  is_nonnegative_ = tribool::tritrue;
308 }
309 
310 void NonNegativeVisitor::bvisit(const Symbol &x)
311 {
312  if (assumptions_) {
313  is_nonnegative_ = assumptions_->is_nonnegative(x.rcp_from_this());
314  } else {
315  is_nonnegative_ = tribool::indeterminate;
316  }
317 }
318 
319 void NonNegativeVisitor::bvisit(const Number &x)
320 {
321  if (is_a_Complex(x)) {
322  is_nonnegative_ = tribool::trifalse;
323  } else if (bool(x.is_negative())) {
324  is_nonnegative_ = tribool::trifalse;
325  } else {
326  is_nonnegative_ = tribool::tritrue;
327  }
328 }
329 
330 tribool NonNegativeVisitor::apply(const Basic &b)
331 {
332  b.accept(*this);
333  return is_nonnegative_;
334 }
335 
336 tribool is_nonnegative(const Basic &b, const Assumptions *assumptions)
337 {
338  NonNegativeVisitor visitor(assumptions);
339  return visitor.apply(b);
340 }
341 
342 void IntegerVisitor::bvisit(const Symbol &x)
343 {
344  if (assumptions_) {
345  is_integer_ = assumptions_->is_integer(x.rcp_from_this());
346  } else {
347  is_integer_ = tribool::indeterminate;
348  }
349 }
350 
351 void IntegerVisitor::bvisit(const Constant &x)
352 {
353  if (eq(x, *pi) or eq(x, *E) or eq(x, *EulerGamma) or eq(x, *Catalan)
354  or eq(x, *GoldenRatio)) {
355  is_integer_ = tribool::trifalse;
356  } else {
357  is_integer_ = tribool::indeterminate;
358  }
359 }
360 
361 void IntegerVisitor::bvisit(const Add &x)
362 {
363  for (const auto &arg : x.get_args()) {
364  arg->accept(*this);
365  if (not is_true(is_integer_)) {
366  is_integer_ = tribool::indeterminate;
367  return;
368  }
369  }
370 }
371 
372 void IntegerVisitor::bvisit(const Mul &x)
373 {
374  for (const auto &arg : x.get_args()) {
375  arg->accept(*this);
376  if (not is_true(is_integer_)) {
377  is_integer_ = tribool::indeterminate;
378  return;
379  }
380  }
381 }
382 
383 tribool IntegerVisitor::apply(const Basic &b)
384 {
385  b.accept(*this);
386  return is_integer_;
387 }
388 
389 tribool is_integer(const Basic &b, const Assumptions *assumptions)
390 {
391  IntegerVisitor visitor(assumptions);
392  return visitor.apply(b);
393 }
394 
395 void RealVisitor::bvisit(const Symbol &x)
396 {
397  if (assumptions_) {
398  is_real_ = assumptions_->is_real(x.rcp_from_this());
399  } else {
400  is_real_ = tribool::indeterminate;
401  }
402 }
403 
404 void RealVisitor::bvisit(const Number &x)
405 {
406  if (is_a_Complex(x) or is_a<Infty>(x) or is_a<NaN>(x)) {
407  is_real_ = tribool::trifalse;
408  } else {
409  is_real_ = tribool::tritrue;
410  }
411 }
412 
413 void RealVisitor::bvisit(const Constant &x)
414 {
415  if (eq(x, *pi) or eq(x, *E) or eq(x, *EulerGamma) or eq(x, *Catalan)
416  or eq(x, *GoldenRatio)) {
417  is_real_ = tribool::tritrue;
418  } else {
419  is_real_ = tribool::indeterminate;
420  }
421 }
422 
423 void RealVisitor::bvisit(const Add &x)
424 {
425  tribool b = tribool::tritrue;
426  for (const auto &arg : x.get_args()) {
427  arg->accept(*this);
428  b = andwk_tribool(b, is_real_);
429  if (is_indeterminate(b))
430  return;
431  }
432 }
433 
434 tribool RealVisitor::apply(const Basic &b)
435 {
436  b.accept(*this);
437  return is_real_;
438 }
439 
440 tribool is_real(const Basic &b, const Assumptions *assumptions)
441 {
442  RealVisitor visitor(assumptions);
443  return visitor.apply(b);
444 }
445 
446 void ComplexVisitor::bvisit(const Symbol &x)
447 {
448  if (assumptions_) {
449  is_complex_ = assumptions_->is_complex(x.rcp_from_this());
450  } else {
451  is_complex_ = tribool::indeterminate;
452  }
453 }
454 
455 void ComplexVisitor::bvisit(const Number &x)
456 {
457  if (is_a<Infty>(x) or is_a<NaN>(x)) {
458  is_complex_ = tribool::trifalse;
459  } else {
460  is_complex_ = tribool::tritrue;
461  }
462 }
463 
464 void ComplexVisitor::bvisit(const Add &x)
465 {
466  tribool b = tribool::tritrue;
467  for (const auto &arg : x.get_args()) {
468  arg->accept(*this);
469  b = andwk_tribool(b, is_complex_);
470  if (is_indeterminate(b) or is_false(b))
471  return;
472  }
473 }
474 
475 void ComplexVisitor::bvisit(const Mul &x)
476 {
477  tribool b = tribool::tritrue;
478  for (const auto &p : x.get_dict()) {
479  this->check_power(*p.first, *p.second);
480  b = andwk_tribool(b, is_complex_);
481  if (is_indeterminate(b) or is_false(b))
482  return;
483  }
484 }
485 
486 void ComplexVisitor::check_power(const Basic &base, const Basic &exp)
487 {
488  base.accept(*this);
489  if (is_true(is_complex_)) {
490  exp.accept(*this);
491  }
492 }
493 
494 void ComplexVisitor::bvisit(const Pow &x)
495 {
496  check_power(*x.get_base(), *x.get_exp());
497 }
498 
499 void ComplexVisitor::bvisit(const Log &x)
500 {
501  complex_arg_not_zero(x, *x.get_arg());
502 }
503 
504 void ComplexVisitor::bvisit(const Tan &x)
505 {
506  complex_arg_not_zero(x, *cos(x.get_arg()));
507 }
508 
509 void ComplexVisitor::complex_arg_not_zero(const OneArgFunction &x,
510  const Basic &not_zero)
511 {
512  // Check if function argument is complex and then if 'not_zero' is not zero
513  x.get_arg()->accept(*this);
514  if (is_true(is_complex_)) {
515  tribool zero = is_zero(not_zero);
516  if (not is_false(zero)) {
517  is_complex_ = not_tribool(zero);
518  }
519  }
520 }
521 
522 void ComplexVisitor::complex_arg_not_pm(const OneArgFunction &x, bool one)
523 {
524  // Check if function argument is complex but not plus/minus 1 (one=True) or
525  // i (one=False)
526  x.get_arg()->accept(*this);
527  if (not is_true(is_complex_))
528  return;
529  RCP<const Number> i1;
530  if (one)
531  i1 = integer(1);
532  else
533  i1 = Complex::from_two_nums(*integer(0), *integer(1));
534  tribool zi1 = is_zero(*sub(x.get_arg(), i1));
535  if (not is_false(zi1)) {
536  is_complex_ = not_tribool(zi1);
537  return;
538  }
539  RCP<const Number> mi1;
540  if (one)
541  mi1 = integer(-1);
542  else
543  mi1 = Complex::from_two_nums(*integer(0), *integer(-1));
544  tribool zmi1 = is_zero(*sub(x.get_arg(), mi1));
545  is_complex_ = not_tribool(zmi1);
546 }
547 
548 void ComplexVisitor::bvisit(const ATan &x)
549 {
550  complex_arg_not_pm(x, false);
551 }
552 
553 void ComplexVisitor::bvisit(const ATanh &x)
554 {
555  complex_arg_not_pm(x, true);
556 }
557 
558 void ComplexVisitor::bvisit(const ACot &x)
559 {
560  complex_arg_not_pm(x, false);
561 }
562 
563 void ComplexVisitor::bvisit(const ACoth &x)
564 {
565  complex_arg_not_pm(x, true);
566 }
567 
568 void ComplexVisitor::bvisit(const Cot &x)
569 {
570  complex_arg_not_zero(x, *sin(x.get_arg()));
571 }
572 
573 void ComplexVisitor::bvisit(const Sec &x)
574 {
575  complex_arg_not_zero(x, *cos(x.get_arg()));
576 }
577 
578 void ComplexVisitor::bvisit(const ASec &x)
579 {
580  complex_arg_not_zero(x, *x.get_arg());
581 }
582 
583 void ComplexVisitor::bvisit(const ASech &x)
584 {
585  complex_arg_not_zero(x, *x.get_arg());
586 }
587 
588 void ComplexVisitor::bvisit(const Csc &x)
589 {
590  complex_arg_not_zero(x, *sin(x.get_arg()));
591 }
592 
593 void ComplexVisitor::bvisit(const ACsc &x)
594 {
595  complex_arg_not_zero(x, *x.get_arg());
596 }
597 
598 void ComplexVisitor::bvisit(const ACsch &x)
599 {
600  complex_arg_not_zero(x, *x.get_arg());
601 }
602 
603 tribool ComplexVisitor::apply(const Basic &b)
604 {
605  b.accept(*this);
606  return is_complex_;
607 }
608 
609 tribool is_complex(const Basic &b, const Assumptions *assumptions)
610 {
611  ComplexVisitor visitor(assumptions);
612  return visitor.apply(b);
613 }
614 
615 void PolynomialVisitor::bvisit(const Basic &x)
616 {
617  auto old_allowed = variables_allowed_;
618  variables_allowed_ = false;
619  for (const auto &p : x.get_args()) {
620  p->accept(*this);
621  if (!is_polynomial_) {
622  variables_allowed_ = old_allowed;
623  return;
624  }
625  }
626  variables_allowed_ = old_allowed;
627 }
628 
629 void PolynomialVisitor::bvisit(const Add &x)
630 {
631  for (const auto &arg : x.get_args()) {
632  arg->accept(*this);
633  if (!is_polynomial_)
634  return;
635  }
636 }
637 
638 void PolynomialVisitor::bvisit(const Mul &x)
639 {
640  for (const auto &p : x.get_dict()) {
641  this->check_power(*p.first, *p.second);
642  if (!is_polynomial_)
643  return;
644  }
645 }
646 
647 void PolynomialVisitor::check_power(const Basic &base, const Basic &exp)
648 {
649  if (variables_allowed_) {
650  variables_allowed_ = false;
651  exp.accept(*this);
652  if (!is_polynomial_) {
653  variables_allowed_ = true;
654  return;
655  }
656  base.accept(*this);
657  variables_allowed_ = true;
658  if (!is_polynomial_) {
659  is_polynomial_ = true;
660  base.accept(*this);
661  is_polynomial_ = is_polynomial_ and is_a<Integer>(exp)
662  and down_cast<const Integer &>(exp).is_positive();
663  }
664  } else {
665  base.accept(*this);
666  if (!is_polynomial_)
667  return;
668  exp.accept(*this);
669  }
670 }
671 
672 void PolynomialVisitor::bvisit(const Pow &x)
673 {
674  check_power(*x.get_base(), *x.get_exp());
675 }
676 
677 void PolynomialVisitor::bvisit(const Symbol &x)
678 {
679  if (variables_allowed_)
680  return;
681 
682  if (variables_.empty()) { // All symbols are variables
683  is_polynomial_ = false;
684  } else {
685  for (const auto &elem : variables_) {
686  if (x.__eq__(*elem)) {
687  is_polynomial_ = false;
688  return;
689  }
690  }
691  }
692 }
693 
694 bool PolynomialVisitor::apply(const Basic &b)
695 {
696  b.accept(*this);
697  return is_polynomial_;
698 }
699 
700 bool is_polynomial(const Basic &b, const set_basic &variables)
701 {
702  PolynomialVisitor visitor(variables);
703  return visitor.apply(b);
704 }
705 
706 void RationalVisitor::bvisit(const Number &x)
707 {
708  is_rational_ = tribool::trifalse;
709  if (is_a_Complex(x) or is_a<Infty>(x) or is_a<NaN>(x)) {
710  neither_ = true;
711  }
712 }
713 
714 void RationalVisitor::bvisit(const Constant &x)
715 {
716  if (eq(x, *pi) or eq(x, *E) or eq(x, *GoldenRatio)) {
717  // It is currently (2021) not known whether Catalan's constant
718  // or Euler's constant are rational or irrational
719  is_rational_ = tribool::trifalse;
720  } else {
721  is_rational_ = tribool::indeterminate;
722  }
723 }
724 
725 void RationalVisitor::bvisit(const Add &x)
726 {
727  tribool b = tribool::tritrue;
728  for (const auto &arg : x.get_args()) {
729  arg->accept(*this);
730  b = andwk_tribool(b, is_rational_);
731  if (is_indeterminate(b))
732  return;
733  }
734 }
735 
736 tribool RationalVisitor::apply(const Basic &b)
737 {
738  b.accept(*this);
739  tribool result = is_rational_;
740  if (not rational_ and not neither_) {
741  result = not_tribool(result);
742  }
743  return result;
744 }
745 
746 tribool is_rational(const Basic &b)
747 {
748  RationalVisitor visitor(true);
749  return visitor.apply(b);
750 }
751 
752 tribool is_irrational(const Basic &b)
753 {
754  RationalVisitor visitor(false);
755  return visitor.apply(b);
756 }
757 } // 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
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:899
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:831