- // simplifications: ncmul(...,*(x1,x2),...,ncmul(x3,x4),...) ->
- // ncmul(...,x1,x2,...,x3,x4,...) (associativity)
- // ncmul(x) -> x
- // ncmul() -> 1
- // ncmul(...,c1,...,c2,...) ->
- // *(c1,c2,ncmul(...)) (pull out commutative elements)
- // ncmul(x1,y1,x2,y2) -> *(ncmul(x1,x2),ncmul(y1,y2))
- // (collect elements of same type)
- // ncmul(x1,x2,x3,...) -> x::eval_ncmul(x1,x2,x3,...)
- // the following rule would be nice, but produces a recursion,
- // which must be trapped by introducing a flag that the sub-ncmuls()
- // are already evaluated (maybe later...)
- // ncmul(x1,x2,...,X,y1,y2,...) ->
- // ncmul(ncmul(x1,x2,...),X,ncmul(y1,y2,...)
- // (X noncommutative_composite)
-
- if ((level==1)&&(flags & status_flags::evaluated)) {
- return *this;
- }
-
- exvector evaledseq=evalchildren(level);
-
- // 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) {
- factors += count_factors(*cit);
- }
-
- exvector assocseq;
- assocseq.reserve(factors);
- for (exvector::const_iterator cit=evaledseq.begin(); cit!=evaledseq.end(); ++cit) {
- append_factors(assocseq,*cit);
- }
-
- // ncmul(x) -> x
- if (assocseq.size()==1) return *(seq.begin());
-
- // ncmul() -> 1
- if (assocseq.size()==0) return _ex1();
-
- // determine return types
- unsignedvector rettypes;
- rettypes.reserve(assocseq.size());
- unsigned i=0;
- unsigned count_commutative=0;
- unsigned count_noncommutative=0;
- unsigned count_noncommutative_composite=0;
- for (exvector::const_iterator cit=assocseq.begin(); cit!=assocseq.end(); ++cit) {
- switch (rettypes[i]=(*cit).return_type()) {
- case return_types::commutative:
- count_commutative++;
- break;
- case return_types::noncommutative:
- count_noncommutative++;
- break;
- case return_types::noncommutative_composite:
- count_noncommutative_composite++;
- break;
- default:
- throw(std::logic_error("ncmul::eval(): invalid return type"));
- }
- ++i;
- }
- GINAC_ASSERT(count_commutative+count_noncommutative+count_noncommutative_composite==assocseq.size());
-
- // ncmul(...,c1,...,c2,...) ->
- // *(c1,c2,ncmul(...)) (pull out commutative elements)
- if (count_commutative!=0) {
- exvector commutativeseq;
- commutativeseq.reserve(count_commutative+1);
- exvector noncommutativeseq;
- noncommutativeseq.reserve(assocseq.size()-count_commutative);
- for (i=0; i<assocseq.size(); ++i) {
- if (rettypes[i]==return_types::commutative) {
- commutativeseq.push_back(assocseq[i]);
- } else {
- noncommutativeseq.push_back(assocseq[i]);
- }
- }
- commutativeseq.push_back((new ncmul(noncommutativeseq,1))->
- setflag(status_flags::dynallocated));
- return (new mul(commutativeseq))->setflag(status_flags::dynallocated);
- }
-
- // ncmul(x1,y1,x2,y2) -> *(ncmul(x1,x2),ncmul(y1,y2))
- // (collect elements of same type)
-
- if (count_noncommutative_composite==0) {
- // there are neither commutative nor noncommutative_composite
- // elements in assocseq
- GINAC_ASSERT(count_commutative==0);
-
- exvectorvector evv;
- unsignedvector rttinfos;
- evv.reserve(assocseq.size());
- rttinfos.reserve(assocseq.size());
-
- for (exvector::const_iterator cit=assocseq.begin(); cit!=assocseq.end(); ++cit) {
- unsigned ti=(*cit).return_type_tinfo();
- // search type in vector of known types
- for (i=0; i<rttinfos.size(); ++i) {
- if (ti==rttinfos[i]) {
- evv[i].push_back(*cit);
- break;
- }
- }
- if (i>=rttinfos.size()) {
- // new type
- rttinfos.push_back(ti);
- evv.push_back(exvector());
- (*(evv.end()-1)).reserve(assocseq.size());
- (*(evv.end()-1)).push_back(*cit);
- }
- }
-
-#ifdef DO_GINAC_ASSERT
- GINAC_ASSERT(evv.size()==rttinfos.size());
- GINAC_ASSERT(evv.size()>0);
- unsigned s=0;
- for (i=0; i<evv.size(); ++i) {
- s += evv[i].size();
- }
- GINAC_ASSERT(s==assocseq.size());
-#endif // def DO_GINAC_ASSERT
-
- // if all elements are of same type, simplify the string
- if (evv.size()==1) {
- 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));
- }
-
- return (new mul(splitseq))->setflag(status_flags::dynallocated);
- }
-
- return (new ncmul(assocseq))->setflag(status_flags::dynallocated |
- status_flags::evaluated);