Loading...
Searching...
No Matches
sets.cpp
1#include <symengine/add.h>
2#include <symengine/logic.h>
4#include <symengine/symengine_casts.h>
5#include <iterator>
6
7namespace SymEngine
8{
9
10Interval::Interval(const RCP<const Number> &start, const RCP<const Number> &end,
11 const bool left_open, const bool right_open)
12 : start_(start), end_(end), left_open_(left_open), right_open_(right_open)
13{
14 SYMENGINE_ASSIGN_TYPEID()
15 SYMENGINE_ASSERT(
16 Interval::is_canonical(start_, end_, left_open_, right_open_));
17}
18
19bool Interval::is_canonical(const RCP<const Number> &s,
20 const RCP<const Number> &e, bool left_open,
21 bool right_open)
22{
23 if (is_a<Complex>(*s) or is_a<Complex>(*e))
24 throw NotImplementedError("Complex set not implemented");
25 if (eq(*e, *s)) {
26 return false;
27 } else if (eq(*min({s, e}), *e)) {
28 return false;
29 }
30 return true;
31}
32
33hash_t Interval::__hash__() const
34{
35 hash_t seed = SYMENGINE_INTERVAL;
36 hash_combine<Basic>(seed, *start_);
37 hash_combine<Basic>(seed, *end_);
38 hash_combine<bool>(seed, left_open_);
39 hash_combine<bool>(seed, right_open_);
40 return seed;
41}
42
43bool Interval::__eq__(const Basic &o) const
44{
45 if (is_a<Interval>(o)) {
46 const Interval &s = down_cast<const Interval &>(o);
47 return ((this->left_open_ == s.left_open_)
48 and (this->right_open_ == s.right_open_)
49 and eq(*this->start_, *s.start_) and eq(*this->end_, *s.end_));
50 }
51 return false;
52}
53
54int Interval::compare(const Basic &s) const
55{
56 // compares two interval based on their length
57 SYMENGINE_ASSERT(is_a<Interval>(s))
58 const Interval &o = down_cast<const Interval &>(s);
59 if (left_open_ and not o.left_open_) {
60 return -1;
61 } else if (not left_open_ and o.left_open_) {
62 return 1;
63 } else if (right_open_ and not o.right_open_) {
64 return 1;
65 } else if (not right_open_ and o.right_open_) {
66 return -1;
67 } else {
68 auto temp = start_->__cmp__(*(o.start_));
69 if (temp != 0) {
70 return temp;
71 } else {
72 return end_->__cmp__(*(o.end_));
73 }
74 }
75}
76
77RCP<const Set> Interval::open() const
78{
79 return interval(start_, end_, true, true);
80}
81
82RCP<const Set> Interval::Lopen() const
83{
84 return interval(start_, end_, true, false);
85}
86
87RCP<const Set> Interval::Ropen() const
88{
89 return interval(start_, end_, false, true);
90}
91
92RCP<const Set> Interval::close() const
93{
94 return interval(start_, end_, false, false);
95}
96
97RCP<const Boolean> Interval::contains(const RCP<const Basic> &a) const
98{
99 if (not is_a_Number(*a)) {
100 if (is_a_Set(*a)) {
101 return boolean(false);
102 } else {
103 return make_rcp<Contains>(a, rcp_from_this_cast<const Set>());
104 }
105 }
106 if (eq(*start_, *a))
107 return boolean(not left_open_);
108 if (eq(*end_, *a))
109 return boolean(not right_open_);
110 if (eq(*min({end_, a}), *end_) or eq(*max({start_, a}), *start_))
111 return boolean(false);
112 return boolean(true);
113}
114
115static RCP<const Set> make_set_union(const set_set &in)
116{
117 if (in.size() > 1) {
118 return make_rcp<const Union>(in);
119 }
120 return *in.begin();
121}
122
123static RCP<const Set> make_set_intersection(const set_set &in)
124{
125 if (in.size() > 1) {
126 return make_rcp<const Intersection>(in);
127 }
128 return *in.begin();
129}
130
131RCP<const Set> Interval::set_intersection(const RCP<const Set> &o) const
132{
133 if (is_a<Interval>(*o)) {
134 const Interval &other = down_cast<const Interval &>(*o);
135 RCP<const Number> start, end;
136 bool left_open, right_open;
137 RCP<const Basic> start_end, end_start;
138 start_end = min({this->start_, other.end_});
139 end_start = min({this->end_, other.start_});
140
141 if (eq(*this->start_, *start_end) and eq(*other.start_, *end_start)) {
142 RCP<const Basic> start_start, end_end;
143 start_start = min({this->start_, other.start_});
144 end_end = min({this->end_, other.end_});
145 if (neq(*this->start_, *other.start_)) {
146 if (eq(*this->start_, *start_start)) {
147 start = other.start_;
148 left_open = other.left_open_;
149 } else {
150 start = this->start_;
151 left_open = this->left_open_;
152 }
153 } else {
154 start = this->start_;
155 left_open = this->left_open_ or other.left_open_;
156 }
157
158 if (neq(*this->end_, *other.end_)) {
159 if (eq(*this->end_, *end_end)) {
160 end = this->end_;
161 right_open = this->right_open_;
162 } else {
163 end = other.end_;
164 right_open = other.right_open_;
165 }
166 } else {
167 end = this->end_;
168 right_open = this->right_open_ or other.right_open_;
169 }
170 return interval(start, end, left_open, right_open);
171 } else {
172 return emptyset();
173 }
174 }
175 if (is_a<Integers>(*o) or is_a<Naturals>(*o) or is_a<Naturals0>(*o)) {
176 if (is_a_Number(*start_) and is_a_Number(*end_)) {
177 auto first = SymEngine::ceiling(start_);
178 auto last = SymEngine::floor(end_);
179 if (is_a<Naturals>(*o)
180 and not down_cast<const Integer &>(*first).is_positive()) {
181 first = integer(1);
182 } else if (is_a<Naturals0>(*o)
183 and down_cast<const Integer &>(*first).is_negative()) {
184 first = integer(0);
185 }
186 if (eq(*first, *start_) and left_open_) {
187 first = add(first, integer(1));
188 }
189 if (eq(*last, *end_) and right_open_) {
190 last = add(last, integer(-1));
191 }
192 if (eq(*Lt(last, first), *boolTrue)) {
193 return emptyset();
194 }
195 set_basic container;
196 while (eq(*Ge(last, first), *boolTrue)) {
197 container.insert(first);
198 first = add(first, integer(1));
199 }
200 return finiteset(container);
201 } else {
202 return SymEngine::set_intersection(
203 {rcp_from_this_cast<const Set>(), o});
204 }
205 }
206 if (is_a<UniversalSet>(*o) or is_a<EmptySet>(*o) or is_a<FiniteSet>(*o)
207 or is_a<Union>(*o) or is_a<Rationals>(*o) or is_a<Reals>(*o)
208 or is_a<Complexes>(*o)) {
209 return (*o).set_intersection(rcp_from_this_cast<const Set>());
210 }
211 return make_set_intersection({rcp_from_this_cast<const Set>(), o});
212}
213
214RCP<const Set> Interval::set_union(const RCP<const Set> &o) const
215{
216 if (is_a<Interval>(*o)) {
217 const Interval &other = down_cast<const Interval &>(*o);
218 RCP<const Basic> start_start, end_end, m;
219 RCP<const Number> start, end;
220 bool left_open, right_open;
221 start_start = max({this->start_, other.start_});
222 end_end = min({this->end_, other.end_});
223 m = min({start_start, end_end});
224 if ((eq(*end_end, *start_start) and eq(*end_end, *m)
225 and ((eq(*end_end, *this->end_) and this->right_open_)
226 or (eq(*end_end, *other.end_) and other.right_open_)))
227 or (eq(*end_end, *m) and not eq(*end_end, *start_start))) {
228 return SymEngine::make_set_union(
229 {rcp_from_this_cast<const Set>(), o});
230 } else {
231 if (eq(*min({this->start_, other.start_}), *this->start_)) {
232 start = this->start_;
233 } else {
234 start = other.start_;
235 }
236 if (eq(*max({this->end_, other.end_}), *this->end_)) {
237 end = this->end_;
238 } else {
239 end = other.end_;
240 }
241 left_open = ((neq(*this->start_, *start) or this->left_open_)
242 and (neq(*other.start_, *start) or other.left_open_));
243 right_open = ((neq(*this->end_, *end) or this->right_open_)
244 and (neq(*other.end_, *end) or other.right_open_));
245 return interval(start, end, left_open, right_open);
246 }
247 }
248 if (is_a<UniversalSet>(*o) or is_a<EmptySet>(*o) or is_a<FiniteSet>(*o)
249 or is_a<Union>(*o) or is_a<Complexes>(*o) or is_a<Reals>(*o)
250 or is_a<Rationals>(*o) or is_a<Integers>(*o) or is_a<Naturals>(*o)
251 or is_a<Naturals0>(*o)) {
252 return (*o).set_union(rcp_from_this_cast<const Set>());
253 }
254 return SymEngine::make_set_union({rcp_from_this_cast<const Set>(), o});
255}
256
257RCP<const Set> Interval::set_complement(const RCP<const Set> &o) const
258{
259 if (is_a<Interval>(*o)) {
260 set_set cont;
261 const Interval &other = down_cast<const Interval &>(*o);
262 if (eq(*max({start_, other.start_}), *start_)) {
263 cont.insert(interval(other.get_start(), start_,
264 other.get_left_open(), not left_open_));
265 }
266 if (eq(*min({end_, other.end_}), *end_)) {
267 cont.insert(interval(end_, other.get_end(), not right_open_,
268 other.get_right_open()));
269 }
270 return SymEngine::set_union(cont);
271 }
272 return SymEngine::set_complement_helper(rcp_from_this_cast<const Set>(), o);
273}
274
275vec_basic Interval::get_args() const
276{
277 return {start_, end_, boolean(left_open_), boolean(right_open_)};
278}
279
280RCP<const Set> Complexes::set_intersection(const RCP<const Set> &o) const
281{
282 if (is_a<Interval>(*o) or is_a<EmptySet>(*o) or is_a<Complexes>(*o)
283 or is_a<Reals>(*o) or is_a<Rationals>(*o) or is_a<Integers>(*o)
284 or is_a<Naturals>(*o) or is_a<Naturals0>(*o)) {
285 return o;
286 } else if (is_a<FiniteSet>(*o)) {
287 return (*o).set_intersection(rcp_from_this_cast<const Set>());
288 } else {
289 return SymEngine::set_intersection(
290 {rcp_from_this_cast<const Set>(), o});
291 }
292}
293
294RCP<const Set> Complexes::set_union(const RCP<const Set> &o) const
295{
296 if (is_a<Interval>(*o) or is_a<EmptySet>(*o) or is_a<Complexes>(*o)
297 or is_a<Reals>(*o) or is_a<Integers>(*o) or is_a<Rationals>(*o)
298 or is_a<Naturals>(*o) or is_a<Naturals0>(*o)) {
299 return complexes();
300 } else if (is_a<FiniteSet>(*o)) {
301 return (*o).set_union(rcp_from_this_cast<const Set>());
302 } else {
303 return SymEngine::set_union({rcp_from_this_cast<const Set>(), o});
304 }
305}
306
307RCP<const Set> Complexes::set_complement(const RCP<const Set> &o) const
308{
309 if (is_a<EmptySet>(*o) or is_a<Complexes>(*o) or is_a<Reals>(*o)
310 or is_a<Rationals>(*o) or is_a<Integers>(*o) or is_a<Interval>(*o)
311 or is_a<Naturals>(*o) or is_a<Naturals0>(*o)) {
312 return emptyset();
313 }
314 if (is_a<UniversalSet>(*o)) {
315 return make_rcp<const Complement>(o, complexes());
316 }
317 return SymEngine::set_complement_helper(rcp_from_this_cast<const Set>(), o);
318}
319
320RCP<const Boolean> Complexes::contains(const RCP<const Basic> &a) const
321{
322 if (not is_a_Number(*a)) {
323 if (is_a_Set(*a)) {
324 return boolean(false);
325 } else {
326 return make_rcp<Contains>(a, rcp_from_this_cast<const Set>());
327 }
328 }
329 return boolean(true);
330}
331
332hash_t Complexes::__hash__() const
333{
334 hash_t seed = SYMENGINE_COMPLEXES;
335 return seed;
336}
337
338bool Complexes::__eq__(const Basic &o) const
339{
340 if (is_a<Complexes>(o))
341 return true;
342 return false;
343}
344
345int Complexes::compare(const Basic &o) const
346{
347 SYMENGINE_ASSERT(is_a<Complexes>(o))
348 return 0;
349}
350
351const RCP<const Complexes> &Complexes::getInstance()
352{
353 const static auto a = make_rcp<const Complexes>();
354 return a;
355}
356
357RCP<const Set> Reals::set_intersection(const RCP<const Set> &o) const
358{
359 if (is_a<Interval>(*o) or is_a<EmptySet>(*o) or is_a<Reals>(*o)
360 or is_a<Rationals>(*o) or is_a<Integers>(*o) or is_a<Naturals>(*o)
361 or is_a<Naturals0>(*o)) {
362 return o;
363 } else if (is_a<FiniteSet>(*o) or is_a<Complexes>(*o)) {
364 return (*o).set_intersection(rcp_from_this_cast<const Set>());
365 } else {
366 return SymEngine::set_intersection(
367 {rcp_from_this_cast<const Set>(), o});
368 }
369}
370
371RCP<const Set> Reals::set_union(const RCP<const Set> &o) const
372{
373 if (is_a<Interval>(*o) or is_a<EmptySet>(*o) or is_a<Reals>(*o)
374 or is_a<Integers>(*o) or is_a<Rationals>(*o) or is_a<Naturals>(*o)
375 or is_a<Naturals0>(*o)) {
376 return reals();
377 } else if (is_a<FiniteSet>(*o) or is_a<Complexes>(*o)) {
378 return (*o).set_union(rcp_from_this_cast<const Set>());
379 } else {
380 return SymEngine::set_union({rcp_from_this_cast<const Set>(), o});
381 }
382}
383
384RCP<const Set> Reals::set_complement(const RCP<const Set> &o) const
385{
386 if (is_a<EmptySet>(*o) or is_a<Reals>(*o) or is_a<Rationals>(*o)
387 or is_a<Integers>(*o) or is_a<Interval>(*o) or is_a<Naturals>(*o)
388 or is_a<Naturals0>(*o)) {
389 return emptyset();
390 }
391 if (is_a<UniversalSet>(*o) or is_a<Complexes>(*o)) {
392 return make_rcp<const Complement>(o, reals());
393 }
394 return SymEngine::set_complement_helper(rcp_from_this_cast<const Set>(), o);
395}
396
397RCP<const Boolean> Reals::contains(const RCP<const Basic> &a) const
398{
399 if (not is_a_Number(*a)) {
400 if (is_a_Set(*a)) {
401 return boolean(false);
402 } else {
403 return make_rcp<Contains>(a, rcp_from_this_cast<const Set>());
404 }
405 }
406 if (is_a<Complex>(*a)) {
407 return boolean(false);
408 }
409 return boolean(true);
410}
411
412hash_t Reals::__hash__() const
413{
414 hash_t seed = SYMENGINE_REALS;
415 return seed;
416}
417
418bool Reals::__eq__(const Basic &o) const
419{
420 if (is_a<Reals>(o))
421 return true;
422 return false;
423}
424
425int Reals::compare(const Basic &o) const
426{
427 SYMENGINE_ASSERT(is_a<Reals>(o))
428 return 0;
429}
430
431const RCP<const Reals> &Reals::getInstance()
432{
433 const static auto a = make_rcp<const Reals>();
434 return a;
435}
436
437RCP<const Set> Rationals::set_intersection(const RCP<const Set> &o) const
438{
439 if (is_a<EmptySet>(*o) or is_a<Rationals>(*o) or is_a<Integers>(*o)
440 or is_a<Naturals>(*o) or is_a<Naturals0>(*o)) {
441 return o;
442 } else if (is_a<FiniteSet>(*o) or is_a<Reals>(*o) or is_a<Complexes>(*o)) {
443 return (*o).set_intersection(rcp_from_this_cast<const Set>());
444 } else {
445 return SymEngine::set_intersection(
446 {rcp_from_this_cast<const Set>(), o});
447 }
448}
449
450RCP<const Set> Rationals::set_union(const RCP<const Set> &o) const
451{
452 if (is_a<EmptySet>(*o) or is_a<Integers>(*o) or is_a<Rationals>(*o)
453 or is_a<Naturals>(*o) or is_a<Naturals0>(*o)) {
454 return rationals();
455 } else if (is_a<FiniteSet>(*o) or is_a<Reals>(*o) or is_a<Complexes>(*o)) {
456 return (*o).set_union(rcp_from_this_cast<const Set>());
457 } else {
458 return SymEngine::set_union({rcp_from_this_cast<const Set>(), o});
459 }
460}
461
462RCP<const Set> Rationals::set_complement(const RCP<const Set> &o) const
463{
464 if (is_a<EmptySet>(*o) or is_a<Rationals>(*o) or is_a<Integers>(*o)
465 or is_a<Naturals>(*o) or is_a<Naturals0>(*o)) {
466 return emptyset();
467 }
468 if (is_a<UniversalSet>(*o) or is_a<Complexes>(*o) or is_a<Reals>(*o)
469 or is_a<Interval>(*o)) {
470 return make_rcp<const Complement>(o, rationals());
471 }
472 return SymEngine::set_complement_helper(rcp_from_this_cast<const Set>(), o);
473}
474
475RCP<const Boolean> Rationals::contains(const RCP<const Basic> &a) const
476{
477 if (not is_a_Number(*a)) {
478 if (is_a_Set(*a)) {
479 return boolean(false);
480 } else {
481 return make_rcp<Contains>(a, rcp_from_this_cast<const Set>());
482 }
483 }
484 if (is_a<Complex>(*a) or not down_cast<const Number &>(*a).is_exact()) {
485 return boolean(false);
486 }
487 return boolean(true);
488}
489
490hash_t Rationals::__hash__() const
491{
492 hash_t seed = SYMENGINE_RATIONALS;
493 return seed;
494}
495
496bool Rationals::__eq__(const Basic &o) const
497{
498 return (is_a<Rationals>(o));
499}
500
501int Rationals::compare(const Basic &o) const
502{
503 SYMENGINE_ASSERT(is_a<Rationals>(o))
504 return 0;
505}
506
507const RCP<const Rationals> &Rationals::getInstance()
508{
509 const static auto a = make_rcp<const Rationals>();
510 return a;
511}
512
513RCP<const Set> Integers::set_intersection(const RCP<const Set> &o) const
514{
515 if (is_a<EmptySet>(*o) or is_a<Integers>(*o) or is_a<Naturals>(*o)
516 or is_a<Naturals0>(*o)) {
517 return o;
518 } else if (is_a<Complexes>(*o) or is_a<Reals>(*o) or is_a<Rationals>(*o)) {
519 return integers();
520 } else if (is_a<FiniteSet>(*o) or is_a<Interval>(*o)) {
521 return (*o).set_intersection(rcp_from_this_cast<const Set>());
522 } else {
523 return SymEngine::set_intersection(
524 {rcp_from_this_cast<const Set>(), o});
525 }
526}
527
528RCP<const Set> Integers::set_union(const RCP<const Set> &o) const
529{
530 if (is_a<Integers>(*o) or is_a<EmptySet>(*o) or is_a<Naturals>(*o)
531 or is_a<Naturals0>(*o)) {
532 return integers();
533 } else if (is_a<Complexes>(*o)) {
534 return complexes();
535 } else if (is_a<Reals>(*o)) {
536 return reals();
537 } else if (is_a<Rationals>(*o)) {
538 return rationals();
539 } else if (is_a<FiniteSet>(*o)) {
540 return (*o).set_union(rcp_from_this_cast<const Set>());
541 } else if (is_a<UniversalSet>(*o)) {
542 return universalset();
543 } else {
544 return SymEngine::make_set_union({rcp_from_this_cast<const Set>(), o});
545 }
546}
547
548RCP<const Set> Integers::set_complement(const RCP<const Set> &o) const
549{
550 if (is_a<EmptySet>(*o) or is_a<Integers>(*o) or is_a<Naturals>(*o)
551 or is_a<Naturals0>(*o)) {
552 return emptyset();
553 }
554 if (is_a<UniversalSet>(*o) or is_a<Rationals>(*o) or is_a<Reals>(*o)
555 or is_a<Complexes>(*o)) {
556 return make_rcp<const Complement>(o, integers());
557 }
558 return SymEngine::set_complement_helper(rcp_from_this_cast<const Set>(), o);
559}
560
561RCP<const Boolean> Integers::contains(const RCP<const Basic> &a) const
562{
563 if (not is_a_Number(*a)) {
564 if (is_a_Set(*a)) {
565 return boolean(false);
566 } else {
567 return make_rcp<Contains>(a, rcp_from_this_cast<const Set>());
568 }
569 }
570 if (is_a<Integer>(*a)) {
571 return boolean(true);
572 }
573 return boolean(false);
574}
575
576hash_t Integers::__hash__() const
577{
578 hash_t seed = SYMENGINE_INTEGERS;
579 return seed;
580}
581
582bool Integers::__eq__(const Basic &o) const
583{
584 if (is_a<Integers>(o))
585 return true;
586 return false;
587}
588
589int Integers::compare(const Basic &o) const
590{
591 SYMENGINE_ASSERT(is_a<Integers>(o))
592 return 0;
593}
594
595const RCP<const Integers> &Integers::getInstance()
596{
597 const static auto a = make_rcp<const Integers>();
598 return a;
599}
600
601RCP<const Set> Naturals::set_intersection(const RCP<const Set> &o) const
602{
603 if (is_a<EmptySet>(*o) or is_a<Naturals>(*o)) {
604 return o;
605 } else if (is_a<Naturals0>(*o) or is_a<Integers>(*o) or is_a<Complexes>(*o)
606 or is_a<Reals>(*o) or is_a<Rationals>(*o)) {
607 return naturals();
608 } else if (is_a<FiniteSet>(*o) or is_a<Interval>(*o)) {
609 return (*o).set_intersection(rcp_from_this_cast<const Set>());
610 } else {
611 return SymEngine::set_intersection(
612 {rcp_from_this_cast<const Set>(), o});
613 }
614}
615
616RCP<const Set> Naturals::set_union(const RCP<const Set> &o) const
617{
618 if (is_a<EmptySet>(*o)) {
619 return naturals();
620 } else if (is_a<Naturals>(*o) or is_a<Naturals0>(*o) or is_a<Integers>(*o)
621 or is_a<Complexes>(*o) or is_a<Reals>(*o) or is_a<Rationals>(*o)
622 or is_a<UniversalSet>(*o)) {
623 return o;
624 } else if (is_a<FiniteSet>(*o)) {
625 return (*o).set_union(rcp_from_this_cast<const Set>());
626 } else {
627 return SymEngine::make_set_union({rcp_from_this_cast<const Set>(), o});
628 }
629}
630
631RCP<const Set> Naturals::set_complement(const RCP<const Set> &o) const
632{
633 if (is_a<EmptySet>(*o) or is_a<Naturals>(*o)) {
634 return emptyset();
635 }
636 if (is_a<Naturals0>(*o)) {
637 finiteset({zero});
638 }
639 if (is_a<UniversalSet>(*o) or is_a<Integers>(*o) or is_a<Rationals>(*o)
640 or is_a<Reals>(*o) or is_a<Complexes>(*o)) {
641 return make_rcp<const Complement>(o, naturals());
642 }
643 return SymEngine::set_complement_helper(rcp_from_this_cast<const Set>(), o);
644}
645
646RCP<const Boolean> Naturals::contains(const RCP<const Basic> &a) const
647{
648 if (not is_a_Number(*a)) {
649 if (is_a_Set(*a)) {
650 return boolean(false);
651 } else {
652 return make_rcp<Contains>(a, rcp_from_this_cast<const Set>());
653 }
654 } else if (is_a<Integer>(*a)
655 and down_cast<const Integer &>(*a).is_positive()) {
656 return boolean(true);
657 } else {
658 return boolean(false);
659 }
660}
661
662hash_t Naturals::__hash__() const
663{
664 hash_t seed = SYMENGINE_NATURALS;
665 return seed;
666}
667
668bool Naturals::__eq__(const Basic &o) const
669{
670 if (is_a<Naturals>(o))
671 return true;
672 return false;
673}
674
675int Naturals::compare(const Basic &o) const
676{
677 SYMENGINE_ASSERT(is_a<Naturals>(o))
678 return 0;
679}
680
681const RCP<const Naturals> &Naturals::getInstance()
682{
683 const static auto a = make_rcp<const Naturals>();
684 return a;
685}
686
687RCP<const Set> Naturals0::set_intersection(const RCP<const Set> &o) const
688{
689 if (is_a<EmptySet>(*o) or is_a<Naturals>(*o) or is_a<Naturals0>(*o)) {
690 return o;
691 } else if (is_a<Integers>(*o) or is_a<Complexes>(*o) or is_a<Reals>(*o)
692 or is_a<Rationals>(*o)) {
693 return naturals0();
694 } else if (is_a<FiniteSet>(*o) or is_a<Interval>(*o)) {
695 return (*o).set_intersection(rcp_from_this_cast<const Set>());
696 } else {
697 return SymEngine::set_intersection(
698 {rcp_from_this_cast<const Set>(), o});
699 }
700}
701
702RCP<const Set> Naturals0::set_union(const RCP<const Set> &o) const
703{
704 if (is_a<EmptySet>(*o) or is_a<Naturals>(*o)) {
705 return naturals0();
706 } else if (is_a<Naturals0>(*o) or is_a<Integers>(*o) or is_a<Complexes>(*o)
707 or is_a<Reals>(*o) or is_a<Rationals>(*o)
708 or is_a<UniversalSet>(*o)) {
709 return o;
710 } else if (is_a<FiniteSet>(*o)) {
711 return (*o).set_union(rcp_from_this_cast<const Set>());
712 } else {
713 return SymEngine::make_set_union({rcp_from_this_cast<const Set>(), o});
714 }
715}
716
717RCP<const Set> Naturals0::set_complement(const RCP<const Set> &o) const
718{
719 if (is_a<EmptySet>(*o) or is_a<Naturals0>(*o) or is_a<Naturals>(*o)) {
720 return emptyset();
721 }
722 if (is_a<UniversalSet>(*o) or is_a<Integers>(*o) or is_a<Rationals>(*o)
723 or is_a<Reals>(*o) or is_a<Complexes>(*o)) {
724 return make_rcp<const Complement>(o, naturals());
725 }
726 return SymEngine::set_complement_helper(rcp_from_this_cast<const Set>(), o);
727}
728
729RCP<const Boolean> Naturals0::contains(const RCP<const Basic> &a) const
730{
731 if (not is_a_Number(*a)) {
732 if (is_a_Set(*a)) {
733 return boolean(false);
734 } else {
735 return make_rcp<Contains>(a, rcp_from_this_cast<const Set>());
736 }
737 } else if (is_a<Integer>(*a)
738 and (not down_cast<const Integer &>(*a).is_negative())) {
739 return boolean(true);
740 } else {
741 return boolean(false);
742 }
743}
744
745hash_t Naturals0::__hash__() const
746{
747 hash_t seed = SYMENGINE_NATURALS0;
748 return seed;
749}
750
751bool Naturals0::__eq__(const Basic &o) const
752{
753 if (is_a<Naturals0>(o))
754 return true;
755 return false;
756}
757
758int Naturals0::compare(const Basic &o) const
759{
760 SYMENGINE_ASSERT(is_a<Naturals0>(o))
761 return 0;
762}
763
764const RCP<const Naturals0> &Naturals0::getInstance()
765{
766 const static auto a = make_rcp<const Naturals0>();
767 return a;
768}
769
770RCP<const Set> EmptySet::set_intersection(const RCP<const Set> &o) const
771{
772 return emptyset();
773}
774
775RCP<const Set> EmptySet::set_union(const RCP<const Set> &o) const
776{
777 return o;
778}
779
780RCP<const Set> EmptySet::set_complement(const RCP<const Set> &o) const
781{
782 return o;
783}
784
785hash_t EmptySet::__hash__() const
786{
787 hash_t seed = SYMENGINE_EMPTYSET;
788 return seed;
789}
790
791bool EmptySet::__eq__(const Basic &o) const
792{
793 if (is_a<EmptySet>(o))
794 return true;
795 return false;
796}
797
798int EmptySet::compare(const Basic &o) const
799{
800 SYMENGINE_ASSERT(is_a<EmptySet>(o))
801 return 0;
802}
803
804const RCP<const EmptySet> &EmptySet::getInstance()
805{
806 const static auto a = make_rcp<const EmptySet>();
807 return a;
808}
809
810RCP<const Set> UniversalSet::set_intersection(const RCP<const Set> &o) const
811{
812 return o;
813}
814
815RCP<const Set> UniversalSet::set_union(const RCP<const Set> &o) const
816{
817 return universalset();
818}
819
820RCP<const Set> UniversalSet::set_complement(const RCP<const Set> &o) const
821{
822 return emptyset();
823}
824
825hash_t UniversalSet::__hash__() const
826{
827 hash_t seed = SYMENGINE_UNIVERSALSET;
828 return seed;
829}
830
831bool UniversalSet::__eq__(const Basic &o) const
832{
833 if (is_a<UniversalSet>(o))
834 return true;
835 return false;
836}
837
838int UniversalSet::compare(const Basic &o) const
839{
840 SYMENGINE_ASSERT(is_a<UniversalSet>(o))
841 return 0;
842}
843
844const RCP<const UniversalSet> &UniversalSet::getInstance()
845{
846 const static auto a = make_rcp<const UniversalSet>();
847 return a;
848}
849
850FiniteSet::FiniteSet(const set_basic &container) : container_(container)
851{
852 SYMENGINE_ASSIGN_TYPEID()
853 SYMENGINE_ASSERT(FiniteSet::is_canonical(container_));
854}
855
856bool FiniteSet::is_canonical(const set_basic &container)
857{
858 return container.size() != 0;
859}
860
862{
863 hash_t seed = SYMENGINE_FINITESET;
864 for (const auto &a : container_)
865 hash_combine<Basic>(seed, *a);
866 return seed;
867}
868
869bool FiniteSet::__eq__(const Basic &o) const
870{
871 if (is_a<FiniteSet>(o)) {
872 const FiniteSet &other = down_cast<const FiniteSet &>(o);
873 return unified_eq(container_, other.container_);
874 }
875 return false;
876}
877
878int FiniteSet::compare(const Basic &o) const
879{
880 // compares two FiniteSet based on their length
881 SYMENGINE_ASSERT(is_a<FiniteSet>(o))
882 const FiniteSet &other = down_cast<const FiniteSet &>(o);
883 return unified_compare(container_, other.container_);
884}
885
886RCP<const Boolean> FiniteSet::contains(const RCP<const Basic> &a) const
887{
888 set_basic rest;
889 for (const auto &elem : container_) {
890 auto cont = Eq(elem, a);
891 if (eq(*cont, *boolTrue))
892 return boolTrue;
893 if (not eq(*cont, *boolFalse))
894 rest.insert(elem);
895 }
896 if (rest.empty()) {
897 return boolFalse;
898 } else {
899 return make_rcp<Contains>(a, finiteset(rest));
900 }
901}
902
903RCP<const Set> FiniteSet::set_union(const RCP<const Set> &o) const
904{
905 if (is_a<FiniteSet>(*o)) {
906 const FiniteSet &other = down_cast<const FiniteSet &>(*o);
907 set_basic container;
908 std::set_union(container_.begin(), container_.end(),
909 other.container_.begin(), other.container_.end(),
910 std::inserter(container, container.begin()),
911 RCPBasicKeyLess{});
912 return finiteset(container);
913 }
914 if (is_a<Interval>(*o)) {
915 set_basic container;
916 const Interval &other = down_cast<const Interval &>(*o);
917 bool left = other.get_left_open(), right = other.get_right_open();
918 for (const auto &a : container_) {
919 auto contain = o->contains(a);
920 if (eq(*contain, *boolFalse)) {
921 if (left)
922 if (eq(*other.get_start(), *a)) {
923 left = false;
924 continue;
925 }
926 if (right)
927 if (eq(*other.get_end(), *a)) {
928 right = false;
929 continue;
930 }
931 container.insert(a);
932 } else if (is_a<Contains>(*contain)) {
933 container.insert(a);
934 }
935 }
936 if (not container.empty()) {
937 if (left == other.get_left_open()
938 and right == other.get_right_open()) {
939 return SymEngine::make_set_union({finiteset(container), o});
940 } else {
941 return SymEngine::make_set_union(
942 set_set({finiteset(container),
943 interval(other.get_start(), other.get_end(), left,
944 right)}));
945 }
946 } else {
947 if (left == other.get_left_open()
948 and right == other.get_right_open()) {
949 return o;
950 } else {
951 return interval(other.get_start(), other.get_end(), left,
952 right);
953 }
954 }
955 }
956 if (is_a<Complexes>(*o)) {
957 set_basic container;
958 for (const auto &elem : container_) {
959 if (!is_a_Number(*elem)) {
960 container.insert(elem);
961 }
962 }
963 if (container.empty()) {
964 return complexes();
965 } else {
966 return SymEngine::make_set_union(
967 {complexes(), finiteset(container)});
968 }
969 }
970 if (is_a<Reals>(*o)) {
971 set_basic container;
972 for (const auto &elem : container_) {
973 if (!is_a_Number(*elem)
974 || down_cast<const Number &>(*elem).is_complex()) {
975 container.insert(elem);
976 }
977 }
978 if (container.empty()) {
979 return reals();
980 } else {
981 return SymEngine::make_set_union({reals(), finiteset(container)});
982 }
983 }
984 if (is_a<Rationals>(*o)) {
985 set_basic container;
986 for (const auto &elem : container_) {
987 if (!is_a_Number(*elem)
988 || down_cast<const Number &>(*elem).is_complex()) {
989 container.insert(elem);
990 }
991 }
992 if (container.empty()) {
993 return rationals();
994 } else {
995 return SymEngine::make_set_union(
996 {rationals(), finiteset(container)});
997 }
998 }
999 if (is_a<Integers>(*o) or is_a<Naturals>(*o) or is_a<Naturals0>(*o)) {
1000 set_basic container;
1001 for (const auto &elem : container_) {
1002 if (is_a<Integers>(*o)) {
1003 if (not is_a<Integer>(*elem)) {
1004 container.insert(elem);
1005 }
1006 } else if (is_a<Naturals>(*o)) {
1007 if (not(is_a<Integer>(*elem)
1008 and down_cast<const Integer &>(*elem).is_positive())) {
1009 container.insert(elem);
1010 }
1011 } else {
1012 if (not(is_a<Integer>(*elem)
1013 and not down_cast<const Integer &>(*elem)
1014 .is_negative())) {
1015 container.insert(elem);
1016 }
1017 }
1018 }
1019 if (container.empty()) {
1020 return o;
1021 } else {
1022 return SymEngine::make_set_union({o, finiteset(container)});
1023 }
1024 }
1025 if (is_a<UniversalSet>(*o) or is_a<EmptySet>(*o) or is_a<Union>(*o)) {
1026 return (*o).set_union(rcp_from_this_cast<const Set>());
1027 }
1028 return SymEngine::make_set_union({rcp_from_this_cast<const Set>(), o});
1029}
1030
1031RCP<const Set> FiniteSet::set_intersection(const RCP<const Set> &o) const
1032{
1033 if (is_a<FiniteSet>(*o)) {
1034 return SymEngine::set_intersection(
1035 {rcp_from_this_cast<const Set>(), o});
1036 }
1037 if (is_a<Interval>(*o)) {
1038 set_basic container;
1039 for (const auto &a : container_) {
1040 auto contain = o->contains(a);
1041 if (eq(*contain, *boolTrue))
1042 container.insert(a);
1043 if (is_a<Contains>(*contain))
1044 return make_set_intersection(
1045 {rcp_from_this_cast<const Set>(), o});
1046 }
1047 return finiteset(container);
1048 }
1049 if (is_a<Complexes>(*o) or is_a<Reals>(*o) or is_a<Rationals>(*o)) {
1050 set_basic kept;
1051 set_basic others;
1052 for (const auto &elem : container_) {
1053 if (is_a_Number(*elem)) {
1054 if (!down_cast<const Number &>(*elem).is_complex()) {
1055 if (!is_a<Rationals>(*o)
1056 or down_cast<const Number &>(*elem).is_exact()) {
1057 kept.insert(elem);
1058 }
1059 } else {
1060 if (is_a<Complexes>(*o)) {
1061 kept.insert(elem);
1062 }
1063 }
1064 } else {
1065 others.insert(elem);
1066 }
1067 }
1068 if (kept.empty()) {
1069 if (others.empty()) {
1070 return emptyset();
1071 } else {
1072 return SymEngine::make_set_intersection({o, finiteset(others)});
1073 }
1074 } else {
1075 if (others.empty()) {
1076 return finiteset(kept);
1077 } else {
1078 others.insert(kept.begin(), kept.end());
1079 return SymEngine::make_set_intersection({o, finiteset(others)});
1080 }
1081 }
1082 }
1083 if (is_a<Integers>(*o) or is_a<Naturals>(*o) or is_a<Naturals0>(*o)) {
1084 set_basic kept_integers;
1085 set_basic others;
1086 for (const auto &elem : container_) {
1087 if (is_a_Number(*elem)) {
1088 if (is_a<Integers>(*o) and is_a<Integer>(*elem)) {
1089 kept_integers.insert(elem);
1090 } else if (is_a<Naturals>(*o) and is_a<Integer>(*elem)
1091 and down_cast<const Integer &>(*elem)
1092 .is_positive()) {
1093 kept_integers.insert(elem);
1094 } else if (is_a<Naturals0>(*o) and is_a<Integer>(*elem)
1095 and (not down_cast<const Integer &>(*elem)
1096 .is_negative())) {
1097 kept_integers.insert(elem);
1098 }
1099 } else {
1100 others.insert(elem);
1101 }
1102 }
1103 if (kept_integers.empty()) {
1104 if (others.empty()) {
1105 return emptyset();
1106 } else {
1107 return SymEngine::make_set_intersection(
1108 {integers(), finiteset(others)});
1109 }
1110 } else {
1111 if (others.empty()) {
1112 return finiteset(kept_integers);
1113 } else {
1114 others.insert(kept_integers.begin(), kept_integers.end());
1115 return SymEngine::make_set_intersection(
1116 {integers(), finiteset(others)});
1117 }
1118 }
1119 }
1120 if (is_a<UniversalSet>(*o) or is_a<EmptySet>(*o) or is_a<Union>(*o)) {
1121 return (*o).set_intersection(rcp_from_this_cast<const Set>());
1122 }
1123 return make_set_intersection({rcp_from_this_cast<const Set>(), o});
1124}
1125
1126RCP<const Set> FiniteSet::set_complement(const RCP<const Set> &o) const
1127{
1128 if (is_a<FiniteSet>(*o)) {
1129 const FiniteSet &other = down_cast<const FiniteSet &>(*o);
1130 set_basic container;
1131 std::set_difference(other.container_.begin(), other.container_.end(),
1132 container_.begin(), container_.end(),
1133 std::inserter(container, container.begin()),
1134 RCPBasicKeyLess{});
1135 return finiteset(container);
1136 }
1137
1138 if (is_a<Interval>(*o)) {
1139 set_set intervals;
1140 auto &other = down_cast<const Interval &>(*o);
1141 RCP<const Number> last = other.get_start();
1142 RCP<const Number> a_num;
1143 set_basic rest;
1144 bool left_open = other.get_left_open(),
1145 right_open = other.get_right_open();
1146 for (auto it = container_.begin(); it != container_.end(); it++) {
1147 if (eq(*max({*it, other.get_start()}), *other.get_start())) {
1148 if (eq(**it, *other.get_start()))
1149 left_open = true;
1150 continue;
1151 }
1152 if (eq(*max({*it, other.get_end()}), **it)) {
1153 if (eq(**it, *other.get_end()))
1154 right_open = true;
1155 break;
1156 }
1157 if (is_a_Number(**it)) {
1158 a_num = rcp_static_cast<const Number>(*it);
1159 intervals.insert(interval(last, a_num, left_open, true));
1160 last = a_num;
1161 left_open = true;
1162 } else {
1163 rest.insert(*it);
1164 }
1165 }
1166
1167 if (eq(*max({last, other.get_end()}), *other.get_end())) {
1168 intervals.insert(
1169 interval(last, other.get_end(), left_open, right_open));
1170 }
1171 if (rest.empty()) {
1172 return SymEngine::make_set_union(intervals);
1173 } else {
1174 return make_rcp<const Complement>(
1175 SymEngine::make_set_union(intervals), finiteset(rest));
1176 }
1177 }
1178
1179 return SymEngine::set_complement_helper(rcp_from_this_cast<const Set>(), o);
1180}
1181
1182RCP<const Set> FiniteSet::create(const set_basic &container) const
1183{
1184 return finiteset(container);
1185}
1186
1187Union::Union(const set_set &in)
1188 : container_(in){SYMENGINE_ASSIGN_TYPEID()
1189 SYMENGINE_ASSERT(Union::is_canonical(in))}
1190
1191 hash_t Union::__hash__() const
1192{
1193 hash_t seed = SYMENGINE_UNION;
1194 for (const auto &a : container_)
1195 hash_combine<Basic>(seed, *a);
1196 return seed;
1197}
1198
1199bool Union::__eq__(const Basic &o) const
1200{
1201 if (is_a<Union>(o)) {
1202 const Union &other = down_cast<const Union &>(o);
1203 return unified_eq(container_, other.container_);
1204 }
1205 return false;
1206}
1207
1208bool Union::is_canonical(const set_set &in)
1209{
1210 if (in.size() <= 1)
1211 return false;
1212 int count = 0;
1213 for (const auto &s : in) {
1214 if (is_a<FiniteSet>(*s)) {
1215 count++;
1216 }
1217 if (count >= 2)
1218 return false;
1219 }
1220 return true;
1221}
1222
1223int Union::compare(const Basic &o) const
1224{
1225 SYMENGINE_ASSERT(is_a<Union>(o))
1226 const Union &other = down_cast<const Union &>(o);
1227 return unified_compare(container_, other.container_);
1228}
1229
1230RCP<const Set> Union::set_union(const RCP<const Set> &o) const
1231{
1232 set_set container(container_);
1233 for (auto iter = container.begin(); iter != container.end(); ++iter) {
1234 auto temp = o->set_union(*iter);
1235 // If we are able to do union with `*iter`, we replace `*iter` with
1236 // the result of union.
1237 auto un = SymEngine::make_set_union({o, *iter});
1238 if (not eq(*temp, *un)) {
1239 iter = container.erase(iter);
1240 container.insert(temp);
1241 return SymEngine::set_union(container);
1242 }
1243 }
1244 container.insert(o);
1245 return SymEngine::make_set_union(container);
1246}
1247
1248RCP<const Set> Union::set_intersection(const RCP<const Set> &o) const
1249{
1250 set_set container;
1251 for (auto &a : container_) {
1252 container.insert(a->set_intersection(o));
1253 }
1254 return SymEngine::set_union(container);
1255}
1256
1257RCP<const Set> Union::set_complement(const RCP<const Set> &o) const
1258{
1259 set_set container;
1260 for (auto &a : container_) {
1261 container.insert(a->set_complement(o));
1262 }
1263 return SymEngine::set_intersection(container);
1264}
1265
1266RCP<const Boolean> Union::contains(const RCP<const Basic> &o) const
1267{
1268 for (auto &a : container_) {
1269 auto contain = a->contains(o);
1270 if (eq(*contain, *boolTrue)) {
1271 return boolean(true);
1272 }
1273 if (is_a<Contains>(*contain))
1274 throw NotImplementedError("Not implemented");
1275 }
1276 return boolean(false);
1277}
1278
1279RCP<const Set> Union::create(const set_set &in) const
1280{
1281 return SymEngine::set_union(in);
1282}
1283
1285{
1286 vec_basic v(container_.begin(), container_.end());
1287 return v;
1288}
1289
1290Intersection::Intersection(const set_set &in)
1291 : container_(in){SYMENGINE_ASSIGN_TYPEID()
1292 SYMENGINE_ASSERT(Intersection::is_canonical(in))}
1293
1294 hash_t Intersection::__hash__() const
1295{
1296 hash_t seed = SYMENGINE_INTERSECTION;
1297 for (const auto &a : container_)
1298 hash_combine<Basic>(seed, *a);
1299 return seed;
1300}
1301
1302bool Intersection::__eq__(const Basic &o) const
1303{
1304 if (is_a<Intersection>(o)) {
1305 const Intersection &other = down_cast<const Intersection &>(o);
1306 return unified_eq(container_, other.container_);
1307 }
1308 return false;
1309}
1310
1311bool Intersection::is_canonical(const set_set &in)
1312{
1313 if (in.size() <= 1)
1314 return false;
1315 return true;
1316}
1317
1318int Intersection::compare(const Basic &o) const
1319{
1320 SYMENGINE_ASSERT(is_a<Intersection>(o))
1321 const Intersection &other = down_cast<const Intersection &>(o);
1322 return unified_compare(container_, other.container_);
1323}
1324
1325RCP<const Set> Intersection::set_union(const RCP<const Set> &o) const
1326{
1327 set_set container;
1328 for (auto &a : container_) {
1329 container.insert(a->set_union(o));
1330 }
1331 return SymEngine::set_intersection(container);
1332}
1333
1334RCP<const Set> Intersection::set_intersection(const RCP<const Set> &o) const
1335{
1336 set_set container(container_);
1337 for (auto iter = container.begin(); iter != container.end(); ++iter) {
1338 auto temp = o->set_intersection(*iter);
1339 // If we are able to do intersection with `*iter`, we replace `*iter`
1340 // with the result of intersection.
1341 auto un = SymEngine::make_set_intersection({o, *iter});
1342 if (not eq(*temp, *un)) {
1343 iter = container.erase(iter);
1344 container.insert(temp);
1345 return SymEngine::set_intersection(container);
1346 }
1347 }
1348 container.insert(o);
1349 return SymEngine::make_set_intersection(container);
1350}
1351
1352RCP<const Set> Intersection::set_complement(const RCP<const Set> &o) const
1353{
1354 set_set container;
1355 for (auto &a : container_) {
1356 container.insert(a->set_complement(o));
1357 }
1358 return SymEngine::set_intersection(container);
1359}
1360
1361RCP<const Boolean> Intersection::contains(const RCP<const Basic> &o) const
1362{
1363 for (auto &a : container_) {
1364 auto contain = a->contains(o);
1365 if (eq(*contain, *boolTrue)) {
1366 return boolean(true);
1367 }
1368 if (is_a<Contains>(*contain))
1369 throw NotImplementedError("Not implemented");
1370 }
1371 return boolean(false);
1372}
1373
1374RCP<const Set> Intersection::create(const set_set &in) const
1375{
1376 return SymEngine::set_intersection(in);
1377}
1378
1380{
1381 vec_basic v(container_.begin(), container_.end());
1382 return v;
1383}
1384
1385Complement::Complement(const RCP<const Set> &universe,
1386 const RCP<const Set> &container)
1387 : universe_(universe), container_(container){SYMENGINE_ASSIGN_TYPEID()}
1388
1390{
1391 hash_t seed = SYMENGINE_COMPLEMENT;
1392 hash_combine<Basic>(seed, *universe_);
1393 hash_combine<Basic>(seed, *container_);
1394 return seed;
1395}
1396
1397bool Complement::__eq__(const Basic &o) const
1398{
1399 if (is_a<Complement>(o)) {
1400 const Complement &other = down_cast<const Complement &>(o);
1401 return unified_eq(universe_, other.universe_)
1402 and unified_eq(container_, other.container_);
1403 }
1404 return false;
1405}
1406
1407int Complement::compare(const Basic &o) const
1408{
1409 SYMENGINE_ASSERT(is_a<Complement>(o))
1410 const Complement &other = down_cast<const Complement &>(o);
1411 int c1 = unified_compare(universe_, other.universe_);
1412 if (c1 != 0) {
1413 return c1;
1414 } else {
1415 return unified_compare(container_, other.container_);
1416 }
1417}
1418
1419RCP<const Boolean> Complement::contains(const RCP<const Basic> &a) const
1420{
1421 return logical_and(
1422 {universe_->contains(a), logical_not(container_->contains(a))});
1423}
1424
1425RCP<const Set> Complement::set_union(const RCP<const Set> &o) const
1426{
1427 // A' U C = (A n C')'
1428 RCP<const Set> ocomplement = o->set_complement(universe_);
1429 RCP<const Set> intersect
1430 = SymEngine::set_intersection({container_, ocomplement});
1431 return intersect->set_complement(universe_);
1432}
1433
1434RCP<const Set> Complement::set_intersection(const RCP<const Set> &o) const
1435{
1436 return SymEngine::set_intersection({rcp_from_this_cast<const Set>(), o});
1437}
1438
1439RCP<const Set> Complement::set_complement(const RCP<const Set> &o) const
1440{
1441 auto newuniv = SymEngine::set_union({o, universe_});
1442 return container_->set_complement(newuniv);
1443}
1444
1445ConditionSet::ConditionSet(const RCP<const Basic> &sym,
1446 const RCP<const Boolean> &condition)
1447 : sym(sym), condition_(condition)
1448{
1449 SYMENGINE_ASSIGN_TYPEID()
1450 SYMENGINE_ASSERT(ConditionSet::is_canonical(sym, condition))
1451}
1452
1453bool ConditionSet::is_canonical(const RCP<const Basic> &sym,
1454 const RCP<const Boolean> &condition)
1455{
1456 if (eq(*condition, *boolFalse) or eq(*condition, *boolTrue)
1457 or not is_a_sub<Symbol>(*sym)) {
1458 return false;
1459 } else if (is_a<Contains>(*condition)) {
1460 return false;
1461 }
1462 return true;
1463}
1464
1466{
1467 hash_t seed = SYMENGINE_CONDITIONSET;
1468 hash_combine<Basic>(seed, *sym);
1469 hash_combine<Basic>(seed, *condition_);
1470 return seed;
1471}
1472
1473bool ConditionSet::__eq__(const Basic &o) const
1474{
1475 if (is_a<ConditionSet>(o)) {
1476 const ConditionSet &other = down_cast<const ConditionSet &>(o);
1477 return unified_eq(sym, other.get_symbol())
1478 and unified_eq(condition_, other.get_condition());
1479 }
1480 return false;
1481}
1482
1483int ConditionSet::compare(const Basic &o) const
1484{
1485 SYMENGINE_ASSERT(is_a<ConditionSet>(o))
1486 const ConditionSet &other = down_cast<const ConditionSet &>(o);
1487 int c1 = unified_compare(sym, other.get_symbol());
1488 if (c1 != 0) {
1489 return c1;
1490 } else {
1491 return unified_compare(condition_, other.get_condition());
1492 }
1493}
1494
1495RCP<const Set> ConditionSet::set_union(const RCP<const Set> &o) const
1496{
1497 return SymEngine::make_set_union({o, rcp_from_this_cast<const Set>()});
1498}
1499
1500RCP<const Set> ConditionSet::set_intersection(const RCP<const Set> &o) const
1501{
1502 if (not is_a<ConditionSet>(*o)) {
1503 return conditionset(sym, logical_and({condition_, o->contains(sym)}));
1504 }
1505 return make_set_intersection({rcp_from_this_cast<const Set>(), o});
1506}
1507
1508RCP<const Set> ConditionSet::set_complement(const RCP<const Set> &o) const
1509{
1510 return make_rcp<const Complement>(o, rcp_from_this_cast<const Set>());
1511}
1512
1513RCP<const Boolean> ConditionSet::contains(const RCP<const Basic> &o) const
1514{
1515 map_basic_basic d;
1516 d[sym] = o;
1517 auto cond = condition_->subs(d);
1518 if (not is_a_Boolean(*cond)) {
1519 throw SymEngineException("expected an object of type Boolean");
1520 }
1521 return rcp_static_cast<const Boolean>(cond);
1522}
1523
1524ImageSet::ImageSet(const RCP<const Basic> &sym, const RCP<const Basic> &expr,
1525 const RCP<const Set> &base)
1526 : sym_(sym), expr_(expr), base_(base)
1527{
1528 SYMENGINE_ASSIGN_TYPEID()
1529 SYMENGINE_ASSERT(ImageSet::is_canonical(sym, expr, base));
1530}
1531
1532hash_t ImageSet::__hash__() const
1533{
1534 hash_t seed = SYMENGINE_IMAGESET;
1535 hash_combine<Basic>(seed, *sym_);
1536 hash_combine<Basic>(seed, *expr_);
1537 hash_combine<Basic>(seed, *base_);
1538 return seed;
1539}
1540
1541bool ImageSet::__eq__(const Basic &o) const
1542{
1543 if (is_a<ImageSet>(o)) {
1544 const ImageSet &other = down_cast<const ImageSet &>(o);
1545 return unified_eq(sym_, other.sym_) and unified_eq(expr_, other.expr_)
1546 and unified_eq(base_, other.base_);
1547 }
1548 return false;
1549}
1550
1551int ImageSet::compare(const Basic &o) const
1552{
1553 SYMENGINE_ASSERT(is_a<ImageSet>(o))
1554 const ImageSet &other = down_cast<const ImageSet &>(o);
1555 int c1 = unified_compare(sym_, other.sym_);
1556 if (c1 != 0) {
1557 return c1;
1558 } else {
1559 int c2 = unified_compare(expr_, other.expr_);
1560 if (c2 != 0) {
1561 return c2;
1562 } else {
1563 return unified_compare(base_, other.base_);
1564 }
1565 }
1566}
1567
1568bool ImageSet::is_canonical(const RCP<const Basic> &sym,
1569 const RCP<const Basic> &expr,
1570 const RCP<const Set> &base)
1571{
1572 if (not is_a_sub<Symbol>(*sym) or eq(*expr, *sym) or is_a_Number(*expr)
1573 or eq(*base, *emptyset()))
1574 return false;
1575 return true;
1576}
1577
1578RCP<const Boolean> ImageSet::contains(const RCP<const Basic> &a) const
1579{
1580 throw SymEngineException("Not implemented");
1581}
1582
1583RCP<const Set> ImageSet::set_union(const RCP<const Set> &o) const
1584{
1585 return make_set_union({rcp_from_this_cast<const Set>(), o});
1586}
1587
1588RCP<const Set> ImageSet::set_intersection(const RCP<const Set> &o) const
1589{
1590 return SymEngine::set_intersection({rcp_from_this_cast<const Set>(), o});
1591}
1592
1593RCP<const Set> ImageSet::set_complement(const RCP<const Set> &o) const
1594{
1595 return SymEngine::set_complement(rcp_from_this_cast<const Set>(), o);
1596}
1597
1598RCP<const Set> ImageSet::create(const RCP<const Basic> &sym,
1599 const RCP<const Basic> &expr,
1600 const RCP<const Set> &base) const
1601{
1602 return imageset(sym, expr, base);
1603}
1604
1605RCP<const Set> set_union(const set_set &in)
1606{
1607 set_set input;
1608 set_basic combined_FiniteSet;
1609 for (auto it = in.begin(); it != in.end(); ++it) {
1610 if (is_a<FiniteSet>(**it)) {
1611 const FiniteSet &other = down_cast<const FiniteSet &>(**it);
1612 combined_FiniteSet.insert(other.get_container().begin(),
1613 other.get_container().end());
1614 } else if (is_a<UniversalSet>(**it)) {
1615 return universalset();
1616 } else if (not is_a<EmptySet>(**it)) {
1617 input.insert(*it);
1618 }
1619 }
1620 if (input.empty()) {
1621 return finiteset(combined_FiniteSet);
1622 } else if (input.size() == 1 && combined_FiniteSet.empty()) {
1623 return *input.begin();
1624 }
1625 // Now we rely on respective containers' own rules
1626 // TODO: Improve it to O(log n)
1627 RCP<const Set> combined_Rest = finiteset(combined_FiniteSet);
1628 for (auto it = input.begin(); it != input.end(); ++it) {
1629 combined_Rest = combined_Rest->set_union(*it);
1630 }
1631 return combined_Rest;
1632}
1633
1634RCP<const Set> set_intersection(const set_set &in)
1635{
1636 // https://en.wikipedia.org/wiki/Intersection_(set_theory)#Nullary_intersection
1637 if (in.empty())
1638 return universalset();
1639
1640 // Global rules
1641 // If found any emptyset then return emptyset
1642 set_set incopy;
1643 for (const auto &input : in) {
1644 if (is_a<EmptySet>(*input)) {
1645 return emptyset();
1646 } else if (not is_a<UniversalSet>(*input)) {
1647 incopy.insert(input);
1648 }
1649 }
1650
1651 if (incopy.empty())
1652 return universalset();
1653 if (incopy.size() == 1)
1654 return *incopy.begin();
1655
1656 // Handle finite sets
1657 std::vector<RCP<const Set>> fsets, othersets;
1658 for (const auto &input : incopy) {
1659 if (is_a<FiniteSet>(*input)) {
1660 fsets.push_back(input);
1661 } else {
1662 othersets.push_back(input);
1663 }
1664 }
1665 if (fsets.size() != 0) {
1666 const FiniteSet &fs = down_cast<const FiniteSet &>(**fsets.begin());
1667 auto cont = fs.get_container();
1668 fsets.erase(fsets.begin());
1669 set_basic finalfs;
1670 for (const auto &fselement : cont) {
1671 bool present = true;
1672 for (const auto &fset : fsets) {
1673 auto contain = fset->contains(fselement);
1674 if (not(eq(*contain, *boolTrue) or eq(*contain, *boolFalse))) {
1675 return make_set_intersection(incopy);
1676 }
1677 present = present and eq(*contain, *boolTrue);
1678 }
1679 if (!present)
1680 continue;
1681 for (const auto &oset : othersets) {
1682 auto contain = oset->contains(fselement);
1683 if (not(eq(*contain, *boolTrue) or eq(*contain, *boolFalse))) {
1684 return make_set_intersection(incopy);
1685 }
1686 present = present and eq(*contain, *boolTrue);
1687 }
1688 if (present)
1689 finalfs.insert(fselement);
1690 }
1691 return finiteset(finalfs);
1692 }
1693
1694 // If any of the sets is union, then return a Union of Intersections
1695 for (auto it = incopy.begin(); it != incopy.end(); ++it) {
1696 if (is_a<Union>(**it)) {
1697 auto container = down_cast<const Union &>(**it).get_container();
1698 incopy.erase(it);
1699 auto other = SymEngine::set_intersection(incopy);
1700 set_set usets;
1701 for (const auto &c : container) {
1702 usets.insert(SymEngine::set_intersection({c, other}));
1703 }
1704 return SymEngine::set_union(usets);
1705 }
1706 }
1707
1708 // Simplify and return a `Complement` if any of the sets is a complement
1709 for (auto it = incopy.begin(); it != incopy.end(); ++it) {
1710 if (is_a<Complement>(**it)) {
1711 auto container
1712 = down_cast<const Complement &>(**it).get_container();
1713 auto universe = down_cast<const Complement &>(**it).get_universe();
1714 incopy.erase(it);
1715 incopy.insert(universe);
1716 auto other = SymEngine::set_intersection(incopy);
1717 return SymEngine::set_complement(other, container);
1718 }
1719 }
1720
1721 // Pair-wise rules
1722 // TO-DO: needs the following improvement once Intersection
1723 // class is implemented.
1724 // input_oset if found to be not simplified, then skip this
1725 // pair.
1726 if (incopy.size() > 1) {
1727 auto temp = *incopy.begin();
1728 auto it = std::next(incopy.begin());
1729 for (; it != incopy.end(); ++it) {
1730 temp = temp->set_intersection(*it);
1731 }
1732 return temp;
1733 }
1734
1735 return make_set_intersection(incopy);
1736}
1737
1738// helper to avoid redundant code
1739RCP<const Set> set_complement_helper(const RCP<const Set> &container,
1740 const RCP<const Set> &universe)
1741{
1742 if (is_a<Union>(*universe)) {
1743 auto univ = down_cast<const Union &>(*universe).get_container();
1744 set_set container_;
1745 for (auto &a : univ) {
1746 container_.insert(container->set_complement(a));
1747 }
1748 return SymEngine::set_union(container_);
1749 } else if (is_a<EmptySet>(*universe)) {
1750 return emptyset();
1751 } else if (is_a<FiniteSet>(*universe)) {
1752 const FiniteSet &other = down_cast<const FiniteSet &>(*universe);
1753 set_basic container_;
1754 set_basic rest;
1755 for (const auto &a : other.get_container()) {
1756 auto contain = container->contains(a);
1757 if (eq(*contain, *boolFalse)) {
1758 container_.insert(a);
1759 } else if (is_a<Contains>(*contain)) {
1760 rest.insert(a);
1761 }
1762 }
1763 if (rest.empty()) {
1764 return finiteset(container_);
1765 } else {
1766 return SymEngine::set_union(
1767 {finiteset(container_),
1768 make_rcp<const Complement>(finiteset(rest), container)});
1769 }
1770 }
1771 return make_rcp<const Complement>(universe, container);
1772}
1773
1774RCP<const Set> set_complement(const RCP<const Set> &universe,
1775 const RCP<const Set> &container)
1776{
1777 // represents universe - container
1778 return container->set_complement(universe);
1779}
1780
1781RCP<const Set> conditionset(const RCP<const Basic> &sym,
1782 const RCP<const Boolean> &condition)
1783{
1784 if (eq(*condition, *boolean(false))) {
1785 return emptyset();
1786 } else if (eq(*condition, *boolean(true))) {
1787 return universalset();
1788 }
1789 if (is_a<And>(*condition)) {
1790 auto cont = down_cast<const And &>(*condition).get_container();
1791 set_boolean newcont;
1792 set_basic present, others;
1793 for (auto it = cont.begin(); it != cont.end(); it++) {
1794 if (is_a<Contains>(**it)
1795 and eq(*down_cast<const Contains &>(**it).get_expr(), *sym)
1796 and is_a<FiniteSet>(
1797 *down_cast<const Contains &>(**it).get_set())) {
1798 auto fset = down_cast<const Contains &>(**it).get_set();
1799 auto fcont
1800 = down_cast<const FiniteSet &>(*fset).get_container();
1801 // use the result of simplification done in `logical_and()`
1802 for (const auto &elem : fcont) {
1803 if (not(is_a_Number(*elem) or is_a<Constant>(*elem))) {
1804 others.insert(elem);
1805 } else {
1806 // logical_and() doesn't guarantee that if element of a
1807 // finiteset is a number, then it satisfies other
1808 // conditions
1809 // it only assures that there doesn't exist any such
1810 // element of finiteset that surely fails in other
1811 // conditions.
1812 auto restCont = cont;
1813 restCont.erase(*it);
1814 auto restCond = logical_and(restCont);
1816 d[sym] = elem;
1817 auto contain = restCond->subs(d);
1818 if (eq(*contain, *boolean(true))) {
1819 present.insert(elem);
1820 } else if (not eq(*contain, *boolean(false))) {
1821 others.insert(elem);
1822 } else {
1823 throw SymEngineException("element should have "
1824 "been removed within "
1825 "logical_and()");
1826 }
1827 }
1828 }
1829 } else {
1830 newcont.insert(*it);
1831 }
1832 }
1833 if (not present.empty()) {
1834 newcont.insert(finiteset(others)->contains(sym));
1835 return SymEngine::set_union(
1836 {finiteset(present), conditionset(sym, logical_and(newcont))});
1837 }
1838 }
1839 if (is_a<Contains>(*condition)) {
1840 return down_cast<const Contains &>(*condition).get_set();
1841 }
1842 return make_rcp<const ConditionSet>(sym, condition);
1843}
1844
1845} // namespace SymEngine
Classes and functions relating to the binary operation of addition.
T begin(T... args)
The lowest unit of symbolic representation.
Definition: basic.h:97
int compare(const Basic &o) const override
Definition: sets.cpp:1407
bool __eq__(const Basic &o) const override
Test equality.
Definition: sets.cpp:1397
hash_t __hash__() const override
Definition: sets.cpp:1389
int compare(const Basic &o) const override
Definition: sets.cpp:1483
bool __eq__(const Basic &o) const override
Test equality.
Definition: sets.cpp:1473
hash_t __hash__() const override
Definition: sets.cpp:1465
bool __eq__(const Basic &o) const override
Test equality.
Definition: sets.cpp:869
int compare(const Basic &o) const override
Definition: sets.cpp:878
hash_t __hash__() const override
Definition: sets.cpp:861
bool __eq__(const Basic &o) const override
Test equality.
Definition: sets.cpp:1541
int compare(const Basic &o) const override
Definition: sets.cpp:1551
bool __eq__(const Basic &o) const override
Test equality.
Definition: sets.cpp:1302
vec_basic get_args() const override
Returns the list of arguments.
Definition: sets.cpp:1379
int compare(const Basic &o) const override
Definition: sets.cpp:1318
hash_t __hash__() const override
Definition: sets.cpp:1191
int compare(const Basic &o) const override
Definition: sets.cpp:1223
vec_basic get_args() const override
Returns the list of arguments.
Definition: sets.cpp:1284
bool __eq__(const Basic &o) const override
Test equality.
Definition: sets.cpp:1199
T empty(T... args)
T end(T... args)
T erase(T... args)
T insert(T... args)
T inserter(T... args)
T left(T... args)
T max(T... args)
T min(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
RCP< const Reals > reals()
Definition: sets.h:560
RCP< const EmptySet > emptyset()
Definition: sets.h:590
RCP< const Set > finiteset(const set_basic &container)
Definition: sets.h:602
RCP< const Basic > max(const vec_basic &arg)
Canonicalize Max:
Definition: functions.cpp:3555
bool eq(const Basic &a, const Basic &b)
Checks equality for a and b
Definition: basic-inl.h:21
RCP< const UniversalSet > universalset()
Definition: sets.h:596
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 Naturals0 > naturals0()
Definition: sets.h:584
RCP< const Basic > ceiling(const RCP< const Basic > &arg)
Canonicalize Ceiling:
Definition: functions.cpp:705
RCP< const Integers > integers()
Definition: sets.h:572
RCP< const Naturals > naturals()
Definition: sets.h:578
RCP< const Rationals > rationals()
Definition: sets.h:566
RCP< const Basic > floor(const RCP< const Basic > &arg)
Canonicalize Floor:
Definition: functions.cpp:611
RCP< const Set > conditionset(const RCP< const Basic > &sym, const RCP< const Boolean > &condition)
Definition: sets.cpp:1781
RCP< const Complexes > complexes()
Definition: sets.h:554
RCP< const Basic > add(const RCP< const Basic > &a, const RCP< const Basic > &b)
Adds two objects (safely).
Definition: add.cpp:425
RCP< const Boolean > Eq(const RCP< const Basic > &lhs)
Returns the canonicalized Equality object from a single argument.
Definition: logic.cpp:653
int unified_compare(const T &a, const T &b)
Definition: dict.h:205
bool neq(const Basic &a, const Basic &b)
Checks inequality for a and b
Definition: basic-inl.h:29
std::enable_if< std::is_integral< T >::value, RCP< constInteger > >::type integer(T i)
Definition: integer.h:197
RCP< const Set > interval(const RCP< const Number > &start, const RCP< const Number > &end, const bool left_open=false, const bool right_open=false)
Definition: sets.h:611
T next(T... args)
T push_back(T... args)
T set_difference(T... args)
T set_union(T... args)
T size(T... args)