]> www.ginac.de Git - ginac.git/blobdiff - ginac/pseries.cpp
Fix pseries::evalf() regression.
[ginac.git] / ginac / pseries.cpp
index 12f4fedebd8c36c49b0a51e55db595afe997fa20..063722b10dd90e34e0b7afec1eb0365db0202b5c 100644 (file)
@@ -4,7 +4,7 @@
  *  methods for series expansion. */
 
 /*
- *  GiNaC Copyright (C) 1999-2016 Johannes Gutenberg University Mainz, Germany
+ *  GiNaC Copyright (C) 1999-2019 Johannes Gutenberg University Mainz, Germany
  *
  *  This program is free software; you can redistribute it and/or modify
  *  it under the terms of the GNU General Public License as published by
@@ -71,6 +71,19 @@ pseries::pseries() { }
 pseries::pseries(const ex &rel_, const epvector &ops_)
   : seq(ops_)
 {
+#ifdef DO_GINAC_ASSERT
+       auto i = seq.begin();
+       while (i != seq.end()) {
+               auto ip1 = i+1;
+               if (ip1 != seq.end())
+                       GINAC_ASSERT(!is_order_function(i->rest));
+               else
+                       break;
+               GINAC_ASSERT(is_a<numeric>(i->coeff));
+               GINAC_ASSERT(ex_to<numeric>(i->coeff) < ex_to<numeric>(ip1->coeff));
+               ++i;
+       }
+#endif // def DO_GINAC_ASSERT
        GINAC_ASSERT(is_a<relational>(rel_));
        GINAC_ASSERT(is_a<symbol>(rel_.lhs()));
        point = rel_.rhs();
@@ -79,6 +92,19 @@ pseries::pseries(const ex &rel_, const epvector &ops_)
 pseries::pseries(const ex &rel_, epvector &&ops_)
   : seq(std::move(ops_))
 {
+#ifdef DO_GINAC_ASSERT
+       auto i = seq.begin();
+       while (i != seq.end()) {
+               auto ip1 = i+1;
+               if (ip1 != seq.end())
+                       GINAC_ASSERT(!is_order_function(i->rest));
+               else
+                       break;
+               GINAC_ASSERT(is_a<numeric>(i->coeff));
+               GINAC_ASSERT(ex_to<numeric>(i->coeff) < ex_to<numeric>(ip1->coeff));
+               ++i;
+       }
+#endif // def DO_GINAC_ASSERT
        GINAC_ASSERT(is_a<relational>(rel_));
        GINAC_ASSERT(is_a<symbol>(rel_.lhs()));
        point = rel_.rhs();
@@ -93,17 +119,15 @@ pseries::pseries(const ex &rel_, epvector &&ops_)
 void pseries::read_archive(const archive_node &n, lst &sym_lst) 
 {
        inherited::read_archive(n, sym_lst);
-       auto first = n.find_first("coeff");
-       auto last = n.find_last("power");
-       ++last;
-       seq.reserve((last-first)/2);
+       auto range = n.find_property_range("coeff", "power");
+       seq.reserve((range.end-range.begin)/2);
 
-       for (auto loc = first; loc < last;) {
+       for (auto loc = range.begin; loc < range.end;) {
                ex rest;
                ex coeff;
                n.find_ex_by_loc(loc++, rest, sym_lst);
                n.find_ex_by_loc(loc++, coeff, sym_lst);
-               seq.push_back(expair(rest, coeff));
+               seq.emplace_back(expair(rest, coeff));
        }
 
        n.find_ex("var", var, sym_lst);
@@ -255,7 +279,7 @@ int pseries::compare_same_type(const basic & other) const
                return cmpval;
        
        // ...and if that failed the individual elements
-       epvector::const_iterator it = seq.begin(), o_it = o.seq.begin();
+       auto it = seq.begin(), o_it = o.seq.begin();
        while (it!=seq.end() && o_it!=o.seq.end()) {
                cmpval = it->compare(*o_it);
                if (cmpval)
@@ -290,25 +314,17 @@ ex pseries::op(size_t i) const
  *  series is examined termwise. */
 int pseries::degree(const ex &s) const
 {
-       if (var.is_equal(s)) {
-               // Return last exponent
-               if (seq.size())
-                       return ex_to<numeric>((seq.end()-1)->coeff).to_int();
-               else
-                       return 0;
-       } else {
-               epvector::const_iterator it = seq.begin(), itend = seq.end();
-               if (it == itend)
-                       return 0;
-               int max_pow = std::numeric_limits<int>::min();
-               while (it != itend) {
-                       int pow = it->rest.degree(s);
-                       if (pow > max_pow)
-                               max_pow = pow;
-                       ++it;
-               }
-               return max_pow;
-       }
+       if (seq.empty())
+               return 0;
+
+       if (var.is_equal(s))
+               // Return last/greatest exponent
+               return ex_to<numeric>((seq.end()-1)->coeff).to_int();
+
+       int max_pow = std::numeric_limits<int>::min();
+       for (auto & it : seq)
+               max_pow = std::max(max_pow, it.rest.degree(s));
+       return max_pow;
 }
 
 /** Return degree of lowest power of the series.  This is usually the exponent
@@ -318,25 +334,17 @@ int pseries::degree(const ex &s) const
  *  I.e.: (1-x) + (1-x)^2 + Order((1-x)^3) has ldegree(x) 1, not 0. */
 int pseries::ldegree(const ex &s) const
 {
-       if (var.is_equal(s)) {
-               // Return first exponent
-               if (seq.size())
-                       return ex_to<numeric>((seq.begin())->coeff).to_int();
-               else
-                       return 0;
-       } else {
-               epvector::const_iterator it = seq.begin(), itend = seq.end();
-               if (it == itend)
-                       return 0;
-               int min_pow = std::numeric_limits<int>::max();
-               while (it != itend) {
-                       int pow = it->rest.ldegree(s);
-                       if (pow < min_pow)
-                               min_pow = pow;
-                       ++it;
-               }
-               return min_pow;
-       }
+       if (seq.empty())
+               return 0;
+
+       if (var.is_equal(s))
+               // Return first/smallest exponent
+               return ex_to<numeric>((seq.begin())->coeff).to_int();
+
+       int min_pow = std::numeric_limits<int>::max();
+       for (auto & it : seq)
+               min_pow = std::min(min_pow, it.rest.degree(s));
+       return min_pow;
 }
 
 /** Return coefficient of degree n in power series if s is the expansion
@@ -389,35 +397,25 @@ ex pseries::eval() const
        if (flags & status_flags::evaluated) {
                return *this;
        }
-       
+
        // Construct a new series with evaluated coefficients
        epvector new_seq;
        new_seq.reserve(seq.size());
-       epvector::const_iterator it = seq.begin(), itend = seq.end();
-       while (it != itend) {
-               new_seq.push_back(expair(it->rest, it->coeff));
-               ++it;
-       }
+       for (auto & it : seq)
+               new_seq.emplace_back(expair(it.rest, it.coeff));
+
        return dynallocate<pseries>(relational(var,point), std::move(new_seq)).setflag(status_flags::evaluated);
 }
 
 /** Evaluate coefficients numerically. */
-ex pseries::evalf(int level) const
+ex pseries::evalf() const
 {
-       if (level == 1)
-               return *this;
-       
-       if (level == -max_recursion_level)
-               throw (std::runtime_error("pseries::evalf(): recursion limit exceeded"));
-       
        // Construct a new series with evaluated coefficients
        epvector new_seq;
        new_seq.reserve(seq.size());
-       epvector::const_iterator it = seq.begin(), itend = seq.end();
-       while (it != itend) {
-               new_seq.push_back(expair(it->rest.evalf(level-1), it->coeff));
-               ++it;
-       }
+       for (auto & it : seq)
+               new_seq.emplace_back(expair(it.rest.evalf(), it.coeff));
+
        return dynallocate<pseries>(relational(var,point), std::move(new_seq)).setflag(status_flags::evaluated);
 }
 
@@ -447,7 +445,7 @@ ex pseries::real_part() const
        epvector v;
        v.reserve(seq.size());
        for (auto & it : seq)
-               v.push_back(expair((it.rest).real_part(), it.coeff));
+               v.emplace_back(expair(it.rest.real_part(), it.coeff));
        return dynallocate<pseries>(var==point, std::move(v));
 }
 
@@ -462,7 +460,7 @@ ex pseries::imag_part() const
        epvector v;
        v.reserve(seq.size());
        for (auto & it : seq)
-               v.push_back(expair((it.rest).imag_part(), it.coeff));
+               v.emplace_back(expair(it.rest.imag_part(), it.coeff));
        return dynallocate<pseries>(var==point, std::move(v));
 }
 
@@ -471,7 +469,7 @@ ex pseries::eval_integ() const
        std::unique_ptr<epvector> newseq(nullptr);
        for (auto i=seq.begin(); i!=seq.end(); ++i) {
                if (newseq) {
-                       newseq->push_back(expair(i->rest.eval_integ(), i->coeff));
+                       newseq->emplace_back(expair(i->rest.eval_integ(), i->coeff));
                        continue;
                }
                ex newterm = i->rest.eval_integ();
@@ -480,7 +478,7 @@ ex pseries::eval_integ() const
                        newseq->reserve(seq.size());
                        for (auto j=seq.begin(); j!=i; ++j)
                                newseq->push_back(*j);
-                       newseq->push_back(expair(newterm, i->coeff));
+                       newseq->emplace_back(expair(newterm, i->coeff));
                }
        }
 
@@ -499,7 +497,7 @@ ex pseries::evalm() const
                if (something_changed) {
                        ex newcoeff = i->rest.evalm();
                        if (!newcoeff.is_zero())
-                               newseq.push_back(expair(newcoeff, i->coeff));
+                               newseq.emplace_back(expair(newcoeff, i->coeff));
                } else {
                        ex newcoeff = i->rest.evalm();
                        if (!are_ex_trivially_equal(newcoeff, i->rest)) {
@@ -507,7 +505,7 @@ ex pseries::evalm() const
                                newseq.reserve(seq.size());
                                std::copy(seq.begin(), i, std::back_inserter<epvector>(newseq));
                                if (!newcoeff.is_zero())
-                                       newseq.push_back(expair(newcoeff, i->coeff));
+                                       newseq.emplace_back(expair(newcoeff, i->coeff));
                        }
                }
        }
@@ -530,7 +528,7 @@ ex pseries::subs(const exmap & m, unsigned options) const
        epvector newseq;
        newseq.reserve(seq.size());
        for (auto & it : seq)
-               newseq.push_back(expair(it.rest.subs(m, options), it.coeff));
+               newseq.emplace_back(expair(it.rest.subs(m, options), it.coeff));
        return dynallocate<pseries>(relational(var,point.subs(m, options)), std::move(newseq));
 }
 
@@ -542,7 +540,7 @@ ex pseries::expand(unsigned options) const
        for (auto & it : seq) {
                ex restexp = it.rest.expand();
                if (!restexp.is_zero())
-                       newseq.push_back(expair(restexp, it.coeff));
+                       newseq.emplace_back(expair(restexp, it.coeff));
        }
        return dynallocate<pseries>(relational(var,point), std::move(newseq)).setflag(options == 0 ? status_flags::expanded : 0);
 }
@@ -558,11 +556,11 @@ ex pseries::derivative(const symbol & s) const
                // FIXME: coeff might depend on var
                for (auto & it : seq) {
                        if (is_order_function(it.rest)) {
-                               new_seq.push_back(expair(it.rest, it.coeff - 1));
+                               new_seq.emplace_back(expair(it.rest, it.coeff - 1));
                        } else {
                                ex c = it.rest * it.coeff;
                                if (!c.is_zero())
-                                       new_seq.push_back(expair(c, it.coeff - 1));
+                                       new_seq.emplace_back(expair(c, it.coeff - 1));
                        }
                }
 
@@ -574,7 +572,7 @@ ex pseries::derivative(const symbol & s) const
                        } else {
                                ex c = it.rest.diff(s);
                                if (!c.is_zero())
-                                       new_seq.push_back(expair(c, it.coeff));
+                                       new_seq.emplace_back(expair(c, it.coeff));
                        }
                }
        }
@@ -628,7 +626,7 @@ ex basic::series(const relational & r, int order, unsigned options) const
 
        // default for order-values that make no sense for Taylor expansion
        if ((order <= 0) && this->has(s)) {
-               seq.push_back(expair(Order(_ex1), order));
+               seq.emplace_back(expair(Order(_ex1), order));
                return pseries(r, std::move(seq));
        }
 
@@ -638,7 +636,7 @@ ex basic::series(const relational & r, int order, unsigned options) const
        ex coeff = deriv.subs(r, subs_options::no_pattern);
 
        if (!coeff.is_zero()) {
-               seq.push_back(expair(coeff, _ex0));
+               seq.emplace_back(expair(coeff, _ex0));
        }
 
        int n;
@@ -653,13 +651,13 @@ ex basic::series(const relational & r, int order, unsigned options) const
 
                coeff = deriv.subs(r, subs_options::no_pattern);
                if (!coeff.is_zero())
-                       seq.push_back(expair(fac * coeff, n));
+                       seq.emplace_back(expair(fac * coeff, n));
        }
        
        // Higher-order terms, if present
        deriv = deriv.diff(s);
        if (!deriv.expand().is_zero())
-               seq.push_back(expair(Order(_ex1), n));
+               seq.emplace_back(expair(Order(_ex1), n));
        return pseries(r, std::move(seq));
 }
 
@@ -674,13 +672,13 @@ ex symbol::series(const relational & r, int order, unsigned options) const
 
        if (this->is_equal_same_type(ex_to<symbol>(r.lhs()))) {
                if (order > 0 && !point.is_zero())
-                       seq.push_back(expair(point, _ex0));
+                       seq.emplace_back(expair(point, _ex0));
                if (order > 1)
-                       seq.push_back(expair(_ex1, _ex1));
+                       seq.emplace_back(expair(_ex1, _ex1));
                else
-                       seq.push_back(expair(Order(_ex1), numeric(order)));
+                       seq.emplace_back(expair(Order(_ex1), numeric(order)));
        } else
-               seq.push_back(expair(*this, _ex0));
+               seq.emplace_back(expair(*this, _ex0));
        return pseries(r, std::move(seq));
 }
 
@@ -741,12 +739,12 @@ ex pseries::add_series(const pseries &other) const
                } else {
                        // Add coefficient of a and b
                        if (is_order_function((*a).rest) || is_order_function((*b).rest)) {
-                               new_seq.push_back(expair(Order(_ex1), (*a).coeff));
+                               new_seq.emplace_back(expair(Order(_ex1), (*a).coeff));
                                break;  // Order term ends the sequence
                        } else {
                                ex sum = (*a).rest + (*b).rest;
                                if (!(sum.is_zero()))
-                                       new_seq.push_back(expair(sum, numeric(pow_a)));
+                                       new_seq.emplace_back(expair(sum, numeric(pow_a)));
                                ++a;
                                ++b;
                        }
@@ -795,7 +793,7 @@ ex pseries::mul_const(const numeric &other) const
        
        for (auto & it : seq) {
                if (!is_order_function(it.rest))
-                       new_seq.push_back(expair(it.rest * other, it.coeff));
+                       new_seq.emplace_back(expair(it.rest * other, it.coeff));
                else
                        new_seq.push_back(it);
        }
@@ -862,10 +860,10 @@ ex pseries::mul_series(const pseries &other) const
                                co += ita->second * itb->second;
                }
                if (!co.is_zero())
-                       new_seq.push_back(expair(co, numeric(cdeg)));
+                       new_seq.emplace_back(expair(co, numeric(cdeg)));
        }
        if (higher_order_c < std::numeric_limits<int>::max())
-               new_seq.push_back(expair(Order(_ex1), numeric(higher_order_c)));
+               new_seq.emplace_back(expair(Order(_ex1), numeric(higher_order_c)));
        return pseries(relational(var, point), std::move(new_seq));
 }
 
@@ -959,9 +957,8 @@ ex mul::series(const relational & r, int order, unsigned options) const
 
        int degsum = std::accumulate(ldegrees.begin(), ldegrees.end(), 0);
 
-       if (degsum >= order) {
-               epvector epv { expair(Order(_ex1), order) };
-               return dynallocate<pseries>(r, std::move(epv));
+       if (degsum > order) {
+               return dynallocate<pseries>(r, epvector{{Order(_ex1), order}});
        }
 
        // Multiply with remaining terms
@@ -1057,14 +1054,14 @@ ex pseries::power_const(const numeric &p, int deg) const
        bool higher_order = false;
        for (int i=0; i<numcoeff; ++i) {
                if (!co[i].is_zero())
-                       new_seq.push_back(expair(co[i], p * ldeg + i));
+                       new_seq.emplace_back(expair(co[i], p * ldeg + i));
                if (is_order_function(co[i])) {
                        higher_order = true;
                        break;
                }
        }
        if (!higher_order)
-               new_seq.push_back(expair(Order(_ex1), p * ldeg + numcoeff));
+               new_seq.emplace_back(expair(Order(_ex1), p * ldeg + numcoeff));
 
        return pseries(relational(var,point), std::move(new_seq));
 }
@@ -1134,9 +1131,9 @@ ex power::series(const relational & r, int order, unsigned options) const
        if (basis.is_equal(r.lhs() - r.rhs())) {
                epvector new_seq;
                if (ex_to<numeric>(exponent).to_int() < order)
-                       new_seq.push_back(expair(_ex1, exponent));
+                       new_seq.emplace_back(expair(_ex1, exponent));
                else
-                       new_seq.push_back(expair(Order(_ex1), exponent));
+                       new_seq.emplace_back(expair(Order(_ex1), exponent));
                return pseries(r, std::move(new_seq));
        }
 
@@ -1193,7 +1190,7 @@ ex pseries::series(const relational & r, int order, unsigned options) const
                        for (auto & it : seq) {
                                int o = ex_to<numeric>(it.coeff).to_int();
                                if (o >= order) {
-                                       new_seq.push_back(expair(Order(_ex1), o));
+                                       new_seq.emplace_back(expair(Order(_ex1), o));
                                        break;
                                }
                                new_seq.push_back(it);
@@ -1219,7 +1216,7 @@ ex integral::series(const relational & r, int order, unsigned options) const
                        ? currcoeff
                        : integral(x, a.subs(r), b.subs(r), currcoeff);
                if (currcoeff != 0)
-                       fexpansion.push_back(
+                       fexpansion.emplace_back(
                                expair(currcoeff, ex_to<pseries>(fseries).exponop(i)));
        }