]> www.ginac.de Git - ginac.git/blobdiff - ginac/power.cpp
Prettified source code.
[ginac.git] / ginac / power.cpp
index 9e720b70b04280a150de8d6ab99e6932f4d39699..999d9b147284f894f1e18298f6bd9a5465c2e9e8 100644 (file)
@@ -3,7 +3,7 @@
  *  Implementation of GiNaC's symbolic exponentiation (basis^exponent). */
 
 /*
- *  GiNaC Copyright (C) 1999-2007 Johannes Gutenberg University Mainz, Germany
+ *  GiNaC Copyright (C) 1999-2009 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
  *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
  */
 
-#include <vector>
-#include <iostream>
-#include <stdexcept>
-#include <limits>
-
 #include "power.h"
 #include "expairseq.h"
 #include "add.h"
 #include "archive.h"
 #include "utils.h"
 #include "relational.h"
+#include "compiler.h"
+
+#include <iostream>
+#include <limits>
+#include <stdexcept>
+#include <vector>
 
 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;
 
@@ -57,7 +59,7 @@ typedef std::vector<int> intvector;
 // default constructor
 //////////
 
-power::power() : inherited(&power::tinfo_static) { }
+power::power() { }
 
 //////////
 // other constructors
@@ -69,8 +71,9 @@ power::power() : inherited(&power::tinfo_static) { }
 // archiving
 //////////
 
-power::power(const archive_node &n, lst &sym_lst) : inherited(n, sym_lst)
+void power::read_archive(const archive_node &n, lst &sym_lst)
 {
+       inherited::read_archive(n, sym_lst);
        n.find_ex("basis", basis, sym_lst);
        n.find_ex("exponent", exponent, sym_lst);
 }
@@ -82,8 +85,6 @@ void power::archive(archive_node &n) const
        n.add_ex("exponent", exponent);
 }
 
-DEFAULT_UNARCHIVE(power)
-
 //////////
 // functions overriding virtual functions from base classes
 //////////
@@ -161,6 +162,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 +187,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 +238,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);
 }
@@ -352,17 +376,13 @@ ex power::eval(int level) const
        const ex & ebasis    = level==1 ? basis    : basis.eval(level-1);
        const ex & eexponent = level==1 ? exponent : exponent.eval(level-1);
        
-       bool basis_is_numerical = false;
-       bool exponent_is_numerical = false;
-       const numeric *num_basis;
-       const numeric *num_exponent;
+       const numeric *num_basis = NULL;
+       const numeric *num_exponent = NULL;
        
        if (is_exactly_a<numeric>(ebasis)) {
-               basis_is_numerical = true;
                num_basis = &ex_to<numeric>(ebasis);
        }
        if (is_exactly_a<numeric>(eexponent)) {
-               exponent_is_numerical = true;
                num_exponent = &ex_to<numeric>(eexponent);
        }
        
@@ -379,7 +399,7 @@ ex power::eval(int level) const
                return ebasis;
 
        // ^(0,c1) -> 0 or exception  (depending on real value of c1)
-       if (ebasis.is_zero() && exponent_is_numerical) {
+       if ( ebasis.is_zero() && num_exponent ) {
                if ((num_exponent->real()).is_zero())
                        throw (std::domain_error("power::eval(): pow(0,I) is undefined"));
                else if ((num_exponent->real()).is_negative())
@@ -400,11 +420,11 @@ ex power::eval(int level) const
        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) {
+       if ( num_exponent ) {
 
                // ^(c1,c2) -> c1^c2  (c1, c2 numeric(),
                // except if c1,c2 are rational, but c1^c2 is not)
-               if (basis_is_numerical) {
+               if ( num_basis ) {
                        const bool basis_is_crational = num_basis->is_crational();
                        const bool exponent_is_crational = num_exponent->is_crational();
                        if (!basis_is_crational || !exponent_is_crational) {
@@ -467,8 +487,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 +497,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(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)) {
@@ -581,7 +630,7 @@ bool power::has(const ex & other, unsigned options) const
 }
 
 // from mul.cpp
-extern bool tryfactsubs(const ex &, const ex &, int &, lst &);
+extern bool tryfactsubs(const ex &, const ex &, int &, exmap&);
 
 ex power::subs(const exmap & m, unsigned options) const
 {      
@@ -597,9 +646,13 @@ ex power::subs(const exmap & m, unsigned options) const
 
        for (exmap::const_iterator it = m.begin(); it != m.end(); ++it) {
                int nummatches = std::numeric_limits<int>::max();
-               lst repls;
-               if (tryfactsubs(*this, it->first, nummatches, repls))
-                       return (ex_to<basic>((*this) * power(it->second.subs(ex(repls), subs_options::no_pattern) / it->first.subs(ex(repls), subs_options::no_pattern), nummatches))).subs_one_level(m, options);
+               exmap repls;
+               if (tryfactsubs(*this, it->first, nummatches, repls)) {
+                       ex anum = it->second.subs(repls, subs_options::no_pattern);
+                       ex aden = it->first.subs(repls, subs_options::no_pattern);
+                       ex result = (*this)*power(anum/aden, nummatches);
+                       return (ex_to<basic>(result)).subs_one_level(m, options);
+               }
        }
 
        return subs_one_level(m, options);
@@ -711,16 +764,19 @@ unsigned power::return_type() const
        return basis.return_type();
 }
 
-tinfo_t power::return_type_tinfo() const
+return_type_t power::return_type_tinfo() const
 {
        return basis.return_type_tinfo();
 }
 
 ex power::expand(unsigned options) const
 {
-       if (options == 0 && (flags & status_flags::expanded))
+       if (is_a<symbol>(basis) && exponent.info(info_flags::integer)) {
+               // A special case worth optimizing.
+               setflag(status_flags::expanded);
                return *this;
-       
+       }
+
        const ex expanded_basis = basis.expand(options);
        const ex expanded_exponent = exponent.expand(options);
        
@@ -807,7 +863,6 @@ ex power::expand_add(const add & a, int n, unsigned options) const
        intvector k(m-1);
        intvector k_cum(m-1); // k_cum[l]:=sum(i=0,l,k[l]);
        intvector upper_limit(m-1);
-       int l;
 
        for (size_t l=0; l<m-1; ++l) {
                k[l] = 0;
@@ -818,7 +873,7 @@ ex power::expand_add(const add & a, int n, unsigned options) const
        while (true) {
                exvector term;
                term.reserve(m+1);
-               for (l=0; l<m-1; ++l) {
+               for (std::size_t l = 0; l < m - 1; ++l) {
                        const ex & b = a.op(l);
                        GINAC_ASSERT(!is_exactly_a<add>(b));
                        GINAC_ASSERT(!is_exactly_a<power>(b) ||
@@ -833,7 +888,7 @@ ex power::expand_add(const add & a, int n, unsigned options) const
                                term.push_back(power(b,k[l]));
                }
 
-               const ex & b = a.op(l);
+               const ex & b = a.op(m - 1);
                GINAC_ASSERT(!is_exactly_a<add>(b));
                GINAC_ASSERT(!is_exactly_a<power>(b) ||
                             !is_exactly_a<numeric>(ex_to<power>(b).exponent) ||
@@ -847,7 +902,7 @@ ex power::expand_add(const add & a, int n, unsigned options) const
                        term.push_back(power(b,n-k_cum[m-2]));
 
                numeric f = binomial(numeric(n),numeric(k[0]));
-               for (l=1; l<m-1; ++l)
+               for (std::size_t l = 1; l < m - 1; ++l)
                        f *= binomial(numeric(n-k_cum[l-1]),numeric(k[l]));
 
                term.push_back(f);
@@ -855,12 +910,19 @@ ex power::expand_add(const add & a, int n, unsigned options) const
                result.push_back(ex((new mul(term))->setflag(status_flags::dynallocated)).expand(options));
 
                // increment k[]
-               l = m-2;
-               while ((l>=0) && ((++k[l])>upper_limit[l])) {
+               bool done = false;
+               std::size_t l = m - 2;
+               while ((++k[l]) > upper_limit[l]) {
                        k[l] = 0;
-                       --l;
+                       if (l != 0)
+                               --l;
+                       else {
+                               done = true;
+                               break;
+                       }
                }
-               if (l<0) break;
+               if (done)
+                       break;
 
                // recalc k_cum[] and upper_limit[]
                k_cum[l] = (l==0 ? k[0] : k_cum[l-1]+k[l]);
@@ -943,7 +1005,7 @@ 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
 {
@@ -953,8 +1015,13 @@ ex power::expand_mul(const mul & m, const numeric & n, unsigned options, bool fr
                return _ex1;
        }
 
+       // do not bother to rename indices if there are no any.
+       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 (get_all_dummy_indices(m).size() > 0 && n.is_positive()) {
+       if ((options & expand_options::expand_rename_idx) &&
+               (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());
@@ -989,4 +1056,6 @@ ex power::expand_mul(const mul & m, const numeric & n, unsigned options, bool fr
        return result;
 }
 
+GINAC_BIND_UNARCHIVER(power);
+
 } // namespace GiNaC