- if ((is_ex_exactly_of_type(e,mul)&&(e.return_type()!=return_types::commutative))||
- (is_ex_exactly_of_type(e,ncmul))) {
- for (unsigned i=0; i<e.nops(); i++)
- append_factors(v,e.op(i));
-
- return;
- }
- v.push_back(e);
-}
-
-typedef vector<unsigned> unsignedvector;
-typedef vector<exvector> exvectorvector;
-
-ex ncmul::eval(int level) const
-{
- // 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);
- }
- }
-
+ if ((is_exactly_a<mul>(e)&&(e.return_type()!=return_types::commutative))||
+ (is_exactly_a<ncmul>(e))) {
+ for (size_t i=0; i<e.nops(); i++)
+ append_factors(v, e.op(i));
+ } else
+ v.push_back(e);
+}
+
+typedef std::vector<unsigned> unsignedvector;
+typedef std::vector<exvector> exvectorvector;
+
+/** Perform automatic term rewriting rules in this class. In the following
+ * x, x1, x2,... stand for a symbolic variables of type ex and c, c1, c2...
+ * stand for such expressions that contain a plain number.
+ * - 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,...)
+ */
+ex ncmul::eval() const
+{
+ // The following additional 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 (flags & status_flags::evaluated) {
+ return *this;
+ }
+
+ // ncmul(...,*(x1,x2),...,ncmul(x3,x4),...) ->
+ // ncmul(...,x1,x2,...,x3,x4,...) (associativity)
+ size_t factors = 0;
+ for (auto & it : seq)
+ factors += count_factors(it);
+
+ exvector assocseq;
+ assocseq.reserve(factors);
+ make_flat_inserter mf(seq, true);
+ for (auto & it : seq) {
+ ex factor = mf.handle_factor(it, 1);
+ append_factors(assocseq, factor);
+ }
+
+ // ncmul(x) -> x
+ if (assocseq.size()==1) return *(seq.begin());
+
+ // ncmul() -> 1
+ if (assocseq.empty()) return _ex1;
+
+ // determine return types
+ unsignedvector rettypes(assocseq.size());
+ size_t i = 0;
+ size_t count_commutative=0;
+ size_t count_noncommutative=0;
+ size_t count_noncommutative_composite=0;
+ for (auto & it : assocseq) {
+ rettypes[i] = it.return_type();
+ switch (rettypes[i]) {
+ 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);
+ size_t num = assocseq.size();
+ for (size_t i=0; i<num; ++i) {
+ if (rettypes[i]==return_types::commutative)
+ commutativeseq.push_back(assocseq[i]);
+ else
+ noncommutativeseq.push_back(assocseq[i]);
+ }
+ commutativeseq.push_back(dynallocate<ncmul>(std::move(noncommutativeseq)));
+ return dynallocate<mul>(std::move(commutativeseq));
+ }
+
+ // 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);
+
+ size_t assoc_num = assocseq.size();
+ exvectorvector evv;
+ std::vector<return_type_t> rttinfos;
+ evv.reserve(assoc_num);
+ rttinfos.reserve(assoc_num);
+
+ for (auto & it : assocseq) {
+ return_type_t ti = it.return_type_tinfo();
+ size_t rtt_num = rttinfos.size();
+ // search type in vector of known types
+ for (i=0; i<rtt_num; ++i) {
+ if(ti == rttinfos[i]) {
+ evv[i].push_back(it);
+ break;
+ }
+ }
+ if (i >= rtt_num) {
+ // new type
+ rttinfos.push_back(ti);
+ evv.push_back(exvector());
+ (evv.end()-1)->reserve(assoc_num);
+ (evv.end()-1)->push_back(it);
+ }
+ }
+
+ size_t evv_num = evv.size();