logic.cpp
1 #include <symengine/logic.h>
2 
3 namespace SymEngine
4 {
5 
6 RCP<const Boolean> Boolean::logical_not() const
7 {
8  return make_rcp<const Not>(this->rcp_from_this_cast<const Boolean>());
9 }
10 
11 BooleanAtom::BooleanAtom(bool b)
12  : b_{b} {SYMENGINE_ASSIGN_TYPEID()}
13 
14  hash_t BooleanAtom::__hash__() const
15 {
16  hash_t seed = SYMENGINE_BOOLEAN_ATOM;
17  if (b_)
18  ++seed;
19  return seed;
20 }
21 bool BooleanAtom::get_val() const
22 {
23  return b_;
24 }
25 
26 vec_basic BooleanAtom::get_args() const
27 {
28  return {};
29 }
30 
31 bool BooleanAtom::__eq__(const Basic &o) const
32 {
33  return is_a<BooleanAtom>(o)
34  and get_val() == down_cast<const BooleanAtom &>(o).get_val();
35 }
36 
37 int BooleanAtom::compare(const Basic &o) const
38 {
39  SYMENGINE_ASSERT(is_a<BooleanAtom>(o))
40  bool ob = down_cast<const BooleanAtom &>(o).get_val();
41  if (get_val()) {
42  return (ob) ? 0 : 1;
43  } else {
44  return (ob) ? -1 : 0;
45  }
46 }
47 
48 RCP<const Boolean> BooleanAtom::logical_not() const
49 {
50  return boolean(not this->get_val());
51 }
52 
53 #define DEFINE_CONST_BOOL(n, v) \
54  RCP<const BooleanAtom> n = []() { \
55  static const RCP<const BooleanAtom> c = make_rcp<BooleanAtom>(v); \
56  return c; \
57  }()
58 
59 DEFINE_CONST_BOOL(boolTrue, true);
60 DEFINE_CONST_BOOL(boolFalse, false);
61 
62 #undef DEFINE_CONST_BOOL
63 
64 Contains::Contains(const RCP<const Basic> &expr, const RCP<const Set> &set)
65  : expr_{expr}, set_{set} {SYMENGINE_ASSIGN_TYPEID()}
66 
67  hash_t Contains::__hash__() const
68 {
69  hash_t seed = SYMENGINE_CONTAINS;
70  hash_combine<Basic>(seed, *expr_);
71  hash_combine<Basic>(seed, *set_);
72  return seed;
73 }
74 
75 RCP<const Basic> Contains::get_expr() const
76 {
77  return expr_;
78 }
79 
80 RCP<const Set> Contains::get_set() const
81 {
82  return set_;
83 }
84 
86 {
87  vec_basic v;
88  v.push_back(expr_);
89  v.push_back(set_);
90  return v;
91 }
92 
93 bool Contains::__eq__(const Basic &o) const
94 {
95  return is_a<Contains>(o)
96  and unified_eq(get_expr(), down_cast<const Contains &>(o).get_expr())
97  and unified_eq(get_set(), down_cast<const Contains &>(o).get_set());
98 }
99 
100 int Contains::compare(const Basic &o) const
101 {
102  SYMENGINE_ASSERT(is_a<Contains>(o))
103  const Contains &c = down_cast<const Contains &>(o);
104  int cmp = unified_compare(get_expr(), c.get_expr());
105  if (cmp != 0)
106  return cmp;
107  return unified_compare(get_set(), c.get_set());
108 }
109 
110 RCP<const Basic> Contains::create(const RCP<const Basic> &lhs,
111  const RCP<const Set> &rhs) const
112 {
113  return contains(lhs, rhs);
114 }
115 
116 RCP<const Boolean> contains(const RCP<const Basic> &expr,
117  const RCP<const Set> &set)
118 {
119  if (is_a_Number(*expr) or is_a_Set(*expr)) {
120  return set->contains(expr);
121  } else {
122  return make_rcp<Contains>(expr, set);
123  }
124 }
125 
126 RCP<const Basic> piecewise(const PiecewiseVec &vec)
127 {
128  PiecewiseVec new_vec;
129  set_boolean conditions;
130  for (auto &p : vec) {
131  if (eq(*p.second, *boolFalse)) {
132  continue;
133  } else if (eq(*p.second, *boolTrue)) {
134  new_vec.push_back(p);
135  conditions.insert(p.second);
136  break;
137  } else if (conditions.find(p.second) == conditions.end()) {
138  new_vec.push_back(p);
139  conditions.insert(p.second);
140  }
141  }
142  if (new_vec.size() == 0) {
143  throw DomainError("piecewise undefined for this domain.");
144  } else if (new_vec.size() == 1 and eq(*new_vec[0].second, *boolTrue)) {
145  return new_vec[0].first;
146  }
147  return make_rcp<Piecewise>(std::move(new_vec));
148 }
149 
151 {
152  SYMENGINE_ASSIGN_TYPEID()
153  SYMENGINE_ASSERT(is_canonical(vec_));
154 }
155 
156 bool Piecewise::is_canonical(const PiecewiseVec &vec)
157 {
158  set_boolean conditions;
159  bool found_true = false;
160  for (auto &p : vec) {
161  if (found_true) {
162  return false;
163  }
164  if (eq(*p.second, *boolFalse)) {
165  return false;
166  } else if (eq(*p.second, *boolTrue)) {
167  found_true = true;
168  } else if (conditions.find(p.second) == conditions.end()) {
169  conditions.insert(p.second);
170  } else {
171  return false;
172  }
173  }
174  if (vec.size() == 0) {
175  return false;
176  } else if (vec.size() == 1 and eq(*vec[0].second, *boolTrue)) {
177  return false;
178  }
179  return true;
180 }
181 
182 hash_t Piecewise::__hash__() const
183 {
184  hash_t seed = this->get_type_code();
185  for (auto &p : vec_) {
186  hash_combine<Basic>(seed, *p.first);
187  hash_combine<Basic>(seed, *p.second);
188  }
189  return seed;
190 }
191 
192 const PiecewiseVec &Piecewise::get_vec() const
193 {
194  return vec_;
195 }
196 
198 {
199  vec_basic v;
200  for (auto &p : vec_) {
201  v.push_back(p.first);
202  v.push_back(p.second);
203  }
204  return v;
205 }
206 
207 bool Piecewise::__eq__(const Basic &o) const
208 {
209  return is_a<Piecewise>(o)
210  and unified_eq(get_vec(), down_cast<const Piecewise &>(o).get_vec());
211 }
212 
213 int Piecewise::compare(const Basic &o) const
214 {
215  SYMENGINE_ASSERT(is_same_type(*this, o))
216  RCP<const Piecewise> t = o.rcp_from_this_cast<Piecewise>();
217  return unified_compare(get_vec(), t->get_vec());
218 }
219 
220 And::And(const set_boolean &s) : container_{s}
221 {
222  SYMENGINE_ASSIGN_TYPEID()
223  SYMENGINE_ASSERT(is_canonical(s));
224 }
225 
226 hash_t And::__hash__() const
227 {
228  hash_t seed = SYMENGINE_AND;
229  for (const auto &a : container_)
230  hash_combine<Basic>(seed, *a);
231  return seed;
232 }
233 
235 {
236  vec_basic v(container_.begin(), container_.end());
237  return v;
238 }
239 
240 bool And::__eq__(const Basic &o) const
241 {
242  return is_a<And>(o)
243  and unified_eq(container_,
244  down_cast<const And &>(o).get_container());
245 }
246 
247 int And::compare(const Basic &o) const
248 {
249  SYMENGINE_ASSERT(is_a<And>(o))
250  return unified_compare(container_,
251  down_cast<const And &>(o).get_container());
252 }
253 
254 bool And::is_canonical(const set_boolean &container_)
255 {
256  if (container_.size() >= 2) {
257  for (auto &a : container_) {
258  if (is_a<BooleanAtom>(*a) or is_a<And>(*a))
259  return false;
260  if (container_.find(SymEngine::logical_not(a)) != container_.end())
261  return false;
262  }
263  return true;
264  }
265  return false;
266 }
267 
268 const set_boolean &And::get_container() const
269 {
270  return container_;
271 }
272 
273 RCP<const Basic> And::create(const set_boolean &a) const
274 {
275  return logical_and(a);
276 }
277 
278 RCP<const Boolean> And::logical_not() const
279 {
280  auto container = this->get_container();
281  set_boolean cont;
282  for (auto &a : container) {
283  cont.insert(SymEngine::logical_not(a));
284  }
285  return make_rcp<const Or>(cont);
286 }
287 
288 Or::Or(const set_boolean &s) : container_{s}
289 {
290  SYMENGINE_ASSIGN_TYPEID()
291  SYMENGINE_ASSERT(is_canonical(s));
292 }
293 
294 hash_t Or::__hash__() const
295 {
296  hash_t seed = SYMENGINE_OR;
297  for (const auto &a : container_)
298  hash_combine<Basic>(seed, *a);
299  return seed;
300 }
301 
303 {
304  vec_basic v(container_.begin(), container_.end());
305  return v;
306 }
307 
308 bool Or::__eq__(const Basic &o) const
309 {
310  return is_a<Or>(o)
311  and unified_eq(container_, down_cast<const Or &>(o).get_container());
312 }
313 
314 int Or::compare(const Basic &o) const
315 {
316  SYMENGINE_ASSERT(is_a<Or>(o))
317  return unified_compare(container_,
318  down_cast<const Or &>(o).get_container());
319 }
320 
321 bool Or::is_canonical(const set_boolean &container_)
322 {
323  if (container_.size() >= 2) {
324  for (auto &a : container_) {
325  if (is_a<BooleanAtom>(*a) or is_a<Or>(*a))
326  return false;
327  if (container_.find(SymEngine::logical_not(a)) != container_.end())
328  return false;
329  }
330  return true;
331  }
332  return false;
333 }
334 
335 const set_boolean &Or::get_container() const
336 {
337  return container_;
338 }
339 
340 RCP<const Boolean> Or::logical_not() const
341 {
342  auto container = this->get_container();
343  set_boolean cont;
344  for (auto &a : container) {
345  cont.insert(SymEngine::logical_not(a));
346  }
347  return make_rcp<const And>(cont);
348 }
349 
350 Not::Not(const RCP<const Boolean> &in) : arg_{in}
351 {
352  SYMENGINE_ASSIGN_TYPEID()
353  SYMENGINE_ASSERT(is_canonical(in));
354 }
355 
356 hash_t Not::__hash__() const
357 {
358  hash_t seed = SYMENGINE_NOT;
359  hash_combine<Basic>(seed, *arg_);
360  return seed;
361 }
362 
364 {
365  vec_basic v;
366  v.push_back(arg_);
367  return v;
368 }
369 
370 bool Not::__eq__(const Basic &o) const
371 {
372  return is_a<Not>(o) and eq(*arg_, *down_cast<const Not &>(o).get_arg());
373 }
374 
375 int Not::compare(const Basic &o) const
376 {
377  SYMENGINE_ASSERT(is_a<Not>(o))
378  return arg_->__cmp__(*down_cast<const Not &>(o).get_arg());
379 }
380 
381 bool Not::is_canonical(const RCP<const Boolean> &in)
382 {
383  if (is_a<BooleanAtom>(*in) or is_a<Not>(*in))
384  return false;
385  return true;
386 }
387 
388 RCP<const Boolean> Not::get_arg() const
389 {
390  return arg_;
391 }
392 
393 RCP<const Boolean> Not::logical_not() const
394 {
395  return this->get_arg();
396 }
397 
398 Xor::Xor(const vec_boolean &s) : container_{s}
399 {
400  SYMENGINE_ASSIGN_TYPEID()
401  SYMENGINE_ASSERT(is_canonical(s));
402 }
403 
404 hash_t Xor::__hash__() const
405 {
406  hash_t seed = SYMENGINE_XOR;
407  for (const auto &a : container_)
408  hash_combine<Basic>(seed, *a);
409  return seed;
410 }
411 
413 {
414  vec_basic v(container_.begin(), container_.end());
415  return v;
416 }
417 
418 bool Xor::__eq__(const Basic &o) const
419 {
420  return is_a<Xor>(o)
421  and unified_eq(container_,
422  down_cast<const Xor &>(o).get_container());
423 }
424 
425 int Xor::compare(const Basic &o) const
426 {
427  SYMENGINE_ASSERT(is_a<Xor>(o))
428  return unified_compare(container_,
429  down_cast<const Xor &>(o).get_container());
430 }
431 
432 bool Xor::is_canonical(const vec_boolean &container_)
433 {
434  if (container_.size() >= 2) {
435  set_boolean args;
436  for (auto &a : container_) {
437  if (is_a<BooleanAtom>(*a) or is_a<Xor>(*a)) {
438  return false;
439  }
440  if (args.find(a) != args.end()) {
441  return false;
442  }
443  if (args.find(SymEngine::logical_not(a)) != args.end()) {
444  return false;
445  }
446  args.insert(a);
447  }
448  return true;
449  }
450  return false;
451 }
452 
453 const vec_boolean &Xor::get_container() const
454 {
455  return container_;
456 }
457 
458 const vec_boolean get_vec_from_set(const set_boolean &s)
459 {
460  vec_boolean v(s.begin(), s.end());
461  return v;
462 }
463 
464 template <typename caller>
465 RCP<const Boolean> and_or(const set_boolean &s, const bool &op_x_notx)
466 {
467  set_boolean args;
468  for (auto &a : s) {
469  if (is_a<BooleanAtom>(*a)) {
470  auto val = down_cast<const BooleanAtom &>(*a).get_val();
471  if (val == op_x_notx)
472  return boolean(op_x_notx);
473  else
474  continue;
475  }
476  if (is_a<caller>(*a)) {
477  const caller &to_insert = down_cast<const caller &>(*a);
478  auto container = to_insert.get_container();
479  args.insert(container.begin(), container.end());
480  continue;
481  }
482  args.insert(a);
483  }
484  for (auto &a : args) {
485  if (args.find(logical_not(a)) != args.end())
486  return boolean(op_x_notx);
487  }
488  if (not op_x_notx) {
489  for (auto it = args.begin(); it != args.end(); it++) {
490  if (is_a<Contains>(**it)
491  and is_a<Symbol>(*down_cast<const Contains &>(**it).get_expr())
492  and is_a<FiniteSet>(
493  *down_cast<const Contains &>(**it).get_set())) {
494  auto sym = down_cast<const Contains &>(**it).get_expr();
495  // iterate through args and check for the condition that
496  // defines the domain of sym.
497  // Simplify if that set is a FiniteSet.
498  set_basic present;
499  auto fset = down_cast<const FiniteSet &>(
500  *down_cast<const Contains &>(**it).get_set())
501  .get_container();
502  // If there exists atleast one number/constant, then only we can
503  // simplify.
504  bool check = false;
505  for (const auto &elem : fset) {
506  if (is_a_Number(*elem) or is_a<Constant>(*elem)) {
507  check = true;
508  break;
509  }
510  }
511  if (!check)
512  break;
513  auto restCont = args;
514  restCont.erase(*it);
515  auto restCond = logical_and(restCont);
516  map_basic_basic d;
517  bool symexists = false;
518  for (const auto &fselement : fset) {
519  d[sym] = fselement;
520  auto contain = restCond->subs(d);
521  if (eq(*contain, *boolean(true))) {
522  present.insert(fselement);
523  } else if (not eq(*contain, *boolean(false))) {
524  present.insert(fselement);
525  symexists = true;
526  }
527  d.clear();
528  }
529  if (not symexists) {
530  // if there are no symbols, then this reduces to a
531  // Contains(sym,finiteset())
532  return finiteset(present)->contains(sym);
533  } else if (present.size() != fset.size()) {
534  restCond = logical_and(
535  {finiteset(present)->contains(sym), restCond});
536  return restCond;
537  } else {
538  // if present is same as fset, then return object of type
539  // `And`.
540  break;
541  }
542  }
543  }
544  }
545  if (args.size() == 1)
546  return *(args.begin());
547  else if (args.size() == 0)
548  return boolean(not op_x_notx);
549  return make_rcp<const caller>(args);
550 }
551 
552 RCP<const Boolean> logical_not(const RCP<const Boolean> &s)
553 {
554  return s->logical_not();
555 }
556 
557 RCP<const Boolean> logical_xor(const vec_boolean &s)
558 {
559  set_boolean args;
560  int nots = 0;
561  for (auto &a : s) {
562  if (is_a<BooleanAtom>(*a)) {
563  auto val = down_cast<const BooleanAtom &>(*a).get_val();
564  if (val == true) {
565  nots++;
566  }
567  continue;
568  } else if (is_a<Xor>(*a)) {
569  auto container = down_cast<const Xor &>(*a).get_container();
570  for (auto &aa : container) {
571  if (args.find(aa) != args.end()) {
572  args.erase(aa);
573  } else {
574  auto pos = args.find(logical_not(aa));
575  if (pos != args.end()) {
576  args.erase(pos);
577  nots++;
578  } else {
579  args.insert(aa);
580  }
581  }
582  }
583  continue;
584  }
585  if (args.find(a) != args.end()) {
586  args.erase(a);
587  } else {
588  auto pos = args.find(logical_not(a));
589  if (pos != args.end()) {
590  args.erase(pos);
591  nots++;
592  } else {
593  args.insert(a);
594  }
595  }
596  }
597 
598  if (nots % 2 == 0) {
599  if (args.size() == 0) {
600  return boolFalse;
601  } else if (args.size() == 1) {
602  return *args.begin();
603  } else {
604  return make_rcp<const Xor>(get_vec_from_set(args));
605  }
606  } else {
607  if (args.size() == 0) {
608  return boolTrue;
609  } else if (args.size() == 1) {
610  return logical_not(*args.begin());
611  } else {
612  return make_rcp<const Not>(
613  make_rcp<const Xor>(get_vec_from_set(args)));
614  }
615  }
616 }
617 
618 Relational::Relational(const RCP<const Basic> &lhs, const RCP<const Basic> &rhs)
619  : TwoArgBasic<Boolean>(lhs, rhs)
620 {
621 }
622 
623 inline bool Relational::is_canonical(const RCP<const Basic> &lhs,
624  const RCP<const Basic> &rhs) const
625 {
626  if (eq(*lhs, *rhs))
627  return false;
628  if (is_a_Number(*lhs) and is_a_Number(*rhs))
629  return false;
630  if (is_a<BooleanAtom>(*lhs) and is_a<BooleanAtom>(*rhs))
631  return false;
632  return true;
633 }
634 
635 Equality::Equality(const RCP<const Basic> &lhs, const RCP<const Basic> &rhs)
636  : Relational(lhs, rhs)
637 {
638  SYMENGINE_ASSIGN_TYPEID();
639  SYMENGINE_ASSERT(is_canonical(lhs, rhs));
640 }
641 
642 RCP<const Basic> Equality::create(const RCP<const Basic> &lhs,
643  const RCP<const Basic> &rhs) const
644 {
645  return Eq(lhs, rhs);
646 }
647 
648 RCP<const Boolean> Equality::logical_not() const
649 {
650  return make_rcp<const Unequality>(get_arg1(), get_arg2());
651 }
652 
653 RCP<const Boolean> Eq(const RCP<const Basic> &lhs)
654 {
655  return Eq(lhs, zero);
656 }
657 
658 RCP<const Boolean> Eq(const RCP<const Basic> &lhs, const RCP<const Basic> &rhs)
659 {
660  if (is_a<NaN>(*lhs) or is_a<NaN>(*rhs))
661  return boolean(false);
662  bool b = eq(*lhs, *rhs);
663  if (b) {
664  return boolean(true);
665  } else {
666  if ((is_a_Number(*lhs) and is_a_Number(*rhs))
667  or (is_a<BooleanAtom>(*lhs) and is_a<BooleanAtom>(*rhs)))
668  return boolean(false);
669  if (lhs->__cmp__(*rhs) == 1)
670  return make_rcp<const Equality>(rhs, lhs);
671  return make_rcp<Equality>(lhs, rhs);
672  }
673 }
674 
675 Unequality::Unequality(const RCP<const Basic> &lhs, const RCP<const Basic> &rhs)
676  : Relational(lhs, rhs)
677 {
678  SYMENGINE_ASSIGN_TYPEID();
679  SYMENGINE_ASSERT(is_canonical(lhs, rhs));
680 }
681 
682 RCP<const Basic> Unequality::create(const RCP<const Basic> &lhs,
683  const RCP<const Basic> &rhs) const
684 {
685  return Ne(lhs, rhs);
686 }
687 
688 RCP<const Boolean> Unequality::logical_not() const
689 {
690  return make_rcp<const Equality>(get_arg1(), get_arg2());
691 }
692 
693 RCP<const Boolean> Ne(const RCP<const Basic> &lhs, const RCP<const Basic> &rhs)
694 {
695  RCP<const Basic> r = Eq(lhs, rhs);
696  if (is_a<BooleanAtom>(*r)) {
697  return logical_not(rcp_static_cast<const BooleanAtom>(r));
698  }
699  if (lhs->__cmp__(*rhs) == 1)
700  return make_rcp<const Unequality>(rhs, lhs);
701  return make_rcp<Unequality>(lhs, rhs);
702 }
703 
704 LessThan::LessThan(const RCP<const Basic> &lhs, const RCP<const Basic> &rhs)
705  : Relational(lhs, rhs)
706 {
707  SYMENGINE_ASSIGN_TYPEID();
708  SYMENGINE_ASSERT(is_canonical(lhs, rhs));
709 }
710 
711 RCP<const Basic> LessThan::create(const RCP<const Basic> &lhs,
712  const RCP<const Basic> &rhs) const
713 {
714  return Le(lhs, rhs);
715 }
716 
717 RCP<const Boolean> LessThan::logical_not() const
718 {
719  return make_rcp<const StrictLessThan>(get_arg2(), get_arg1());
720 }
721 
722 RCP<const Boolean> Le(const RCP<const Basic> &lhs, const RCP<const Basic> &rhs)
723 {
724  if (is_a_Complex(*lhs) or is_a_Complex(*rhs))
725  throw SymEngineException("Invalid comparison of complex numbers.");
726  if (is_a<NaN>(*lhs) or is_a<NaN>(*rhs))
727  throw SymEngineException("Invalid NaN comparison.");
728  if (eq(*lhs, *ComplexInf) or eq(*rhs, *ComplexInf))
729  throw SymEngineException("Invalid comparison of complex zoo.");
730  if (is_a<BooleanAtom>(*lhs) or is_a<BooleanAtom>(*rhs))
731  throw SymEngineException("Invalid comparison of Boolean objects.");
732  if (eq(*lhs, *rhs))
733  return boolean(true);
734  if (is_a_Number(*lhs) and is_a_Number(*rhs)) {
735  RCP<const Number> s = down_cast<const Number &>(*lhs).sub(
736  down_cast<const Number &>(*rhs));
737  if (s->is_negative())
738  return boolean(true);
739  return boolean(false);
740  }
741  return make_rcp<const LessThan>(lhs, rhs);
742 }
743 
744 RCP<const Boolean> Ge(const RCP<const Basic> &lhs, const RCP<const Basic> &rhs)
745 {
746  return Le(rhs, lhs);
747 }
748 
749 StrictLessThan::StrictLessThan(const RCP<const Basic> &lhs,
750  const RCP<const Basic> &rhs)
751  : Relational(lhs, rhs)
752 {
753  SYMENGINE_ASSIGN_TYPEID();
754  SYMENGINE_ASSERT(is_canonical(lhs, rhs));
755 }
756 
757 RCP<const Basic> StrictLessThan::create(const RCP<const Basic> &lhs,
758  const RCP<const Basic> &rhs) const
759 {
760  return Lt(lhs, rhs);
761 }
762 
763 RCP<const Boolean> StrictLessThan::logical_not() const
764 {
765  return make_rcp<const LessThan>(get_arg2(), get_arg1());
766 }
767 
768 RCP<const Boolean> Lt(const RCP<const Basic> &lhs, const RCP<const Basic> &rhs)
769 {
770  if (is_a_Complex(*lhs) or is_a_Complex(*rhs))
771  throw SymEngineException("Invalid comparison of complex numbers.");
772  if (is_a<NaN>(*lhs) or is_a<NaN>(*rhs))
773  throw SymEngineException("Invalid NaN comparison.");
774  if (eq(*lhs, *ComplexInf) or eq(*rhs, *ComplexInf))
775  throw SymEngineException("Invalid comparison of complex zoo.");
776  if (is_a<BooleanAtom>(*lhs) or is_a<BooleanAtom>(*rhs))
777  throw SymEngineException("Invalid comparison of Boolean objects.");
778  if (eq(*lhs, *rhs))
779  return boolean(false);
780  if (is_a_Number(*lhs) and is_a_Number(*rhs)) {
781  RCP<const Number> s = down_cast<const Number &>(*lhs).sub(
782  down_cast<const Number &>(*rhs));
783  if (s->is_negative())
784  return boolean(true);
785  return boolean(false);
786  }
787  return make_rcp<const StrictLessThan>(lhs, rhs);
788 }
789 
790 RCP<const Boolean> Gt(const RCP<const Basic> &lhs, const RCP<const Basic> &rhs)
791 {
792  return Lt(rhs, lhs);
793 }
794 
795 RCP<const Boolean> logical_and(const set_boolean &s)
796 {
797  return and_or<And>(s, false);
798 }
799 
800 RCP<const Boolean> logical_nand(const set_boolean &s)
801 {
802  RCP<const Boolean> a = logical_and(s);
803  return logical_not(a);
804 }
805 
806 RCP<const Boolean> logical_or(const set_boolean &s)
807 {
808  return and_or<Or>(s, true);
809 }
810 
811 RCP<const Boolean> logical_nor(const set_boolean &s)
812 {
813  return logical_not(and_or<Or>(s, true));
814 }
815 
816 RCP<const Boolean> logical_xnor(const vec_boolean &s)
817 {
818  return logical_not(logical_xor(s));
819 }
820 } // namespace SymEngine
hash_t __hash__() const override
Definition: logic.cpp:226
bool __eq__(const Basic &o) const override
Test equality.
Definition: logic.cpp:240
int compare(const Basic &o) const override
Structural equality comparator.
Definition: logic.cpp:247
vec_basic get_args() const override
Returns the list of arguments.
Definition: logic.cpp:234
The lowest unit of symbolic representation.
Definition: basic.h:97
bool __eq__(const Basic &o) const override
Test equality.
Definition: logic.cpp:93
int compare(const Basic &o) const override
Structural equality comparator.
Definition: logic.cpp:100
vec_basic get_args() const override
Returns the list of arguments.
Definition: logic.cpp:85
hash_t __hash__() const override
Definition: logic.cpp:67
RCP< const T2 > rcp_from_this_cast() const
Get RCP<T2> pointer to self (it will cast the pointer to T2)
RCP< const Basic > create(const RCP< const Basic > &lhs, const RCP< const Basic > &rhs) const override
Method to construct classes with canonicalization.
Definition: logic.cpp:642
vec_basic get_args() const override
Returns the list of arguments.
Definition: logic.cpp:363
int compare(const Basic &o) const override
Structural equality comparator.
Definition: logic.cpp:375
hash_t __hash__() const override
Definition: logic.cpp:356
bool __eq__(const Basic &o) const override
Test equality.
Definition: logic.cpp:370
vec_basic get_args() const override
Returns the list of arguments.
Definition: logic.cpp:302
hash_t __hash__() const override
Definition: logic.cpp:294
bool __eq__(const Basic &o) const override
Test equality.
Definition: logic.cpp:308
int compare(const Basic &o) const override
Structural equality comparator.
Definition: logic.cpp:314
vec_basic get_args() const override
Returns the list of arguments.
Definition: logic.cpp:197
Piecewise(PiecewiseVec &&vec)
Constructor.
Definition: logic.cpp:150
bool __eq__(const Basic &o) const override
Test equality.
Definition: logic.cpp:207
int compare(const Basic &o) const override
Structural equality comparator.
Definition: logic.cpp:213
hash_t __hash__() const override
Definition: logic.cpp:182
Relational(const RCP< const Basic > &lhs, const RCP< const Basic > &rhs)
Constructor.
Definition: logic.cpp:618
virtual bool is_canonical(const RCP< const Basic > &lhs, const RCP< const Basic > &rhs) const
Definition: logic.cpp:623
RCP< const Basic > get_arg1() const
Definition: functions.h:91
RCP< const Basic > get_arg2() const
Definition: functions.h:96
bool __eq__(const Basic &o) const override
Test equality.
Definition: logic.cpp:418
int compare(const Basic &o) const override
Definition: logic.cpp:425
vec_basic get_args() const override
Returns the list of arguments.
Definition: logic.cpp:412
T end(T... args)
T erase(T... args)
T find(T... args)
T insert(T... args)
T move(T... args)
Main namespace for SymEngine package.
Definition: add.cpp:19
bool is_a_Number(const Basic &b)
Definition: number.h:130
RCP< const Boolean > Ge(const RCP< const Basic > &lhs, const RCP< const Basic > &rhs)
Convenience function returning LessThan object.
Definition: logic.cpp:744
bool eq(const Basic &a, const Basic &b)
Checks equality for a and b
Definition: basic-inl.h:21
RCP< const Boolean > Lt(const RCP< const Basic > &lhs, const RCP< const Basic > &rhs)
Returns the canonicalized StrictLessThan object from the arguments.
Definition: logic.cpp:768
RCP< const Boolean > Le(const RCP< const Basic > &lhs, const RCP< const Basic > &rhs)
Returns the canonicalized LessThan object from the arguments.
Definition: logic.cpp:722
bool is_same_type(const Basic &a, const Basic &b)
Returns true if a and b are exactly the same type T.
Definition: basic-inl.h:47
RCP< const Boolean > Eq(const RCP< const Basic > &lhs)
Returns the canonicalized Equality object from a single argument.
Definition: logic.cpp:653
RCP< const Set > finiteset(const set_basic &container)
Definition: sets.h:602
int unified_compare(const T &a, const T &b)
Definition: dict.h:205
bool is_a_Complex(const Basic &b)
Definition: complex.h:24
RCP< const Boolean > Gt(const RCP< const Basic > &lhs, const RCP< const Basic > &rhs)
Convenience function returning StrictLessThan object.
Definition: logic.cpp:790
RCP< const Boolean > Ne(const RCP< const Basic > &lhs, const RCP< const Basic > &rhs)
Returns the canonicalized Unequality object from the arguments.
Definition: logic.cpp:693
T push_back(T... args)
T size(T... args)