]> www.ginac.de Git - ginac.git/blobdiff - ginac/power.cpp
Convert some more ctors from copying to moving STL containers.
[ginac.git] / ginac / power.cpp
index f951e4fdbafdea30eb10df0102c29b8fffdf4bfe..bf48e93eb3fdc334703dac1aa72aec72ff492b32 100644 (file)
@@ -571,7 +571,7 @@ ex power::eval(int level) const
                if (num_exponent->is_pos_integer() &&
                    ebasis.return_type() != return_types::commutative &&
                    !is_a<matrix>(ebasis)) {
-                       return ncmul(exvector(num_exponent->to_int(), ebasis), true);
+                       return ncmul(exvector(num_exponent->to_int(), ebasis));
                }
        }
        
@@ -695,51 +695,71 @@ ex power::conjugate() const
 
 ex power::real_part() const
 {
+       // basis == a+I*b, exponent == c+I*d
+       const ex a = basis.real_part();
+       const ex c = exponent.real_part();
+       if (basis.is_equal(a) && exponent.is_equal(c)) {
+               // Re(a^c)
+               return *this;
+       }
+
+       const ex b = basis.imag_part();
        if (exponent.info(info_flags::integer)) {
-               ex basis_real = basis.real_part();
-               if (basis_real == basis)
-                       return *this;
-               realsymbol a("a"),b("b");
-               ex result;
-               if (exponent.info(info_flags::posint))
-                       result = power(a+I*b,exponent);
-               else
-                       result = power(a/(a*a+b*b)-I*b/(a*a+b*b),-exponent);
-               result = result.expand();
-               result = result.real_part();
-               result = result.subs(lst( a==basis_real, b==basis.imag_part() ));
+               // Re((a+I*b)^c)  w/  c ∈ ℤ
+               long N = ex_to<numeric>(c).to_long();
+               // Use real terms in Binomial expansion to construct
+               // Re(expand(power(a+I*b, N))).
+               long NN = N > 0 ? N : -N;
+               ex numer = N > 0 ? _ex1 : power(power(a,2) + power(b,2), NN);
+               ex result = 0;
+               for (long n = 0; n <= NN; n += 2) {
+                       ex term = binomial(NN, n) * power(a, NN-n) * power(b, n) / numer;
+                       if (n % 4 == 0) {
+                               result += term;  // sign: I^n w/ n == 4*m
+                       } else {
+                               result -= term;  // sign: I^n w/ n == 4*m+2
+                       }
+               }
                return result;
        }
-       
-       ex a = basis.real_part();
-       ex b = basis.imag_part();
-       ex c = exponent.real_part();
-       ex d = exponent.imag_part();
+
+       // Re((a+I*b)^(c+I*d))
+       const ex d = exponent.imag_part();
        return power(abs(basis),c)*exp(-d*atan2(b,a))*cos(c*atan2(b,a)+d*log(abs(basis)));
 }
 
 ex power::imag_part() const
 {
+       const ex a = basis.real_part();
+       const ex c = exponent.real_part();
+       if (basis.is_equal(a) && exponent.is_equal(c)) {
+               // Im(a^c)
+               return 0;
+       }
+
+       const ex b = basis.imag_part();
        if (exponent.info(info_flags::integer)) {
-               ex basis_real = basis.real_part();
-               if (basis_real == basis)
-                       return 0;
-               realsymbol a("a"),b("b");
-               ex result;
-               if (exponent.info(info_flags::posint))
-                       result = power(a+I*b,exponent);
-               else
-                       result = power(a/(a*a+b*b)-I*b/(a*a+b*b),-exponent);
-               result = result.expand();
-               result = result.imag_part();
-               result = result.subs(lst( a==basis_real, b==basis.imag_part() ));
+               // Im((a+I*b)^c)  w/  c ∈ ℤ
+               long N = ex_to<numeric>(c).to_long();
+               // Use imaginary terms in Binomial expansion to construct
+               // Im(expand(power(a+I*b, N))).
+               long p = N > 0 ? 1 : 3;  // modulus for positive sign
+               long NN = N > 0 ? N : -N;
+               ex numer = N > 0 ? _ex1 : power(power(a,2) + power(b,2), NN);
+               ex result = 0;
+               for (long n = 1; n <= NN; n += 2) {
+                       ex term = binomial(NN, n) * power(a, NN-n) * power(b, n) / numer;
+                       if (n % 4 == p) {
+                               result += term;  // sign: I^n w/ n == 4*m+p
+                       } else {
+                               result -= term;  // sign: I^n w/ n == 4*m+2+p
+                       }
+               }
                return result;
        }
-       
-       ex a=basis.real_part();
-       ex b=basis.imag_part();
-       ex c=exponent.real_part();
-       ex d=exponent.imag_part();
+
+       // Im((a+I*b)^(c+I*d))
+       const ex d = exponent.imag_part();
        return power(abs(basis),c)*exp(-d*atan2(b,a))*sin(c*atan2(b,a)+d*log(abs(basis)));
 }
 
@@ -755,7 +775,7 @@ ex power::derivative(const symbol & s) const
                newseq.reserve(2);
                newseq.push_back(expair(basis, exponent - _ex1));
                newseq.push_back(expair(basis.diff(s), _ex1));
-               return mul(newseq, exponent);
+               return mul(std::move(newseq), exponent);
        } else {
                // D(b^e) = b^e * (D(e)*ln(b) + e*D(b)/b)
                return mul(*this,
@@ -829,9 +849,9 @@ ex power::expand(unsigned options) const
                // In either case we set a flag to avoid the second run on a part
                // which does not have positive/negative terms.
                if (prodseq.size() > 0) {
-                       ex newbasis = coeff*mul(powseq);
+                       ex newbasis = coeff*mul(std::move(powseq));
                        ex_to<basic>(newbasis).setflag(status_flags::purely_indefinite);
-                       return ((new mul(prodseq))->setflag(status_flags::dynallocated)*(new power(newbasis, exponent))->setflag(status_flags::dynallocated).expand(options)).expand(options);
+                       return ((new mul(std::move(prodseq)))->setflag(status_flags::dynallocated)*(new power(newbasis, exponent))->setflag(status_flags::dynallocated).expand(options)).expand(options);
                } else
                        ex_to<basic>(basis).setflag(status_flags::purely_indefinite);
        }
@@ -1071,7 +1091,7 @@ public:
  *  where n = p1+p2+...+pk, i.e. p is a partition of n.
  */
 const numeric
-multinomial_coefficient(const std::vector<int> p)
+multinomial_coefficient(const std::vector<int> p)
 {
        numeric n = 0, d = 1;
        for (auto & it : p) {
@@ -1187,7 +1207,6 @@ ex power::expand_add(const add & a, int n, unsigned options) const
                                numeric factor = coeff;
                                for (unsigned i = 0; i < exponent.size(); ++i) {
                                        const ex & r = a.seq[i].rest;
-                                       const ex & c = a.seq[i].coeff;
                                        GINAC_ASSERT(!is_exactly_a<add>(r));
                                        GINAC_ASSERT(!is_exactly_a<power>(r) ||
                                                     !is_exactly_a<numeric>(ex_to<power>(r).exponent) ||
@@ -1195,15 +1214,19 @@ ex power::expand_add(const add & a, int n, unsigned options) const
                                                     !is_exactly_a<add>(ex_to<power>(r).basis) ||
                                                     !is_exactly_a<mul>(ex_to<power>(r).basis) ||
                                                     !is_exactly_a<power>(ex_to<power>(r).basis));
+                                       GINAC_ASSERT(is_exactly_a<numeric>(a.seq[i].coeff));
+                                       const numeric & c = ex_to<numeric>(a.seq[i].coeff);
                                        if (exponent[i] == 0) {
                                                // optimize away
                                        } else if (exponent[i] == 1) {
                                                // optimized
                                                term.push_back(r);
-                                               factor = factor.mul(ex_to<numeric>(c));
+                                               if (c != *_num1_p)
+                                                       factor = factor.mul(c);
                                        } else { // general case exponent[i] > 1
                                                term.push_back((new power(r, exponent[i]))->setflag(status_flags::dynallocated));
-                                               factor = factor.mul(ex_to<numeric>(c).power(exponent[i]));
+                                               if (c != *_num1_p)
+                                                       factor = factor.mul(c.power(exponent[i]));
                                        }
                                }
                                result.push_back(a.combine_ex_with_coeff_to_pair(mul(term).expand(options), factor));
@@ -1214,11 +1237,11 @@ ex power::expand_add(const add & a, int n, unsigned options) const
        GINAC_ASSERT(result.size() == result_size);
 
        if (a.overall_coeff.is_zero()) {
-               return (new add(result))->setflag(status_flags::dynallocated |
-                                                 status_flags::expanded);
+               return (new add(std::move(result)))->setflag(status_flags::dynallocated |
+                                                            status_flags::expanded);
        } else {
-               return (new add(result, ex_to<numeric>(a.overall_coeff).power(n)))->setflag(status_flags::dynallocated |
-                                                                                           status_flags::expanded);
+               return (new add(std::move(result), ex_to<numeric>(a.overall_coeff).power(n)))->setflag(status_flags::dynallocated |
+                                                                                                      status_flags::expanded);
        }
 }
 
@@ -1286,7 +1309,7 @@ ex power::expand_add_2(const add & a, unsigned options) const
        
        GINAC_ASSERT(sum.size()==(a_nops*(a_nops+1))/2);
        
-       return (new add(sum))->setflag(status_flags::dynallocated | status_flags::expanded);
+       return (new add(std::move(sum)))->setflag(status_flags::dynallocated | status_flags::expanded);
 }
 
 /** Expand factors of m in m^n where m is a mul and n is an integer.