]> www.ginac.de Git - ginac.git/blobdiff - ginac/mul.cpp
improve mul::info(): the product of two negative terms is positive, ...
[ginac.git] / ginac / mul.cpp
index 3733bc4ac88115c3b8ffbb45a16265eee4f3615f..cee5cd7a7a9f4faf3405eb1f4c9af0b52bd26c02 100644 (file)
@@ -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-2011 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,89 @@ bool mul::info(unsigned inf) const
                        }
                        return false;
                }
+               case info_flags::positive:
                case info_flags::negative: {
-                       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::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;
+                       return (inf ==info_flags::positive? pos : !pos);
+               }
+               case info_flags::nonnegative: {
+                       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; 
                }
        }
        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::integer))) {
+                       return false;
+               }
+       }
+       return true;
+}
+
 int mul::degree(const ex & s) const
 {
        // Sum up degrees of factors
@@ -437,24 +478,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<mul>(i->rest)) ||
-                            (!(ex_to<numeric>(i->coeff).is_integer())));
-               GINAC_ASSERT(!(i->is_canonical_numeric()));
-               if (is_exactly_a<numeric>(recombine_pair_to_ex(*i)))
-                   print(print_tree(std::cerr));
-               GINAC_ASSERT(!is_exactly_a<numeric>(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 +512,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 +564,7 @@ ex mul::eval(int level) const
                        primitive->setflag(status_flags::dynallocated);
                        primitive->clearflag(status_flags::hash_calculated);
                        primitive->overall_coeff = ex_to<numeric>(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<numeric>(ai->coeff).div_dyn(c);
                        
                        s->push_back(expair(*primitive, _ex1));
@@ -726,8 +748,8 @@ 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<bool> &subsed,
-               std::vector<bool> &matched)
+                                  int factor, int &nummatches, const std::vector<bool> &subsed,
+                                  std::vector<bool> &matched)
 {
        GINAC_ASSERT(subsed.size() == e.nops());
        GINAC_ASSERT(matched.size() == e.nops());
@@ -831,6 +853,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.
@@ -893,7 +947,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())
@@ -929,7 +983,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
 {
@@ -942,7 +996,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
 {
@@ -955,7 +1009,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<numeric>(p.coeff).is_equal(*_num1_p)) 
@@ -967,22 +1021,22 @@ ex mul::recombine_pair_to_ex(const expair & p) const
 bool mul::expair_needs_further_processing(epp it)
 {
        if (is_exactly_a<mul>(it->rest) &&
-               ex_to<numeric>(it->coeff).is_integer()) {
+           ex_to<numeric>(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<numeric>(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;
 }