]> www.ginac.de Git - ginac.git/blobdiff - ginac/pseries.cpp
Added missing namespace qualifier
[ginac.git] / ginac / pseries.cpp
index 0d2dde29caf41ece49ce808b54ec3f2394351042..d622ecc20f6c442c2576bc6836073be7bac27f41 100644 (file)
@@ -4,7 +4,7 @@
  *  methods for series expansion. */
 
 /*
- *  GiNaC Copyright (C) 1999-2003 Johannes Gutenberg University Mainz, Germany
+ *  GiNaC Copyright (C) 1999-2004 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
@@ -21,7 +21,7 @@
  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  */
 
-#include <iostream>
+#include <numeric>
 #include <stdexcept>
 
 #include "pseries.h"
@@ -513,14 +513,14 @@ ex basic::series(const relational & r, int order, unsigned options) const
        epvector seq;
        numeric fac = 1;
        ex deriv = *this;
-       ex coeff = deriv.subs(r);
+       ex coeff = deriv.subs(r, subs_options::no_pattern);
        const symbol &s = ex_to<symbol>(r.lhs());
        
        if (!coeff.is_zero())
                seq.push_back(expair(coeff, _ex0));
        
        int n;
-       for (n=1; n<order; ++n) {
+       for (n=1; n<=order; ++n) {
                fac = fac.mul(n);
                // We need to test for zero in order to see if the series terminates.
                // The problem is that there is no such thing as a perfect test for
@@ -529,15 +529,40 @@ ex basic::series(const relational & r, int order, unsigned options) const
                if (deriv.is_zero())  // Series terminates
                        return pseries(r, seq);
 
-               coeff = deriv.subs(r);
+               coeff = deriv.subs(r, subs_options::no_pattern);
                if (!coeff.is_zero())
                        seq.push_back(expair(fac.inverse() * coeff, n));
        }
        
        // Higher-order terms, if present
-       deriv = deriv.diff(s);
-       if (!deriv.expand().is_zero())
-               seq.push_back(expair(Order(_ex1), n));
+       int ldeg;
+       try {
+               ldeg = std::abs(deriv.ldegree(s));
+       }
+       catch (std::runtime_error) {
+               ldeg = 0;
+       }
+       if (ldeg != 0) {
+               // pure polynomial
+               if (!deriv.subs(r, subs_options::no_pattern).is_zero()) {
+                       seq.push_back(expair(Order(_ex1), n));
+               } else {
+               seq.push_back(expair(Order(_ex1), n+ldeg-1));
+               }
+       } else {
+               // something more complicated -> loop until next coefficient is found
+               for (;; ++n) {
+                       deriv = deriv.diff(s).expand();
+                       if (deriv.is_zero()) {
+                               break;
+                       }
+                       if (!deriv.subs(r, subs_options::no_pattern).is_zero()) {
+                               seq.push_back(expair(Order(_ex1), n));
+                               break;
+                       }
+               }
+       }
+       
        return pseries(r, seq);
 }
 
@@ -747,19 +772,59 @@ ex mul::series(const relational & r, int order, unsigned options) const
 {
        pseries acc; // Series accumulator
 
+       GINAC_ASSERT(is_a<symbol>(r.lhs()));
+       const ex& sym = r.lhs();
+               
+       // holds ldegrees of the series of individual factors
+       std::vector<int> ldegrees;
+       // flag if series have to be re-calculated
+       bool negldegree = false;
+
        // Multiply with remaining terms
        const epvector::const_iterator itbeg = seq.begin();
        const epvector::const_iterator itend = seq.end();
        for (epvector::const_iterator it=itbeg; it!=itend; ++it) {
                ex op = recombine_pair_to_ex(*it).series(r, order, options);
 
+               int ldeg = op.ldegree(sym);
+               ldegrees.push_back(ldeg);
+               if (ldeg < 0) {
+                       negldegree = true;
+               }
+
                // Series multiplication
                if (it==itbeg)
                        acc = ex_to<pseries>(op);
                else
                        acc = ex_to<pseries>(acc.mul_series(ex_to<pseries>(op)));
        }
-       return acc.mul_const(ex_to<numeric>(overall_coeff));
+
+       if (seq.size() > 1) {
+
+               // re-calculation of series
+
+               pseries newacc;
+
+               const int degsum = std::accumulate(ldegrees.begin(), ldegrees.end(), 0);
+
+               // Multiply with remaining terms
+               const epvector::const_reverse_iterator itbeg = seq.rbegin();
+               const epvector::const_reverse_iterator itend = seq.rend();
+               std::vector<int>::const_reverse_iterator itd = ldegrees.rbegin();
+               for (epvector::const_reverse_iterator it=itbeg; it!=itend; ++it, ++itd) {
+
+                       ex op = recombine_pair_to_ex(*it).series(r, order-degsum+(*itd), options);
+
+                       // Series multiplication
+                       if (it==itbeg)
+                               newacc = ex_to<pseries>(op);
+                       else
+                               newacc = ex_to<pseries>(newacc.mul_series(ex_to<pseries>(op)));
+               }
+               return newacc.mul_const(ex_to<numeric>(overall_coeff));
+       } else {
+               return acc.mul_const(ex_to<numeric>(overall_coeff));
+       }
 }
 
 
@@ -805,6 +870,9 @@ ex pseries::power_const(const numeric &p, int deg) const
        if (!(p*ldeg).is_integer())
                throw std::runtime_error("pseries::power_const(): trying to assemble a Puiseux series");
 
+       // adjust number of coefficients
+       deg = deg - p.to_int()*ldeg;
+       
        // O(x^n)^(-m) is undefined
        if (seq.size() == 1 && is_order_function(seq[0].rest) && p.real().is_negative())
                throw pole_error("pseries::power_const(): division by zero",1);
@@ -814,7 +882,7 @@ ex pseries::power_const(const numeric &p, int deg) const
        co.reserve(deg);
        co.push_back(power(coeff(var, ldeg), p));
        bool all_sums_zero = true;
-       for (int i=1; i<deg; ++i) {
+       for (int i=1; i<=deg; ++i) {
                ex sum = _ex0;
                for (int j=1; j<=i; ++j) {
                        ex c = coeff(var, j + ldeg);
@@ -832,7 +900,7 @@ ex pseries::power_const(const numeric &p, int deg) const
        // Construct new series (of non-zero coefficients)
        epvector new_seq;
        bool higher_order = false;
-       for (int i=0; i<deg; ++i) {
+       for (int i=0; i<=deg; ++i) {
                if (!co[i].is_zero())
                        new_seq.push_back(expair(co[i], p * ldeg + i));
                if (is_order_function(co[i])) {
@@ -841,7 +909,8 @@ ex pseries::power_const(const numeric &p, int deg) const
                }
        }
        if (!higher_order && !all_sums_zero)
-               new_seq.push_back(expair(Order(_ex1), p * ldeg + deg));
+               new_seq.push_back(expair(Order(_ex1), p * ldeg + deg + 1));
+
        return pseries(relational(var,point), new_seq);
 }
 
@@ -871,7 +940,7 @@ ex power::series(const relational & r, int order, unsigned options) const
        // Basis is not a series, may there be a singularity?
        bool must_expand_basis = false;
        try {
-               basis.subs(r);
+               basis.subs(r, subs_options::no_pattern);
        } catch (pole_error) {
                must_expand_basis = true;
        }
@@ -879,9 +948,9 @@ ex power::series(const relational & r, int order, unsigned options) const
        // Is the expression of type something^(-int)?
        if (!must_expand_basis && !exponent.info(info_flags::negint))
                return basic::series(r, order, options);
-               
+
        // Is the expression of type 0^something?
-       if (!must_expand_basis && !basis.subs(r).is_zero())
+       if (!must_expand_basis && !basis.subs(r, subs_options::no_pattern).is_zero())
                return basic::series(r, order, options);
 
        // Singularity encountered, is the basis equal to (var - point)?
@@ -895,8 +964,13 @@ ex power::series(const relational & r, int order, unsigned options) const
        }
 
        // No, expand basis into series
+       int intexp = ex_to<numeric>(exponent).to_int();
        ex e = basis.series(r, order, options);
-       return ex_to<pseries>(e).power_const(ex_to<numeric>(exponent), order);
+       int ldeg = ex_to<pseries>(e).ldegree(r.lhs());
+       if (intexp * ldeg < 0) {
+               e = basis.series(r, order + ldeg*(1-intexp), options);
+       }
+       return ex_to<pseries>(e).power_const(intexp, order);
 }