// Mul (t^exp) to the dict "d" void Mul::dict_add_term(map_basic_basic &d, const RCP<const Basic> &exp, const RCP<const Basic> &t) { auto it = d.find(t); if (it == d.end()) { insert(d, t, exp); } else { // Very common case, needs to be fast: if (is_a_Number(*it->second) && is_a_Number(*exp)) { RCP<const Number> tmp = rcp_static_cast<const Number>(it->second); iaddnum(outArg(tmp), rcp_static_cast<const Number>(exp)); if (tmp->is_zero()) { d.erase(it); } else { it->second = tmp; } } else { // General case: it->second = add(it->second, exp); if (is_a<Integer>(*it->second) && rcp_static_cast<const Integer>(it->second)->is_zero()) { d.erase(it); } } } }
RCP<const Basic> Mul::power_all_terms(const RCP<const Basic> &exp) const { CSymPy::map_basic_basic d; RCP<const Basic> new_coef = pow(coef_, exp); RCP<const Number> coef_num = one; RCP<const Basic> new_exp; for (auto &p: dict_) { new_exp = mul(p.second, exp); if (is_a_Number(*new_exp)) { // No need for additional dict checks here. // The dict should be of standard form before this is // called. if (rcp_static_cast<const Number>(new_exp)->is_zero()) { continue; } else { Mul::dict_add_term_new(outArg(coef_num), d, new_exp, p.first); } } else { Mul::dict_add_term_new(outArg(coef_num), d, new_exp, p.first); } } if (is_a_Number(*new_coef)) { imulnum(outArg(coef_num), rcp_static_cast<const Number>(new_coef)); return Mul::from_dict(coef_num, std::move(d)); } else { // TODO: this can be made faster probably: return mul(mul(new_coef, coef_num), Mul::from_dict(one, std::move(d))); } }
RCP<const Basic> mul(const RCP<const Basic> &a, const RCP<const Basic> &b) { SymEngine::map_basic_basic d; RCP<const Number> coef = one; if (SymEngine::is_a<Mul>(*a) && SymEngine::is_a<Mul>(*b)) { RCP<const Mul> A = rcp_static_cast<const Mul>(a); RCP<const Mul> B = rcp_static_cast<const Mul>(b); // This is important optimization, as coef=1 if Mul is inside an Add. // To further speed this up, the upper level code could tell us that we // are inside an Add, then we don't even have can simply skip the // following two lines. if (!(A->coef_->is_one()) || !(B->coef_->is_one())) coef = mulnum(A->coef_, B->coef_); d = A->dict_; for (auto &p: B->dict_) Mul::dict_add_term_new(outArg(coef), d, p.second, p.first); } else if (SymEngine::is_a<Mul>(*a)) { RCP<const Basic> exp; RCP<const Basic> t; coef = (rcp_static_cast<const Mul>(a))->coef_; d = (rcp_static_cast<const Mul>(a))->dict_; if (is_a_Number(*b)) { imulnum(outArg(coef), rcp_static_cast<const Number>(b)); } else { Mul::as_base_exp(b, outArg(exp), outArg(t)); Mul::dict_add_term_new(outArg(coef), d, exp, t); } } else if (SymEngine::is_a<Mul>(*b)) { RCP<const Basic> exp; RCP<const Basic> t; coef = (rcp_static_cast<const Mul>(b))->coef_; d = (rcp_static_cast<const Mul>(b))->dict_; if (is_a_Number(*a)) { imulnum(outArg(coef), rcp_static_cast<const Number>(a)); } else { Mul::as_base_exp(a, outArg(exp), outArg(t)); Mul::dict_add_term_new(outArg(coef), d, exp, t); } } else { RCP<const Basic> exp; RCP<const Basic> t; if (is_a_Number(*a)) { imulnum(outArg(coef), rcp_static_cast<const Number>(a)); } else { Mul::as_base_exp(a, outArg(exp), outArg(t)); Mul::dict_add_term_new(outArg(coef), d, exp, t); } if (is_a_Number(*b)) { imulnum(outArg(coef), rcp_static_cast<const Number>(b)); } else { Mul::as_base_exp(b, outArg(exp), outArg(t)); Mul::dict_add_term_new(outArg(coef), d, exp, t); } } return Mul::from_dict(coef, std::move(d)); }
// Mul (t^exp) to the dict "d" void Mul::dict_add_term_new(const Ptr<RCP<const Number>> &coef, map_basic_basic &d, const RCP<const Basic> &exp, const RCP<const Basic> &t) { auto it = d.find(t); if (it == d.end()) { // Don't check for `exp = 0` here // `pow` for Complex is not expanded by default if (is_a<Integer>(*exp) && (is_a<Integer>(*t) || is_a<Rational>(*t))) { imulnum(outArg(*coef), pownum(rcp_static_cast<const Number>(t), rcp_static_cast<const Number>(exp))); } else if (is_a<Integer>(*exp) && is_a<Complex>(*t)) { if (rcp_static_cast<const Integer>(exp)->is_one()) { imulnum(outArg(*coef), rcp_static_cast<const Number>(t)); } else if (rcp_static_cast<const Integer>(exp)->is_minus_one()) { idivnum(outArg(*coef), rcp_static_cast<const Number>(t)); } else { insert(d, t, exp); } } else { insert(d, t, exp); } } else { // Very common case, needs to be fast: if (is_a_Number(*exp) && is_a_Number(*it->second)) { RCP<const Number> tmp = rcp_static_cast<const Number>(it->second); iaddnum(outArg(tmp), rcp_static_cast<const Number>(exp)); it->second = tmp; } else it->second = add(it->second, exp); if (is_a<Integer>(*it->second)) { // `pow` for Complex is not expanded by default if (is_a<Integer>(*t) || is_a<Rational>(*t)) { if (!rcp_static_cast<const Integer>(it->second)->is_zero()) { imulnum(outArg(*coef), pownum(rcp_static_cast<const Number>(t), rcp_static_cast<const Number>(it->second))); } d.erase(it); } else if (rcp_static_cast<const Integer>(it->second)->is_zero()) { d.erase(it); } else if (is_a<Complex>(*t)) { if (rcp_static_cast<const Integer>(it->second)->is_one()) { imulnum(outArg(*coef), rcp_static_cast<const Number>(t)); d.erase(it); } else if (rcp_static_cast<const Integer>(it->second)->is_minus_one()) { idivnum(outArg(*coef), rcp_static_cast<const Number>(t)); d.erase(it); } } } } }
RCP<const Basic> log(const RCP<const Basic> &arg) { if (eq(*arg, *zero)) { throw NotImplementedError( "log(0) is complex infinity. Yet to be implemented"); } if (eq(*arg, *one)) return zero; if (eq(*arg, *E)) return one; if (is_a_Number(*arg)) { RCP<const Number> _arg = rcp_static_cast<const Number>(arg); if (not _arg->is_exact()) { return _arg->get_eval().log(*_arg); } else if (_arg->is_negative()) { throw NotImplementedError( "Imaginary Result. Yet to be implemented"); } } if (is_a<Rational>(*arg)) { RCP<const Integer> num, den; get_num_den(static_cast<const Rational &>(*arg), outArg(num), outArg(den)); return sub(log(num), log(den)); } return make_rcp<const Log>(arg); }
void Mul::as_base_exp(const RCP<const Basic> &self, const Ptr<RCP<const Basic>> &exp, const Ptr<RCP<const Basic>> &base) { if (is_a_Number(*self)) { // Always ensure it is of form |num| > |den| // in case of Integers den = 1 if (is_a<Rational>(*self)) { RCP<const Rational> self_new = rcp_static_cast<const Rational>(self); if (abs(self_new->i.get_num()) < abs(self_new->i.get_den())) { *exp = minus_one; *base = self_new->rdiv(*rcp_static_cast<const Number>(one)); } else { *exp = one; *base = self; } } else { *exp = one; *base = self; } } else if (is_a<Pow>(*self)) { *exp = rcp_static_cast<const Pow>(self)->exp_; *base = rcp_static_cast<const Pow>(self)->base_; } else { SYMENGINE_ASSERT(!is_a<Mul>(*self)); *exp = one; *base = self; } }
RCP<const Basic> Mul::subs(const map_basic_basic &subs_dict) const { RCP<const Mul> self = rcp_const_cast<Mul>(rcp(this)); auto it = subs_dict.find(self); if (it != subs_dict.end()) return it->second; RCP<const Number> coef = coef_; map_basic_basic d; for (auto &p: dict_) { RCP<const Basic> factor_old = pow(p.first, p.second); RCP<const Basic> factor = factor_old->subs(subs_dict); if (factor == factor_old) { Mul::dict_add_term_new(outArg(coef), d, p.second, p.first); } else if (is_a<Integer>(*factor) && rcp_static_cast<const Integer>(factor)->is_zero()) { return zero; } else if (is_a_Number(*factor)) { imulnum(outArg(coef), rcp_static_cast<const Number>(factor)); } else if (is_a<Mul>(*factor)) { RCP<const Mul> tmp = rcp_static_cast<const Mul>(factor); imulnum(outArg(coef), tmp->coef_); for (auto &q: tmp->dict_) { Mul::dict_add_term_new(outArg(coef), d, q.second, q.first); } } else { RCP<const Basic> exp, t; Mul::as_base_exp(factor, outArg(exp), outArg(t)); Mul::dict_add_term_new(outArg(coef), d, exp, t); } } return Mul::from_dict(coef, std::move(d)); }
RCP<const Basic> Add::subs(const map_basic_basic &subs_dict) const { RCP<const Add> self = rcp_const_cast<Add>(rcp(this)); auto it = subs_dict.find(self); if (it != subs_dict.end()) return it->second; CSymPy::umap_basic_num d; RCP<const Number> coef=coef_, coef2; RCP<const Basic> t; for (auto &p: dict_) { RCP<const Basic> term = p.first->subs(subs_dict); if (term == p.first) { Add::dict_add_term(d, p.second, p.first); } else if (is_a<Integer>(*term) && rcp_static_cast<const Integer>(term)->is_zero()) { continue; } else if (is_a_Number(*term)) { iaddnum(outArg(coef), mulnum(p.second, rcp_static_cast<const Number>(term))); } else if (is_a<Add>(*term)) { for (auto &q: (rcp_static_cast<const Add>(term))->dict_) Add::dict_add_term(d, q.second, q.first); iaddnum(outArg(coef), rcp_static_cast<const Add>(term)->coef_); } else { Add::as_coef_term(mul(p.second, term), outArg(coef2), outArg(t)); Add::dict_add_term(d, coef2, t); } } return Add::from_dict(coef, std::move(d)); }
static RCP<const Basic> diff(const Mul &self, const RCP<const Symbol> &x) { RCP<const Number> overall_coef = zero; umap_basic_num add_dict; for (auto &p: self.dict_) { RCP<const Number> coef = self.coef_; RCP<const Basic> factor = pow(p.first, p.second)->diff(x); if (is_a<Integer>(*factor) && rcp_static_cast<const Integer>(factor)->is_zero()) continue; map_basic_basic d = self.dict_; d.erase(p.first); if (is_a_Number(*factor)) { imulnum(outArg(coef), rcp_static_cast<const Number>(factor)); } else if (is_a<Mul>(*factor)) { RCP<const Mul> tmp = rcp_static_cast<const Mul>(factor); imulnum(outArg(coef), tmp->coef_); for (auto &q: tmp->dict_) { Mul::dict_add_term_new(outArg(coef), d, q.second, q.first); } } else { RCP<const Basic> exp, t; Mul::as_base_exp(factor, outArg(exp), outArg(t)); Mul::dict_add_term_new(outArg(coef), d, exp, t); } if (d.size() == 0) { iaddnum(outArg(overall_coef), coef); } else { RCP<const Basic> mul = Mul::from_dict(one, std::move(d)); Add::dict_add_term(add_dict, coef, mul); } } return Add::from_dict(overall_coef, std::move(add_dict)); }
static RCP<const Basic> diff(const Pow &self, const RCP<const Symbol> &x) { if (is_a_Number(*(self.get_exp()))) return mul(mul(self.get_exp(), pow(self.get_base(), sub(self.get_exp(), one))), self.get_base()->diff(x)); else return mul(pow(self.get_base(), self.get_exp()), mul(self.get_exp(), log(self.get_base()))->diff(x)); }
RCP<const Basic> Mul::diff(const RCP<const Symbol> &x) const { RCP<const Basic> r=zero; for (auto &p: dict_) { RCP<const Number> coef = coef_; RCP<const Basic> factor = pow(p.first, p.second)->diff(x); if (is_a<Integer>(*factor) && rcp_static_cast<const Integer>(factor)->is_zero()) continue; map_basic_basic d = dict_; d.erase(p.first); if (is_a_Number(*factor)) { imulnum(outArg(coef), rcp_static_cast<const Number>(factor)); } else if (is_a<Mul>(*factor)) { RCP<const Mul> tmp = rcp_static_cast<const Mul>(factor); imulnum(outArg(coef), tmp->coef_); for (auto &q: tmp->dict_) { Mul::dict_add_term_new(outArg(coef), d, q.second, q.first); } } else { RCP<const Basic> exp, t; Mul::as_base_exp(factor, outArg(exp), outArg(t)); Mul::dict_add_term_new(outArg(coef), d, exp, t); } // TODO: speed this up: r = add(r, Mul::from_dict(coef, std::move(d))); } return r; }
RCP<const Basic> Pow::diff(const RCP<const Symbol> &x) const { if (is_a_Number(*exp_)) return mul(mul(exp_, pow(base_, sub(exp_, one))), base_->diff(x)); else return mul(pow(base_, exp_), mul(exp_, log(base_))->diff(x)); }
RCP<const Basic> add(const RCP<const Basic> &a, const RCP<const Basic> &b) { CSymPy::umap_basic_num d; RCP<const Number> coef; RCP<const Basic> t; if (CSymPy::is_a<Add>(*a) && CSymPy::is_a<Add>(*b)) { coef = (rcp_static_cast<const Add>(a))->coef_; d = (rcp_static_cast<const Add>(a))->dict_; for (auto &p: (rcp_static_cast<const Add>(b))->dict_) Add::dict_add_term(d, p.second, p.first); iaddnum(outArg(coef), rcp_static_cast<const Add>(b)->coef_); } else if (CSymPy::is_a<Add>(*a)) { coef = (rcp_static_cast<const Add>(a))->coef_; d = (rcp_static_cast<const Add>(a))->dict_; if (is_a_Number(*b)) { iaddnum(outArg(coef), rcp_static_cast<const Number>(b)); } else { RCP<const Number> coef2; Add::as_coef_term(b, outArg(coef2), outArg(t)); Add::dict_add_term(d, coef2, t); } } else if (CSymPy::is_a<Add>(*b)) { coef = (rcp_static_cast<const Add>(b))->coef_; d = (rcp_static_cast<const Add>(b))->dict_; if (is_a_Number(*a)) { iaddnum(outArg(coef), rcp_static_cast<const Number>(a)); } else { RCP<const Number> coef2; Add::as_coef_term(a, outArg(coef2), outArg(t)); Add::dict_add_term(d, coef2, t); } } else { Add::as_coef_term(a, outArg(coef), outArg(t)); Add::dict_add_term(d, coef, t); Add::as_coef_term(b, outArg(coef), outArg(t)); Add::dict_add_term(d, coef, t); auto it = d.find(one); if (it == d.end()) { coef = zero; } else { coef = it->second; d.erase(it); } return Add::from_dict(coef, std::move(d)); } return Add::from_dict(coef, std::move(d)); }
RCP<const Basic> expand(const RCP<const Basic> &self) { if (is_a<Symbol>(*self)) return self; if (is_a_Number(*self)) return self; if (is_a<Add>(*self)) return add_expand(rcp_static_cast<const Add>(self)); if (is_a<Mul>(*self)) return mul_expand(rcp_static_cast<const Mul>(self)); if (is_a<Pow>(*self)) return pow_expand(rcp_static_cast<const Pow>(self)); return self; }
void bvisit(const Number &x) { if (not is_a_Number(*pow(the_base, x.rcp_from_this()))) { if (x.is_positive()) gen_set[one] = x.rcp_from_this_cast<const Number>(); else gen_set[minus_one] = mulnum(x.rcp_from_this_cast<const Number>(), minus_one); } }
bool Log::is_canonical(const Basic &arg) const { // log(0) if (is_a<Integer>(arg) and static_cast<const Integer &>(arg).is_zero()) return false; // log(1) if (is_a<Integer>(arg) and static_cast<const Integer &>(arg).is_one()) return false; // log(E) if (eq(arg, *E)) return false; // Currently not implemented, however should be expanded as `-ipi + // log(-arg)` if (is_a_Number(arg) and static_cast<const Number &>(arg).is_negative()) return false; if (is_a_Number(arg) and not static_cast<const Number &>(arg).is_exact()) return false; // log(num/den) = log(num) - log(den) if (is_a<Rational>(arg)) return false; return true; }
void Add::as_coef_term(const RCP<Basic> &self, const Ptr<RCP<Number>> &coef, const Ptr<RCP<Basic>> &term) { if (is_a<Mul>(*self)) { *coef = (rcp_static_cast<Mul>(self))->coef_; *term = Mul::from_dict(one, (rcp_static_cast<Mul>(self))->dict_); } else if (is_a_Number(*self)) { *coef = rcp_static_cast<Number>(self); *term = one; } else { *coef = one; *term = self; } }
RCP<const Boolean> Interval::contains(const RCP<const Basic> &a) const { if (not is_a_Number(*a)) return make_rcp<Contains>(a, rcp_from_this_cast<const Set>()); if ((eq(*start_, *a) and left_open_) or (eq(*end_, *a) and right_open_)) return boolean(false); if (eq(*start_, *a) or eq(*end_, *a)) return boolean(true); if (eq(*min({end_, a}), *end_)) return boolean(false); if (eq(*max({start_, a}), *start_)) return boolean(false); return boolean(true); }
RCP<const Basic> Mul::power_all_terms(const RCP<const Basic> &exp) const { SymEngine::map_basic_basic d; RCP<const Basic> new_coef = pow(coef_, exp); RCP<const Number> coef_num = one; RCP<const Basic> new_exp; for (auto &p: dict_) { new_exp = mul(p.second, exp); if (is_a_Number(*new_exp)) { // No need for additional dict checks here. // The dict should be of standard form before this is // called. if (rcp_static_cast<const Number>(new_exp)->is_zero()) { continue; } else { Mul::dict_add_term_new(outArg(coef_num), d, new_exp, p.first); } } else { Mul::dict_add_term_new(outArg(coef_num), d, new_exp, p.first); } } if (is_a_Number(*new_coef)) { imulnum(outArg(coef_num), rcp_static_cast<const Number>(new_coef)); } else if (is_a<Mul>(*new_coef)) { RCP<const Mul> tmp = rcp_static_cast<const Mul>(new_coef); imulnum(outArg(coef_num), tmp->coef_); for (auto &q: tmp->dict_) { Mul::dict_add_term_new(outArg(coef_num), d, q.second, q.first); } } else { RCP<const Basic> _exp, t; Mul::as_base_exp(new_coef, outArg(_exp), outArg(t)); Mul::dict_add_term_new(outArg(coef_num), d, _exp, t); } return Mul::from_dict(coef_num, std::move(d)); }
// Very quickly (!) creates the appropriate instance (i.e. Add, Symbol, // Integer, Mul) depending on the size of the dictionary 'd'. // If d.size() > 1 then it just returns Add. This means that the dictionary // must be in canonical form already. For d.size == 1, it returns Mul, Pow, // Symbol or Integer, depending on the expression. RCP<Basic> Add::from_dict(const RCP<Number> &coef, const umap_basic_int &d) { if (d.size() == 0) { return coef; } else if (d.size() == 1 && coef->is_zero()) { auto p = d.begin(); if (is_a<Integer>(*(p->second))) { if (rcp_static_cast<Integer>(p->second)->is_zero()) { return zero; } if (rcp_static_cast<Integer>(p->second)->is_one()) { return p->first; } if (is_a<Mul>(*(p->first))) { return Mul::from_dict(p->second, rcp_static_cast<Mul>(p->first)->dict_); } map_basic_basic m; if (is_a<Pow>(*(p->first))) { insert(m, rcp_static_cast<Pow>(p->first)->base_, rcp_static_cast<Pow>(p->first)->exp_); } else { insert(m, p->first, one); } return rcp(new Mul(p->second, m)); } map_basic_basic m; if (is_a_Number(*p->second)) { if (is_a<Mul>(*(p->first))) { return Mul::from_dict(p->second, rcp_static_cast<Mul>(p->first)->dict_); } if (is_a<Pow>(*p->first)) { insert(m, rcp_static_cast<Pow>(p->first)->base_, rcp_static_cast<Pow>(p->first)->exp_); } else { insert(m, p->first, one); } return rcp(new Mul(p->second, m)); } else { insert(m, p->first, one); insert(m, p->second, one); return rcp(new Mul(one, m)); } } else { return rcp(new Add(coef, d)); } }
RCP<const Basic> pow(const RCP<const Basic> &a, const RCP<const Basic> &b) { if (eq(b, zero)) return one; if (eq(b, one)) return a; if (eq(a, zero)) return zero; if (eq(a, one)) return one; if (is_a_Number(*a) && is_a<Integer>(*b)) return pownum(rcp_static_cast<const Number>(a), rcp_static_cast<const Integer>(b)); if (is_a<Mul>(*a)) return rcp_static_cast<const Mul>(a)->power_all_terms(b); if (is_a<Pow>(*a)) { RCP<const Pow> A = rcp_static_cast<const Pow>(a); return pow(A->base_, mul(A->exp_, b)); } return rcp(new Pow(a, b)); }
void Add::as_coef_term(const RCP<const Basic> &self, const Ptr<RCP<const Number>> &coef, const Ptr<RCP<const Basic>> &term) { if (is_a<Mul>(*self)) { *coef = (rcp_static_cast<const Mul>(self))->coef_; // We need to copy our 'dict_' here, as 'term' has to have its own. map_basic_basic d2 = (rcp_static_cast<const Mul>(self))->dict_; *term = Mul::from_dict(one, std::move(d2)); } else if (is_a_Number(*self)) { *coef = rcp_static_cast<const Number>(self); *term = one; } else { *coef = one; *term = self; } }
RCP<const Basic> log(const RCP<const Basic> &arg) { if (eq(arg, zero)) { throw std::runtime_error("log(0) is complex infinity. Yet to be implemented"); } if (eq(arg, one)) return zero; if (eq(arg, E)) return one; if (is_a_Number(*arg) && rcp_static_cast<const Number>(arg)->is_negative()) { throw std::runtime_error("Imaginary Result. Yet to be implemented"); } if (is_a<Rational>(*arg)) { RCP<const Integer> num, den; get_num_den(rcp_static_cast<const Rational>(arg), outArg(num), outArg(den)); return sub(log(num), log(den)); } return rcp(new Log(arg)); }
bool Log::is_canonical(const RCP<const Basic> &arg) { if (arg == null) return false; // log(0) if (is_a<Integer>(*arg) && rcp_static_cast<const Integer>(arg)->is_zero()) return false; // log(1) if (is_a<Integer>(*arg) && rcp_static_cast<const Integer>(arg)->is_one()) return false; // log(E) if (eq(arg, E)) return false; // Currently not implemented, however should be expanded as `-ipi + log(-arg)` if (is_a_Number(*arg) && rcp_static_cast<const Number>(arg)->is_negative()) return false; // log(num/den) = log(num) - log(den) if (is_a<Rational>(*arg)) return false; return true; }
void Add::coef_dict_add_term(const Ptr<RCP<const Number>> &coef, umap_basic_num &d, const RCP<const Number> &c, const RCP<const Basic> &term) { if (is_a_Number(*term)) { iaddnum(coef, mulnum(c, rcp_static_cast<const Number>(term))); } else if (is_a<Add>(*term)) { if (c->is_one()) { for (const auto &q: (rcp_static_cast<const Add>(term))->dict_) Add::dict_add_term(d, q.second, q.first); iaddnum(coef, rcp_static_cast<const Add>(term)->coef_); } else { Add::dict_add_term(d, c, term); } } else { RCP<const Number> coef2; RCP<const Basic> t; Add::as_coef_term(term, outArg(coef2), outArg(t)); Add::dict_add_term(d, mulnum(c, coef2), t); } }
void Mul::as_base_exp(const RCP<const Basic> &self, const Ptr<RCP<const Basic>> &exp, const Ptr<RCP<const Basic>> &base) { if (is_a<Symbol>(*self)) { *exp = one; *base = self; } else if (is_a_Number(*self)) { // Always ensure it is of form |num| > |den| // in case of Integers den = 1 if (is_a<Rational>(*self)) { RCP<const Rational> self_new = rcp_static_cast<const Rational>(self); if (abs(self_new->i.get_num()) < abs(self_new->i.get_den())) { *exp = minus_one; *base = self_new->rdiv(*rcp_static_cast<const Number>(one)); } else { *exp = one; *base = self; } } else { *exp = one; *base = self; } } else if (is_a<Pow>(*self)) { *exp = rcp_static_cast<const Pow>(self)->exp_; *base = rcp_static_cast<const Pow>(self)->base_; } else if (is_a<Add>(*self)) { *exp = one; *base = self; } else if (is_a<Log>(*self)) { *exp = one; *base = self; } else if (is_a_sub<Function>(*self)) { *exp = one; *base = self; } else { std::cout << "as_base_exp: " << *self << std::endl; throw std::runtime_error("Not implemented yet."); } }
RCP<const Basic> Add::diff(const RCP<const Symbol> &x) const { CSymPy::umap_basic_num d; RCP<const Number> coef=zero, coef2; RCP<const Basic> t; for (auto &p: dict_) { RCP<const Basic> term = p.first->diff(x); if (is_a<Integer>(*term) && rcp_static_cast<const Integer>(term)->is_zero()) { continue; } else if (is_a_Number(*term)) { iaddnum(outArg(coef), mulnum(p.second, rcp_static_cast<const Number>(term))); } else if (is_a<Add>(*term)) { for (auto &q: (rcp_static_cast<const Add>(term))->dict_) Add::dict_add_term(d, q.second, q.first); iaddnum(outArg(coef), rcp_static_cast<const Add>(term)->coef_); } else { Add::as_coef_term(mul(p.second, term), outArg(coef2), outArg(t)); Add::dict_add_term(d, coef2, t); } } return Add::from_dict(coef, std::move(d)); }
// Very quickly (!) creates the appropriate instance (i.e. Add, Symbol, // Integer, Mul) depending on the size of the dictionary 'd'. // If d.size() > 1 then it just returns Add. This means that the dictionary // must be in canonical form already. For d.size == 1, it returns Mul, Pow, // Symbol or Integer, depending on the expression. RCP<const Basic> Add::from_dict(const RCP<const Number> &coef, umap_basic_num &&d) { if (d.size() == 0) { return coef; } else if (d.size() == 1 && coef->is_zero()) { auto p = d.begin(); if (is_a<Integer>(*(p->second))) { if (rcp_static_cast<const Integer>(p->second)->is_zero()) { return zero; } if (rcp_static_cast<const Integer>(p->second)->is_one()) { return p->first; } if (is_a<Mul>(*(p->first))) { #if !defined(WITH_CSYMPY_THREAD_SAFE) && defined(WITH_CSYMPY_RCP) if (rcp_static_cast<const Mul>(p->first)->refcount_ == 1) { // We can steal the dictionary: // Cast away const'ness, so that we can move 'dict_', since // 'p->first' will be destroyed when 'd' is at the end of // this function, so we "steal" its dict_ to avoid an // unnecessary copy. We know the refcount_ is one, so // nobody else is using the Mul except us. const map_basic_basic &d2 = rcp_static_cast<const Mul>(p->first)->dict_; map_basic_basic &d3 = const_cast<map_basic_basic &>(d2); return Mul::from_dict(p->second, std::move(d3)); } else { #else { #endif // We need to copy the dictionary: map_basic_basic d2 = rcp_static_cast<const Mul>(p->first)->dict_; return Mul::from_dict(p->second, std::move(d2)); } } map_basic_basic m; if (is_a<Pow>(*(p->first))) { insert(m, rcp_static_cast<const Pow>(p->first)->base_, rcp_static_cast<const Pow>(p->first)->exp_); } else { insert(m, p->first, one); } return rcp(new Mul(p->second, std::move(m))); } map_basic_basic m; if (is_a_Number(*p->second)) { if (is_a<Mul>(*(p->first))) { #if !defined(WITH_CSYMPY_THREAD_SAFE) && defined(WITH_CSYMPY_RCP) if (rcp_static_cast<const Mul>(p->first)->refcount_ == 1) { // We can steal the dictionary: // Cast away const'ness, so that we can move 'dict_', since // 'p->first' will be destroyed when 'd' is at the end of // this function, so we "steal" its dict_ to avoid an // unnecessary copy. We know the refcount_ is one, so // nobody else is using the Mul except us. const map_basic_basic &d2 = rcp_static_cast<const Mul>(p->first)->dict_; map_basic_basic &d3 = const_cast<map_basic_basic &>(d2); return Mul::from_dict(p->second, std::move(d3)); } else { #else { #endif // We need to copy the dictionary: map_basic_basic d2 = rcp_static_cast<const Mul>(p->first)->dict_; return Mul::from_dict(p->second, std::move(d2)); } } if (is_a<Pow>(*p->first)) { insert(m, rcp_static_cast<const Pow>(p->first)->base_, rcp_static_cast<const Pow>(p->first)->exp_); } else { insert(m, p->first, one); } return rcp(new Mul(p->second, std::move(m))); } else { insert(m, p->first, one); insert(m, p->second, one); return rcp(new Mul(one, std::move(m))); } } else { return rcp(new Add(coef, std::move(d))); } } // Adds (coef*t) to the dict "d" // Assumption: "t" does not have any numerical coefficients, those are in "coef" void Add::dict_add_term(umap_basic_num &d, const RCP<const Number> &coef, const RCP<const Basic> &t) { auto it = d.find(t); if (it == d.end()) { // Not found, add it in if it is nonzero: if (!(coef->is_zero())) insert(d, t, coef); } else { iaddnum(outArg(it->second), coef); if (it->second->is_zero()) d.erase(it); } }
RCP<const Basic> pow(const RCP<const Basic> &a, const RCP<const Basic> &b) { if (eq(b, zero)) return one; if (eq(b, one)) return a; if (eq(a, zero)) return zero; if (eq(a, one)) return one; if (eq(a, minus_one)) { if (is_a<Integer>(*b)) { return is_a<Integer>(*div(b, integer(2))) ? one : minus_one; } else if (is_a<Rational>(*b) && (rcp_static_cast<const Rational>(b)->i.get_num() == 1) && (rcp_static_cast<const Rational>(b)->i.get_den() == 2)) { return I; } } if (is_a_Number(*a) && is_a_Number(*b)) { if (is_a<Integer>(*b)) { if (is_a<Rational>(*a)) { RCP<const Rational> exp_new = rcp_static_cast<const Rational>(a); return exp_new->powrat(*rcp_static_cast<const Integer>(b)); } else if (is_a<Integer>(*a)) { RCP<const Integer> exp_new = rcp_static_cast<const Integer>(a); return exp_new->powint(*rcp_static_cast<const Integer>(b)); } else if (is_a<Complex>(*a)) { RCP<const Complex> exp_new = rcp_static_cast<const Complex>(a); RCP<const Integer> pow_new = rcp_static_cast<const Integer>(b); RCP<const Number> res = exp_new->pow(*pow_new); return res; } else { throw std::runtime_error("Not implemented"); } } else if (is_a<Rational>(*b)) { mpz_class q, r, num, den; num = rcp_static_cast<const Rational>(b)->i.get_num(); den = rcp_static_cast<const Rational>(b)->i.get_den(); if (num > den || num < 0) { mpz_fdiv_qr(q.get_mpz_t(), r.get_mpz_t(), num.get_mpz_t(), den.get_mpz_t()); } else { return rcp(new Pow(a, b)); } // Here we make the exponent postive and a fraction between // 0 and 1. We multiply numerator and denominator appropriately // to achieve this if (is_a<Rational>(*a)) { RCP<const Rational> exp_new = rcp_static_cast<const Rational>(a); RCP<const Basic> frac = div(exp_new->powrat(Integer(q)), integer(exp_new->i.get_den())); RCP<const Basic> surds = mul(rcp(new Pow(integer(exp_new->i.get_num()), div(integer(r), integer(den)))), rcp(new Pow(integer(exp_new->i.get_den()), sub(one, div(integer(r), integer(den)))))); return mul(frac, surds); } else if (is_a<Integer>(*a)) { RCP<const Integer> exp_new = rcp_static_cast<const Integer>(a); RCP<const Number> frac = exp_new->powint(Integer(q)); map_basic_basic surd; if ((exp_new->is_negative()) && (2 * r == den)) { frac = mulnum(frac, I); exp_new = exp_new->mulint(*minus_one); // if exp_new is one, no need to add it to dict if (exp_new->is_one()) return frac; surd[exp_new] = div(integer(r), integer(den)); } else { surd[exp_new] = div(integer(r), integer(den)); } return rcp(new Mul(frac, std::move(surd))); } else if (is_a<Complex>(*a)) { return rcp(new Pow(a, b)); } else { throw std::runtime_error("Not implemented"); } } else if (is_a<Complex>(*b)) { return rcp(new Pow(a, b)); } else { throw std::runtime_error("Not implemented"); } } if (is_a<Mul>(*a) && is_a<Integer>(*b)) { // Convert (x*y)^b = x^b*y^b, where 'b' is an integer. This holds for // any complex 'x', 'y' and integer 'b'. return rcp_static_cast<const Mul>(a)->power_all_terms(b); } if (is_a<Pow>(*a) && is_a<Integer>(*b)) { // Convert (x^y)^b = x^(b*y), where 'b' is an integer. This holds for // any complex 'x', 'y' and integer 'b'. RCP<const Pow> A = rcp_static_cast<const Pow>(a); return pow(A->base_, mul(A->exp_, b)); } return rcp(new Pow(a, b)); }
RCP<const Basic> pow_expand(const RCP<const Pow> &self) { RCP<const Basic> _base = expand(self->base_); bool negative_pow = false; if (! is_a<Integer>(*self->exp_) || ! is_a<Add>(*_base)) { if (neq(_base, self->base_)) { return pow(_base, self->exp_); } else { return self; } } map_vec_mpz r; int n = rcp_static_cast<const Integer>(self->exp_)->as_int(); if (n < 0) { n = -n; negative_pow = true; } RCP<const Add> base = rcp_static_cast<const Add>(_base); umap_basic_num base_dict = base->dict_; if (! (base->coef_->is_zero())) { // Add the numerical coefficient into the dictionary. This // allows a little bit easier treatment below. insert(base_dict, base->coef_, one); } int m = base_dict.size(); multinomial_coefficients_mpz(m, n, r); umap_basic_num rd; // This speeds up overall expansion. For example for the benchmark // (y + x + z + w)^60 it improves the timing from 135ms to 124ms. rd.reserve(2*r.size()); RCP<const Number> add_overall_coeff=zero; for (auto &p: r) { auto power = p.first.begin(); auto i2 = base_dict.begin(); map_basic_basic d; RCP<const Number> overall_coeff=one; for (; power != p.first.end(); ++power, ++i2) { if (*power > 0) { RCP<const Integer> exp = rcp(new Integer(*power)); RCP<const Basic> base = i2->first; if (is_a<Integer>(*base)) { imulnum(outArg(overall_coeff), rcp_static_cast<const Number>( rcp_static_cast<const Integer>(base)->powint(*exp))); } else if (is_a<Symbol>(*base)) { Mul::dict_add_term(d, exp, base); } else { RCP<const Basic> exp2, t, tmp; tmp = pow(base, exp); if (is_a<Mul>(*tmp)) { for (auto &p: (rcp_static_cast<const Mul>(tmp))->dict_) { Mul::dict_add_term_new(outArg(overall_coeff), d, p.second, p.first); } imulnum(outArg(overall_coeff), (rcp_static_cast<const Mul>(tmp))->coef_); } else { Mul::as_base_exp(tmp, outArg(exp2), outArg(t)); Mul::dict_add_term_new(outArg(overall_coeff), d, exp2, t); } } if (!(i2->second->is_one())) { if (is_a<Integer>(*(i2->second)) || is_a<Rational>(*(i2->second))) { imulnum(outArg(overall_coeff), pownum(i2->second, rcp_static_cast<const Number>(exp))); } else if (is_a<Complex>(*(i2->second))) { RCP<const Number> tmp = rcp_static_cast<const Complex>(i2->second)->pow(*exp); imulnum(outArg(overall_coeff), tmp); } } } } RCP<const Basic> term = Mul::from_dict(overall_coeff, std::move(d)); RCP<const Number> coef2 = rcp(new Integer(p.second)); if (is_a_Number(*term)) { iaddnum(outArg(add_overall_coeff), mulnum(rcp_static_cast<const Number>(term), coef2)); } else { if (is_a<Mul>(*term) && !(rcp_static_cast<const Mul>(term)->coef_->is_one())) { // Tidy up things like {2x: 3} -> {x: 6} imulnum(outArg(coef2), rcp_static_cast<const Mul>(term)->coef_); // We make a copy of the dict_: map_basic_basic d2 = rcp_static_cast<const Mul>(term)->dict_; term = Mul::from_dict(one, std::move(d2)); } Add::dict_add_term(rd, coef2, term); } } RCP<const Basic> result = Add::from_dict(add_overall_coeff, std::move(rd)); if (negative_pow) result = pow(result, minus_one); return result; }