X-Git-Url: https://www.ginac.de/ginac.git//ginac.git?p=ginac.git;a=blobdiff_plain;f=ginac%2Fpower.cpp;h=fab41d833279cc42d2691ac88f9c5356a106ec0a;hp=be7c2d371f61a12f1ec72697bd21f7d0ff41fa3b;hb=052d42fd9eb8b7e59eff497da98e1f58cde413a4;hpb=34704348ad3e512010cbf85b6a9dee9fff22cd66 diff --git a/ginac/power.cpp b/ginac/power.cpp index be7c2d37..fab41d83 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-2002 Johannes Gutenberg University Mainz, Germany + * GiNaC Copyright (C) 1999-2003 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 @@ -23,6 +23,7 @@ #include #include #include +#include #include "power.h" #include "expairseq.h" @@ -31,10 +32,12 @@ #include "ncmul.h" #include "numeric.h" #include "constant.h" +#include "operators.h" #include "inifcns.h" // for log() in power::derivative() #include "matrix.h" #include "indexed.h" #include "symbol.h" +#include "lst.h" #include "print.h" #include "archive.h" #include "utils.h" @@ -46,22 +49,13 @@ GINAC_IMPLEMENT_REGISTERED_CLASS(power, basic) typedef std::vector intvector; ////////// -// default ctor, dtor, copy ctor, assignment operator and helpers +// default constructor ////////// power::power() : inherited(TINFO_power) { } -void power::copy(const power & other) -{ - inherited::copy(other); - basis = other.basis; - exponent = other.exponent; -} - -DEFAULT_DESTROY(power) - ////////// -// other ctors +// other constructors ////////// // all inlined @@ -70,7 +64,7 @@ DEFAULT_DESTROY(power) // archiving ////////// -power::power(const archive_node &n, const lst &sym_lst) : inherited(n, sym_lst) +power::power(const archive_node &n, lst &sym_lst) : inherited(n, sym_lst) { n.find_ex("basis", basis, sym_lst); n.find_ex("exponent", exponent, sym_lst); @@ -95,7 +89,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 parenthisation is really necessary. + // to learn why such a parenthesation is really necessary. if (exp == 1) { x.print(c); } else if (exp == 2) { @@ -125,7 +119,7 @@ void power::print(const print_context & c, unsigned level) const // Integer powers of symbols are printed in a special, optimized way if (exponent.info(info_flags::integer) - && (is_exactly_a(basis) || is_exactly_a(basis))) { + && (is_a(basis) || is_a(basis))) { int exp = ex_to(exponent).to_int(); if (exp > 0) c.s << '('; @@ -172,11 +166,23 @@ void power::print(const print_context & c, unsigned level) const bool is_tex = is_a(c); - if (exponent.is_equal(_ex1_2)) { + if (is_tex && is_exactly_a(exponent) && ex_to(exponent).is_negative()) { + + // Powers with negative numeric exponents are printed as fractions in TeX + c.s << "\\frac{1}{"; + power(basis, -exponent).eval().print(c); + c.s << "}"; + + } else if (exponent.is_equal(_ex1_2)) { + + // Square roots are printed in a special way c.s << (is_tex ? "\\sqrt{" : "sqrt("); basis.print(c); c.s << (is_tex ? '}' : ')'); + } else { + + // Ordinary output of powers using '^' or '**' if (precedence() <= level) c.s << (is_tex ? "{(" : "("); basis.print(c, precedence()); @@ -213,14 +219,13 @@ bool power::info(unsigned inf) const return inherited::info(inf); } -unsigned power::nops() const +size_t power::nops() const { return 2; } -ex & power::let_op(int i) +ex power::op(size_t i) const { - GINAC_ASSERT(i>=0); GINAC_ASSERT(i<2); return i==0 ? basis : exponent; @@ -235,7 +240,7 @@ int power::degree(const ex & s) const { if (is_equal(ex_to(s))) return 1; - else if (is_ex_exactly_of_type(exponent, numeric) && ex_to(exponent).is_integer()) { + else if (is_exactly_a(exponent) && ex_to(exponent).is_integer()) { if (basis.is_equal(s)) return ex_to(exponent).to_int(); else @@ -250,7 +255,7 @@ int power::ldegree(const ex & s) const { if (is_equal(ex_to(s))) return 1; - else if (is_ex_exactly_of_type(exponent, numeric) && ex_to(exponent).is_integer()) { + else if (is_exactly_a(exponent) && ex_to(exponent).is_integer()) { if (basis.is_equal(s)) return ex_to(exponent).to_int(); else @@ -273,7 +278,7 @@ ex power::coeff(const ex & s, int n) const return _ex0; } else { // basis equal to s - if (is_ex_exactly_of_type(exponent, numeric) && ex_to(exponent).is_integer()) { + if (is_exactly_a(exponent) && ex_to(exponent).is_integer()) { // integer exponent int int_exp = ex_to(exponent).to_int(); if (n == int_exp) @@ -319,11 +324,11 @@ ex power::eval(int level) const const numeric *num_basis; const numeric *num_exponent; - if (is_ex_exactly_of_type(ebasis, numeric)) { + if (is_exactly_a(ebasis)) { basis_is_numerical = true; num_basis = &ex_to(ebasis); } - if (is_ex_exactly_of_type(eexponent, numeric)) { + if (is_exactly_a(eexponent)) { exponent_is_numerical = true; num_exponent = &ex_to(eexponent); } @@ -414,11 +419,11 @@ ex power::eval(int level) const // ^(^(x,c1),c2) -> ^(x,c1*c2) // (c1, c2 numeric(), c2 integer or -1 < c1 <= 1, // case c1==1 should not happen, see below!) - if (is_ex_exactly_of_type(ebasis,power)) { + if (is_exactly_a(ebasis)) { const power & sub_power = ex_to(ebasis); const ex & sub_basis = sub_power.basis; const ex & sub_exponent = sub_power.exponent; - if (is_ex_exactly_of_type(sub_exponent,numeric)) { + if (is_exactly_a(sub_exponent)) { const numeric & num_sub_exponent = ex_to(sub_exponent); GINAC_ASSERT(num_sub_exponent!=numeric(1)); if (num_exponent->is_integer() || (abs(num_sub_exponent) - _num1).is_negative()) @@ -427,13 +432,13 @@ ex power::eval(int level) const } // ^(*(x,y,z),c1) -> *(x^c1,y^c1,z^c1) (c1 integer) - if (num_exponent->is_integer() && is_ex_exactly_of_type(ebasis,mul)) { + if (num_exponent->is_integer() && is_exactly_a(ebasis)) { 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) - if (is_ex_exactly_of_type(ebasis,mul)) { + if (is_exactly_a(ebasis)) { GINAC_ASSERT(!num_exponent->is_integer()); // should have been handled above const mul & mulref = ex_to(ebasis); if (!mulref.overall_coeff.is_equal(_ex1)) { @@ -464,7 +469,7 @@ ex power::eval(int level) const // ^(nc,c1) -> ncmul(nc,nc,...) (c1 positive integer, unless nc is a matrix) if (num_exponent->is_pos_integer() && ebasis.return_type() != return_types::commutative && - !is_ex_of_type(ebasis,matrix)) { + !is_a(ebasis)) { return ncmul(exvector(num_exponent->to_int(), ebasis), true); } } @@ -498,33 +503,46 @@ ex power::evalf(int level) const return power(ebasis,eexponent); } -ex power::evalm(void) const +ex power::evalm() const { const ex ebasis = basis.evalm(); const ex eexponent = exponent.evalm(); - if (is_ex_of_type(ebasis,matrix)) { - if (is_ex_of_type(eexponent,numeric)) { + if (is_a(ebasis)) { + if (is_exactly_a(eexponent)) { return (new matrix(ex_to(ebasis).pow(eexponent)))->setflag(status_flags::dynallocated); } } return (new power(ebasis, eexponent))->setflag(status_flags::dynallocated); } -ex power::subs(const lst & ls, const lst & lr, bool no_pattern) const -{ - const ex &subsed_basis = basis.subs(ls, lr, no_pattern); - const ex &subsed_exponent = exponent.subs(ls, lr, no_pattern); +// from mul.cpp +extern bool tryfactsubs(const ex &, const ex &, int &, lst &); - if (are_ex_trivially_equal(basis, subsed_basis) - && are_ex_trivially_equal(exponent, subsed_exponent)) - return basic::subs(ls, lr, no_pattern); - else - return power(subsed_basis, subsed_exponent).basic::subs(ls, lr, no_pattern); +ex power::subs(const exmap & m, unsigned options) const +{ + const ex &subsed_basis = basis.subs(m, options); + const ex &subsed_exponent = exponent.subs(m, options); + + if (!are_ex_trivially_equal(basis, subsed_basis) + || !are_ex_trivially_equal(exponent, subsed_exponent)) + return power(subsed_basis, subsed_exponent).subs_one_level(m, options); + + if (!(options & subs_options::algebraic)) + return subs_one_level(m, options); + + 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); + } + + return subs_one_level(m, options); } -ex power::simplify_ncmul(const exvector & v) const +ex power::eval_ncmul(const exvector & v) const { - return inherited::simplify_ncmul(v); + return inherited::eval_ncmul(v); } // protected @@ -560,12 +578,12 @@ int power::compare_same_type(const basic & other) const return exponent.compare(o.exponent); } -unsigned power::return_type(void) const +unsigned power::return_type() const { return basis.return_type(); } -unsigned power::return_type_tinfo(void) const +unsigned power::return_type_tinfo() const { return basis.return_type_tinfo(); } @@ -579,7 +597,7 @@ ex power::expand(unsigned options) const const ex expanded_exponent = exponent.expand(options); // x^(a+b) -> x^a * x^b - if (is_ex_exactly_of_type(expanded_exponent, add)) { + if (is_exactly_a(expanded_exponent)) { const add &a = ex_to(expanded_exponent); exvector distrseq; distrseq.reserve(a.seq.size() + 1); @@ -594,7 +612,7 @@ ex power::expand(unsigned options) const if (ex_to(a.overall_coeff).is_integer()) { const numeric &num_exponent = ex_to(a.overall_coeff); int int_exponent = num_exponent.to_int(); - if (int_exponent > 0 && is_ex_exactly_of_type(expanded_basis, add)) + if (int_exponent > 0 && is_exactly_a(expanded_basis)) distrseq.push_back(expand_add(ex_to(expanded_basis), int_exponent)); else distrseq.push_back(power(expanded_basis, a.overall_coeff)); @@ -606,7 +624,7 @@ ex power::expand(unsigned options) const return r.expand(); } - if (!is_ex_exactly_of_type(expanded_exponent, numeric) || + if (!is_exactly_a(expanded_exponent) || !ex_to(expanded_exponent).is_integer()) { if (are_ex_trivially_equal(basis,expanded_basis) && are_ex_trivially_equal(exponent,expanded_exponent)) { return this->hold(); @@ -620,11 +638,11 @@ ex power::expand(unsigned options) const int int_exponent = num_exponent.to_int(); // (x+y)^n, n>0 - if (int_exponent > 0 && is_ex_exactly_of_type(expanded_basis,add)) + if (int_exponent > 0 && is_exactly_a(expanded_basis)) return expand_add(ex_to(expanded_basis), int_exponent); // (x*y)^n -> x^n * y^n - if (is_ex_exactly_of_type(expanded_basis,mul)) + if (is_exactly_a(expanded_basis)) return expand_mul(ex_to(expanded_basis), num_exponent); // cannot expand further @@ -651,7 +669,7 @@ ex power::expand_add(const add & a, int n) const if (n==2) return expand_add_2(a); - const int m = a.nops(); + const size_t m = a.nops(); exvector result; // The number of terms will be the number of combinatorial compositions, // i.e. the number of unordered arrangement of m nonnegative integers @@ -663,7 +681,7 @@ ex power::expand_add(const add & a, int n) const intvector upper_limit(m-1); int l; - for (int l=0; l(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)) + if (is_exactly_a(b)) term.push_back(expand_mul(ex_to(b),numeric(k[l]))); else term.push_back(power(b,k[l])); @@ -695,7 +713,7 @@ ex power::expand_add(const add & a, int n) const !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)) + if (is_exactly_a(b)) term.push_back(expand_mul(ex_to(b),numeric(n-k_cum[m-2]))); else term.push_back(power(b,n-k_cum[m-2])); @@ -719,10 +737,10 @@ ex power::expand_add(const add & a, int n) const // recalc k_cum[] and upper_limit[] k_cum[l] = (l==0 ? k[0] : k_cum[l-1]+k[l]); - for (int i=l+1; i(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)) { + if (c.is_equal(_ex1)) { + if (is_exactly_a(r)) { sum.push_back(expair(expand_mul(ex_to(r),_num2), _ex1)); } else { @@ -763,15 +781,15 @@ ex power::expand_add_2(const add & a) const _ex1)); } } else { - if (is_ex_exactly_of_type(r,mul)) { - sum.push_back(expair(expand_mul(ex_to(r),_num2), + if (is_exactly_a(r)) { + sum.push_back(a.combine_ex_with_coeff_to_pair(expand_mul(ex_to(r),_num2), ex_to(c).power_dyn(_num2))); } else { - sum.push_back(expair((new power(r,_ex2))->setflag(status_flags::dynallocated), + sum.push_back(a.combine_ex_with_coeff_to_pair((new power(r,_ex2))->setflag(status_flags::dynallocated), ex_to(c).power_dyn(_num2))); } } - + for (epvector::const_iterator cit1=cit0+1; cit1!=last; ++cit1) { const ex & r1 = cit1->rest; const ex & c1 = cit1->coeff; @@ -811,16 +829,16 @@ ex power::expand_mul(const mul & m, const numeric & n) const epvector::const_iterator last = m.seq.end(); epvector::const_iterator cit = m.seq.begin(); while (cit!=last) { - if (is_ex_exactly_of_type((*cit).rest,numeric)) { - distrseq.push_back(m.combine_pair_with_coeff_to_pair(*cit,n)); + if (is_exactly_a(cit->rest)) { + distrseq.push_back(m.combine_pair_with_coeff_to_pair(*cit, n)); } else { // it is safe not to call mul::combine_pair_with_coeff_to_pair() // since n is an integer - distrseq.push_back(expair((*cit).rest, ex_to((*cit).coeff).mul(n))); + distrseq.push_back(expair(cit->rest, ex_to(cit->coeff).mul(n))); } ++cit; } - return (new mul(distrseq,ex_to(m.overall_coeff).power_dyn(n)))->setflag(status_flags::dynallocated); + return (new mul(distrseq, ex_to(m.overall_coeff).power_dyn(n)))->setflag(status_flags::dynallocated); } } // namespace GiNaC