X-Git-Url: https://www.ginac.de/ginac.git//ginac.git?a=blobdiff_plain;f=ginac%2Fpower.cpp;h=33f572f973745544ba2db9df4c6c08955a90a265;hb=53924dabb046e212f3aa27cb2a21dc7b0842308f;hp=47efc2fd3806583b0e61197354111f090b11755e;hpb=05c47b615d0d309d4868c688cd26f68376fa4277;p=ginac.git diff --git a/ginac/power.cpp b/ginac/power.cpp index 47efc2fd..33f572f9 100644 --- a/ginac/power.cpp +++ b/ginac/power.cpp @@ -67,17 +67,7 @@ DEFAULT_DESTROY(power) // other ctors ////////// -power::power(const ex & lh, const ex & rh) : inherited(TINFO_power), basis(lh), exponent(rh) -{ - debugmsg("power ctor from ex,ex",LOGLEVEL_CONSTRUCT); -} - -/** Ctor from an ex and a bare numeric. This is somewhat more efficient than - * the normal ctor from two ex whenever it can be used. */ -power::power(const ex & lh, const numeric & rh) : inherited(TINFO_power), basis(lh), exponent(rh) -{ - debugmsg("power ctor from ex,numeric",LOGLEVEL_CONSTRUCT); -} +// all inlined ////////// // archiving @@ -100,7 +90,7 @@ void power::archive(archive_node &n) const DEFAULT_UNARCHIVE(power) ////////// -// functions overriding virtual functions from bases classes +// functions overriding virtual functions from base classes ////////// // public @@ -109,7 +99,7 @@ static void print_sym_pow(const print_context & c, const symbol &x, int exp) { // Optimal output of integer powers of symbols to aid compiler CSE. // C.f. ISO/IEC 14882:1998, section 1.9 [intro execution], paragraph 15 - // to learn why such a hack is really necessary. + // to learn why such a parenthisation is really necessary. if (exp == 1) { x.print(c); } else if (exp == 2) { @@ -250,13 +240,10 @@ ex power::map(map_function & f) const int power::degree(const ex & s) const { - if (is_exactly_of_type(*exponent.bp,numeric)) { - if (basis.is_equal(s)) { - if (ex_to(exponent).is_integer()) - return ex_to(exponent).to_int(); - else - return 0; - } else + if (is_ex_exactly_of_type(exponent, numeric) && ex_to(exponent).is_integer()) { + if (basis.is_equal(s)) + return ex_to(exponent).to_int(); + else return basis.degree(s) * ex_to(exponent).to_int(); } return 0; @@ -264,13 +251,10 @@ int power::degree(const ex & s) const int power::ldegree(const ex & s) const { - if (is_exactly_of_type(*exponent.bp,numeric)) { - if (basis.is_equal(s)) { - if (ex_to(exponent).is_integer()) - return ex_to(exponent).to_int(); - else - return 0; - } else + if (is_ex_exactly_of_type(exponent, numeric) && ex_to(exponent).is_integer()) { + if (basis.is_equal(s)) + return ex_to(exponent).to_int(); + else return basis.ldegree(s) * ex_to(exponent).to_int(); } return 0; @@ -286,7 +270,7 @@ ex power::coeff(const ex & s, int n) const return _ex0(); } else { // basis equal to s - if (is_exactly_of_type(*exponent.bp, numeric) && ex_to(exponent).is_integer()) { + if (is_ex_exactly_of_type(exponent, numeric) && ex_to(exponent).is_integer()) { // integer exponent int int_exp = ex_to(exponent).to_int(); if (n == int_exp) @@ -303,18 +287,22 @@ ex power::coeff(const ex & s, int n) const } } +/** Perform automatic term rewriting rules in this class. In the following + * x, x1, x2,... stand for a symbolic variables of type ex and c, c1, c2... + * stand for such expressions that contain a plain number. + * - ^(x,0) -> 1 (also handles ^(0,0)) + * - ^(x,1) -> x + * - ^(0,c) -> 0 or exception (depending on the real part of c) + * - ^(1,x) -> 1 + * - ^(c1,c2) -> *(c1^n,c1^(c2-n)) (so that 0<(c2-n)<1, try to evaluate roots, possibly in numerator and denominator of c1) + * - ^(^(x,c1),c2) -> ^(x,c1*c2) (c2 integer or -1 < c1 <= 1, case c1=1 should not happen, see below!) + * - ^(*(x,y,z),c) -> *(x^c,y^c,z^c) (if c integer) + * - ^(*(x,c1),c2) -> ^(x,c2)*c1^c2 (c1>0) + * - ^(*(x,c1),c2) -> ^(-x,c2)*c1^c2 (c1<0) + * + * @param level cut-off in recursive evaluation */ ex power::eval(int level) const { - // simplifications: ^(x,0) -> 1 (0^0 handled here) - // ^(x,1) -> x - // ^(0,c1) -> 0 or exception (depending on real value of c1) - // ^(1,x) -> 1 - // ^(c1,c2) -> *(c1^n,c1^(c2-n)) (c1, c2 numeric(), 0<(c2-n)<1 except if c1,c2 are rational, but c1^c2 is not) - // ^(^(x,c1),c2) -> ^(x,c1*c2) (c1, c2 numeric(), c2 integer or -1 < c1 <= 1, case c1=1 should not happen, see below!) - // ^(*(x,y,z),c1) -> *(x^c1,y^c1,z^c1) (c1 integer) - // ^(*(x,c1),c2) -> ^(x,c2)*c1^c2 (c1, c2 numeric(), c1>0) - // ^(*(x,c1),c2) -> ^(-x,c2)*c1^c2 (c1, c2 numeric(), c1<0) - debugmsg("power eval",LOGLEVEL_MEMBER_FUNCTION); if ((level==1) && (flags & status_flags::evaluated)) @@ -327,19 +315,19 @@ ex power::eval(int level) const bool basis_is_numerical = false; bool exponent_is_numerical = false; - numeric * num_basis; - numeric * num_exponent; + const numeric *num_basis; + const numeric *num_exponent; - if (is_exactly_of_type(*ebasis.bp,numeric)) { + if (is_ex_exactly_of_type(ebasis, numeric)) { basis_is_numerical = true; - num_basis = static_cast(ebasis.bp); + num_basis = &ex_to(ebasis); } - if (is_exactly_of_type(*eexponent.bp,numeric)) { + if (is_ex_exactly_of_type(eexponent, numeric)) { exponent_is_numerical = true; - num_exponent = static_cast(eexponent.bp); + num_exponent = &ex_to(eexponent); } - // ^(x,0) -> 1 (0^0 also handled here) + // ^(x,0) -> 1 (0^0 also handled here) if (eexponent.is_zero()) { if (ebasis.is_zero()) throw (std::domain_error("power::eval(): pow(0,0) is undefined")); @@ -350,8 +338,8 @@ ex power::eval(int level) const // ^(x,1) -> x if (eexponent.is_equal(_ex1())) return ebasis; - - // ^(0,c1) -> 0 or exception (depending on real value of c1) + + // ^(0,c1) -> 0 or exception (depending on real value of c1) if (ebasis.is_zero() && exponent_is_numerical) { if ((num_exponent->real()).is_zero()) throw (std::domain_error("power::eval(): pow(0,I) is undefined")); @@ -360,44 +348,64 @@ ex power::eval(int level) const else return _ex0(); } - + // ^(1,x) -> 1 if (ebasis.is_equal(_ex1())) return _ex1(); - + if (exponent_is_numerical) { - // ^(c1,c2) -> c1^c2 (c1, c2 numeric(), + // ^(c1,c2) -> c1^c2 (c1, c2 numeric(), // except if c1,c2 are rational, but c1^c2 is not) if (basis_is_numerical) { - bool basis_is_crational = num_basis->is_crational(); - bool exponent_is_crational = num_exponent->is_crational(); - numeric res = num_basis->power(*num_exponent); - - if ((!basis_is_crational || !exponent_is_crational) - || res.is_crational()) { + 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) { + // return a plain float + return (new numeric(num_basis->power(*num_exponent)))->setflag(status_flags::dynallocated | + status_flags::evaluated | + status_flags::expanded); + } + + const numeric res = num_basis->power(*num_exponent); + if (res.is_crational()) { return res; } GINAC_ASSERT(!num_exponent->is_integer()); // has been handled by now - // ^(c1,n/m) -> *(c1^q,c1^(n/m-q)), 0<(n/m-h)<1, q integer + // ^(c1,n/m) -> *(c1^q,c1^(n/m-q)), 0<(n/m-q)<1, q integer if (basis_is_crational && exponent_is_crational - && num_exponent->is_real() - && !num_exponent->is_integer()) { - numeric n = num_exponent->numer(); - numeric m = num_exponent->denom(); + && num_exponent->is_real() + && !num_exponent->is_integer()) { + const numeric n = num_exponent->numer(); + const numeric m = num_exponent->denom(); numeric r; numeric q = iquo(n, m, r); if (r.is_negative()) { - r = r.add(m); - q = q.sub(_num1()); + r += m; + --q; } - if (q.is_zero()) // the exponent was in the allowed range 0<(n/m)<1 + if (q.is_zero()) { // the exponent was in the allowed range 0<(n/m)<1 + if (num_basis->is_rational() && !num_basis->is_integer()) { + // try it for numerator and denominator separately, in order to + // partially simplify things like (5/8)^(1/3) -> 1/2*5^(1/3) + const numeric bnum = num_basis->numer(); + const numeric bden = num_basis->denom(); + const numeric res_bnum = bnum.power(*num_exponent); + const numeric res_bden = bden.power(*num_exponent); + if (res_bnum.is_integer()) + return (new mul(power(bden,-*num_exponent),res_bnum))->setflag(status_flags::dynallocated | status_flags::evaluated); + if (res_bden.is_integer()) + return (new mul(power(bnum,*num_exponent),res_bden.inverse()))->setflag(status_flags::dynallocated | status_flags::evaluated); + } return this->hold(); - else { - epvector res; - res.push_back(expair(ebasis,r.div(m))); - return (new mul(res,ex(num_basis->power_dyn(q))))->setflag(status_flags::dynallocated | status_flags::evaluated); + } else { + // assemble resulting product, but allowing for a re-evaluation, + // because otherwise we'll end up with something like + // (7/8)^(4/3) -> 7/8*(1/2*7^(1/3)) + // instead of 7/16*7^(1/3). + ex prod = power(*num_basis,r.div(m)); + return prod*power(*num_basis,q); } } } @@ -422,8 +430,8 @@ ex power::eval(int level) const return expand_mul(ex_to(ebasis), *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) + // ^(*(...,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_ex_exactly_of_type(ebasis,mul)) { GINAC_ASSERT(!num_exponent->is_integer()); // should have been handled above const mul & mulref = ex_to(ebasis); @@ -431,7 +439,7 @@ ex power::eval(int level) const const numeric & num_coeff = ex_to(mulref.overall_coeff); if (num_coeff.is_real()) { if (num_coeff.is_positive()) { - mul * mulp = new mul(mulref); + mul *mulp = new mul(mulref); mulp->overall_coeff = _ex1(); mulp->clearflag(status_flags::evaluated); mulp->clearflag(status_flags::hash_calculated); @@ -440,7 +448,7 @@ ex power::eval(int level) const } else { GINAC_ASSERT(num_coeff.compare(_num0())<0); if (num_coeff.compare(_num_1())!=0) { - mul * mulp = new mul(mulref); + mul *mulp = new mul(mulref); mulp->overall_coeff = _ex_1(); mulp->clearflag(status_flags::evaluated); mulp->clearflag(status_flags::hash_calculated); @@ -461,17 +469,17 @@ ex power::eval(int level) const } if (are_ex_trivially_equal(ebasis,basis) && - are_ex_trivially_equal(eexponent,exponent)) { + are_ex_trivially_equal(eexponent,exponent)) { return this->hold(); } return (new power(ebasis, eexponent))->setflag(status_flags::dynallocated | - status_flags::evaluated); + status_flags::evaluated); } ex power::evalf(int level) const { debugmsg("power evalf",LOGLEVEL_MEMBER_FUNCTION); - + ex ebasis; ex eexponent; @@ -482,7 +490,7 @@ ex power::evalf(int level) const throw(std::runtime_error("max recursion level reached")); } else { ebasis = basis.evalf(level-1); - if (!is_ex_exactly_of_type(eexponent,numeric)) + if (!is_ex_exactly_of_type(exponent,numeric)) eexponent = exponent.evalf(level-1); else eexponent = exponent; @@ -493,8 +501,8 @@ ex power::evalf(int level) const ex power::evalm(void) const { - ex ebasis = basis.evalm(); - ex eexponent = exponent.evalm(); + const ex ebasis = basis.evalm(); + const ex eexponent = exponent.evalm(); if (is_ex_of_type(ebasis,matrix)) { if (is_ex_of_type(eexponent,numeric)) { return (new matrix(ex_to(ebasis).pow(eexponent)))->setflag(status_flags::dynallocated); @@ -512,7 +520,7 @@ ex power::subs(const lst & ls, const lst & lr, bool no_pattern) const && are_ex_trivially_equal(exponent, subsed_exponent)) return basic::subs(ls, lr, no_pattern); else - return ex(power(subsed_basis, subsed_exponent)).bp->basic::subs(ls, lr, no_pattern); + return power(subsed_basis, subsed_exponent).basic::subs(ls, lr, no_pattern); } ex power::simplify_ncmul(const exvector & v) const @@ -543,15 +551,14 @@ ex power::derivative(const symbol & s) const int power::compare_same_type(const basic & other) const { - GINAC_ASSERT(is_exactly_of_type(other, power)); - const power & o=static_cast(const_cast(other)); + GINAC_ASSERT(is_exactly_a(other)); + const power &o = static_cast(other); - int cmpval; - cmpval=basis.compare(o.basis); - if (cmpval==0) { + int cmpval = basis.compare(o.basis); + if (cmpval) + return cmpval; + else return exponent.compare(o.exponent); - } - return cmpval; } unsigned power::return_type(void) const @@ -566,11 +573,11 @@ unsigned power::return_type_tinfo(void) const ex power::expand(unsigned options) const { - if (flags & status_flags::expanded) + if (options == 0 && (flags & status_flags::expanded)) return *this; - ex expanded_basis = basis.expand(options); - ex expanded_exponent = exponent.expand(options); + const ex expanded_basis = basis.expand(options); + const ex expanded_exponent = exponent.expand(options); // x^(a+b) -> x^a * x^b if (is_ex_exactly_of_type(expanded_exponent, add)) { @@ -581,7 +588,7 @@ ex power::expand(unsigned options) const epvector::const_iterator cit = a.seq.begin(); while (cit!=last) { distrseq.push_back(power(expanded_basis, a.recombine_pair_to_ex(*cit))); - cit++; + ++cit; } // Make sure that e.g. (x+y)^(2+a) expands the (x+y)^2 factor @@ -605,7 +612,7 @@ ex power::expand(unsigned options) const if (are_ex_trivially_equal(basis,expanded_basis) && are_ex_trivially_equal(exponent,expanded_exponent)) { return this->hold(); } else { - return (new power(expanded_basis,expanded_exponent))->setflag(status_flags::dynallocated | status_flags::expanded); + return (new power(expanded_basis,expanded_exponent))->setflag(status_flags::dynallocated | (options == 0 ? status_flags::expanded : 0)); } } @@ -625,7 +632,7 @@ ex power::expand(unsigned options) const if (are_ex_trivially_equal(basis,expanded_basis) && are_ex_trivially_equal(exponent,expanded_exponent)) return this->hold(); else - return (new power(expanded_basis,expanded_exponent))->setflag(status_flags::dynallocated | status_flags::expanded); + return (new power(expanded_basis,expanded_exponent))->setflag(status_flags::dynallocated | (options == 0 ? status_flags::expanded : 0)); } ////////// @@ -659,18 +666,18 @@ ex power::expand_add(const add & a, int n) const upper_limit[l] = n; } - while (1) { + while (true) { exvector term; term.reserve(m+1); for (l=0; l(b).exponent,numeric) || + GINAC_ASSERT(!is_exactly_a(b)); + GINAC_ASSERT(!is_exactly_a(b) || + !is_exactly_a(ex_to(b).exponent) || !ex_to(ex_to(b).exponent).is_pos_integer() || - !is_ex_exactly_of_type(ex_to(b).basis,add) || - !is_ex_exactly_of_type(ex_to(b).basis,mul) || - !is_ex_exactly_of_type(ex_to(b).basis,power)); + !is_exactly_a(ex_to(b).basis) || + !is_exactly_a(ex_to(b).basis) || + !is_exactly_a(ex_to(b).basis)); if (is_ex_exactly_of_type(b,mul)) term.push_back(expand_mul(ex_to(b),numeric(k[l]))); else @@ -678,13 +685,13 @@ ex power::expand_add(const add & a, int n) const } const ex & b = a.op(l); - GINAC_ASSERT(!is_ex_exactly_of_type(b,add)); - GINAC_ASSERT(!is_ex_exactly_of_type(b,power) || - !is_ex_exactly_of_type(ex_to(b).exponent,numeric) || + GINAC_ASSERT(!is_exactly_a(b)); + GINAC_ASSERT(!is_exactly_a(b) || + !is_exactly_a(ex_to(b).exponent) || !ex_to(ex_to(b).exponent).is_pos_integer() || - !is_ex_exactly_of_type(ex_to(b).basis,add) || - !is_ex_exactly_of_type(ex_to(b).basis,mul) || - !is_ex_exactly_of_type(ex_to(b).basis,power)); + !is_exactly_a(ex_to(b).basis) || + !is_exactly_a(ex_to(b).basis) || + !is_exactly_a(ex_to(b).basis)); if (is_ex_exactly_of_type(b,mul)) term.push_back(expand_mul(ex_to(b),numeric(n-k_cum[m-2]))); else @@ -696,25 +703,14 @@ ex power::expand_add(const add & a, int n) const term.push_back(f); - /* - cout << "begin term" << endl; - for (int i=0; isetflag(status_flags::dynallocated)); // increment k[] l = m-2; - while ((l>=0)&&((++k[l])>upper_limit[l])) { + while ((l>=0) && ((++k[l])>upper_limit[l])) { k[l] = 0; - l--; + --l; } if (l<0) break; @@ -731,7 +727,7 @@ ex power::expand_add(const add & a, int n) const upper_limit[i] = n-k_cum[i-1]; } return (new add(sum))->setflag(status_flags::dynallocated | - status_flags::expanded ); + status_flags::expanded ); } @@ -747,16 +743,16 @@ ex power::expand_add_2(const add & a) const // power(+(x,...,z;c),2)=power(+(x,...,z;0),2)+2*c*+(x,...,z;0)+c*c // first part: ignore overall_coeff and expand other terms for (epvector::const_iterator cit0=a.seq.begin(); cit0!=last; ++cit0) { - const ex & r = (*cit0).rest; - const ex & c = (*cit0).coeff; + const ex & r = cit0->rest; + const ex & c = cit0->coeff; - GINAC_ASSERT(!is_ex_exactly_of_type(r,add)); - GINAC_ASSERT(!is_ex_exactly_of_type(r,power) || - !is_ex_exactly_of_type(ex_to(r).exponent,numeric) || + GINAC_ASSERT(!is_exactly_a(r)); + GINAC_ASSERT(!is_exactly_a(r) || + !is_exactly_a(ex_to(r).exponent) || !ex_to(ex_to(r).exponent).is_pos_integer() || - !is_ex_exactly_of_type(ex_to(r).basis,add) || - !is_ex_exactly_of_type(ex_to(r).basis,mul) || - !is_ex_exactly_of_type(ex_to(r).basis,power)); + !is_exactly_a(ex_to(r).basis) || + !is_exactly_a(ex_to(r).basis) || + !is_exactly_a(ex_to(r).basis)); if (are_ex_trivially_equal(c,_ex1())) { if (is_ex_exactly_of_type(r,mul)) { @@ -777,8 +773,8 @@ ex power::expand_add_2(const add & a) const } for (epvector::const_iterator cit1=cit0+1; cit1!=last; ++cit1) { - const ex & r1 = (*cit1).rest; - const ex & c1 = (*cit1).coeff; + const ex & r1 = cit1->rest; + const ex & c1 = cit1->coeff; sum.push_back(a.combine_ex_with_coeff_to_pair((new mul(r,r1))->setflag(status_flags::dynallocated), _num2().mul(ex_to(c)).mul_dyn(ex_to(c1)))); } @@ -788,8 +784,10 @@ ex power::expand_add_2(const add & a) const // second part: add terms coming from overall_factor (if != 0) if (!a.overall_coeff.is_zero()) { - for (epvector::const_iterator cit=a.seq.begin(); cit!=a.seq.end(); ++cit) { - sum.push_back(a.combine_pair_with_coeff_to_pair(*cit,ex_to(a.overall_coeff).mul_dyn(_num2()))); + epvector::const_iterator i = a.seq.begin(), end = a.seq.end(); + while (i != end) { + sum.push_back(a.combine_pair_with_coeff_to_pair(*i, ex_to(a.overall_coeff).mul_dyn(_num2()))); + ++i; } sum.push_back(expair(ex_to(a.overall_coeff).power_dyn(_num2()),_ex1())); } @@ -823,18 +821,6 @@ ex power::expand_mul(const mul & m, const numeric & n) const return (new mul(distrseq,ex_to(m.overall_coeff).power_dyn(n)))->setflag(status_flags::dynallocated); } -/* -ex power::expand_noncommutative(const ex & basis, const numeric & exponent, - unsigned options) const -{ - ex rest_power = ex(power(basis,exponent.add(_num_1()))). - expand(options | expand_options::internal_do_not_expand_power_operands); - - return ex(mul(rest_power,basis),0). - expand(options | expand_options::internal_do_not_expand_mul_operands); -} -*/ - // helper function ex sqrt(const ex & a)