X-Git-Url: https://www.ginac.de/ginac.git//ginac.git?p=ginac.git;a=blobdiff_plain;f=ginac%2Fmul.cpp;h=2b404877c9840aa53a071e712aa222e51680533a;hp=dfda4100648a4eadb91c50a403d4cb391f674901;hb=e100f94d92d574ea89a817eca8c58c5eb3418821;hpb=8a30acc990818792ec4e8f8f4d48f5dd8286dbed diff --git a/ginac/mul.cpp b/ginac/mul.cpp index dfda4100..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-2010 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 @@ -283,10 +283,6 @@ bool mul::info(unsigned inf) const case info_flags::integer: case info_flags::crational: case info_flags::cinteger: - case info_flags::positive: - case info_flags::nonnegative: - case info_flags::posint: - case info_flags::nonnegint: case info_flags::even: case info_flags::crational_polynomial: case info_flags::rational_function: { @@ -309,44 +305,114 @@ bool mul::info(unsigned inf) const } return false; } + case info_flags::positive: case info_flags::negative: { - bool neg = false; + 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)) - neg = !neg; + pos = !pos; else return false; } if (overall_coeff.info(info_flags::negative)) - neg = !neg; - return neg; + 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 neg = 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::posint)) continue; else if (factor.info(info_flags::negint)) - neg = !neg; + 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)) - neg = !neg; + pos = !pos; else if (!overall_coeff.info(info_flags::posint)) return false; - return neg; + 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 @@ -437,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)); @@ -489,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(); @@ -541,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)); @@ -717,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 @@ -726,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; @@ -755,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; @@ -771,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; @@ -781,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)) @@ -829,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. @@ -891,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()) @@ -927,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 { @@ -940,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 { @@ -953,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)) @@ -965,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; } @@ -1212,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