End of story. There was just too much risk involved in somebody not
caring enough whether there are noncommutatating objects inside
expressions to be multiplied and it could potentially end up in people
using operator% instead of operator* all the time, just to be safe.
In any case, it was our firm believe that noncommutatividity is a
property of the class objects belong to and hence of the objects and
not at all of the sign to symbol the object (as Maple, Reduce and others
want to make us believe). Finally we found out how to code operator*
so that it handles both cases without any performance loss. It couldn't
be less intrusive! There is no measurable performance degradation.
(Except perhaps for the tgamma-expansion which seems to show some 3%
loss while others mysteriously become somewhat faster -- my brain is
melting.) Enough, now...
* sqrfree() factorization fixed and improved syntactically.
* subs() works on matrices.
* Fixed memory leak in expand().
* sqrfree() factorization fixed and improved syntactically.
* subs() works on matrices.
* Fixed memory leak in expand().
+* Operator% for objects of class ncmul has gone. Use operator* now for that
+ case too, which is much more natural.
0.7.3 (28 February 2001)
* Several bugfixes and minor performance tunings.
0.7.3 (28 February 2001)
* Several bugfixes and minor performance tunings.
+/** Used internally by operator+() to add two ex objects together. */
ex ex::exadd(const ex & rh) const
{
return (new add(*this,rh))->setflag(status_flags::dynallocated);
}
ex ex::exadd(const ex & rh) const
{
return (new add(*this,rh))->setflag(status_flags::dynallocated);
}
+/** Used internally by operator*() to multiply two ex objects together. */
ex ex::exmul(const ex & rh) const
{
ex ex::exmul(const ex & rh) const
{
- return (new mul(*this,rh))->setflag(status_flags::dynallocated);
-}
-
-ex ex::exncmul(const ex & rh) const
-{
- return (new ncmul(*this,rh))->setflag(status_flags::dynallocated);
+ // Check if we are constructing a mul object or a ncmul object. Due to
+ // ncmul::eval()'s rule to pull out commutative elements we need to check
+ // only one of the elements.
+ if (rh.bp->return_type()==return_types::commutative ||
+ bp->return_type()==return_types::commutative)
+ return (new mul(*this,rh))->setflag(status_flags::dynallocated);
+ else
+ return (new ncmul(*this,rh))->setflag(status_flags::dynallocated);
ex exadd(const ex & rh) const;
ex exmul(const ex & rh) const;
ex exadd(const ex & rh) const;
ex exmul(const ex & rh) const;
- ex exncmul(const ex & rh) const;
private:
void construct_from_basic(const basic & other);
void construct_from_int(int i);
private:
void construct_from_basic(const basic & other);
void construct_from_int(int i);
| exp '-' exp {$$ = $1 - $3;}
| exp '*' exp {$$ = $1 * $3;}
| exp '/' exp {$$ = $1 / $3;}
| exp '-' exp {$$ = $1 - $3;}
| exp '*' exp {$$ = $1 * $3;}
| exp '/' exp {$$ = $1 / $3;}
- | exp '%' exp {$$ = $1 % $3;}
| '-' exp %prec NEG {$$ = -$2;}
| '+' exp %prec NEG {$$ = $2;}
| exp '^' exp {$$ = pow($1, $3);}
| '-' exp %prec NEG {$$ = -$2;}
| '+' exp %prec NEG {$$ = $2;}
| exp '^' exp {$$ = pow($1, $3);}
void ncmul::print(std::ostream & os, unsigned upper_precedence) const
{
debugmsg("ncmul print",LOGLEVEL_PRINT);
void ncmul::print(std::ostream & os, unsigned upper_precedence) const
{
debugmsg("ncmul print",LOGLEVEL_PRINT);
- printseq(os,'(','%',')',precedence,upper_precedence);
+ printseq(os,'(','*',')',precedence,upper_precedence);
}
void ncmul::printraw(std::ostream & os) const
{
debugmsg("ncmul printraw",LOGLEVEL_PRINT);
}
void ncmul::printraw(std::ostream & os) const
{
debugmsg("ncmul printraw",LOGLEVEL_PRINT);
for (exvector::const_iterator it=seq.begin(); it!=seq.end(); ++it) {
(*it).bp->printraw(os);
os << ",";
for (exvector::const_iterator it=seq.begin(); it!=seq.end(); ++it) {
(*it).bp->printraw(os);
os << ",";
// ncmul(ncmul(x1,x2,...),X,ncmul(y1,y2,...)
// (X noncommutative_composite)
// ncmul(ncmul(x1,x2,...),X,ncmul(y1,y2,...)
// (X noncommutative_composite)
- if ((level==1)&&(flags & status_flags::evaluated)) {
+ if ((level==1) && (flags & status_flags::evaluated)) {
// ncmul(...,*(x1,x2),...,ncmul(x3,x4),...) ->
// ncmul(...,x1,x2,...,x3,x4,...) (associativity)
unsigned factors=0;
// ncmul(...,*(x1,x2),...,ncmul(x3,x4),...) ->
// ncmul(...,x1,x2,...,x3,x4,...) (associativity)
unsigned factors=0;
- for (exvector::const_iterator cit=evaledseq.begin(); cit!=evaledseq.end(); ++cit) {
+ for (exvector::const_iterator cit=evaledseq.begin(); cit!=evaledseq.end(); ++cit)
factors += count_factors(*cit);
factors += count_factors(*cit);
exvector assocseq;
assocseq.reserve(factors);
exvector assocseq;
assocseq.reserve(factors);
- for (exvector::const_iterator cit=evaledseq.begin(); cit!=evaledseq.end(); ++cit) {
+ for (exvector::const_iterator cit=evaledseq.begin(); cit!=evaledseq.end(); ++cit)
append_factors(assocseq,*cit);
append_factors(assocseq,*cit);
// ncmul(x) -> x
if (assocseq.size()==1) return *(seq.begin());
// ncmul(x) -> x
if (assocseq.size()==1) return *(seq.begin());
exvector noncommutativeseq;
noncommutativeseq.reserve(assocseq.size()-count_commutative);
for (i=0; i<assocseq.size(); ++i) {
exvector noncommutativeseq;
noncommutativeseq.reserve(assocseq.size()-count_commutative);
for (i=0; i<assocseq.size(); ++i) {
- if (rettypes[i]==return_types::commutative) {
+ if (rettypes[i]==return_types::commutative)
commutativeseq.push_back(assocseq[i]);
commutativeseq.push_back(assocseq[i]);
noncommutativeseq.push_back(assocseq[i]);
noncommutativeseq.push_back(assocseq[i]);
}
commutativeseq.push_back((new ncmul(noncommutativeseq,1))->setflag(status_flags::dynallocated));
return (new mul(commutativeseq))->setflag(status_flags::dynallocated);
}
commutativeseq.push_back((new ncmul(noncommutativeseq,1))->setflag(status_flags::dynallocated));
return (new mul(commutativeseq))->setflag(status_flags::dynallocated);
#endif // def DO_GINAC_ASSERT
// if all elements are of same type, simplify the string
#endif // def DO_GINAC_ASSERT
// if all elements are of same type, simplify the string
return evv[0][0].simplify_ncmul(evv[0]);
return evv[0][0].simplify_ncmul(evv[0]);
exvector splitseq;
splitseq.reserve(evv.size());
for (i=0; i<evv.size(); ++i) {
splitseq.push_back((new ncmul(evv[i]))->setflag(status_flags::dynallocated));
}
exvector splitseq;
splitseq.reserve(evv.size());
for (i=0; i<evv.size(); ++i) {
splitseq.push_back((new ncmul(evv[i]))->setflag(status_flags::dynallocated));
}
return (new mul(splitseq))->setflag(status_flags::dynallocated);
}
return (new mul(splitseq))->setflag(status_flags::dynallocated);
}
return lh.exmul(power(rh,_ex_1()));
}
return lh.exmul(power(rh,_ex_1()));
}
-ex operator%(const ex & lh, const ex & rh)
-{
- debugmsg("operator%(ex,ex)",LOGLEVEL_OPERATOR);
- return lh.exncmul(rh);
-}
-
// binary arithmetic operators numeric with numeric
// binary arithmetic operators numeric with numeric
return (lh=lh.exmul(power(rh,_ex_1())));
}
return (lh=lh.exmul(power(rh,_ex_1())));
}
-const ex & operator%=(ex & lh, const ex & rh)
-{
- debugmsg("operator%=(ex,ex)",LOGLEVEL_OPERATOR);
- return (lh=lh%rh);
-}
-
// binary arithmetic assignment operators with numeric
// binary arithmetic assignment operators with numeric
ex operator-(const ex & lh, const ex & rh);
ex operator*(const ex & lh, const ex & rh);
ex operator/(const ex & lh, const ex & rh);
ex operator-(const ex & lh, const ex & rh);
ex operator*(const ex & lh, const ex & rh);
ex operator/(const ex & lh, const ex & rh);
-ex operator%(const ex & lh, const ex & rh); // non-commutative multiplication
// binary arithmetic operators numeric with numeric
numeric operator+(const numeric & lh, const numeric & rh);
// binary arithmetic operators numeric with numeric
numeric operator+(const numeric & lh, const numeric & rh);
const ex & operator-=(ex & lh, const ex & rh);
const ex & operator*=(ex & lh, const ex & rh);
const ex & operator/=(ex & lh, const ex & rh);
const ex & operator-=(ex & lh, const ex & rh);
const ex & operator*=(ex & lh, const ex & rh);
const ex & operator/=(ex & lh, const ex & rh);
-const ex & operator%=(ex & lh, const ex & rh); // non-commutative multiplication
// binary arithmetic assignment operators with numeric
const numeric & operator+=(numeric & lh, const numeric & rh);
// binary arithmetic assignment operators with numeric
const numeric & operator+=(numeric & lh, const numeric & rh);
| exp '-' exp {$$ = $1 - $3;}
| exp '*' exp {$$ = $1 * $3;}
| exp '/' exp {$$ = $1 / $3;}
| exp '-' exp {$$ = $1 - $3;}
| exp '*' exp {$$ = $1 * $3;}
| exp '/' exp {$$ = $1 / $3;}
- | exp '%' exp {$$ = $1 % $3;}
| '-' exp %prec NEG {$$ = -$2;}
| '+' exp %prec NEG {$$ = $2;}
| exp '^' exp {$$ = power($1, $3);}
| '-' exp %prec NEG {$$ = -$2;}
| '+' exp %prec NEG {$$ = $2;}
| exp '^' exp {$$ = power($1, $3);}