X-Git-Url: https://www.ginac.de/ginac.git//ginac.git?p=ginac.git;a=blobdiff_plain;f=ginac%2Fpower.cpp;h=a4a33c576ca415e0a3baa7e6b089fd8dae22b81f;hp=faaef1842d6e085faa12288448a0231cbb1733b2;hb=58a84c0adac7cbaa63a50c06815aed9c7a0bcdcc;hpb=47923e5885d0e437d6cbe257c25f9bca757ea001 diff --git a/ginac/power.cpp b/ginac/power.cpp index faaef184..a4a33c57 100644 --- a/ginac/power.cpp +++ b/ginac/power.cpp @@ -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-2008 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 @@ -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(&power::do_print_latex). print_func(&power::do_print_csrc). print_func(&power::do_print_python). - print_func(&power::do_print_python_repr)) + print_func(&power::do_print_python_repr). + print_func(&power::do_print_csrc_cl_N)) typedef std::vector 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(c)) - c.s << "recip("; - else - c.s << "1.0/("; + c.s << "1.0/("; } print_sym_pow(c, ex_to(basis), exp); c.s << ')'; // ^-1 is printed as "1.0/" or with the recip() function of CLN } else if (exponent.is_equal(_ex_1)) { - if (is_a(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(c)) - c.s << "expt("; - else - c.s << "pow("; + c.s << "pow("; basis.print(c); c.s << ','; exponent.print(c); @@ -233,6 +241,21 @@ bool power::info(unsigned inf) const 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); } @@ -482,25 +505,29 @@ ex power::eval(int level) const // (2*x + 6*y)^(-4) -> 1/16*(x + 3*y)^(-4) if (num_exponent->is_integer() && is_exactly_a(ebasis)) { - const numeric icont = ebasis.integer_content(); - const numeric& lead_coeff = - ex_to(ex_to(ebasis).seq.begin()->coeff).div_dyn(icont); + numeric icont = ebasis.integer_content(); + const numeric lead_coeff = + ex_to(ex_to(ebasis).seq.begin()->coeff).div(icont); const bool canonicalizable = lead_coeff.is_integer(); const bool unit_normal = lead_coeff.is_pos_integer(); - - if (icont != *_num1_p) { - return (new mul(power(ebasis/icont, *num_exponent), power(icont, *num_exponent)) - )->setflag(status_flags::dynallocated); - } - - if (canonicalizable && (! unit_normal)) { - if (num_exponent->is_even()) { - return power(-ebasis, *num_exponent); - } else { - return (new mul(power(-ebasis, *num_exponent), *_num_1_p) - )->setflag(status_flags::dynallocated); - } + if (canonicalizable && (! unit_normal)) + icont = icont.mul(*_num_1_p); + + if (canonicalizable && (icont != *_num1_p)) { + const add& addref = ex_to(ebasis); + add* addp = new add(addref); + addp->setflag(status_flags::dynallocated); + addp->clearflag(status_flags::hash_calculated); + addp->overall_coeff = ex_to(addp->overall_coeff).div_dyn(icont); + for (epvector::iterator i = addp->seq.begin(); i != addp->seq.end(); ++i) + i->coeff = ex_to(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); } } @@ -608,7 +635,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 { @@ -624,9 +651,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::max(); - lst repls; - if (tryfactsubs(*this, it->first, nummatches, repls)) - return (ex_to((*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(result)).subs_one_level(m, options); + } } return subs_one_level(m, options); @@ -745,9 +776,12 @@ tinfo_t power::return_type_tinfo() const ex power::expand(unsigned options) const { - if (options == 0 && (flags & status_flags::expanded)) + if (is_a(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); @@ -834,7 +868,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(b)); GINAC_ASSERT(!is_exactly_a(b) || @@ -860,7 +893,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(b)); GINAC_ASSERT(!is_exactly_a(b) || !is_exactly_a(ex_to(b).exponent) || @@ -874,7 +907,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; lsetflag(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]); @@ -980,8 +1020,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());