Loading...
Searching...
No Matches
solve.cpp
1#include <symengine/solve.h>
2#include <symengine/polys/basic_conversions.h>
3#include <symengine/logic.h>
4#include <symengine/mul.h>
5#include <symengine/as_real_imag.cpp>
6
7namespace SymEngine
8{
9
10RCP<const Set> solve_poly_linear(const vec_basic &coeffs,
11 const RCP<const Set> &domain)
12{
13 if (coeffs.size() != 2) {
14 throw SymEngineException("Expected a polynomial of degree 1. Try with "
15 "solve() or solve_poly()");
16 }
17 auto root = neg(div(coeffs[0], coeffs[1]));
18 return set_intersection({domain, finiteset({root})});
19}
20
21RCP<const Set> solve_poly_quadratic(const vec_basic &coeffs,
22 const RCP<const Set> &domain)
23{
24 if (coeffs.size() != 3) {
25 throw SymEngineException("Expected a polynomial of degree 2. Try with "
26 "solve() or solve_poly()");
27 }
28
29 auto a = coeffs[2];
30 auto b = div(coeffs[1], a), c = div(coeffs[0], a);
31 RCP<const Basic> root1, root2;
32 if (eq(*c, *zero)) {
33 root1 = neg(b);
34 root2 = zero;
35 } else if (eq(*b, *zero)) {
36 root1 = sqrt(neg(c));
37 root2 = neg(root1);
38 } else {
39 auto discriminant = sub(mul(b, b), mul(integer(4), c));
40 auto lterm = div(neg(b), integer(2));
41 auto rterm = div(sqrt(discriminant), integer(2));
42 root1 = add(lterm, rterm);
43 root2 = sub(lterm, rterm);
44 }
45 return set_intersection({domain, finiteset({root1, root2})});
46}
47
48RCP<const Set> solve_poly_cubic(const vec_basic &coeffs,
49 const RCP<const Set> &domain)
50{
51 if (coeffs.size() != 4) {
52 throw SymEngineException("Expected a polynomial of degree 3. Try with "
53 "solve() or solve_poly()");
54 }
55
56 auto a = coeffs[3];
57 auto b = div(coeffs[2], a), c = div(coeffs[1], a), d = div(coeffs[0], a);
58
59 // ref :
60 // https://en.wikipedia.org/wiki/Cubic_function#General_solution_to_the_cubic_equation_with_real_coefficients
61 auto i2 = integer(2), i3 = integer(3), i4 = integer(4), i9 = integer(9),
62 i27 = integer(27);
63
64 RCP<const Basic> root1, root2, root3;
65 if (eq(*d, *zero)) {
66 root1 = zero;
67 auto fset = solve_poly_quadratic({c, b, one}, domain);
68 SYMENGINE_ASSERT(is_a<FiniteSet>(*fset));
69 auto cont = down_cast<const FiniteSet &>(*fset).get_container();
70 if (cont.size() == 2) {
71 root2 = *cont.begin();
72 root3 = *std::next(cont.begin());
73 } else {
74 root2 = root3 = *cont.begin();
75 }
76 } else {
77 auto delta0 = sub(mul(b, b), mul(i3, c));
78 auto delta1
79 = add(sub(mul(pow(b, i3), i2), mul({i9, b, c})), mul(i27, d));
80 auto delta = div(sub(mul(i4, pow(delta0, i3)), pow(delta1, i2)), i27);
81 if (eq(*delta, *zero)) {
82 if (eq(*delta0, *zero)) {
83 root1 = root2 = root3 = div(neg(b), i3);
84 } else {
85 root1 = root2
86 = div(sub(mul(i9, d), mul(b, c)), mul(i2, delta0));
87 root3 = div(sub(mul({i4, b, c}), add(mul(d, i9), pow(b, i3))),
88 delta0);
89 }
90 } else {
91 auto temp = sqrt(mul(neg(i27), delta));
92 auto Cexpr = div(add(delta1, temp), i2);
93 if (eq(*Cexpr, *zero)) {
94 Cexpr = div(sub(delta1, temp), i2);
95 }
96 auto C = pow(Cexpr, div(one, i3));
97 root1 = neg(div(add(b, add(C, div(delta0, C))), i3));
98 auto coef = div(mul(I, sqrt(i3)), i2);
99 temp = neg(div(one, i2));
100 auto cbrt1 = add(temp, coef);
101 auto cbrt2 = sub(temp, coef);
102 root2 = neg(div(
103 add(b, add(mul(cbrt1, C), div(delta0, mul(cbrt1, C)))), i3));
104 root3 = neg(div(
105 add(b, add(mul(cbrt2, C), div(delta0, mul(cbrt2, C)))), i3));
106 }
107 }
108 return set_intersection({domain, finiteset({root1, root2, root3})});
109}
110
111RCP<const Set> solve_poly_quartic(const vec_basic &coeffs,
112 const RCP<const Set> &domain)
113{
114 if (coeffs.size() != 5) {
115 throw SymEngineException("Expected a polynomial of degree 4. Try with "
116 "solve() or solve_poly()");
117 }
118
119 auto i2 = integer(2), i3 = integer(3), i4 = integer(4), i8 = integer(8),
120 i16 = integer(16), i64 = integer(64), i256 = integer(256);
121
122 // ref : http://mathforum.org/dr.math/faq/faq.cubic.equations.html
123 auto lc = coeffs[4];
124 auto a = div(coeffs[3], lc), b = div(coeffs[2], lc), c = div(coeffs[1], lc),
125 d = div(coeffs[0], lc);
126 set_basic roots;
127
128 if (eq(*d, *zero)) {
129 vec_basic newcoeffs(4);
130 newcoeffs[0] = c, newcoeffs[1] = b, newcoeffs[2] = a,
131 newcoeffs[3] = one;
132 auto rcubic = solve_poly_cubic(newcoeffs, domain);
133 SYMENGINE_ASSERT(is_a<FiniteSet>(*rcubic));
134 roots = down_cast<const FiniteSet &>(*rcubic).get_container();
135 roots.insert(zero);
136 } else {
137 // substitute x = y-a/4 to get equation of the form y**4 + e*y**2 + f*y
138 // + g = 0
139 auto sqa = mul(a, a);
140 auto cba = mul(sqa, a);
141 auto aby4 = div(a, i4);
142 auto e = sub(b, div(mul(i3, sqa), i8));
143 auto ff = sub(add(c, div(cba, i8)), div(mul(a, b), i2));
144 auto g = sub(add(d, div(mul(sqa, b), i16)),
145 add(div(mul(a, c), i4), div(mul({i3, cba, a}), i256)));
146
147 // two special cases
148 if (eq(*g, *zero)) {
149 vec_basic newcoeffs(4);
150 newcoeffs[0] = ff, newcoeffs[1] = e, newcoeffs[2] = zero,
151 newcoeffs[3] = one;
152 auto rcubic = solve_poly_cubic(newcoeffs, domain);
153 SYMENGINE_ASSERT(is_a<FiniteSet>(*rcubic));
154 auto rtemp = down_cast<const FiniteSet &>(*rcubic).get_container();
155 SYMENGINE_ASSERT(rtemp.size() > 0 and rtemp.size() <= 3);
156 for (auto &r : rtemp) {
157 roots.insert(sub(r, aby4));
158 }
159 roots.insert(neg(aby4));
160 } else if (eq(*ff, *zero)) {
161 vec_basic newcoeffs(3);
162 newcoeffs[0] = g, newcoeffs[1] = e, newcoeffs[2] = one;
163 auto rquad = solve_poly_quadratic(newcoeffs, domain);
164 SYMENGINE_ASSERT(is_a<FiniteSet>(*rquad));
165 auto rtemp = down_cast<const FiniteSet &>(*rquad).get_container();
166 SYMENGINE_ASSERT(rtemp.size() > 0 and rtemp.size() <= 2);
167 for (auto &r : rtemp) {
168 auto sqrtr = sqrt(r);
169 roots.insert(sub(sqrtr, aby4));
170 roots.insert(sub(neg(sqrtr), aby4));
171 }
172 } else {
173 // Leonhard Euler's method
174 vec_basic newcoeffs(4);
175 newcoeffs[0] = neg(div(mul(ff, ff), i64)),
176 newcoeffs[1] = div(sub(mul(e, e), mul(i4, g)), i16),
177 newcoeffs[2] = div(e, i2);
178 newcoeffs[3] = one;
179
180 auto rcubic = solve_poly_cubic(newcoeffs);
181 SYMENGINE_ASSERT(is_a<FiniteSet>(*rcubic));
182 roots = down_cast<const FiniteSet &>(*rcubic).get_container();
183 SYMENGINE_ASSERT(roots.size() > 0 and roots.size() <= 3);
184 auto p = sqrt(*roots.begin());
185 auto q = p;
186 if (roots.size() > 1) {
187 q = sqrt(*std::next(roots.begin()));
188 }
189 auto r = div(neg(ff), mul({i8, p, q}));
190 roots.clear();
191 roots.insert(add({p, q, r, neg(aby4)}));
192 roots.insert(add({p, neg(q), neg(r), neg(aby4)}));
193 roots.insert(add({neg(p), q, neg(r), neg(aby4)}));
194 roots.insert(add({neg(p), neg(q), r, neg(aby4)}));
195 }
196 }
197 return set_intersection({domain, finiteset(roots)});
198}
199
200RCP<const Set> solve_poly_heuristics(const vec_basic &coeffs,
201 const RCP<const Set> &domain)
202{
203 auto degree = coeffs.size() - 1;
204 switch (degree) {
205 case 0: {
206 if (eq(*coeffs[0], *zero)) {
207 return domain;
208 } else {
209 return emptyset();
210 }
211 }
212 case 1:
213 return solve_poly_linear(coeffs, domain);
214 case 2:
215 return solve_poly_quadratic(coeffs, domain);
216 case 3:
217 return solve_poly_cubic(coeffs, domain);
218 case 4:
219 return solve_poly_quartic(coeffs, domain);
220 default:
221 throw SymEngineException(
222 "expected a polynomial of order between 0 to 4");
223 }
224}
225
226inline RCP<const Basic> get_coeff_basic(const integer_class &i)
227{
228 return integer(i);
229}
230
231inline RCP<const Basic> get_coeff_basic(const Expression &i)
232{
233 return i.get_basic();
234}
235
236template <typename Poly>
237inline vec_basic extract_coeffs(const RCP<const Poly> &f)
238{
239 int degree = f->get_degree();
240 vec_basic coeffs;
241 for (int i = 0; i <= degree; i++)
242 coeffs.push_back(get_coeff_basic(f->get_coeff(i)));
243 return coeffs;
244}
245
246RCP<const Set> solve_poly(const RCP<const Basic> &f,
247 const RCP<const Symbol> &sym,
248 const RCP<const Set> &domain)
249{
250
251#if defined(HAVE_SYMENGINE_FLINT) && __FLINT_RELEASE > 20502
252 try {
253 auto poly = from_basic<UIntPolyFlint>(f, sym);
254 auto fac = factors(*poly);
255 set_set solns;
256 for (const auto &elem : fac) {
257 auto uip = UIntPoly::from_poly(*elem.first);
258 auto degree = uip->get_poly().degree();
259 if (degree <= 4) {
260 solns.insert(
261 solve_poly_heuristics(extract_coeffs(uip), domain));
262 } else {
263 solns.insert(
264 conditionset(sym, logical_and({Eq(uip->as_symbolic(), zero),
265 domain->contains(sym)})));
266 }
267 }
268 return SymEngine::set_union(solns);
269 } catch (SymEngineException &x) {
270 // Try next
271 }
272#endif
273 RCP<const Basic> gen = rcp_static_cast<const Basic>(sym);
274 auto uexp = from_basic<UExprPoly>(f, gen);
275 auto degree = uexp->get_degree();
276 if (degree <= 4) {
277 return solve_poly_heuristics(extract_coeffs(uexp), domain);
278 } else {
279 return conditionset(sym,
280 logical_and({Eq(f, zero), domain->contains(sym)}));
281 }
282}
283
284RCP<const Set> solve_rational(const RCP<const Basic> &f,
285 const RCP<const Symbol> &sym,
286 const RCP<const Set> &domain)
287{
288 RCP<const Basic> num, den;
289 as_numer_denom(f, outArg(num), outArg(den));
290 if (has_symbol(*den, *sym)) {
291 auto numsoln = solve(num, sym, domain);
292 auto densoln = solve(den, sym, domain);
293 return set_complement(numsoln, densoln);
294 }
295 return solve_poly(num, sym, domain);
296}
297
298/* Helper Visitors for solve_trig */
299
301 : public BaseVisitor<IsALinearArgTrigVisitor, LocalStopVisitor>
302{
303protected:
304 Ptr<const Symbol> x_;
305 bool is_;
306
307public:
308 IsALinearArgTrigVisitor(Ptr<const Symbol> x) : x_(x) {}
309
310 bool apply(const Basic &b)
311 {
312 stop_ = false;
313 is_ = true;
314 preorder_traversal_local_stop(b, *this);
315 return is_;
316 }
317
318 bool apply(const RCP<const Basic> &b)
319 {
320 return apply(*b);
321 }
322
323 void bvisit(const Basic &x)
324 {
325 local_stop_ = false;
326 }
327
328 void bvisit(const Symbol &x)
329 {
330 if (x_->__eq__(x)) {
331 is_ = 0;
332 stop_ = true;
333 }
334 }
335
336 template <typename T,
337 typename
338 = enable_if_t<std::is_base_of<TrigFunction, T>::value
340 void bvisit(const T &x)
341 {
342 is_ = (from_basic<UExprPoly>(x.get_args()[0], (*x_).rcp_from_this())
343 ->get_degree()
344 <= 1);
345 if (not is_)
346 stop_ = true;
347 local_stop_ = true;
348 }
349};
350
351bool is_a_LinearArgTrigEquation(const Basic &b, const Symbol &x)
352{
353 IsALinearArgTrigVisitor v(ptrFromRef(x));
354 return v.apply(b);
355}
356
357class InvertComplexVisitor : public BaseVisitor<InvertComplexVisitor>
358{
359protected:
360 RCP<const Set> result_;
361 RCP<const Set> gY_;
362 RCP<const Dummy> nD_;
363 RCP<const Symbol> sym_;
364 RCP<const Set> domain_;
365
366public:
367 InvertComplexVisitor(RCP<const Set> gY, RCP<const Dummy> nD,
368 RCP<const Symbol> sym, RCP<const Set> domain)
369 : gY_(gY), nD_(nD), sym_(sym), domain_(domain)
370 {
371 }
372
373 void bvisit(const Basic &x)
374 {
375 result_ = gY_;
376 }
377
378 void bvisit(const Add &x)
379 {
380 vec_basic f1X, f2X;
381 for (auto &elem : x.get_args()) {
382 if (has_symbol(*elem, *sym_)) {
383 f1X.push_back(elem);
384 } else {
385 f2X.push_back(elem);
386 }
387 }
388 auto depX = add(f1X), indepX = add(f2X);
389 if (not eq(*indepX, *zero)) {
390 gY_ = imageset(nD_, sub(nD_, indepX), gY_);
391 result_ = apply(*depX);
392 } else {
393 result_ = gY_;
394 }
395 }
396
397 void bvisit(const Mul &x)
398 {
399 vec_basic f1X, f2X;
400 for (auto &elem : x.get_args()) {
401 if (has_symbol(*elem, *sym_)) {
402 f1X.push_back(elem);
403 } else {
404 f2X.push_back(elem);
405 }
406 }
407 auto depX = mul(f1X), indepX = mul(f2X);
408 if (not eq(*indepX, *one)) {
409 if (eq(*indepX, *NegInf) or eq(*indepX, *Inf)
410 or eq(*indepX, *ComplexInf)) {
411 result_ = emptyset();
412 } else {
413 gY_ = imageset(nD_, div(nD_, indepX), gY_);
414 result_ = apply(*depX);
415 }
416 } else {
417 result_ = gY_;
418 }
419 }
420
421 void bvisit(const Pow &x)
422 {
423 if (eq(*x.get_base(), *E) and is_a<FiniteSet>(*gY_)) {
424 set_set inv;
425 for (const auto &elem :
426 down_cast<const FiniteSet &>(*gY_).get_container()) {
427 if (eq(*elem, *zero))
428 continue;
429 RCP<const Basic> re, im;
430 as_real_imag(elem, outArg(re), outArg(im));
431 auto logabs = log(add(mul(re, re), mul(im, im)));
432 auto logarg = atan2(im, re);
433 inv.insert(imageset(
434 nD_,
435 add(mul(add(mul({integer(2), nD_, pi}), logarg), I),
436 div(logabs, integer(2))),
437 interval(NegInf, Inf, true,
438 true))); // TODO : replace interval(-oo,oo) with
439 // Set of Integers once Class for Range is implemented.
440 }
441 gY_ = set_union(inv);
442 apply(*x.get_exp());
443 return;
444 }
445 result_ = gY_;
446 }
447
448 RCP<const Set> apply(const Basic &b)
449 {
450 result_ = gY_;
451 b.accept(*this);
452 return set_intersection({domain_, result_});
453 }
454};
455
456RCP<const Set> invertComplex(const RCP<const Basic> &fX,
457 const RCP<const Set> &gY,
458 const RCP<const Symbol> &sym,
459 const RCP<const Dummy> &nD,
460 const RCP<const Set> &domain)
461{
462 InvertComplexVisitor v(gY, nD, sym, domain);
463 return v.apply(*fX);
464}
465
466RCP<const Set> solve_trig(const RCP<const Basic> &f,
467 const RCP<const Symbol> &sym,
468 const RCP<const Set> &domain)
469{
470 // TODO : first simplify f using `fu`.
471 auto exp_f = rewrite_as_exp(f);
472 RCP<const Basic> num, den;
473 as_numer_denom(exp_f, outArg(num), outArg(den));
474
475 auto xD = dummy("x");
476 map_basic_basic d;
477 auto temp = exp(mul(I, sym));
478 d[temp] = xD;
479 num = expand(num), den = expand(den);
480 num = num->subs(d);
481 den = den->subs(d);
482
483 if (has_symbol(*num, *sym) or has_symbol(*den, *sym)) {
484 return conditionset(sym, logical_and({Eq(f, zero)}));
485 }
486
487 auto soln = set_complement(solve(num, xD), solve(den, xD));
488 if (eq(*soln, *emptyset()))
489 return emptyset();
490 else if (is_a<FiniteSet>(*soln)) {
491 set_set res;
492 auto nD
493 = dummy("n"); // use the same dummy for finding every solution set.
494 auto n = symbol(
495 "n"); // replaces the above dummy in final set of solutions.
496 map_basic_basic d;
497 d[nD] = n;
498 for (const auto &elem :
499 down_cast<const FiniteSet &>(*soln).get_container()) {
500 res.insert(
501 invertComplex(exp(mul(I, sym)), finiteset({elem}), sym, nD));
502 }
503 auto ans = set_union(res)->subs(d);
504 if (not is_a_Set(*ans))
505 throw SymEngineException("Expected an object of type Set");
506 return set_intersection({rcp_static_cast<const Set>(ans), domain});
507 }
508 return conditionset(sym, logical_and({Eq(f, zero), domain->contains(sym)}));
509}
510
511RCP<const Set> solve(const RCP<const Basic> &f, const RCP<const Symbol> &sym,
512 const RCP<const Set> &domain)
513{
514 if (eq(*f, *boolTrue))
515 return domain;
516 if (eq(*f, *boolFalse))
517 return emptyset();
518 if (is_a<Equality>(*f)) {
519 return solve(sub(down_cast<const Relational &>(*f).get_arg1(),
520 down_cast<const Relational &>(*f).get_arg2()),
521 sym, domain);
522 } else if (is_a<Unequality>(*f)) {
523 auto soln = solve(sub(down_cast<const Relational &>(*f).get_arg1(),
524 down_cast<const Relational &>(*f).get_arg2()),
525 sym, domain);
526 return set_complement(domain, soln);
527 } else if (is_a_Relational(*f)) {
528 // Solving inequalities is not implemented yet.
529 return conditionset(sym, logical_and({rcp_static_cast<const Boolean>(f),
530 domain->contains(sym)}));
531 }
532
533 if (is_a_Number(*f)) {
534 if (eq(*f, *zero)) {
535 return domain;
536 } else {
537 return emptyset();
538 }
539 }
540
541 if (not has_symbol(*f, *sym))
542 return emptyset();
543
544 if (is_a_LinearArgTrigEquation(*f, *sym)) {
545 return solve_trig(f, sym, domain);
546 }
547
548 if (is_a<Mul>(*f)) {
549 auto args = f->get_args();
550 set_set solns;
551 for (auto &a : args) {
552 solns.insert(solve(a, sym, domain));
553 }
554 return SymEngine::set_union(solns);
555 }
556
557 return solve_rational(f, sym, domain);
558}
559
560vec_basic linsolve_helper(const DenseMatrix &A, const DenseMatrix &b)
561{
562 DenseMatrix res(A.nrows(), 1);
563 fraction_free_gauss_jordan_solve(A, b, res);
564 vec_basic fs;
565 for (unsigned i = 0; i < res.nrows(); i++) {
566 fs.push_back(res.get(i, 0));
567 }
568 return fs;
569}
570
571vec_basic linsolve(const DenseMatrix &system, const vec_sym &syms)
572{
573 DenseMatrix A(system.nrows(), system.ncols() - 1), b(system.nrows(), 1);
574 system.submatrix(A, 0, 0, system.nrows() - 1, system.ncols() - 2);
575 system.submatrix(b, 0, system.ncols() - 1, system.nrows() - 1,
576 system.ncols() - 1);
577 return linsolve_helper(A, b);
578}
579
580vec_basic linsolve(const vec_basic &system, const vec_sym &syms)
581{
582 auto mat = linear_eqns_to_matrix(system, syms);
583 DenseMatrix A = mat.first, b = mat.second;
584 return linsolve_helper(A, b);
585}
586
587set_basic get_set_from_vec(const vec_sym &syms)
588{
589 set_basic sb;
590 for (auto &s : syms)
591 sb.insert(s);
592 return sb;
593}
594
596linear_eqns_to_matrix(const vec_basic &equations, const vec_sym &syms)
597{
598 auto size = numeric_cast<unsigned int>(syms.size());
599 DenseMatrix A(numeric_cast<unsigned int>(equations.size()), size);
600 zeros(A);
601 vec_basic bvec;
602
603 int row = 0;
604 auto gens = get_set_from_vec(syms);
605 umap_basic_uint index_of_sym;
606 for (unsigned int i = 0; i < size; i++) {
607 index_of_sym[syms[i]] = i;
608 }
609 for (const auto &eqn : equations) {
610 auto neqn = eqn;
611 if (is_a<Equality>(*eqn)) {
612 neqn = sub(down_cast<const Equality &>(*eqn).get_arg2(),
613 down_cast<const Equality &>(*eqn).get_arg1());
614 }
615
616 auto mpoly = from_basic<MExprPoly>(neqn, gens);
617 RCP<const Basic> rem = zero;
618 for (const auto &p : mpoly->get_poly().dict_) {
619 RCP<const Basic> res = (p.second.get_basic());
620 int whichvar = 0, non_zero = 0;
621 RCP<const Basic> cursim;
622 for (auto &sym : gens) {
623 if (0 != p.first[whichvar]) {
624 non_zero++;
625 cursim = sym;
626 if (p.first[whichvar] != 1 or non_zero == 2) {
627 throw SymEngineException("Expected a linear equation.");
628 }
629 }
630 whichvar++;
631 }
632 if (not non_zero) {
633 rem = res;
634 } else {
635 A.set(row, index_of_sym[cursim], res);
636 }
637 }
638 bvec.push_back(neg(rem));
639 ++row;
640 }
641 return std::make_pair(
642 A, DenseMatrix(numeric_cast<unsigned int>(equations.size()), 1, bvec));
643}
644} // namespace SymEngine
The base class for representing addition in symbolic expressions.
Definition: add.h:27
virtual vec_basic get_args() const
Returns the arguments of the Add.
Definition: add.cpp:397
The lowest unit of symbolic representation.
Definition: basic.h:97
virtual vec_basic get_args() const
Returns the list of arguments.
Definition: mul.cpp:507
RCP< const Basic > get_base() const
Definition: pow.h:37
RCP< const Basic > get_exp() const
Definition: pow.h:42
T insert(T... args)
T make_pair(T... args)
Main namespace for SymEngine package.
Definition: add.cpp:19
bool is_a_Number(const Basic &b)
Definition: number.h:130
RCP< const Basic > div(const RCP< const Basic > &a, const RCP< const Basic > &b)
Division.
Definition: mul.cpp:431
RCP< const EmptySet > emptyset()
Definition: sets.h:562
RCP< const Set > finiteset(const set_basic &container)
Definition: sets.h:574
bool eq(const Basic &a, const Basic &b)
Checks equality for a and b
Definition: basic-inl.h:21
RCP< const Basic > atan2(const RCP< const Basic > &num, const RCP< const Basic > &den)
Canonicalize ATan2:
Definition: functions.cpp:1614
RCP< const Basic > sub(const RCP< const Basic > &a, const RCP< const Basic > &b)
Substracts b from a.
Definition: add.cpp:495
RCP< const Basic > exp(const RCP< const Basic > &x)
Returns the natural exponential function E**x = pow(E, x)
Definition: pow.cpp:271
RCP< const Basic > mul(const RCP< const Basic > &a, const RCP< const Basic > &b)
Multiplication.
Definition: mul.cpp:352
RCP< const Set > conditionset(const RCP< const Basic > &sym, const RCP< const Boolean > &condition)
Definition: sets.cpp:1688
RCP< const Dummy > dummy()
inline version to return Dummy
Definition: symbol.h:88
RCP< const Symbol > symbol(const std::string &name)
inline version to return Symbol
Definition: symbol.h:82
RCP< const Basic > log(const RCP< const Basic > &arg)
Returns the Natural Logarithm from argument arg
Definition: functions.cpp:1774
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
RCP< const Basic > expand(const RCP< const Basic > &self, bool deep=true)
Expands self
Definition: expand.cpp:369
std::enable_if< std::is_integral< T >::value, RCP< constInteger > >::type integer(T i)
Definition: integer.h:200
RCP< const Basic > neg(const RCP< const Basic > &a)
Negation.
Definition: mul.cpp:443
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:583
T next(T... args)
T pow(T... args)
T push_back(T... args)
T set_intersection(T... args)
T set_union(T... args)
T sqrt(T... args)
T system(T... args)