Пример #1
0
// 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);
            }
        }
    }
}
Пример #2
0
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)));
    }
}
Пример #3
0
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));
}
Пример #4
0
// 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);
                }
            }
        }
    }
}
Пример #5
0
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);
}
Пример #6
0
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;
    }
}
Пример #7
0
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));
}
Пример #8
0
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));
}
Пример #9
0
 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));
 }
Пример #10
0
 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));
 }
Пример #11
0
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;
}
Пример #12
0
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));
}
Пример #13
0
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));
}
Пример #14
0
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;
}
Пример #15
0
 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);
     }
 }
Пример #16
0
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;
}
Пример #17
0
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;
    }
}
Пример #18
0
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);
}
Пример #19
0
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));
}
Пример #20
0
// 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));
    }
}
Пример #21
0
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));
}
Пример #22
0
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;
    }
}
Пример #23
0
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));
}
Пример #24
0
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;
}
Пример #25
0
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);
    }
}
Пример #26
0
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.");
    }
}
Пример #27
0
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));
}
Пример #28
0
// 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);
    }
}
Пример #29
0
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));
}
Пример #30
0
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;
}