]> www.ginac.de Git - ginac.git/blobdiff - ginac/power.cpp
- Apparently, in ~ 30% of calls to mul::expand the expression is monomial.
[ginac.git] / ginac / power.cpp
index fb5e351e7390204dbe6b024f5cc2f8a80c67625b..1b28b509ac4bd35ef4bbcf7777e40069bcf056f2 100644 (file)
@@ -41,6 +41,7 @@
 #include "archive.h"
 #include "utils.h"
 #include "relational.h"
+#include "compiler.h"
 
 namespace GiNaC {
 
@@ -49,7 +50,8 @@ GINAC_IMPLEMENT_REGISTERED_CLASS_OPT(power, basic,
   print_func<print_latex>(&power::do_print_latex).
   print_func<print_csrc>(&power::do_print_csrc).
   print_func<print_python>(&power::do_print_python).
-  print_func<print_python_repr>(&power::do_print_python_repr))
+  print_func<print_python_repr>(&power::do_print_python_repr).
+  print_func<print_csrc_cl_N>(&power::do_print_csrc_cl_N))
 
 typedef std::vector<int> intvector;
 
@@ -161,6 +163,21 @@ static void print_sym_pow(const print_context & c, const symbol &x, int exp)
        }
 }
 
+void power::do_print_csrc_cl_N(const print_csrc_cl_N& c, unsigned level) const
+{
+       if (exponent.is_equal(_ex_1)) {
+               c.s << "recip(";
+               basis.print(c);
+               c.s << ')';
+               return;
+       }
+       c.s << "expt(";
+       basis.print(c);
+       c.s << ", ";
+       exponent.print(c);
+       c.s << ')';
+}
+
 void power::do_print_csrc(const print_csrc & c, unsigned level) const
 {
        // Integer powers of symbols are printed in a special, optimized way
@@ -171,29 +188,20 @@ void power::do_print_csrc(const print_csrc & c, unsigned level) const
                        c.s << '(';
                else {
                        exp = -exp;
-                       if (is_a<print_csrc_cl_N>(c))
-                               c.s << "recip(";
-                       else
-                               c.s << "1.0/(";
+                       c.s << "1.0/(";
                }
                print_sym_pow(c, ex_to<symbol>(basis), exp);
                c.s << ')';
 
        // <expr>^-1 is printed as "1.0/<expr>" or with the recip() function of CLN
        } else if (exponent.is_equal(_ex_1)) {
-               if (is_a<print_csrc_cl_N>(c))
-                       c.s << "recip(";
-               else
-                       c.s << "1.0/(";
+               c.s << "1.0/(";
                basis.print(c);
                c.s << ')';
 
-       // Otherwise, use the pow() or expt() (CLN) functions
+       // Otherwise, use the pow() function
        } else {
-               if (is_a<print_csrc_cl_N>(c))
-                       c.s << "expt(";
-               else
-                       c.s << "pow(";
+               c.s << "pow(";
                basis.print(c);
                c.s << ',';
                exponent.print(c);
@@ -231,6 +239,23 @@ bool power::info(unsigned inf) const
                case info_flags::algebraic:
                        return !exponent.info(info_flags::integer) ||
                               basis.info(inf);
+               case info_flags::expanded:
+                       return (flags & status_flags::expanded);
+               case info_flags::has_indices: {
+                       if (flags & status_flags::has_indices)
+                               return true;
+                       else if (flags & status_flags::has_no_indices)
+                               return false;
+                       else if (basis.info(info_flags::has_indices)) {
+                               setflag(status_flags::has_indices);
+                               clearflag(status_flags::has_no_indices);
+                               return true;
+                       } else {
+                               clearflag(status_flags::has_indices);
+                               setflag(status_flags::has_no_indices);
+                               return false;
+                       }
+               }
        }
        return inherited::info(inf);
 }
@@ -467,8 +492,9 @@ 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())
+                               if (num_exponent->is_integer() || (abs(num_sub_exponent) - (*_num1_p)).is_negative()) {
                                        return power(sub_basis,num_sub_exponent.mul(*num_exponent));
+                               }
                        }
                }
        
@@ -476,7 +502,35 @@ ex power::eval(int level) const
                if (num_exponent->is_integer() && is_exactly_a<mul>(ebasis)) {
                        return expand_mul(ex_to<mul>(ebasis), *num_exponent, 0);
                }
-       
+
+               // (2*x + 6*y)^(-4) -> 1/16*(x + 3*y)^(-4)
+               if (num_exponent->is_integer() && is_exactly_a<add>(ebasis)) {
+                       numeric icont = ebasis.integer_content();
+                       const numeric& lead_coeff = 
+                               ex_to<numeric>(ex_to<add>(ebasis).seq.begin()->coeff).div_dyn(icont);
+
+                       const bool canonicalizable = lead_coeff.is_integer();
+                       const bool unit_normal = lead_coeff.is_pos_integer();
+                       if (canonicalizable && (! unit_normal))
+                               icont = icont.mul(*_num_1_p);
+                       
+                       if (canonicalizable && (icont != *_num1_p)) {
+                               const add& addref = ex_to<add>(ebasis);
+                               add* addp = new add(addref);
+                               addp->setflag(status_flags::dynallocated);
+                               addp->clearflag(status_flags::hash_calculated);
+                               addp->overall_coeff = ex_to<numeric>(addp->overall_coeff).div_dyn(icont);
+                               for (epvector::iterator i = addp->seq.begin(); i != addp->seq.end(); ++i)
+                                       i->coeff = ex_to<numeric>(i->coeff).div_dyn(icont);
+
+                               const numeric c = icont.power(*num_exponent);
+                               if (likely(c != *_num1_p))
+                                       return (new mul(power(*addp, *num_exponent), c))->setflag(status_flags::dynallocated);
+                               else
+                                       return power(*addp, *num_exponent);
+                       }
+               }
+
                // ^(*(...,x;c1),c2) -> *(^(*(...,x;1),c2),c1^c2)  (c1, c2 numeric(), c1>0)
                // ^(*(...,x;c1),c2) -> *(^(*(...,x;-1),c2),(-c1)^c2)  (c1, c2 numeric(), c1<0)
                if (is_exactly_a<mul>(ebasis)) {
@@ -718,6 +772,9 @@ tinfo_t power::return_type_tinfo() const
 
 ex power::expand(unsigned options) const
 {
+       if (is_a<symbol>(basis) && exponent.info(info_flags::integer))
+               return (new power(*this))->setflag(status_flags::dynallocated | status_flags::expanded);
+
        if (options == 0 && (flags & status_flags::expanded))
                return *this;