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::bvisit(const Number &x)
95 {
96  if (is_a_Complex(x)) {
97  is_positive_ = tribool::trifalse;
98  } else if (bool(x.is_positive())) {
99  is_positive_ = tribool::tritrue;
100  } else {
101  is_positive_ = tribool::trifalse;
102  }
103 }
104 
105 tribool PositiveVisitor::apply(const Basic &b)
106 {
107  b.accept(*this);
108  return is_positive_;
109 }
110 
111 tribool is_positive(const Basic &b)
112 {
113  PositiveVisitor visitor;
114  return visitor.apply(b);
115 }
116 
117 void NonPositiveVisitor::bvisit(const Number &x)
118 {
119  if (is_a_Complex(x)) {
120  is_nonpositive_ = tribool::trifalse;
121  } else if (bool(x.is_positive())) {
122  is_nonpositive_ = tribool::trifalse;
123  } else {
124  is_nonpositive_ = tribool::tritrue;
125  }
126 }
127 
128 tribool NonPositiveVisitor::apply(const Basic &b)
129 {
130  b.accept(*this);
131  return is_nonpositive_;
132 }
133 
134 tribool is_nonpositive(const Basic &b)
135 {
136  NonPositiveVisitor visitor;
137  return visitor.apply(b);
138 }
139 
140 void NegativeVisitor::bvisit(const Number &x)
141 {
142  if (is_a_Complex(x)) {
143  is_negative_ = tribool::trifalse;
144  } else if (bool(x.is_negative())) {
145  is_negative_ = tribool::tritrue;
146  } else {
147  is_negative_ = tribool::trifalse;
148  }
149 }
150 
151 tribool NegativeVisitor::apply(const Basic &b)
152 {
153  b.accept(*this);
154  return is_negative_;
155 }
156 
157 tribool is_negative(const Basic &b)
158 {
159  NegativeVisitor visitor;
160  return visitor.apply(b);
161 }
162 
163 void NonNegativeVisitor::bvisit(const Number &x)
164 {
165  if (is_a_Complex(x)) {
166  is_nonnegative_ = tribool::trifalse;
167  } else if (bool(x.is_negative())) {
168  is_nonnegative_ = tribool::trifalse;
169  } else {
170  is_nonnegative_ = tribool::tritrue;
171  }
172 }
173 
174 tribool NonNegativeVisitor::apply(const Basic &b)
175 {
176  b.accept(*this);
177  return is_nonnegative_;
178 }
179 
180 tribool is_nonnegative(const Basic &b)
181 {
182  NonNegativeVisitor visitor;
183  return visitor.apply(b);
184 }
185 
186 void IntegerVisitor::bvisit(const Symbol &x)
187 {
188  if (assumptions_) {
189  is_integer_ = assumptions_->is_integer(x.rcp_from_this());
190  } else {
191  is_integer_ = tribool::indeterminate;
192  }
193 }
194 
195 void IntegerVisitor::bvisit(const Constant &x)
196 {
197  if (eq(x, *pi) or eq(x, *E) or eq(x, *EulerGamma) or eq(x, *Catalan)
198  or eq(x, *GoldenRatio)) {
199  is_integer_ = tribool::trifalse;
200  } else {
201  is_integer_ = tribool::indeterminate;
202  }
203 }
204 
205 void IntegerVisitor::bvisit(const Add &x)
206 {
207  for (const auto &arg : x.get_args()) {
208  arg->accept(*this);
209  if (not is_true(is_integer_)) {
210  is_integer_ = tribool::indeterminate;
211  return;
212  }
213  }
214 }
215 
216 void IntegerVisitor::bvisit(const Mul &x)
217 {
218  for (const auto &arg : x.get_args()) {
219  arg->accept(*this);
220  if (not is_true(is_integer_)) {
221  is_integer_ = tribool::indeterminate;
222  return;
223  }
224  }
225 }
226 
227 tribool IntegerVisitor::apply(const Basic &b)
228 {
229  b.accept(*this);
230  return is_integer_;
231 }
232 
233 tribool is_integer(const Basic &b, const Assumptions *assumptions)
234 {
235  IntegerVisitor visitor(assumptions);
236  return visitor.apply(b);
237 }
238 
239 void RealVisitor::bvisit(const Symbol &x)
240 {
241  if (assumptions_) {
242  is_real_ = assumptions_->is_real(x.rcp_from_this());
243  } else {
244  is_real_ = tribool::indeterminate;
245  }
246 }
247 
248 void RealVisitor::bvisit(const Number &x)
249 {
250  if (is_a_Complex(x) or is_a<Infty>(x) or is_a<NaN>(x)) {
251  is_real_ = tribool::trifalse;
252  } else {
253  is_real_ = tribool::tritrue;
254  }
255 }
256 
257 void RealVisitor::bvisit(const Constant &x)
258 {
259  if (eq(x, *pi) or eq(x, *E) or eq(x, *EulerGamma) or eq(x, *Catalan)
260  or eq(x, *GoldenRatio)) {
261  is_real_ = tribool::tritrue;
262  } else {
263  is_real_ = tribool::indeterminate;
264  }
265 }
266 
267 void RealVisitor::bvisit(const Add &x)
268 {
269  tribool b = tribool::tritrue;
270  for (const auto &arg : x.get_args()) {
271  arg->accept(*this);
272  b = andwk_tribool(b, is_real_);
273  if (is_indeterminate(b))
274  return;
275  }
276 }
277 
278 tribool RealVisitor::apply(const Basic &b)
279 {
280  b.accept(*this);
281  return is_real_;
282 }
283 
284 tribool is_real(const Basic &b, const Assumptions *assumptions)
285 {
286  RealVisitor visitor(assumptions);
287  return visitor.apply(b);
288 }
289 
290 void ComplexVisitor::bvisit(const Symbol &x)
291 {
292  if (assumptions_) {
293  is_complex_ = assumptions_->is_complex(x.rcp_from_this());
294  } else {
295  is_complex_ = tribool::indeterminate;
296  }
297 }
298 
299 void ComplexVisitor::bvisit(const Number &x)
300 {
301  if (is_a<Infty>(x) or is_a<NaN>(x)) {
302  is_complex_ = tribool::trifalse;
303  } else {
304  is_complex_ = tribool::tritrue;
305  }
306 }
307 
308 void ComplexVisitor::bvisit(const Add &x)
309 {
310  tribool b = tribool::tritrue;
311  for (const auto &arg : x.get_args()) {
312  arg->accept(*this);
313  b = andwk_tribool(b, is_complex_);
314  if (is_indeterminate(b) or is_false(b))
315  return;
316  }
317 }
318 
319 void ComplexVisitor::bvisit(const Mul &x)
320 {
321  tribool b = tribool::tritrue;
322  for (const auto &p : x.get_dict()) {
323  this->check_power(*p.first, *p.second);
324  b = andwk_tribool(b, is_complex_);
325  if (is_indeterminate(b) or is_false(b))
326  return;
327  }
328 }
329 
330 void ComplexVisitor::check_power(const Basic &base, const Basic &exp)
331 {
332  base.accept(*this);
333  if (is_true(is_complex_)) {
334  exp.accept(*this);
335  }
336 }
337 
338 void ComplexVisitor::bvisit(const Pow &x)
339 {
340  check_power(*x.get_base(), *x.get_exp());
341 }
342 
343 void ComplexVisitor::bvisit(const Log &x)
344 {
345  complex_arg_not_zero(x, *x.get_arg());
346 }
347 
348 void ComplexVisitor::bvisit(const Tan &x)
349 {
350  complex_arg_not_zero(x, *cos(x.get_arg()));
351 }
352 
353 void ComplexVisitor::complex_arg_not_zero(const OneArgFunction &x,
354  const Basic &not_zero)
355 {
356  // Check if function argument is complex and then if 'not_zero' is not zero
357  x.get_arg()->accept(*this);
358  if (is_true(is_complex_)) {
359  tribool zero = is_zero(not_zero);
360  if (not is_false(zero)) {
361  is_complex_ = not_tribool(zero);
362  }
363  }
364 }
365 
366 void ComplexVisitor::complex_arg_not_pm(const OneArgFunction &x, bool one)
367 {
368  // Check if function argument is complex but not plus/minus 1 (one=True) or
369  // i (one=False)
370  x.get_arg()->accept(*this);
371  if (not is_true(is_complex_))
372  return;
373  RCP<const Number> i1;
374  if (one)
375  i1 = integer(1);
376  else
377  i1 = Complex::from_two_nums(*integer(0), *integer(1));
378  tribool zi1 = is_zero(*sub(x.get_arg(), i1));
379  if (not is_false(zi1)) {
380  is_complex_ = not_tribool(zi1);
381  return;
382  }
383  RCP<const Number> mi1;
384  if (one)
385  mi1 = integer(-1);
386  else
387  mi1 = Complex::from_two_nums(*integer(0), *integer(-1));
388  tribool zmi1 = is_zero(*sub(x.get_arg(), mi1));
389  is_complex_ = not_tribool(zmi1);
390 }
391 
392 void ComplexVisitor::bvisit(const ATan &x)
393 {
394  complex_arg_not_pm(x, false);
395 }
396 
397 void ComplexVisitor::bvisit(const ATanh &x)
398 {
399  complex_arg_not_pm(x, true);
400 }
401 
402 void ComplexVisitor::bvisit(const ACot &x)
403 {
404  complex_arg_not_pm(x, false);
405 }
406 
407 void ComplexVisitor::bvisit(const ACoth &x)
408 {
409  complex_arg_not_pm(x, true);
410 }
411 
412 void ComplexVisitor::bvisit(const Cot &x)
413 {
414  complex_arg_not_zero(x, *sin(x.get_arg()));
415 }
416 
417 void ComplexVisitor::bvisit(const Sec &x)
418 {
419  complex_arg_not_zero(x, *cos(x.get_arg()));
420 }
421 
422 void ComplexVisitor::bvisit(const ASec &x)
423 {
424  complex_arg_not_zero(x, *x.get_arg());
425 }
426 
427 void ComplexVisitor::bvisit(const ASech &x)
428 {
429  complex_arg_not_zero(x, *x.get_arg());
430 }
431 
432 void ComplexVisitor::bvisit(const Csc &x)
433 {
434  complex_arg_not_zero(x, *sin(x.get_arg()));
435 }
436 
437 void ComplexVisitor::bvisit(const ACsc &x)
438 {
439  complex_arg_not_zero(x, *x.get_arg());
440 }
441 
442 void ComplexVisitor::bvisit(const ACsch &x)
443 {
444  complex_arg_not_zero(x, *x.get_arg());
445 }
446 
447 tribool ComplexVisitor::apply(const Basic &b)
448 {
449  b.accept(*this);
450  return is_complex_;
451 }
452 
453 tribool is_complex(const Basic &b, const Assumptions *assumptions)
454 {
455  ComplexVisitor visitor(assumptions);
456  return visitor.apply(b);
457 }
458 
459 void PolynomialVisitor::bvisit(const Basic &x)
460 {
461  auto old_allowed = variables_allowed_;
462  variables_allowed_ = false;
463  for (const auto &p : x.get_args()) {
464  p->accept(*this);
465  if (!is_polynomial_) {
466  variables_allowed_ = old_allowed;
467  return;
468  }
469  }
470  variables_allowed_ = old_allowed;
471 }
472 
473 void PolynomialVisitor::bvisit(const Add &x)
474 {
475  for (const auto &arg : x.get_args()) {
476  arg->accept(*this);
477  if (!is_polynomial_)
478  return;
479  }
480 }
481 
482 void PolynomialVisitor::bvisit(const Mul &x)
483 {
484  for (const auto &p : x.get_dict()) {
485  this->check_power(*p.first, *p.second);
486  if (!is_polynomial_)
487  return;
488  }
489 }
490 
491 void PolynomialVisitor::check_power(const Basic &base, const Basic &exp)
492 {
493  if (variables_allowed_) {
494  variables_allowed_ = false;
495  exp.accept(*this);
496  if (!is_polynomial_) {
497  variables_allowed_ = true;
498  return;
499  }
500  base.accept(*this);
501  variables_allowed_ = true;
502  if (!is_polynomial_) {
503  is_polynomial_ = true;
504  base.accept(*this);
505  is_polynomial_ = is_polynomial_ and is_a<Integer>(exp)
506  and down_cast<const Integer &>(exp).is_positive();
507  }
508  } else {
509  base.accept(*this);
510  if (!is_polynomial_)
511  return;
512  exp.accept(*this);
513  }
514 }
515 
516 void PolynomialVisitor::bvisit(const Pow &x)
517 {
518  check_power(*x.get_base(), *x.get_exp());
519 }
520 
521 void PolynomialVisitor::bvisit(const Symbol &x)
522 {
523  if (variables_allowed_)
524  return;
525 
526  if (variables_.empty()) { // All symbols are variables
527  is_polynomial_ = false;
528  } else {
529  for (const auto &elem : variables_) {
530  if (x.__eq__(*elem)) {
531  is_polynomial_ = false;
532  return;
533  }
534  }
535  }
536 }
537 
538 bool PolynomialVisitor::apply(const Basic &b)
539 {
540  b.accept(*this);
541  return is_polynomial_;
542 }
543 
544 bool is_polynomial(const Basic &b, const set_basic &variables)
545 {
546  PolynomialVisitor visitor(variables);
547  return visitor.apply(b);
548 }
549 
550 void RationalVisitor::bvisit(const Number &x)
551 {
552  is_rational_ = tribool::trifalse;
553  if (is_a_Complex(x) or is_a<Infty>(x) or is_a<NaN>(x)) {
554  neither_ = true;
555  }
556 }
557 
558 void RationalVisitor::bvisit(const Constant &x)
559 {
560  if (eq(x, *pi) or eq(x, *E) or eq(x, *GoldenRatio)) {
561  // It is currently (2021) not known whether Catalan's constant
562  // or Euler's constant are rational or irrational
563  is_rational_ = tribool::trifalse;
564  } else {
565  is_rational_ = tribool::indeterminate;
566  }
567 }
568 
569 void RationalVisitor::bvisit(const Add &x)
570 {
571  tribool b = tribool::tritrue;
572  for (const auto &arg : x.get_args()) {
573  arg->accept(*this);
574  b = andwk_tribool(b, is_rational_);
575  if (is_indeterminate(b))
576  return;
577  }
578 }
579 
580 tribool RationalVisitor::apply(const Basic &b)
581 {
582  b.accept(*this);
583  tribool result = is_rational_;
584  if (not rational_ and not neither_) {
585  result = not_tribool(result);
586  }
587  return result;
588 }
589 
590 tribool is_rational(const Basic &b)
591 {
592  RationalVisitor visitor(true);
593  return visitor.apply(b);
594 }
595 
596 tribool is_irrational(const Basic &b)
597 {
598  RationalVisitor visitor(false);
599  return visitor.apply(b);
600 }
601 } // 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