]> www.ginac.de Git - ginac.git/blobdiff - ginac/pseries.cpp
- lcm_of_coefficients_denominators(1/2+x^10) returned 1024 instead of 2 and
[ginac.git] / ginac / pseries.cpp
index 9dc0921ed3317a299ee15533b11789a16d6ad130..3b2ac7010e051a5d2b49fb2dd90e65aab7c24b82 100644 (file)
@@ -4,7 +4,7 @@
  *  methods for series expansion. */
 
 /*
- *  GiNaC Copyright (C) 1999-2000 Johannes Gutenberg University Mainz, Germany
+ *  GiNaC Copyright (C) 1999-2001 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
 #include "utils.h"
 #include "debugmsg.h"
 
-#ifndef NO_NAMESPACE_GINAC
 namespace GiNaC {
-#endif // ndef NO_NAMESPACE_GINAC
 
 GINAC_IMPLEMENT_REGISTERED_CLASS(pseries, basic)
 
 /*
- *  Default constructor, destructor, copy constructor, assignment operator and helpers
+ *  Default ctor, dtor, copy ctor, assignment operator and helpers
  */
 
 pseries::pseries() : basic(TINFO_pseries)
 {
-       debugmsg("pseries default constructor", LOGLEVEL_CONSTRUCT);
-}
-
-pseries::~pseries()
-{
-       debugmsg("pseries destructor", LOGLEVEL_DESTRUCT);
-       destroy(false);
-}
-
-pseries::pseries(const pseries &other)
-{
-       debugmsg("pseries copy constructor", LOGLEVEL_CONSTRUCT);
-       copy(other);
-}
-
-const pseries &pseries::operator=(const pseries & other)
-{
-       debugmsg("pseries operator=", LOGLEVEL_ASSIGNMENT);
-       if (this != &other) {
-               destroy(true);
-               copy(other);
-       }
-       return *this;
+       debugmsg("pseries default ctor", LOGLEVEL_CONSTRUCT);
 }
 
 void pseries::copy(const pseries &other)
@@ -88,7 +64,7 @@ void pseries::destroy(bool call_parent)
 
 
 /*
- *  Other constructors
+ *  Other ctors
  */
 
 /** Construct pseries from a vector of coefficients and powers.
@@ -102,7 +78,7 @@ void pseries::destroy(bool call_parent)
  *  @return newly constructed pseries */
 pseries::pseries(const ex &rel_, const epvector &ops_) : basic(TINFO_pseries), seq(ops_)
 {
-       debugmsg("pseries constructor from ex,epvector", LOGLEVEL_CONSTRUCT);
+       debugmsg("pseries ctor from ex,epvector", LOGLEVEL_CONSTRUCT);
        GINAC_ASSERT(is_ex_exactly_of_type(rel_, relational));
        GINAC_ASSERT(is_ex_exactly_of_type(rel_.lhs(),symbol));
        point = rel_.rhs();
@@ -117,7 +93,7 @@ pseries::pseries(const ex &rel_, const epvector &ops_) : basic(TINFO_pseries), s
 /** Construct object from archive_node. */
 pseries::pseries(const archive_node &n, const lst &sym_lst) : inherited(n, sym_lst)
 {
-       debugmsg("pseries constructor from archive_node", LOGLEVEL_CONSTRUCT);
+       debugmsg("pseries ctor from archive_node", LOGLEVEL_CONSTRUCT);
        for (unsigned int i=0; true; ++i) {
                ex rest;
                ex coeff;
@@ -154,19 +130,15 @@ void pseries::archive(archive_node &n) const
 // functions overriding virtual functions from bases classes
 //////////
 
-basic *pseries::duplicate() const
-{
-       debugmsg("pseries duplicate", LOGLEVEL_DUPLICATE);
-       return new pseries(*this);
-}
-
 void pseries::print(std::ostream &os, unsigned upper_precedence) const
 {
        debugmsg("pseries print", LOGLEVEL_PRINT);
+       if (precedence<=upper_precedence) os << "(";
+       // objects of type pseries must not have any zero entries, so the
+       // trivial (zero) pseries needs a special treatment here:
+       if (seq.size()==0)
+               os << '0';
        for (epvector::const_iterator i=seq.begin(); i!=seq.end(); ++i) {
-               // omit zero terms
-               if (i->rest.is_zero())
-                       continue;
                // print a sign, if needed
                if (i!=seq.begin())
                        os << '+';
@@ -196,16 +168,16 @@ void pseries::print(std::ostream &os, unsigned upper_precedence) const
                        os << Order(power(var-point,i->coeff));
                }
        }
+       if (precedence<=upper_precedence) os << ")";
 }
 
 
 void pseries::printraw(std::ostream &os) const
 {
        debugmsg("pseries printraw", LOGLEVEL_PRINT);
-       os << "pseries(" << var << ";" << point << ";";
-       for (epvector::const_iterator i=seq.begin(); i!=seq.end(); ++i) {
+       os << class_name() << "(" << var << ";" << point << ";";
+       for (epvector::const_iterator i=seq.begin(); i!=seq.end(); ++i)
                os << "(" << (*i).rest << "," << (*i).coeff << "),";
-       }
        os << ")";
 }
 
@@ -213,7 +185,7 @@ void pseries::printraw(std::ostream &os) const
 void pseries::printtree(std::ostream & os, unsigned indent) const
 {
        debugmsg("pseries printtree",LOGLEVEL_PRINT);
-       os << std::string(indent,' ') << "pseries " 
+       os << std::string(indent,' ') << class_name()
           << ", hash=" << hashvalue
           << " (0x" << std::hex << hashvalue << std::dec << ")"
           << ", flags=" << flags << std::endl;
@@ -227,6 +199,39 @@ void pseries::printtree(std::ostream & os, unsigned indent) const
        point.printtree(os, indent+delta_indent);
 }
 
+int pseries::compare_same_type(const basic & other) const
+{
+       GINAC_ASSERT(is_of_type(other, pseries));
+       const pseries &o = static_cast<const pseries &>(other);
+       
+       // first compare the lengths of the series...
+       if (seq.size()>o.seq.size())
+               return 1;
+       if (seq.size()<o.seq.size())
+               return -1;
+       
+       // ...then the expansion point...
+       int cmpval = var.compare(o.var);
+       if (cmpval)
+               return cmpval;
+       cmpval = point.compare(o.point);
+       if (cmpval)
+               return cmpval;
+       
+       // ...and if that failed the individual elements
+       epvector::const_iterator it = seq.begin(), o_it = o.seq.begin();
+       while (it!=seq.end() && o_it!=o.seq.end()) {
+               cmpval = it->compare(*o_it);
+               if (cmpval)
+                       return cmpval;
+               ++it;
+               ++o_it;
+       }
+
+       // so they are equal.
+       return 0;
+}
+
 /** Return the number of operands including a possible order term. */
 unsigned pseries::nops(void) const
 {
@@ -303,6 +308,13 @@ int pseries::ldegree(const symbol &s) const
        }
 }
 
+/** Return coefficient of degree n in power series if s is the expansion
+ *  variable.  If the expansion point is nonzero, by definition the n=1
+ *  coefficient in s of a+b*(s-z)+c*(s-z)^2+Order((s-z)^3) is b (assuming
+ *  the expansion took place in the s in the first place).
+ *  If s is not the expansion variable, an attempt is made to convert the
+ *  series to a polynomial and return the corresponding coefficient from
+ *  there. */
 ex pseries::coeff(const symbol &s, int n) const
 {
        if (var.is_equal(s)) {
@@ -334,7 +346,7 @@ ex pseries::coeff(const symbol &s, int n) const
                return convert_to_poly().coeff(s, n);
 }
 
-
+/** Does nothing. */
 ex pseries::collect(const symbol &s) const
 {
        return *this;
@@ -405,14 +417,15 @@ ex pseries::subs(const lst & ls, const lst & lr) const
 
 
 /** Implementation of ex::expand() for a power series.  It expands all the
- *  terms individually and returns the resulting series as a new pseries.
- *  @see ex::diff */
+ *  terms individually and returns the resulting series as a new pseries. */
 ex pseries::expand(unsigned options) const
 {
        epvector newseq;
-       newseq.reserve(seq.size());
-       for (epvector::const_iterator i=seq.begin(); i!=seq.end(); ++i)
-               newseq.push_back(expair(i->rest.expand(), i->coeff));
+       for (epvector::const_iterator i=seq.begin(); i!=seq.end(); ++i) {
+               ex restexp = i->rest.expand();
+               if (!restexp.is_zero())
+                       newseq.push_back(expair(restexp, i->coeff));
+       }
        return (new pseries(relational(var,point), newseq))
                ->setflag(status_flags::dynallocated | status_flags::expanded);
 }
@@ -445,10 +458,6 @@ ex pseries::derivative(const symbol & s) const
 }
 
 
-/*
- *  Construct ordinary polynomial out of series
- */
-
 /** Convert a pseries object to an ordinary polynomial.
  *
  *  @param no_order flag: discard higher order terms */
@@ -468,6 +477,7 @@ ex pseries::convert_to_poly(bool no_order) const
        return e;
 }
 
+
 /** Returns true if there is no order term, i.e. the series terminates and
  *  false otherwise. */
 bool pseries::is_terminating(void) const
@@ -477,7 +487,7 @@ bool pseries::is_terminating(void) const
 
 
 /*
- *  Implementation of series expansion
+ *  Implementations of series expansion
  */
 
 /** Default implementation of ex::series(). This performs Taylor expansion.
@@ -753,17 +763,46 @@ ex mul::series(const relational & r, int order, unsigned options) const
  *  @param deg  truncation order of series calculation */
 ex pseries::power_const(const numeric &p, int deg) const
 {
-       int i;
+       // method:
+       // let A(x) be this series and for the time being let it start with a
+       // constant (later we'll generalize):
+       //     A(x) = a_0 + a_1*x + a_2*x^2 + ...
+       // We want to compute
+       //     C(x) = A(x)^p
+       //     C(x) = c_0 + c_1*x + c_2*x^2 + ...
+       // Taking the derivative on both sides and multiplying with A(x) one
+       // immediately arrives at
+       //     C'(x)*A(x) = p*C(x)*A'(x)
+       // Multiplying this out and comparing coefficients we get the recurrence
+       // formula
+       //     c_i = (i*p*a_i*c_0 + ((i-1)*p-1)*a_{i-1}*c_1 + ...
+       //                    ... + (p-(i-1))*a_1*c_{i-1})/(a_0*i)
+       // which can easily be solved given the starting value c_0 = (a_0)^p.
+       // For the more general case where the leading coefficient of A(x) is not
+       // a constant, just consider A2(x) = A(x)*x^m, with some integer m and
+       // repeat the above derivation.  The leading power of C2(x) = A2(x)^2 is
+       // then of course x^(p*m) but the recurrence formula still holds.
+       
+       if (seq.size()==0) {
+               // as a spacial case, handle the empty (zero) series honoring the
+               // usual power laws such as implemented in power::eval()
+               if (p.real().is_zero())
+                       throw (std::domain_error("pseries::power_const(): pow(0,I) is undefined"));
+               else if (p.real().is_negative())
+                       throw (pole_error("pseries::power_const(): division by zero",1));
+               else
+                       return *this;
+       }
+       
        const symbol *s = static_cast<symbol *>(var.bp);
        int ldeg = ldegree(*s);
        
-       // Calculate coefficients of powered series
+       // Compute coefficients of the powered series
        exvector co;
        co.reserve(deg);
-       ex co0;
-       co.push_back(co0 = power(coeff(*s, ldeg), p));
+       co.push_back(power(coeff(*s, ldeg), p));
        bool all_sums_zero = true;
-       for (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(*s, j + ldeg);
@@ -775,13 +814,13 @@ ex pseries::power_const(const numeric &p, int deg) const
                }
                if (!sum.is_zero())
                        all_sums_zero = false;
-               co.push_back(co0 * sum / numeric(i));
+               co.push_back(sum / coeff(*s, ldeg) / numeric(i));
        }
        
        // Construct new series (of non-zero coefficients)
        epvector new_seq;
        bool higher_order = false;
-       for (i=0; i<deg; ++i) {
+       for (int i=0; i<deg; ++i) {
                if (!co[i].is_zero())
                        new_seq.push_back(expair(co[i], numeric(i) + p * ldeg));
                if (is_order_function(co[i])) {
@@ -812,12 +851,20 @@ ex power::series(const relational & r, int order, unsigned options) const
 {
        ex e;
        if (!is_ex_exactly_of_type(basis, pseries)) {
-               // Basis is not a series, may there be a singulary?
-               if (!exponent.info(info_flags::negint))
+               // Basis is not a series, may there be a singularity?
+               bool must_expand_basis = false;
+               try {
+                       basis.subs(r);
+               } catch (pole_error) {
+                       must_expand_basis = true;
+               }
+               
+               // Is the expression of type something^(-int)?
+               if (!must_expand_basis && !exponent.info(info_flags::negint))
                        return basic::series(r, order, options);
                
-               // Expression is of type something^(-int), check for singularity
-               if (!basis.subs(r).is_zero())
+               // Is the expression of type 0^something?
+               if (!must_expand_basis && !basis.subs(r).is_zero())
                        return basic::series(r, order, options);
                
                // Singularity encountered, expand basis into series
@@ -891,11 +938,12 @@ ex ex::series(const ex & r, int order, unsigned options) const
        return e;
 }
 
+//////////
+// static member variables
+//////////
+
+// protected
 
-// Global constants
-const pseries some_pseries;
-const std::type_info & typeid_pseries = typeid(some_pseries);
+unsigned pseries::precedence = 38;  // for clarity just below add::precedence
 
-#ifndef NO_NAMESPACE_GINAC
 } // namespace GiNaC
-#endif // ndef NO_NAMESPACE_GINAC