]> www.ginac.de Git - ginac.git/blobdiff - ginac/power.cpp
Patch by Stefan Weinzierl that fixes a bug in series expansion.
[ginac.git] / ginac / power.cpp
index 120f579a3a9fd62a44e30e0af7d363c9e0b4d3e6..a63556b20a55da3307be74f1f456fae25e6a4f84 100644 (file)
@@ -3,7 +3,7 @@
  *  Implementation of GiNaC's symbolic exponentiation (basis^exponent). */
 
 /*
- *  GiNaC Copyright (C) 1999-2005 Johannes Gutenberg University Mainz, Germany
+ *  GiNaC Copyright (C) 1999-2007 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
@@ -325,6 +325,7 @@ ex power::coeff(const ex & s, int n) const
  *  - ^(0,c) -> 0 or exception  (depending on the real part of c)
  *  - ^(1,x) -> 1
  *  - ^(c1,c2) -> *(c1^n,c1^(c2-n))  (so that 0<(c2-n)<1, try to evaluate roots, possibly in numerator and denominator of c1)
+ *  - ^(^(x,c1),c2) -> ^(x,c1*c2)  if x is positive and c1 is real.
  *  - ^(^(x,c1),c2) -> ^(x,c1*c2)  (c2 integer or -1 < c1 <= 1, case c1=1 should not happen, see below!)
  *  - ^(*(x,y,z),c) -> *(x^c,y^c,z^c)  (if c integer)
  *  - ^(*(x,c1),c2) -> ^(x,c2)*c1^c2  (c1>0)
@@ -381,6 +382,10 @@ ex power::eval(int level) const
        if (ebasis.is_equal(_ex1))
                return _ex1;
 
+       // Turn (x^c)^d into x^(c*d) in the case that x is positive and c is real.
+       if (is_exactly_a<power>(ebasis) && ebasis.op(0).info(info_flags::positive) && ebasis.op(1).info(info_flags::real))
+               return power(ebasis.op(0), ebasis.op(1) * eexponent);
+
        if (exponent_is_numerical) {
 
                // ^(c1,c2) -> c1^c2  (c1, c2 numeric(),
@@ -448,7 +453,7 @@ ex power::eval(int level) const
                        if (is_exactly_a<numeric>(sub_exponent)) {
                                const numeric & num_sub_exponent = ex_to<numeric>(sub_exponent);
                                GINAC_ASSERT(num_sub_exponent!=numeric(1));
-                               if (num_exponent->is_integer() || (abs(num_sub_exponent) - _num1).is_negative())
+                               if (num_exponent->is_integer() || (abs(num_sub_exponent) - (*_num1_p)).is_negative())
                                        return power(sub_basis,num_sub_exponent.mul(*num_exponent));
                        }
                }
@@ -474,8 +479,8 @@ ex power::eval(int level) const
                                                return (new mul(power(*mulp,exponent),
                                                                power(num_coeff,*num_exponent)))->setflag(status_flags::dynallocated);
                                        } else {
-                                               GINAC_ASSERT(num_coeff.compare(_num0)<0);
-                                               if (!num_coeff.is_equal(_num_1)) {
+                                               GINAC_ASSERT(num_coeff.compare(*_num0_p)<0);
+                                               if (!num_coeff.is_equal(*_num_1_p)) {
                                                        mul *mulp = new mul(mulref);
                                                        mulp->overall_coeff = _ex_1;
                                                        mulp->clearflag(status_flags::evaluated);
@@ -583,7 +588,7 @@ ex power::conjugate() const
  *  @see ex::diff */
 ex power::derivative(const symbol & s) const
 {
-       if (exponent.info(info_flags::real)) {
+       if (is_a<numeric>(exponent)) {
                // D(b^r) = r * b^(r-1) * D(b) (faster than the formula below)
                epvector newseq;
                newseq.reserve(2);
@@ -704,7 +709,7 @@ ex power::expand_add(const add & a, int n, unsigned options) const
        const size_t m = a.nops();
        exvector result;
        // The number of terms will be the number of combinatorial compositions,
-       // i.e. the number of unordered arrangement of m nonnegative integers
+       // i.e. the number of unordered arrangements of m nonnegative integers
        // which sum up to n.  It is frequently written as C_n(m) and directly
        // related with binomial coefficients:
        result.reserve(binomial(numeric(n+m-1), numeric(m-1)).to_int());
@@ -806,7 +811,7 @@ ex power::expand_add_2(const add & a, unsigned options) const
                
                if (c.is_equal(_ex1)) {
                        if (is_exactly_a<mul>(r)) {
-                               sum.push_back(expair(expand_mul(ex_to<mul>(r), _num2, options, true),
+                               sum.push_back(expair(expand_mul(ex_to<mul>(r), *_num2_p, options, true),
                                                     _ex1));
                        } else {
                                sum.push_back(expair((new power(r,_ex2))->setflag(status_flags::dynallocated),
@@ -814,11 +819,11 @@ ex power::expand_add_2(const add & a, unsigned options) const
                        }
                } else {
                        if (is_exactly_a<mul>(r)) {
-                               sum.push_back(a.combine_ex_with_coeff_to_pair(expand_mul(ex_to<mul>(r), _num2, options, true),
-                                                    ex_to<numeric>(c).power_dyn(_num2)));
+                               sum.push_back(a.combine_ex_with_coeff_to_pair(expand_mul(ex_to<mul>(r), *_num2_p, options, true),
+                                                    ex_to<numeric>(c).power_dyn(*_num2_p)));
                        } else {
                                sum.push_back(a.combine_ex_with_coeff_to_pair((new power(r,_ex2))->setflag(status_flags::dynallocated),
-                                                    ex_to<numeric>(c).power_dyn(_num2)));
+                                                    ex_to<numeric>(c).power_dyn(*_num2_p)));
                        }
                }
 
@@ -826,7 +831,7 @@ ex power::expand_add_2(const add & a, unsigned options) const
                        const ex & r1 = cit1->rest;
                        const ex & c1 = cit1->coeff;
                        sum.push_back(a.combine_ex_with_coeff_to_pair((new mul(r,r1))->setflag(status_flags::dynallocated),
-                                                                     _num2.mul(ex_to<numeric>(c)).mul_dyn(ex_to<numeric>(c1))));
+                                                                     _num2_p->mul(ex_to<numeric>(c)).mul_dyn(ex_to<numeric>(c1))));
                }
        }
        
@@ -836,10 +841,10 @@ ex power::expand_add_2(const add & a, unsigned options) const
        if (!a.overall_coeff.is_zero()) {
                epvector::const_iterator i = a.seq.begin(), end = a.seq.end();
                while (i != end) {
-                       sum.push_back(a.combine_pair_with_coeff_to_pair(*i, ex_to<numeric>(a.overall_coeff).mul_dyn(_num2)));
+                       sum.push_back(a.combine_pair_with_coeff_to_pair(*i, ex_to<numeric>(a.overall_coeff).mul_dyn(*_num2_p)));
                        ++i;
                }
-               sum.push_back(expair(ex_to<numeric>(a.overall_coeff).power_dyn(_num2),_ex1));
+               sum.push_back(expair(ex_to<numeric>(a.overall_coeff).power_dyn(*_num2_p),_ex1));
        }
        
        GINAC_ASSERT(sum.size()==(a_nops*(a_nops+1))/2);
@@ -847,14 +852,23 @@ ex power::expand_add_2(const add & a, unsigned options) const
        return (new add(sum))->setflag(status_flags::dynallocated | status_flags::expanded);
 }
 
-/** Expand factors of m in m^n where m is a mul and n is and integer.
+/** Expand factors of m in m^n where m is a mul and n is an integer.
  *  @see power::expand */
 ex power::expand_mul(const mul & m, const numeric & n, unsigned options, bool from_expand) const
 {
        GINAC_ASSERT(n.is_integer());
 
-       if (n.is_zero())
+       if (n.is_zero()) {
                return _ex1;
+       }
+
+       // Leave it to multiplication since dummy indices have to be renamed
+       if (get_all_dummy_indices(m).size() > 0 && n.is_positive()) {
+               ex result = m;
+               for (int i=1; i < n.to_int(); i++)
+                       result *= rename_dummy_indices_uniquely(m,m);
+               return result;
+       }
 
        epvector distrseq;
        distrseq.reserve(m.seq.size());
@@ -863,19 +877,13 @@ ex power::expand_mul(const mul & m, const numeric & n, unsigned options, bool fr
        epvector::const_iterator last = m.seq.end();
        epvector::const_iterator cit = m.seq.begin();
        while (cit!=last) {
-               if (is_exactly_a<numeric>(cit->rest)) {
-                       distrseq.push_back(m.combine_pair_with_coeff_to_pair(*cit, n));
-               } else {
-                       // it is safe not to call mul::combine_pair_with_coeff_to_pair()
-                       // since n is an integer
-                       numeric new_coeff = ex_to<numeric>(cit->coeff).mul(n);
-                       if (from_expand && is_exactly_a<add>(cit->rest) && new_coeff.is_pos_integer()) {
-                               // this happens when e.g. (a+b)^(1/2) gets squared and
-                               // the resulting product needs to be reexpanded
-                               need_reexpand = true;
-                       }
-                       distrseq.push_back(expair(cit->rest, new_coeff));
+               expair p = m.combine_pair_with_coeff_to_pair(*cit, n);
+               if (from_expand && is_exactly_a<add>(cit->rest) && ex_to<numeric>(p.coeff).is_pos_integer()) {
+                       // this happens when e.g. (a+b)^(1/2) gets squared and
+                       // the resulting product needs to be reexpanded
+                       need_reexpand = true;
                }
+               distrseq.push_back(p);
                ++cit;
        }