* Implementation of GiNaC's products of expressions. */
/*
- * 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
#include <iostream>
#include <vector>
#include <stdexcept>
+#include <limits>
#include "mul.h"
#include "add.h"
#include "power.h"
+#include "operators.h"
#include "matrix.h"
+#include "lst.h"
#include "archive.h"
#include "utils.h"
//////////
// public
-
void mul::print(const print_context & c, unsigned level) const
{
if (is_a<print_tree>(c)) {
while (it != itend) {
// If the first argument is a negative integer power, it gets printed as "1.0/<expr>"
- if (it == seq.begin() && ex_to<numeric>(it->coeff).is_integer() && it->coeff.info(info_flags::negative)) {
- if (is_a<print_csrc_cl_N>(c))
+ bool needclosingparenthesis = false;
+ if (it == seq.begin() && it->coeff.info(info_flags::negint)) {
+ if (is_a<print_csrc_cl_N>(c)) {
c.s << "recip(";
- else
+ needclosingparenthesis = true;
+ } else
c.s << "1.0/";
}
// If the exponent is 1 or -1, it is left out
if (it->coeff.is_equal(_ex1) || it->coeff.is_equal(_ex_1))
it->rest.print(c, precedence());
- else {
- // Outer parens around ex needed for broken gcc-2.95 parser:
- (ex(power(it->rest, abs(ex_to<numeric>(it->coeff))))).print(c, level);
- }
+ else if (it->coeff.info(info_flags::negint))
+ // Outer parens around ex needed for broken GCC parser:
+ (ex(power(it->rest, -ex_to<numeric>(it->coeff)))).print(c, level);
+ else
+ // Outer parens around ex needed for broken GCC parser:
+ (ex(power(it->rest, ex_to<numeric>(it->coeff)))).print(c, level);
+
+ if (needclosingparenthesis)
+ c.s << ")";
// Separator is "/" for negative integer powers, "*" otherwise
++it;
if (it != itend) {
- if (ex_to<numeric>(it->coeff).is_integer() && it->coeff.info(info_flags::negative))
+ if (it->coeff.info(info_flags::negint))
c.s << "/";
else
c.s << "*";
} else if (is_a<print_python_repr>(c)) {
c.s << class_name() << '(';
op(0).print(c);
- for (unsigned i=1; i<nops(); ++i) {
+ for (size_t i=1; i<nops(); ++i) {
c.s << ',';
op(i).print(c);
}
c.s << "(";
}
- bool first = true;
-
// First print the overall numeric coefficient
- numeric coeff = ex_to<numeric>(overall_coeff);
+ const numeric &coeff = ex_to<numeric>(overall_coeff);
if (coeff.csgn() == -1)
c.s << '-';
if (!coeff.is_equal(_num1) &&
// Then proceed with the remaining factors
epvector::const_iterator it = seq.begin(), itend = seq.end();
- while (it != itend) {
- if (!first) {
- if (is_a<print_latex>(c))
- c.s << ' ';
+ if (is_a<print_latex>(c)) {
+
+ // Separate factors into those with negative numeric exponent
+ // and all others
+ exvector neg_powers, others;
+ while (it != itend) {
+ GINAC_ASSERT(is_exactly_a<numeric>(it->coeff));
+ if (ex_to<numeric>(it->coeff).is_negative())
+ neg_powers.push_back(recombine_pair_to_ex(expair(it->rest, -(it->coeff))));
else
- c.s << '*';
+ others.push_back(recombine_pair_to_ex(*it));
+ ++it;
+ }
+
+ if (!neg_powers.empty()) {
+
+ // Factors with negative exponent are printed as a fraction
+ c.s << "\\frac{";
+ mul(others).eval().print(c);
+ c.s << "}{";
+ mul(neg_powers).eval().print(c);
+ c.s << "}";
+
} else {
- first = false;
+
+ // All other factors are printed in the ordinary way
+ exvector::const_iterator vit = others.begin(), vitend = others.end();
+ while (vit != vitend) {
+ c.s << ' ';
+ vit->print(c, precedence());
+ ++vit;
+ }
+ }
+
+ } else {
+
+ bool first = true;
+ while (it != itend) {
+ if (!first)
+ c.s << '*';
+ else
+ first = false;
+ recombine_pair_to_ex(*it).print(c, precedence());
+ ++it;
}
- recombine_pair_to_ex(*it).print(c, precedence());
- ++it;
}
if (precedence() <= level) {
return (new mul(s, overall_coeff))->setflag(status_flags::dynallocated);
}
-ex mul::simplify_ncmul(const exvector & v) const
+ex mul::eval_ncmul(const exvector & v) const
{
if (seq.empty())
- return inherited::simplify_ncmul(v);
+ return inherited::eval_ncmul(v);
- // Find first noncommutative element and call its simplify_ncmul()
+ // Find first noncommutative element and call its eval_ncmul()
epvector::const_iterator i = seq.begin(), end = seq.end();
while (i != end) {
if (i->rest.return_type() == return_types::noncommutative)
- return i->rest.simplify_ncmul(v);
+ return i->rest.eval_ncmul(v);
++i;
}
- return inherited::simplify_ncmul(v);
+ return inherited::eval_ncmul(v);
+}
+
+bool tryfactsubs(const ex & origfactor, const ex & patternfactor, int & nummatches, lst & repls)
+{
+ ex origbase;
+ int origexponent;
+ int origexpsign;
+
+ if (is_exactly_a<power>(origfactor) && origfactor.op(1).info(info_flags::integer)) {
+ origbase = origfactor.op(0);
+ int expon = ex_to<numeric>(origfactor.op(1)).to_int();
+ origexponent = expon > 0 ? expon : -expon;
+ origexpsign = expon > 0 ? 1 : -1;
+ } else {
+ origbase = origfactor;
+ origexponent = 1;
+ origexpsign = 1;
+ }
+
+ ex patternbase;
+ int patternexponent;
+ int patternexpsign;
+
+ if (is_exactly_a<power>(patternfactor) && patternfactor.op(1).info(info_flags::integer)) {
+ patternbase = patternfactor.op(0);
+ int expon = ex_to<numeric>(patternfactor.op(1)).to_int();
+ patternexponent = expon > 0 ? expon : -expon;
+ patternexpsign = expon > 0 ? 1 : -1;
+ } else {
+ patternbase = patternfactor;
+ patternexponent = 1;
+ patternexpsign = 1;
+ }
+
+ lst saverepls = repls;
+ if (origexponent < patternexponent || origexpsign != patternexpsign || !origbase.match(patternbase,saverepls))
+ return false;
+ repls = saverepls;
+
+ int newnummatches = origexponent / patternexponent;
+ if (newnummatches < nummatches)
+ nummatches = newnummatches;
+ return true;
+}
+
+ex mul::algebraic_subs_mul(const lst & ls, const lst & lr, unsigned options) const
+{
+ std::vector<bool> subsed(seq.size(), false);
+ exvector subsresult(seq.size());
+
+ for (size_t i=0; i<ls.nops(); i++) {
+
+ if (is_exactly_a<mul>(ls.op(i))) {
+
+ int nummatches = std::numeric_limits<int>::max();
+ std::vector<bool> currsubsed(seq.size(), false);
+ bool succeed = true;
+ lst repls;
+
+ for (size_t j=0; j<ls.op(i).nops(); j++) {
+ bool found=false;
+ for (size_t k=0; k<nops(); k++) {
+ if (currsubsed[k] || subsed[k])
+ continue;
+ if (tryfactsubs(op(k), ls.op(i).op(j), nummatches, repls)) {
+ currsubsed[k] = true;
+ found = true;
+ break;
+ }
+ }
+ if (!found) {
+ succeed = false;
+ break;
+ }
+ }
+ if (!succeed)
+ continue;
+
+ bool foundfirstsubsedfactor = false;
+ for (size_t j=0; j<subsed.size(); j++) {
+ if (currsubsed[j]) {
+ if (foundfirstsubsedfactor)
+ subsresult[j] = op(j);
+ else {
+ foundfirstsubsedfactor = true;
+ subsresult[j] = op(j) * power(lr.op(i).subs(ex(repls), subs_options::subs_no_pattern) / ls.op(i).subs(ex(repls), subs_options::subs_no_pattern), nummatches);
+ }
+ subsed[j] = true;
+ }
+ }
+
+ } else {
+
+ int nummatches = std::numeric_limits<int>::max();
+ lst repls;
+
+ for (size_t j=0; j<this->nops(); j++) {
+ if (!subsed[j] && tryfactsubs(op(j), ls.op(i), nummatches, repls)) {
+ subsed[j] = true;
+ subsresult[j] = op(j) * power(lr.op(i).subs(ex(repls), subs_options::subs_no_pattern) / ls.op(i).subs(ex(repls), subs_options::subs_no_pattern), nummatches);
+ }
+ }
+ }
+ }
+
+ bool subsfound = false;
+ for (size_t i=0; i<subsed.size(); i++) {
+ if (subsed[i]) {
+ subsfound = true;
+ break;
+ }
+ }
+ if (!subsfound)
+ return basic::subs(ls, lr, options | subs_options::subs_algebraic);
+
+ exvector ev; ev.reserve(nops());
+ for (size_t i=0; i<nops(); i++) {
+ if (subsed[i])
+ ev.push_back(subsresult[i]);
+ else
+ ev.push_back(op(i));
+ }
+
+ return (new mul(ev))->setflag(status_flags::dynallocated);
}
// protected
* @see ex::diff */
ex mul::derivative(const symbol & s) const
{
- unsigned num = seq.size();
+ size_t num = seq.size();
exvector addseq;
addseq.reserve(num);
return inherited::compare_same_type(other);
}
-bool mul::is_equal_same_type(const basic & other) const
-{
- return inherited::is_equal_same_type(other);
-}
-
unsigned mul::return_type(void) const
{
if (seq.empty()) {
{
// to avoid duplication of power simplification rules,
// we create a temporary power object
- // otherwise it would be hard to correctly simplify
+ // otherwise it would be hard to correctly evaluate
// expression like (4^(1/3))^(3/2)
- if (are_ex_trivially_equal(c,_ex1))
+ if (c.is_equal(_ex1))
return split_ex_to_pair(e);
-
+
return split_ex_to_pair(power(e,c));
}
{
// to avoid duplication of power simplification rules,
// we create a temporary power object
- // otherwise it would be hard to correctly simplify
+ // otherwise it would be hard to correctly evaluate
// expression like (4^(1/3))^(3/2)
- if (are_ex_trivially_equal(c,_ex1))
+ if (c.is_equal(_ex1))
return p;
-
+
return split_ex_to_pair(power(recombine_pair_to_ex(p),c));
}
if (ex_to<numeric>(p.coeff).is_equal(_num1))
return p.rest;
else
- return power(p.rest,p.coeff);
+ return (new power(p.rest,p.coeff))->setflag(status_flags::dynallocated);
}
bool mul::expair_needs_further_processing(epp it)
{
- if (is_exactly_a<mul>((*it).rest) &&
- ex_to<numeric>((*it).coeff).is_integer()) {
+ if (is_exactly_a<mul>(it->rest) &&
+ 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)) {
- expair ep=split_ex_to_pair(recombine_pair_to_ex(*it));
+ if (is_exactly_a<numeric>(it->rest)) {
+ 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 (ex_to<numeric>((*it).coeff).is_equal(_num1)) {
+ if (it->coeff.is_equal(_ex1)) {
// combined pair has coeff 1 and must be moved to the end
return true;
}
(cit->coeff.is_equal(_ex1))) {
++number_of_adds;
if (is_exactly_a<add>(last_expanded)) {
-#if 0
- // Expand a product of two sums, simple and robust version.
- const add & add1 = ex_to<add>(last_expanded);
- const add & add2 = ex_to<add>(cit->rest);
- const int n1 = add1.nops();
- const int n2 = add2.nops();
- ex tmp_accu;
- exvector distrseq;
- distrseq.reserve(n2);
- for (int i1=0; i1<n1; ++i1) {
- distrseq.clear();
- // cache the first operand (for efficiency):
- const ex op1 = add1.op(i1);
- for (int i2=0; i2<n2; ++i2)
- distrseq.push_back(op1 * add2.op(i2));
- tmp_accu += (new add(distrseq))->
- setflag(status_flags::dynallocated);
- }
- last_expanded = tmp_accu;
-#else
+
// Expand a product of two sums, aggressive version.
// Caring for the overall coefficients in separate loops can
// sometimes give a performance gain of up to 15%!
tmp_accu += (new add(distrseq, oc))->setflag(status_flags::dynallocated);
}
last_expanded = tmp_accu;
-#endif
+
} else {
non_adds.push_back(split_ex_to_pair(last_expanded));
last_expanded = cit->rest;
if (is_exactly_a<add>(last_expanded)) {
const add & finaladd = ex_to<add>(last_expanded);
exvector distrseq;
- int n = finaladd.nops();
+ size_t n = finaladd.nops();
distrseq.reserve(n);
- for (int i=0; i<n; ++i) {
+ for (size_t i=0; i<n; ++i) {
epvector factors = non_adds;
factors.push_back(split_ex_to_pair(finaladd.op(i)));
distrseq.push_back((new mul(factors, overall_coeff))->