X-Git-Url: https://www.ginac.de/ginac.git//ginac.git?p=ginac.git;a=blobdiff_plain;f=ginac%2Fmul.cpp;h=2b404877c9840aa53a071e712aa222e51680533a;hp=c09a0a537e748590d13a808ff999a12cd096f12a;hb=e100f94d92d574ea89a817eca8c58c5eb3418821;hpb=4c47ecd9caa39ba1a31f5294e395fcbdf2006431 diff --git a/ginac/mul.cpp b/ginac/mul.cpp index c09a0a53..2b404877 100644 --- a/ginac/mul.cpp +++ b/ginac/mul.cpp @@ -3,7 +3,7 @@ * Implementation of GiNaC's products of expressions. */ /* - * GiNaC Copyright (C) 1999-2008 Johannes Gutenberg University Mainz, Germany + * GiNaC Copyright (C) 1999-2015 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 @@ -20,11 +20,6 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ -#include -#include -#include -#include - #include "mul.h" #include "add.h" #include "power.h" @@ -37,6 +32,11 @@ #include "symbol.h" #include "compiler.h" +#include +#include +#include +#include + namespace GiNaC { GINAC_IMPLEMENT_REGISTERED_CLASS_OPT(mul, expairseq, @@ -278,6 +278,12 @@ bool mul::info(unsigned inf) const case info_flags::integer_polynomial: case info_flags::cinteger_polynomial: case info_flags::rational_polynomial: + case info_flags::real: + case info_flags::rational: + case info_flags::integer: + case info_flags::crational: + case info_flags::cinteger: + case info_flags::even: case info_flags::crational_polynomial: case info_flags::rational_function: { epvector::const_iterator i = seq.begin(), end = seq.end(); @@ -286,6 +292,8 @@ bool mul::info(unsigned inf) const return false; ++i; } + if (overall_coeff.is_equal(*_num1_p) && inf == info_flags::even) + return true; return overall_coeff.info(inf); } case info_flags::algebraic: { @@ -297,10 +305,114 @@ bool mul::info(unsigned inf) const } return false; } + case info_flags::positive: + case info_flags::negative: { + if ((inf==info_flags::positive) && (flags & status_flags::is_positive)) + return true; + else if ((inf==info_flags::negative) && (flags & status_flags::is_negative)) + return true; + if (flags & status_flags::purely_indefinite) + return false; + + bool pos = true; + epvector::const_iterator i = seq.begin(), end = seq.end(); + while (i != end) { + const ex& factor = recombine_pair_to_ex(*i++); + if (factor.info(info_flags::positive)) + continue; + else if (factor.info(info_flags::negative)) + pos = !pos; + else + return false; + } + if (overall_coeff.info(info_flags::negative)) + pos = !pos; + setflag(pos ? status_flags::is_positive : status_flags::is_negative); + return (inf == info_flags::positive? pos : !pos); + } + case info_flags::nonnegative: { + if (flags & status_flags::is_positive) + return true; + bool pos = true; + epvector::const_iterator i = seq.begin(), end = seq.end(); + while (i != end) { + const ex& factor = recombine_pair_to_ex(*i++); + if (factor.info(info_flags::nonnegative) || factor.info(info_flags::positive)) + continue; + else if (factor.info(info_flags::negative)) + pos = !pos; + else + return false; + } + return (overall_coeff.info(info_flags::negative)? !pos : pos); + } + case info_flags::posint: + case info_flags::negint: { + bool pos = true; + epvector::const_iterator i = seq.begin(), end = seq.end(); + while (i != end) { + const ex& factor = recombine_pair_to_ex(*i++); + if (factor.info(info_flags::posint)) + continue; + else if (factor.info(info_flags::negint)) + pos = !pos; + else + return false; + } + if (overall_coeff.info(info_flags::negint)) + pos = !pos; + else if (!overall_coeff.info(info_flags::posint)) + return false; + return (inf ==info_flags::posint? pos : !pos); + } + case info_flags::nonnegint: { + bool pos = true; + epvector::const_iterator i = seq.begin(), end = seq.end(); + while (i != end) { + const ex& factor = recombine_pair_to_ex(*i++); + if (factor.info(info_flags::nonnegint) || factor.info(info_flags::posint)) + continue; + else if (factor.info(info_flags::negint)) + pos = !pos; + else + return false; + } + if (overall_coeff.info(info_flags::negint)) + pos = !pos; + else if (!overall_coeff.info(info_flags::posint)) + return false; + return pos; + } + case info_flags::indefinite: { + if (flags & status_flags::purely_indefinite) + return true; + if (flags & (status_flags::is_positive | status_flags::is_negative)) + return false; + epvector::const_iterator i = seq.begin(), end = seq.end(); + while (i != end) { + const ex& term = recombine_pair_to_ex(*i); + if (term.info(info_flags::positive) || term.info(info_flags::negative)) + return false; + ++i; + } + setflag(status_flags::purely_indefinite); + return true; + } } return inherited::info(inf); } +bool mul::is_polynomial(const ex & var) const +{ + for (epvector::const_iterator i=seq.begin(); i!=seq.end(); ++i) { + if (!i->rest.is_polynomial(var) || + (i->rest.has(var) && !i->coeff.info(info_flags::nonnegint))) { + return false; + } + } + return true; +} + int mul::degree(const ex & s) const { // Sum up degrees of factors @@ -391,24 +503,6 @@ ex mul::eval(int level) const setflag(status_flags::dynallocated); } -#ifdef DO_GINAC_ASSERT - epvector::const_iterator i = seq.begin(), end = seq.end(); - while (i != end) { - GINAC_ASSERT((!is_exactly_a(i->rest)) || - (!(ex_to(i->coeff).is_integer()))); - GINAC_ASSERT(!(i->is_canonical_numeric())); - if (is_exactly_a(recombine_pair_to_ex(*i))) - print(print_tree(std::cerr)); - GINAC_ASSERT(!is_exactly_a(recombine_pair_to_ex(*i))); - /* for paranoia */ - expair p = split_ex_to_pair(recombine_pair_to_ex(*i)); - GINAC_ASSERT(p.rest.is_equal(i->rest)); - GINAC_ASSERT(p.coeff.is_equal(i->coeff)); - /* end paranoia */ - ++i; - } -#endif // def DO_GINAC_ASSERT - if (flags & status_flags::evaluated) { GINAC_ASSERT(seq.size()>0); GINAC_ASSERT(seq.size()>1 || !overall_coeff.is_equal(_ex1)); @@ -443,7 +537,7 @@ ex mul::eval(int level) const )->setflag(status_flags::dynallocated | status_flags::evaluated); } 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 + // 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(); @@ -495,8 +589,7 @@ ex mul::eval(int level) const 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) + 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)); @@ -671,7 +764,7 @@ bool tryfactsubs(const ex & origfactor, const ex & patternfactor, int & nummatch return true; } -/** Checks wheter e matches to the pattern pat and the (possibly to be updated) +/** Checks whether e matches to the pattern pat and the (possibly to be updated) * list of replacements repls. This matching is in the sense of algebraic * substitutions. Matching starts with pat.op(factor) of the pattern because * the factors before this one have already been matched. The (possibly @@ -680,9 +773,12 @@ bool tryfactsubs(const ex & origfactor, const ex & patternfactor, int & nummatch * is true for factors that have been matched by the current match. */ bool algebraic_match_mul_with_mul(const mul &e, const ex &pat, exmap& repls, - int factor, int &nummatches, const std::vector &subsed, - std::vector &matched) + int factor, int &nummatches, const std::vector &subsed, + std::vector &matched) { + GINAC_ASSERT(subsed.size() == e.nops()); + GINAC_ASSERT(matched.size() == e.nops()); + if (factor == (int)pat.nops()) return true; @@ -709,13 +805,13 @@ bool algebraic_match_mul_with_mul(const mul &e, const ex &pat, exmap& repls, bool mul::has(const ex & pattern, unsigned options) const { - if(!(options&has_options::algebraic)) + if(!(options & has_options::algebraic)) return basic::has(pattern,options); if(is_a(pattern)) { exmap repls; int nummatches = std::numeric_limits::max(); - std::vector subsed(seq.size(), false); - std::vector matched(seq.size(), false); + std::vector subsed(nops(), false); + std::vector matched(nops(), false); if(algebraic_match_mul_with_mul(*this, pattern, repls, 0, nummatches, subsed, matched)) return true; @@ -725,8 +821,7 @@ bool mul::has(const ex & pattern, unsigned options) const ex mul::algebraic_subs_mul(const exmap & m, unsigned options) const { - std::vector subsed(seq.size(), false); - exvector subsresult(seq.size()); + std::vector subsed(nops(), false); ex divide_by = 1; ex multiply_by = 1; @@ -735,7 +830,7 @@ ex mul::algebraic_subs_mul(const exmap & m, unsigned options) const if (is_exactly_a(it->first)) { retry1: int nummatches = std::numeric_limits::max(); - std::vector currsubsed(seq.size(), false); + std::vector currsubsed(nops(), false); exmap repls; if(!algebraic_match_mul_with_mul(*this, it->first, repls, 0, nummatches, subsed, currsubsed)) @@ -783,6 +878,38 @@ retry1: return ((*this)/divide_by)*multiply_by; } +ex mul::conjugate() const +{ + // The base class' method is wrong here because we have to be careful at + // branch cuts. power::conjugate takes care of that already, so use it. + epvector *newepv = 0; + for (epvector::const_iterator i=seq.begin(); i!=seq.end(); ++i) { + if (newepv) { + newepv->push_back(split_ex_to_pair(recombine_pair_to_ex(*i).conjugate())); + continue; + } + ex x = recombine_pair_to_ex(*i); + ex c = x.conjugate(); + if (c.is_equal(x)) { + continue; + } + newepv = new epvector; + newepv->reserve(seq.size()); + for (epvector::const_iterator j=seq.begin(); j!=i; ++j) { + newepv->push_back(*j); + } + newepv->push_back(split_ex_to_pair(c)); + } + ex x = overall_coeff.conjugate(); + if (!newepv && are_ex_trivially_equal(x, overall_coeff)) { + return *this; + } + ex result = thisexpairseq(newepv ? *newepv : seq, x); + delete newepv; + return result; +} + + // protected /** Implementation of ex::diff() for a product. It applies the product rule. @@ -845,7 +972,7 @@ unsigned mul::return_type() const // all factors checked return all_commutative ? return_types::commutative : return_types::noncommutative; } - + return_type_t mul::return_type_tinfo() const { if (seq.empty()) @@ -881,7 +1008,7 @@ expair mul::split_ex_to_pair(const ex & e) const } return expair(e,_ex1); } - + expair mul::combine_ex_with_coeff_to_pair(const ex & e, const ex & c) const { @@ -894,7 +1021,7 @@ expair mul::combine_ex_with_coeff_to_pair(const ex & e, return split_ex_to_pair(power(e,c)); } - + expair mul::combine_pair_with_coeff_to_pair(const expair & p, const ex & c) const { @@ -907,7 +1034,7 @@ expair mul::combine_pair_with_coeff_to_pair(const expair & p, return split_ex_to_pair(power(recombine_pair_to_ex(p),c)); } - + ex mul::recombine_pair_to_ex(const expair & p) const { if (ex_to(p.coeff).is_equal(*_num1_p)) @@ -919,22 +1046,22 @@ ex mul::recombine_pair_to_ex(const expair & p) const bool mul::expair_needs_further_processing(epp it) { if (is_exactly_a(it->rest) && - ex_to(it->coeff).is_integer()) { + ex_to(it->coeff).is_integer()) { // combined pair is product with integer power -> expand it *it = split_ex_to_pair(recombine_pair_to_ex(*it)); return true; } if (is_exactly_a(it->rest)) { + if (it->coeff.is_equal(_ex1)) { + // pair has coeff 1 and must be moved to the end + return true; + } expair ep = split_ex_to_pair(recombine_pair_to_ex(*it)); if (!ep.is_equal(*it)) { // combined pair is a numeric power which can be simplified *it = ep; return true; } - if (it->coeff.is_equal(_ex1)) { - // combined pair has coeff 1 and must be moved to the end - return true; - } } return false; } @@ -1166,7 +1293,7 @@ ex mul::expand(unsigned options) const /** Member-wise expand the expairs representing this sequence. This must be * overridden from expairseq::expandchildren() and done iteratively in order - * to allow for early cancallations and thus safe memory. + * to allow for early cancellations and thus safe memory. * * @see mul::expand() * @return pointer to epvector containing expanded representation or zero