]> www.ginac.de Git - ginac.git/blobdiff - ginac/power.cpp
Speed up power::real_part() and power::imag_part().
[ginac.git] / ginac / power.cpp
index 1a4f57dbfe142741fc6117044f3c778673eb3389..bf72d97320b667d1bcee62cf6572adee24845678 100644 (file)
@@ -178,8 +178,8 @@ void power::do_print_csrc_cl_N(const print_csrc_cl_N& c, unsigned level) const
 void power::do_print_csrc(const print_csrc & c, unsigned level) const
 {
        // Integer powers of symbols are printed in a special, optimized way
-       if (exponent.info(info_flags::integer)
-        && (is_a<symbol>(basis) || is_a<constant>(basis))) {
+       if (exponent.info(info_flags::integer) &&
+           (is_a<symbol>(basis) || is_a<constant>(basis))) {
                int exp = ex_to<numeric>(exponent).to_int();
                if (exp > 0)
                        c.s << '(';
@@ -495,8 +495,8 @@ 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_p)).is_negative() 
-                                               || (num_sub_exponent == *_num_1_p && num_exponent->is_positive())) {
+                               if (num_exponent->is_integer() || (abs(num_sub_exponent) - (*_num1_p)).is_negative() ||
+                                   (num_sub_exponent == *_num_1_p && num_exponent->is_positive())) {
                                        return power(sub_basis,num_sub_exponent.mul(*num_exponent));
                                }
                        }
@@ -622,20 +622,18 @@ bool power::has(const ex & other, unsigned options) const
                return basic::has(other, options);
        if (!is_a<power>(other))
                return basic::has(other, options);
-       if (!exponent.info(info_flags::integer)
-                       || !other.op(1).info(info_flags::integer))
+       if (!exponent.info(info_flags::integer) ||
+           !other.op(1).info(info_flags::integer))
                return basic::has(other, options);
-       if (exponent.info(info_flags::posint)
-                       && other.op(1).info(info_flags::posint)
-                       && ex_to<numeric>(exponent).to_int()
-                                       > ex_to<numeric>(other.op(1)).to_int()
-                       && basis.match(other.op(0)))
+       if (exponent.info(info_flags::posint) &&
+           other.op(1).info(info_flags::posint) &&
+           ex_to<numeric>(exponent) > ex_to<numeric>(other.op(1)) &&
+           basis.match(other.op(0)))
                return true;
-       if (exponent.info(info_flags::negint)
-                       && other.op(1).info(info_flags::negint)
-                       && ex_to<numeric>(exponent).to_int()
-                                       < ex_to<numeric>(other.op(1)).to_int()
-                       && basis.match(other.op(0)))
+       if (exponent.info(info_flags::negint) &&
+           other.op(1).info(info_flags::negint) &&
+           ex_to<numeric>(exponent) < ex_to<numeric>(other.op(1)) &&
+           basis.match(other.op(0)))
                return true;
        return basic::has(other, options);
 }
@@ -697,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)));
 }
 
@@ -1310,12 +1328,12 @@ ex power::expand_mul(const mul & m, const numeric & n, unsigned options, bool fr
        }
 
        // do not bother to rename indices if there are no any.
-       if ((!(options & expand_options::expand_rename_idx)) 
-                       && m.info(info_flags::has_indices))
+       if (!(options & expand_options::expand_rename_idx) &&
+           m.info(info_flags::has_indices))
                options |= expand_options::expand_rename_idx;
        // Leave it to multiplication since dummy indices have to be renamed
        if ((options & expand_options::expand_rename_idx) &&
-               (get_all_dummy_indices(m).size() > 0) && n.is_positive()) {
+           (get_all_dummy_indices(m).size() > 0) && n.is_positive()) {
                ex result = m;
                exvector va = get_all_dummy_indices(m);
                sort(va.begin(), va.end(), ex_is_less());