* Implementation of GiNaC's products of expressions. */
/*
- * GiNaC Copyright (C) 1999-2000 Johannes Gutenberg University Mainz, Germany
+ * GiNaC Copyright (C) 1999-2001 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 "debugmsg.h"
#include "utils.h"
-#ifndef NO_NAMESPACE_GINAC
namespace GiNaC {
-#endif // ndef NO_NAMESPACE_GINAC
GINAC_IMPLEMENT_REGISTERED_CLASS(mul, expairseq)
//////////
-// default constructor, destructor, copy constructor assignment operator and helpers
+// default ctor, dctor, copy ctor assignment operator and helpers
//////////
// public
mul::mul()
{
- debugmsg("mul default constructor",LOGLEVEL_CONSTRUCT);
+ debugmsg("mul default ctor",LOGLEVEL_CONSTRUCT);
tinfo_key = TINFO_mul;
}
-mul::~mul()
-{
- debugmsg("mul destructor",LOGLEVEL_DESTRUCT);
- destroy(false);
-}
-
-mul::mul(const mul & other)
-{
- debugmsg("mul copy constructor",LOGLEVEL_CONSTRUCT);
- copy(other);
-}
-
-const mul & mul::operator=(const mul & other)
-{
- debugmsg("mul operator=",LOGLEVEL_ASSIGNMENT);
- if (this != &other) {
- destroy(true);
- copy(other);
- }
- return *this;
-}
-
// protected
+/** For use by copy ctor and assignment operator. */
void mul::copy(const mul & other)
{
inherited::copy(other);
}
//////////
-// other constructors
+// other ctors
//////////
// public
mul::mul(const ex & lh, const ex & rh)
{
- debugmsg("mul constructor from ex,ex",LOGLEVEL_CONSTRUCT);
+ debugmsg("mul ctor from ex,ex",LOGLEVEL_CONSTRUCT);
tinfo_key = TINFO_mul;
overall_coeff = _ex1();
construct_from_2_ex(lh,rh);
mul::mul(const exvector & v)
{
- debugmsg("mul constructor from exvector",LOGLEVEL_CONSTRUCT);
+ debugmsg("mul ctor from exvector",LOGLEVEL_CONSTRUCT);
tinfo_key = TINFO_mul;
overall_coeff = _ex1();
construct_from_exvector(v);
mul::mul(const epvector & v)
{
- debugmsg("mul constructor from epvector",LOGLEVEL_CONSTRUCT);
+ debugmsg("mul ctor from epvector",LOGLEVEL_CONSTRUCT);
tinfo_key = TINFO_mul;
overall_coeff = _ex1();
construct_from_epvector(v);
mul::mul(const epvector & v, const ex & oc)
{
- debugmsg("mul constructor from epvector,ex",LOGLEVEL_CONSTRUCT);
+ debugmsg("mul ctor from epvector,ex",LOGLEVEL_CONSTRUCT);
tinfo_key = TINFO_mul;
overall_coeff = oc;
construct_from_epvector(v);
mul::mul(epvector * vp, const ex & oc)
{
- debugmsg("mul constructor from epvector *,ex",LOGLEVEL_CONSTRUCT);
+ debugmsg("mul ctor from epvector *,ex",LOGLEVEL_CONSTRUCT);
tinfo_key = TINFO_mul;
GINAC_ASSERT(vp!=0);
overall_coeff = oc;
mul::mul(const ex & lh, const ex & mh, const ex & rh)
{
- debugmsg("mul constructor from ex,ex,ex",LOGLEVEL_CONSTRUCT);
+ debugmsg("mul ctor from ex,ex,ex",LOGLEVEL_CONSTRUCT);
tinfo_key = TINFO_mul;
exvector factors;
factors.reserve(3);
/** Construct object from archive_node. */
mul::mul(const archive_node &n, const lst &sym_lst) : inherited(n, sym_lst)
{
- debugmsg("mul constructor from archive_node", LOGLEVEL_CONSTRUCT);
+ debugmsg("mul ctor from archive_node", LOGLEVEL_CONSTRUCT);
}
/** Unarchive the object. */
// public
-basic * mul::duplicate() const
-{
- debugmsg("mul duplicate",LOGLEVEL_ASSIGNMENT);
- return new mul(*this);
-}
-
void mul::print(std::ostream & os, unsigned upper_precedence) const
{
debugmsg("mul print",LOGLEVEL_PRINT);
if (precedence<=upper_precedence) os << "(";
- bool first=true;
+ bool first = true;
// first print the overall numeric coefficient:
numeric coeff = ex_to_numeric(overall_coeff);
if (coeff.csgn()==-1) os << '-';
return inherited::info(inf);
}
-typedef std::vector<int> intvector;
-
int mul::degree(const symbol & s) const
{
int deg_sum = 0;
for (epvector::const_iterator cit=seq.begin(); cit!=seq.end(); ++cit) {
- deg_sum+=(*cit).rest.degree(s) * ex_to_numeric((*cit).coeff).to_int();
+ if (ex_to_numeric(cit->coeff).is_integer())
+ deg_sum+=cit->rest.degree(s) * ex_to_numeric(cit->coeff).to_int();
}
return deg_sum;
}
{
int deg_sum = 0;
for (epvector::const_iterator cit=seq.begin(); cit!=seq.end(); ++cit) {
- deg_sum+=(*cit).rest.ldegree(s) * ex_to_numeric((*cit).coeff).to_int();
+ if (ex_to_numeric(cit->coeff).is_integer())
+ deg_sum+=cit->rest.ldegree(s) * ex_to_numeric(cit->coeff).to_int();
}
return deg_sum;
}
if (n==0) {
// product of individual coeffs
// if a non-zero power of s is found, the resulting product will be 0
- epvector::const_iterator it=seq.begin();
+ epvector::const_iterator it = seq.begin();
while (it!=seq.end()) {
coeffseq.push_back(recombine_pair_to_ex(*it).coeff(s,n));
++it;
coeffseq.push_back(overall_coeff);
return (new mul(coeffseq))->setflag(status_flags::dynallocated);
}
-
+
epvector::const_iterator it=seq.begin();
- bool coeff_found=0;
+ bool coeff_found = 0;
while (it!=seq.end()) {
- ex t=recombine_pair_to_ex(*it);
- ex c=t.coeff(s,n);
+ ex t = recombine_pair_to_ex(*it);
+ ex c = t.coeff(s,n);
if (!c.is_zero()) {
coeffseq.push_back(c);
- coeff_found=1;
+ coeff_found = 1;
} else {
coeffseq.push_back(t);
}
// *(+(x,y,...);c) -> *(+(*(x,c),*(y,c),...)) (c numeric())
// *(x;1) -> x
// *(;c) -> c
-
+
debugmsg("mul eval",LOGLEVEL_MEMBER_FUNCTION);
-
- epvector * evaled_seqp=evalchildren(level);
+
+ epvector * evaled_seqp = evalchildren(level);
if (evaled_seqp!=0) {
// do more evaluation later
return (new mul(evaled_seqp,overall_coeff))->
- setflag(status_flags::dynallocated);
+ setflag(status_flags::dynallocated);
}
-
+
#ifdef DO_GINAC_ASSERT
for (epvector::const_iterator cit=seq.begin(); cit!=seq.end(); ++cit) {
- GINAC_ASSERT((!is_ex_exactly_of_type((*cit).rest,mul))||
- (!(ex_to_numeric((*cit).coeff).is_integer())));
- GINAC_ASSERT(!((*cit).is_numeric_with_coeff_1()));
- if (is_ex_exactly_of_type(recombine_pair_to_ex(*cit),numeric)) {
- printtree(cerr,0);
- }
+ GINAC_ASSERT((!is_ex_exactly_of_type((*cit).rest,mul)) ||
+ (!(ex_to_numeric((*cit).coeff).is_integer())));
+ GINAC_ASSERT(!(cit->is_canonical_numeric()));
+ if (is_ex_exactly_of_type(recombine_pair_to_ex(*cit),numeric))
+ printtree(std::cerr,0);
GINAC_ASSERT(!is_ex_exactly_of_type(recombine_pair_to_ex(*cit),numeric));
/* for paranoia */
- expair p=split_ex_to_pair(recombine_pair_to_ex(*cit));
+ expair p = split_ex_to_pair(recombine_pair_to_ex(*cit));
GINAC_ASSERT(p.rest.is_equal((*cit).rest));
GINAC_ASSERT(p.coeff.is_equal((*cit).coeff));
/* end paranoia */
}
#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()));
+ GINAC_ASSERT(seq.size()>1 || !overall_coeff.is_equal(_ex1()));
return *this;
}
-
- int seq_size=seq.size();
+
+ int seq_size = seq.size();
if (overall_coeff.is_equal(_ex0())) {
// *(...,x;0) -> 0
return _ex0();
} else if (seq_size==0) {
// *(;c) -> c
return overall_coeff;
- } else if ((seq_size==1)&&overall_coeff.is_equal(_ex1())) {
+ } else if (seq_size==1 && overall_coeff.is_equal(_ex1())) {
// *(x;1) -> x
return recombine_pair_to_ex(*(seq.begin()));
} else if ((seq_size==1) &&
is_ex_exactly_of_type((*seq.begin()).rest,add) &&
ex_to_numeric((*seq.begin()).coeff).is_equal(_num1())) {
// *(+(x,y,...);c) -> +(*(x,c),*(y,c),...) (c numeric(), no powers of +())
- const add & addref=ex_to_add((*seq.begin()).rest);
+ const add & addref = ex_to_add((*seq.begin()).rest);
epvector distrseq;
distrseq.reserve(addref.seq.size());
for (epvector::const_iterator cit=addref.seq.begin(); cit!=addref.seq.end(); ++cit) {
return mul(s,overall_coeff.evalf(level));
}
-exvector mul::get_indices(void) const
-{
- // return union of indices of factors
- exvector iv;
- for (epvector::const_iterator cit=seq.begin(); cit!=seq.end(); ++cit) {
- exvector subiv=(*cit).rest.get_indices();
- iv.reserve(iv.size()+subiv.size());
- for (exvector::const_iterator cit2=subiv.begin(); cit2!=subiv.end(); ++cit2) {
- iv.push_back(*cit2);
- }
- }
- return iv;
-}
-
ex mul::simplify_ncmul(const exvector & v) const
{
throw(std::logic_error("mul::simplify_ncmul() should never have been called!"));
// mul without factors: should not happen, but commutes
return return_types::commutative;
}
-
+
bool all_commutative = 1;
unsigned rt;
epvector::const_iterator cit_noncommutative_element; // point to first found nc element
-
+
for (epvector::const_iterator cit=seq.begin(); cit!=seq.end(); ++cit) {
rt=(*cit).rest.return_type();
if (rt==return_types::noncommutative_composite) return rt; // one ncc -> mul also ncc
unsigned mul::return_type_tinfo(void) const
{
- if (seq.size()==0) {
- // mul without factors: should not happen
- return tinfo_key;
- }
+ if (seq.size()==0)
+ return tinfo_key; // mul without factors: should not happen
+
// return type_info of first noncommutative element
for (epvector::const_iterator cit=seq.begin(); cit!=seq.end(); ++cit) {
- if ((*cit).rest.return_type()==return_types::noncommutative) {
+ if ((*cit).rest.return_type()==return_types::noncommutative)
return (*cit).rest.return_type_tinfo();
- }
}
// no noncommutative element found, should not happen
return tinfo_key;
expair mul::split_ex_to_pair(const ex & e) const
{
if (is_ex_exactly_of_type(e,power)) {
- const power & powerref=ex_to_power(e);
- if (is_ex_exactly_of_type(powerref.exponent,numeric)) {
+ const power & powerref = ex_to_power(e);
+ if (is_ex_exactly_of_type(powerref.exponent,numeric))
return expair(powerref.basis,powerref.exponent);
- }
}
return expair(e,_ex1());
}
if (is_ex_exactly_of_type((*it).rest,mul) &&
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));
+ *it = split_ex_to_pair(recombine_pair_to_ex(*it));
return true;
}
if (is_ex_exactly_of_type((*it).rest,numeric)) {
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;
+ *it = ep;
return true;
}
if (ex_to_numeric((*it).coeff).is_equal(_num1())) {
return *this;
exvector sub_expanded_seq;
- intvector positions_of_adds;
- intvector number_of_add_operands;
epvector * expanded_seqp = expandchildren(options);
const epvector & expanded_seq = expanded_seqp==0 ? seq : *expanded_seqp;
- positions_of_adds.resize(expanded_seq.size());
- number_of_add_operands.resize(expanded_seq.size());
-
int number_of_adds = 0;
- int number_of_expanded_terms = 1;
-
- unsigned current_position = 0;
+ epvector non_adds;
+ non_adds.reserve(expanded_seq.size());
+ epvector::const_iterator cit = expanded_seq.begin();
epvector::const_iterator last = expanded_seq.end();
- for (epvector::const_iterator cit = expanded_seq.begin(); cit!=last; ++cit) {
+ ex last_expanded = _ex1();
+ while (cit!=last) {
if (is_ex_exactly_of_type((*cit).rest,add) &&
((*cit).coeff.is_equal(_ex1()))) {
- positions_of_adds[number_of_adds] = current_position;
- const add & expanded_addref = ex_to_add((*cit).rest);
- unsigned addref_nops = expanded_addref.nops();
- number_of_add_operands[number_of_adds] = addref_nops;
- number_of_expanded_terms *= addref_nops;
++number_of_adds;
+ if (is_ex_exactly_of_type(last_expanded,add)) {
+ // expand adds
+ const add & add1 = ex_to_add(last_expanded);
+ const add & add2 = ex_to_add((*cit).rest);
+ int n1 = add1.nops();
+ int n2 = add2.nops();
+ exvector distrseq;
+ distrseq.reserve(n1*n2);
+ for (int i1=0; i1<n1; ++i1) {
+ for (int i2=0; i2<n2; ++i2) {
+ distrseq.push_back(add1.op(i1)*add2.op(i2));
+ }
+ }
+ last_expanded = (new add(distrseq))->setflag(status_flags::dynallocated | status_flags::expanded);
+ } else {
+ non_adds.push_back(split_ex_to_pair(last_expanded));
+ last_expanded = (*cit).rest;
+ }
+ } else {
+ non_adds.push_back(*cit);
}
- ++current_position;
- }
-
- if (number_of_adds==0) {
- if (expanded_seqp==0)
- return this->setflag(status_flags::expanded);
- else
- return ((new mul(expanded_seqp,overall_coeff))->
- setflag(status_flags::dynallocated | status_flags::expanded));
+ ++cit;
}
-
- exvector distrseq;
- distrseq.reserve(number_of_expanded_terms);
-
- intvector k;
- k.resize(number_of_adds, 0);
-
- for (;;) {
- epvector term;
- term = expanded_seq;
- for (int l=0; l<number_of_adds; ++l) {
- const add & addref = ex_to_add(expanded_seq[positions_of_adds[l]].rest);
- GINAC_ASSERT(term[positions_of_adds[l]].coeff.compare(_ex1())==0);
- term[positions_of_adds[l]]=split_ex_to_pair(addref.op(k[l]));
- }
- distrseq.push_back((new mul(term,overall_coeff))->
- setflag(status_flags::dynallocated | status_flags::expanded));
-
- // increment k[]
- int l = number_of_adds-1;
- while ((l>=0) && ((++k[l])>=number_of_add_operands[l])) {
- k[l] = 0;
- --l;
+ if (expanded_seqp)
+ delete expanded_seqp;
+
+ if (is_ex_exactly_of_type(last_expanded,add)) {
+ add const & finaladd = ex_to_add(last_expanded);
+ exvector distrseq;
+ int n = finaladd.nops();
+ distrseq.reserve(n);
+ for (int 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))->setflag(status_flags::dynallocated | status_flags::expanded));
}
- if (l < 0) break;
+ return ((new add(distrseq))->
+ setflag(status_flags::dynallocated | status_flags::expanded));
}
-
- if (expanded_seqp!=0)
- delete expanded_seqp;
-
- return (new add(distrseq))->setflag(status_flags::dynallocated |
- status_flags::expanded);
+ non_adds.push_back(split_ex_to_pair(last_expanded));
+ return (new mul(non_adds,overall_coeff))->
+ setflag(status_flags::dynallocated | status_flags::expanded);
}
+
//////////
// new virtual functions which can be overridden by derived classes
//////////
// non-virtual functions in this class
//////////
+
+/** 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.
+ *
+ * @see mul::expand()
+ * @return pointer to epvector containing expanded representation or zero
+ * pointer, if sequence is unchanged. */
epvector * mul::expandchildren(unsigned options) const
{
epvector::const_iterator last = seq.end();
if (!are_ex_trivially_equal(factor,expanded_factor)) {
// something changed, copy seq, eval and return it
- epvector *s=new epvector;
+ epvector *s = new epvector;
s->reserve(seq.size());
// copy parts of seq which are known not to have changed
return 0; // nothing has changed
}
-
+
//////////
// static member variables
//////////
unsigned mul::precedence = 50;
-
-//////////
-// global constants
-//////////
-
-const mul some_mul;
-const std::type_info & typeid_mul = typeid(some_mul);
-
-#ifndef NO_NAMESPACE_GINAC
} // namespace GiNaC
-#endif // ndef NO_NAMESPACE_GINAC