From: Jens Vollinga Date: Mon, 27 Aug 2007 16:46:44 +0000 (+0000) Subject: Converting terms into primitive polynomials optimized [A.Sheplyakov] X-Git-Tag: release_1-4-0~7 X-Git-Url: https://www.ginac.de/ginac.git//ginac.git?p=ginac.git;a=commitdiff_plain;h=9e1051ad0a532338a6f995b9f41f17ac5cdc47a6;hp=47923e5885d0e437d6cbe257c25f9bca757ea001 Converting terms into primitive polynomials optimized [A.Sheplyakov] --- diff --git a/ginac/mul.cpp b/ginac/mul.cpp index b4ef8972..9ed27c6c 100644 --- a/ginac/mul.cpp +++ b/ginac/mul.cpp @@ -34,6 +34,7 @@ #include "lst.h" #include "archive.h" #include "utils.h" +#include "compiler.h" namespace GiNaC { @@ -422,7 +423,7 @@ ex mul::eval(int level) const return *this; } - int seq_size = seq.size(); + size_t seq_size = seq.size(); if (overall_coeff.is_zero()) { // *(...,x;0) -> 0 return _ex0; @@ -448,14 +449,18 @@ ex mul::eval(int level) const ex_to(addref.overall_coeff). mul_dyn(ex_to(overall_coeff))) )->setflag(status_flags::dynallocated | status_flags::evaluated); - } else if (seq_size >= 2) { + } else if ((seq_size >= 2) && (! (flags & status_flags::expanded))) { // Strip the content and the unit part from each term. Thus // things like (-x+a)*(3*x-3*a) automagically turn into - 3*(x-a)2 epvector::const_iterator last = seq.end(); epvector::const_iterator i = seq.begin(); + epvector::const_iterator j = seq.begin(); + std::auto_ptr s(new epvector); + numeric oc = *_num1_p; + bool something_changed = false; while (i!=last) { - if (! (is_a(i->rest) && i->coeff.is_equal(_ex1))) { + if (likely(! (is_a(i->rest) && i->coeff.is_equal(_ex1)))) { // power::eval has such a rule, no need to handle powers here ++i; continue; @@ -472,32 +477,47 @@ ex mul::eval(int level) const // very unlucky event it can even loop forever). Hopefully the main // variable will be the same for all terms in *this const bool unit_normal = lead_coeff.is_pos_integer(); - if ((c == *_num1_p) && ((! canonicalizable) || unit_normal)) { + if (likely((c == *_num1_p) && ((! canonicalizable) || unit_normal))) { ++i; continue; } - std::auto_ptr s(new epvector); - s->reserve(seq.size()); + if (! something_changed) { + s->reserve(seq_size); + something_changed = true; + } - epvector::const_iterator j=seq.begin(); - while (j!=i) { + while ((j!=i) && (j!=last)) { s->push_back(*j); ++j; } - if (! unit_normal) { + if (! unit_normal) c = c.mul(*_num_1_p); - } - const ex primitive = (i->rest)/c; - s->push_back(expair(primitive, _ex1)); - ++j; + oc = oc.mul(c); + + // divide add by the number in place to save at least 2 .eval() calls + const add& addref = ex_to(i->rest); + add* primitive = new add(addref); + primitive->setflag(status_flags::dynallocated); + primitive->clearflag(status_flags::hash_calculated); + primitive->overall_coeff = ex_to(primitive->overall_coeff).div_dyn(c); + for (epvector::iterator ai = primitive->seq.begin(); + ai != primitive->seq.end(); ++ai) + ai->coeff = ex_to(ai->coeff).div_dyn(c); + + s->push_back(expair(*primitive, _ex1)); + + ++i; + ++j; + } + if (something_changed) { while (j!=last) { s->push_back(*j); ++j; } - return (new mul(s, ex_to(overall_coeff).mul_dyn(c)) + return (new mul(s, ex_to(overall_coeff).mul_dyn(oc)) )->setflag(status_flags::dynallocated); } } diff --git a/ginac/power.cpp b/ginac/power.cpp index faaef184..faa0d05c 100644 --- a/ginac/power.cpp +++ b/ginac/power.cpp @@ -41,6 +41,7 @@ #include "archive.h" #include "utils.h" #include "relational.h" +#include "compiler.h" namespace GiNaC { @@ -482,25 +483,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(); + numeric icont = ebasis.integer_content(); const numeric& lead_coeff = ex_to(ex_to(ebasis).seq.begin()->coeff).div_dyn(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); } }