]> www.ginac.de Git - ginac.git/blob - ginac/expairseq.cpp
Synced to HEAD:
[ginac.git] / ginac / expairseq.cpp
1 /** @file expairseq.cpp
2  *
3  *  Implementation of sequences of expression pairs. */
4
5 /*
6  *  GiNaC Copyright (C) 1999-2005 Johannes Gutenberg University Mainz, Germany
7  *
8  *  This program is free software; you can redistribute it and/or modify
9  *  it under the terms of the GNU General Public License as published by
10  *  the Free Software Foundation; either version 2 of the License, or
11  *  (at your option) any later version.
12  *
13  *  This program is distributed in the hope that it will be useful,
14  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
15  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  *  GNU General Public License for more details.
17  *
18  *  You should have received a copy of the GNU General Public License
19  *  along with this program; if not, write to the Free Software
20  *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
21  */
22
23 #include <iostream>
24 #include <algorithm>
25 #include <string>
26 #include <stdexcept>
27
28 #include "expairseq.h"
29 #include "lst.h"
30 #include "mul.h"
31 #include "power.h"
32 #include "relational.h"
33 #include "wildcard.h"
34 #include "archive.h"
35 #include "operators.h"
36 #include "utils.h"
37
38 #if EXPAIRSEQ_USE_HASHTAB
39 #include <cmath>
40 #endif // EXPAIRSEQ_USE_HASHTAB
41
42 namespace GiNaC {
43
44         
45 GINAC_IMPLEMENT_REGISTERED_CLASS_OPT(expairseq, basic,
46   print_func<print_context>(&expairseq::do_print).
47   print_func<print_tree>(&expairseq::do_print_tree))
48
49
50 //////////
51 // helper classes
52 //////////
53
54 class epp_is_less
55 {
56 public:
57         bool operator()(const epp &lh, const epp &rh) const
58         {
59                 return (*lh).is_less(*rh);
60         }
61 };
62
63 //////////
64 // default constructor
65 //////////
66
67 // public
68
69 expairseq::expairseq() : inherited(TINFO_expairseq)
70 #if EXPAIRSEQ_USE_HASHTAB
71                                                    , hashtabsize(0)
72 #endif // EXPAIRSEQ_USE_HASHTAB
73 {}
74
75 // protected
76
77 #if 0
78 /** For use by copy ctor and assignment operator. */
79 void expairseq::copy(const expairseq &other)
80 {
81         seq = other.seq;
82         overall_coeff = other.overall_coeff;
83 #if EXPAIRSEQ_USE_HASHTAB
84         // copy hashtab
85         hashtabsize = other.hashtabsize;
86         if (hashtabsize!=0) {
87                 hashmask = other.hashmask;
88                 hashtab.resize(hashtabsize);
89                 epvector::const_iterator osb = other.seq.begin();
90                 for (unsigned i=0; i<hashtabsize; ++i) {
91                         hashtab[i].clear();
92                         for (epplist::const_iterator cit=other.hashtab[i].begin();
93                              cit!=other.hashtab[i].end(); ++cit) {
94                                 hashtab[i].push_back(seq.begin()+((*cit)-osb));
95                         }
96                 }
97         } else {
98                 hashtab.clear();
99         }
100 #endif // EXPAIRSEQ_USE_HASHTAB
101 }
102 #endif
103
104 //////////
105 // other constructors
106 //////////
107
108 expairseq::expairseq(const ex &lh, const ex &rh) : inherited(TINFO_expairseq)
109 {
110         construct_from_2_ex(lh,rh);
111         GINAC_ASSERT(is_canonical());
112 }
113
114 expairseq::expairseq(const exvector &v) : inherited(TINFO_expairseq)
115 {
116         construct_from_exvector(v);
117         GINAC_ASSERT(is_canonical());
118 }
119
120 expairseq::expairseq(const epvector &v, const ex &oc)
121   : inherited(TINFO_expairseq), overall_coeff(oc)
122 {
123         GINAC_ASSERT(is_a<numeric>(oc));
124         construct_from_epvector(v);
125         GINAC_ASSERT(is_canonical());
126 }
127
128 expairseq::expairseq(std::auto_ptr<epvector> vp, const ex &oc)
129   : inherited(TINFO_expairseq), overall_coeff(oc)
130 {
131         GINAC_ASSERT(vp.get()!=0);
132         GINAC_ASSERT(is_a<numeric>(oc));
133         construct_from_epvector(*vp);
134         GINAC_ASSERT(is_canonical());
135 }
136
137 //////////
138 // archiving
139 //////////
140
141 expairseq::expairseq(const archive_node &n, lst &sym_lst) : inherited(n, sym_lst)
142 #if EXPAIRSEQ_USE_HASHTAB
143         , hashtabsize(0)
144 #endif
145 {
146         for (unsigned int i=0; true; i++) {
147                 ex rest;
148                 ex coeff;
149                 if (n.find_ex("rest", rest, sym_lst, i) && n.find_ex("coeff", coeff, sym_lst, i))
150                         seq.push_back(expair(rest, coeff));
151                 else
152                         break;
153         }
154
155         n.find_ex("overall_coeff", overall_coeff, sym_lst);
156
157         canonicalize();
158         GINAC_ASSERT(is_canonical());
159 }
160
161 void expairseq::archive(archive_node &n) const
162 {
163         inherited::archive(n);
164         epvector::const_iterator i = seq.begin(), iend = seq.end();
165         while (i != iend) {
166                 n.add_ex("rest", i->rest);
167                 n.add_ex("coeff", i->coeff);
168                 ++i;
169         }
170         n.add_ex("overall_coeff", overall_coeff);
171 }
172
173 DEFAULT_UNARCHIVE(expairseq)
174
175 //////////
176 // functions overriding virtual functions from base classes
177 //////////
178
179 // public
180
181 void expairseq::do_print(const print_context & c, unsigned level) const
182 {
183         c.s << "[[";
184         printseq(c, ',', precedence(), level);
185         c.s << "]]";
186 }
187
188 void expairseq::do_print_tree(const print_tree & c, unsigned level) const
189 {
190         c.s << std::string(level, ' ') << class_name() << " @" << this
191             << std::hex << ", hash=0x" << hashvalue << ", flags=0x" << flags << std::dec
192             << ", nops=" << nops()
193             << std::endl;
194         size_t num = seq.size();
195         for (size_t i=0; i<num; ++i) {
196                 seq[i].rest.print(c, level + c.delta_indent);
197                 seq[i].coeff.print(c, level + c.delta_indent);
198                 if (i != num - 1)
199                         c.s << std::string(level + c.delta_indent, ' ') << "-----" << std::endl;
200         }
201         if (!overall_coeff.is_equal(default_overall_coeff())) {
202                 c.s << std::string(level + c.delta_indent, ' ') << "-----" << std::endl
203                     << std::string(level + c.delta_indent, ' ') << "overall_coeff" << std::endl;
204                 overall_coeff.print(c, level + c.delta_indent);
205         }
206         c.s << std::string(level + c.delta_indent,' ') << "=====" << std::endl;
207 #if EXPAIRSEQ_USE_HASHTAB
208         c.s << std::string(level + c.delta_indent,' ')
209             << "hashtab size " << hashtabsize << std::endl;
210         if (hashtabsize == 0) return;
211 #define MAXCOUNT 5
212         unsigned count[MAXCOUNT+1];
213         for (int i=0; i<MAXCOUNT+1; ++i)
214                 count[i] = 0;
215         unsigned this_bin_fill;
216         unsigned cum_fill_sq = 0;
217         unsigned cum_fill = 0;
218         for (unsigned i=0; i<hashtabsize; ++i) {
219                 this_bin_fill = 0;
220                 if (hashtab[i].size() > 0) {
221                         c.s << std::string(level + c.delta_indent, ' ')
222                             << "bin " << i << " with entries ";
223                         for (epplist::const_iterator it=hashtab[i].begin();
224                              it!=hashtab[i].end(); ++it) {
225                                 c.s << *it-seq.begin() << " ";
226                                 ++this_bin_fill;
227                         }
228                         c.s << std::endl;
229                         cum_fill += this_bin_fill;
230                         cum_fill_sq += this_bin_fill*this_bin_fill;
231                 }
232                 if (this_bin_fill<MAXCOUNT)
233                         ++count[this_bin_fill];
234                 else
235                         ++count[MAXCOUNT];
236         }
237         unsigned fact = 1;
238         double cum_prob = 0;
239         double lambda = (1.0*seq.size()) / hashtabsize;
240         for (int k=0; k<MAXCOUNT; ++k) {
241                 if (k>0)
242                         fact *= k;
243                 double prob = std::pow(lambda,k)/fact * std::exp(-lambda);
244                 cum_prob += prob;
245                 c.s << std::string(level + c.delta_indent, ' ') << "bins with " << k << " entries: "
246                     << int(1000.0*count[k]/hashtabsize)/10.0 << "% (expected: "
247                     << int(prob*1000)/10.0 << ")" << std::endl;
248         }
249         c.s << std::string(level + c.delta_indent, ' ') << "bins with more entries: "
250             << int(1000.0*count[MAXCOUNT]/hashtabsize)/10.0 << "% (expected: "
251             << int((1-cum_prob)*1000)/10.0 << ")" << std::endl;
252
253         c.s << std::string(level + c.delta_indent, ' ') << "variance: "
254             << 1.0/hashtabsize*cum_fill_sq-(1.0/hashtabsize*cum_fill)*(1.0/hashtabsize*cum_fill)
255             << std::endl;
256         c.s << std::string(level + c.delta_indent, ' ') << "average fill: "
257             << (1.0*cum_fill)/hashtabsize
258             << " (should be equal to " << (1.0*seq.size())/hashtabsize << ")" << std::endl;
259 #endif // EXPAIRSEQ_USE_HASHTAB
260 }
261
262 bool expairseq::info(unsigned inf) const
263 {
264         return inherited::info(inf);
265 }
266
267 size_t expairseq::nops() const
268 {
269         if (overall_coeff.is_equal(default_overall_coeff()))
270                 return seq.size();
271         else
272                 return seq.size()+1;
273 }
274
275 ex expairseq::op(size_t i) const
276 {
277         if (i < seq.size())
278                 return recombine_pair_to_ex(seq[i]);
279         GINAC_ASSERT(!overall_coeff.is_equal(default_overall_coeff()));
280         return overall_coeff;
281 }
282
283 ex expairseq::map(map_function &f) const
284 {
285         std::auto_ptr<epvector> v(new epvector);
286         v->reserve(seq.size()+1);
287
288         epvector::const_iterator cit = seq.begin(), last = seq.end();
289         while (cit != last) {
290                 v->push_back(split_ex_to_pair(f(recombine_pair_to_ex(*cit))));
291                 ++cit;
292         }
293
294         if (overall_coeff.is_equal(default_overall_coeff()))
295                 return thisexpairseq(v, default_overall_coeff());
296         else {
297       ex newcoeff = f(overall_coeff);
298       if(is_a<numeric>(newcoeff))
299          return thisexpairseq(v, newcoeff);
300       else {
301          v->push_back(split_ex_to_pair(newcoeff));
302          return thisexpairseq(v, default_overall_coeff());
303       }
304    }
305 }
306
307 /** Perform coefficient-wise automatic term rewriting rules in this class. */
308 ex expairseq::eval(int level) const
309 {
310         if ((level==1) && (flags &status_flags::evaluated))
311                 return *this;
312         
313         std::auto_ptr<epvector> vp = evalchildren(level);
314         if (vp.get() == 0)
315                 return this->hold();
316         
317         return (new expairseq(vp, overall_coeff))->setflag(status_flags::dynallocated | status_flags::evaluated);
318 }
319
320 epvector* conjugateepvector(const epvector&epv)
321 {
322         epvector *newepv = 0;
323         for (epvector::const_iterator i=epv.begin(); i!=epv.end(); ++i) {
324                 if(newepv) {
325                         newepv->push_back(i->conjugate());
326                         continue;
327                 }
328                 expair x = i->conjugate();
329                 if (x.is_equal(*i)) {
330                         continue;
331                 }
332                 newepv = new epvector;
333                 newepv->reserve(epv.size());
334                 for (epvector::const_iterator j=epv.begin(); j!=i; ++j) {
335                         newepv->push_back(*j);
336                 }
337                 newepv->push_back(x);
338         }
339         return newepv;
340 }
341
342 ex expairseq::conjugate() const
343 {
344         epvector* newepv = conjugateepvector(seq);
345         ex x = overall_coeff.conjugate();
346         if (!newepv && are_ex_trivially_equal(x, overall_coeff)) {
347                 return *this;
348         }
349         ex result = thisexpairseq(newepv ? *newepv : seq, x);
350         if (newepv) {
351                 delete newepv;
352         }
353         return result;
354 }
355
356 bool expairseq::match(const ex & pattern, lst & repl_lst) const
357 {
358         // This differs from basic::match() because we want "a+b+c+d" to
359         // match "d+*+b" with "*" being "a+c", and we want to honor commutativity
360
361         if (this->tinfo() == ex_to<basic>(pattern).tinfo()) {
362
363                 // Check whether global wildcard (one that matches the "rest of the
364                 // expression", like "*" above) is present
365                 bool has_global_wildcard = false;
366                 ex global_wildcard;
367                 for (size_t i=0; i<pattern.nops(); i++) {
368                         if (is_exactly_a<wildcard>(pattern.op(i))) {
369                                 has_global_wildcard = true;
370                                 global_wildcard = pattern.op(i);
371                                 break;
372                         }
373                 }
374
375                 // Unfortunately, this is an O(N^2) operation because we can't
376                 // sort the pattern in a useful way...
377
378                 // Chop into terms
379                 exvector ops;
380                 ops.reserve(nops());
381                 for (size_t i=0; i<nops(); i++)
382                         ops.push_back(op(i));
383
384                 // Now, for every term of the pattern, look for a matching term in
385                 // the expression and remove the match
386                 for (size_t i=0; i<pattern.nops(); i++) {
387                         ex p = pattern.op(i);
388                         if (has_global_wildcard && p.is_equal(global_wildcard))
389                                 continue;
390                         exvector::iterator it = ops.begin(), itend = ops.end();
391                         while (it != itend) {
392                                 lst::const_iterator last_el = repl_lst.end();
393                                 --last_el;
394                                 if (it->match(p, repl_lst)) {
395                                         ops.erase(it);
396                                         goto found;
397                                 }
398                                 while(true) {
399                                         lst::const_iterator next_el = last_el;
400                                         ++next_el;
401                                         if(next_el == repl_lst.end())
402                                                 break;
403                                         else
404                                                 repl_lst.remove_last();
405                                 }
406                                 ++it;
407                         }
408                         return false; // no match found
409 found:          ;
410                 }
411
412                 if (has_global_wildcard) {
413
414                         // Assign all the remaining terms to the global wildcard (unless
415                         // it has already been matched before, in which case the matches
416                         // must be equal)
417                         size_t num = ops.size();
418                         std::auto_ptr<epvector> vp(new epvector);
419                         vp->reserve(num);
420                         for (size_t i=0; i<num; i++)
421                                 vp->push_back(split_ex_to_pair(ops[i]));
422                         ex rest = thisexpairseq(vp, default_overall_coeff());
423                         for (lst::const_iterator it = repl_lst.begin(); it != repl_lst.end(); ++it) {
424                                 if (it->op(0).is_equal(global_wildcard))
425                                         return rest.is_equal(it->op(1));
426                         }
427                         repl_lst.append(global_wildcard == rest);
428                         return true;
429
430                 } else {
431
432                         // No global wildcard, then the match fails if there are any
433                         // unmatched terms left
434                         return ops.empty();
435                 }
436         }
437         return inherited::match(pattern, repl_lst);
438 }
439
440 ex expairseq::subs(const exmap & m, unsigned options) const
441 {
442         std::auto_ptr<epvector> vp = subschildren(m, options);
443         if (vp.get())
444                 return ex_to<basic>(thisexpairseq(vp, overall_coeff));
445         else if ((options & subs_options::algebraic) && is_exactly_a<mul>(*this))
446                 return static_cast<const mul *>(this)->algebraic_subs_mul(m, options);
447         else
448                 return subs_one_level(m, options);
449 }
450
451 // protected
452
453 int expairseq::compare_same_type(const basic &other) const
454 {
455         GINAC_ASSERT(is_a<expairseq>(other));
456         const expairseq &o = static_cast<const expairseq &>(other);
457         
458         int cmpval;
459         
460         // compare number of elements
461         if (seq.size() != o.seq.size())
462                 return (seq.size()<o.seq.size()) ? -1 : 1;
463         
464         // compare overall_coeff
465         cmpval = overall_coeff.compare(o.overall_coeff);
466         if (cmpval!=0)
467                 return cmpval;
468         
469 #if EXPAIRSEQ_USE_HASHTAB
470         GINAC_ASSERT(hashtabsize==o.hashtabsize);
471         if (hashtabsize==0) {
472 #endif // EXPAIRSEQ_USE_HASHTAB
473                 epvector::const_iterator cit1 = seq.begin();
474                 epvector::const_iterator cit2 = o.seq.begin();
475                 epvector::const_iterator last1 = seq.end();
476                 epvector::const_iterator last2 = o.seq.end();
477                 
478                 for (; (cit1!=last1)&&(cit2!=last2); ++cit1, ++cit2) {
479                         cmpval = (*cit1).compare(*cit2);
480                         if (cmpval!=0) return cmpval;
481                 }
482                 
483                 GINAC_ASSERT(cit1==last1);
484                 GINAC_ASSERT(cit2==last2);
485                 
486                 return 0;
487 #if EXPAIRSEQ_USE_HASHTAB
488         }
489         
490         // compare number of elements in each hashtab entry
491         for (unsigned i=0; i<hashtabsize; ++i) {
492                 unsigned cursize=hashtab[i].size();
493                 if (cursize != o.hashtab[i].size())
494                         return (cursize < o.hashtab[i].size()) ? -1 : 1;
495         }
496         
497         // compare individual (sorted) hashtab entries
498         for (unsigned i=0; i<hashtabsize; ++i) {
499                 unsigned sz = hashtab[i].size();
500                 if (sz>0) {
501                         const epplist &eppl1 = hashtab[i];
502                         const epplist &eppl2 = o.hashtab[i];
503                         epplist::const_iterator it1 = eppl1.begin();
504                         epplist::const_iterator it2 = eppl2.begin();
505                         while (it1!=eppl1.end()) {
506                                 cmpval = (*(*it1)).compare(*(*it2));
507                                 if (cmpval!=0)
508                                         return cmpval;
509                                 ++it1;
510                                 ++it2;
511                         }
512                 }
513         }
514         
515         return 0; // equal
516 #endif // EXPAIRSEQ_USE_HASHTAB
517 }
518
519 bool expairseq::is_equal_same_type(const basic &other) const
520 {
521         const expairseq &o = static_cast<const expairseq &>(other);
522         
523         // compare number of elements
524         if (seq.size()!=o.seq.size())
525                 return false;
526         
527         // compare overall_coeff
528         if (!overall_coeff.is_equal(o.overall_coeff))
529                 return false;
530         
531 #if EXPAIRSEQ_USE_HASHTAB
532         // compare number of elements in each hashtab entry
533         if (hashtabsize!=o.hashtabsize) {
534                 std::cout << "this:" << std::endl;
535                 print(print_tree(std::cout));
536                 std::cout << "other:" << std::endl;
537                 other.print(print_tree(std::cout));
538         }
539                 
540         GINAC_ASSERT(hashtabsize==o.hashtabsize);
541         
542         if (hashtabsize==0) {
543 #endif // EXPAIRSEQ_USE_HASHTAB
544                 epvector::const_iterator cit1 = seq.begin();
545                 epvector::const_iterator cit2 = o.seq.begin();
546                 epvector::const_iterator last1 = seq.end();
547                 
548                 while (cit1!=last1) {
549                         if (!(*cit1).is_equal(*cit2)) return false;
550                         ++cit1;
551                         ++cit2;
552                 }
553                 
554                 return true;
555 #if EXPAIRSEQ_USE_HASHTAB
556         }
557         
558         for (unsigned i=0; i<hashtabsize; ++i) {
559                 if (hashtab[i].size() != o.hashtab[i].size())
560                         return false;
561         }
562
563         // compare individual sorted hashtab entries
564         for (unsigned i=0; i<hashtabsize; ++i) {
565                 unsigned sz = hashtab[i].size();
566                 if (sz>0) {
567                         const epplist &eppl1 = hashtab[i];
568                         const epplist &eppl2 = o.hashtab[i];
569                         epplist::const_iterator it1 = eppl1.begin();
570                         epplist::const_iterator it2 = eppl2.begin();
571                         while (it1!=eppl1.end()) {
572                                 if (!(*(*it1)).is_equal(*(*it2))) return false;
573                                 ++it1;
574                                 ++it2;
575                         }
576                 }
577         }
578         
579         return true;
580 #endif // EXPAIRSEQ_USE_HASHTAB
581 }
582
583 unsigned expairseq::return_type() const
584 {
585         return return_types::noncommutative_composite;
586 }
587
588 unsigned expairseq::calchash() const
589 {
590         unsigned v = golden_ratio_hash(this->tinfo());
591         epvector::const_iterator i = seq.begin();
592         const epvector::const_iterator end = seq.end();
593         while (i != end) {
594                 v ^= i->rest.gethash();
595 #if !EXPAIRSEQ_USE_HASHTAB
596                 // rotation spoils commutativity!
597                 v = rotate_left(v);
598                 v ^= i->coeff.gethash();
599 #endif // !EXPAIRSEQ_USE_HASHTAB
600                 ++i;
601         }
602
603         v ^= overall_coeff.gethash();
604
605         // store calculated hash value only if object is already evaluated
606         if (flags &status_flags::evaluated) {
607                 setflag(status_flags::hash_calculated);
608                 hashvalue = v;
609         }
610         
611         return v;
612 }
613
614 ex expairseq::expand(unsigned options) const
615 {
616         std::auto_ptr<epvector> vp = expandchildren(options);
617         if (vp.get())
618                 return thisexpairseq(vp, overall_coeff);
619         else {
620                 // The terms have not changed, so it is safe to declare this expanded
621                 return (options == 0) ? setflag(status_flags::expanded) : *this;
622         }
623 }
624
625 //////////
626 // new virtual functions which can be overridden by derived classes
627 //////////
628
629 // protected
630
631 /** Create an object of this type.
632  *  This method works similar to a constructor.  It is useful because expairseq
633  *  has (at least) two possible different semantics but we want to inherit
634  *  methods thus avoiding code duplication.  Sometimes a method in expairseq
635  *  has to create a new one of the same semantics, which cannot be done by a
636  *  ctor because the name (add, mul,...) is unknown on the expaiseq level.  In
637  *  order for this trick to work a derived class must of course override this
638  *  definition. */
639 ex expairseq::thisexpairseq(const epvector &v, const ex &oc) const
640 {
641         return expairseq(v, oc);
642 }
643
644 ex expairseq::thisexpairseq(std::auto_ptr<epvector> vp, const ex &oc) const
645 {
646         return expairseq(vp, oc);
647 }
648
649 void expairseq::printpair(const print_context & c, const expair & p, unsigned upper_precedence) const
650 {
651         c.s << "[[";
652         p.rest.print(c, precedence());
653         c.s << ",";
654         p.coeff.print(c, precedence());
655         c.s << "]]";
656 }
657
658 void expairseq::printseq(const print_context & c, char delim,
659                          unsigned this_precedence,
660                          unsigned upper_precedence) const
661 {
662         if (this_precedence <= upper_precedence)
663                 c.s << "(";
664         epvector::const_iterator it, it_last = seq.end() - 1;
665         for (it=seq.begin(); it!=it_last; ++it) {
666                 printpair(c, *it, this_precedence);
667                 c.s << delim;
668         }
669         printpair(c, *it, this_precedence);
670         if (!overall_coeff.is_equal(default_overall_coeff())) {
671                 c.s << delim;
672                 overall_coeff.print(c, this_precedence);
673         }
674         
675         if (this_precedence <= upper_precedence)
676                 c.s << ")";
677 }
678
679
680 /** Form an expair from an ex, using the corresponding semantics.
681  *  @see expairseq::recombine_pair_to_ex() */
682 expair expairseq::split_ex_to_pair(const ex &e) const
683 {
684         return expair(e,_ex1);
685 }
686
687
688 expair expairseq::combine_ex_with_coeff_to_pair(const ex &e,
689                                                 const ex &c) const
690 {
691         GINAC_ASSERT(is_exactly_a<numeric>(c));
692         
693         return expair(e,c);
694 }
695
696
697 expair expairseq::combine_pair_with_coeff_to_pair(const expair &p,
698                                                   const ex &c) const
699 {
700         GINAC_ASSERT(is_exactly_a<numeric>(p.coeff));
701         GINAC_ASSERT(is_exactly_a<numeric>(c));
702         
703         return expair(p.rest,ex_to<numeric>(p.coeff).mul_dyn(ex_to<numeric>(c)));
704 }
705
706
707 /** Form an ex out of an expair, using the corresponding semantics.
708  *  @see expairseq::split_ex_to_pair() */
709 ex expairseq::recombine_pair_to_ex(const expair &p) const
710 {
711         return lst(p.rest,p.coeff);
712 }
713
714 bool expairseq::expair_needs_further_processing(epp it)
715 {
716 #if EXPAIRSEQ_USE_HASHTAB
717         //#  error "FIXME: expair_needs_further_processing not yet implemented for hashtabs, sorry. A.F."
718 #endif // EXPAIRSEQ_USE_HASHTAB
719         return false;
720 }
721
722 ex expairseq::default_overall_coeff() const
723 {
724         return _ex0;
725 }
726
727 void expairseq::combine_overall_coeff(const ex &c)
728 {
729         GINAC_ASSERT(is_exactly_a<numeric>(overall_coeff));
730         GINAC_ASSERT(is_exactly_a<numeric>(c));
731         overall_coeff = ex_to<numeric>(overall_coeff).add_dyn(ex_to<numeric>(c));
732 }
733
734 void expairseq::combine_overall_coeff(const ex &c1, const ex &c2)
735 {
736         GINAC_ASSERT(is_exactly_a<numeric>(overall_coeff));
737         GINAC_ASSERT(is_exactly_a<numeric>(c1));
738         GINAC_ASSERT(is_exactly_a<numeric>(c2));
739         overall_coeff = ex_to<numeric>(overall_coeff).
740                         add_dyn(ex_to<numeric>(c1).mul(ex_to<numeric>(c2)));
741 }
742
743 bool expairseq::can_make_flat(const expair &p) const
744 {
745         return true;
746 }
747
748
749 //////////
750 // non-virtual functions in this class
751 //////////
752
753 void expairseq::construct_from_2_ex_via_exvector(const ex &lh, const ex &rh)
754 {
755         exvector v;
756         v.reserve(2);
757         v.push_back(lh);
758         v.push_back(rh);
759         construct_from_exvector(v);
760 #if EXPAIRSEQ_USE_HASHTAB
761         GINAC_ASSERT((hashtabsize==0)||(hashtabsize>=minhashtabsize));
762         GINAC_ASSERT(hashtabsize==calc_hashtabsize(seq.size()));
763 #endif // EXPAIRSEQ_USE_HASHTAB
764 }
765
766 void expairseq::construct_from_2_ex(const ex &lh, const ex &rh)
767 {
768         if (ex_to<basic>(lh).tinfo()==this->tinfo()) {
769                 if (ex_to<basic>(rh).tinfo()==this->tinfo()) {
770 #if EXPAIRSEQ_USE_HASHTAB
771                         unsigned totalsize = ex_to<expairseq>(lh).seq.size() +
772                                              ex_to<expairseq>(rh).seq.size();
773                         if (calc_hashtabsize(totalsize)!=0) {
774                                 construct_from_2_ex_via_exvector(lh,rh);
775                         } else {
776 #endif // EXPAIRSEQ_USE_HASHTAB
777                                 construct_from_2_expairseq(ex_to<expairseq>(lh),
778                                                            ex_to<expairseq>(rh));
779 #if EXPAIRSEQ_USE_HASHTAB
780                         }
781 #endif // EXPAIRSEQ_USE_HASHTAB
782                         return;
783                 } else {
784 #if EXPAIRSEQ_USE_HASHTAB
785                         unsigned totalsize = ex_to<expairseq>(lh).seq.size()+1;
786                         if (calc_hashtabsize(totalsize)!=0) {
787                                 construct_from_2_ex_via_exvector(lh, rh);
788                         } else {
789 #endif // EXPAIRSEQ_USE_HASHTAB
790                                 construct_from_expairseq_ex(ex_to<expairseq>(lh), rh);
791 #if EXPAIRSEQ_USE_HASHTAB
792                         }
793 #endif // EXPAIRSEQ_USE_HASHTAB
794                         return;
795                 }
796         } else if (ex_to<basic>(rh).tinfo()==this->tinfo()) {
797 #if EXPAIRSEQ_USE_HASHTAB
798                 unsigned totalsize=ex_to<expairseq>(rh).seq.size()+1;
799                 if (calc_hashtabsize(totalsize)!=0) {
800                         construct_from_2_ex_via_exvector(lh,rh);
801                 } else {
802 #endif // EXPAIRSEQ_USE_HASHTAB
803                         construct_from_expairseq_ex(ex_to<expairseq>(rh),lh);
804 #if EXPAIRSEQ_USE_HASHTAB
805                 }
806 #endif // EXPAIRSEQ_USE_HASHTAB
807                 return;
808         }
809         
810 #if EXPAIRSEQ_USE_HASHTAB
811         if (calc_hashtabsize(2)!=0) {
812                 construct_from_2_ex_via_exvector(lh,rh);
813                 return;
814         }
815         hashtabsize = 0;
816 #endif // EXPAIRSEQ_USE_HASHTAB
817         
818         if (is_exactly_a<numeric>(lh)) {
819                 if (is_exactly_a<numeric>(rh)) {
820                         combine_overall_coeff(lh);
821                         combine_overall_coeff(rh);
822                 } else {
823                         combine_overall_coeff(lh);
824                         seq.push_back(split_ex_to_pair(rh));
825                 }
826         } else {
827                 if (is_exactly_a<numeric>(rh)) {
828                         combine_overall_coeff(rh);
829                         seq.push_back(split_ex_to_pair(lh));
830                 } else {
831                         expair p1 = split_ex_to_pair(lh);
832                         expair p2 = split_ex_to_pair(rh);
833                         
834                         int cmpval = p1.rest.compare(p2.rest);
835                         if (cmpval==0) {
836                                 p1.coeff = ex_to<numeric>(p1.coeff).add_dyn(ex_to<numeric>(p2.coeff));
837                                 if (!ex_to<numeric>(p1.coeff).is_zero()) {
838                                         // no further processing is necessary, since this
839                                         // one element will usually be recombined in eval()
840                                         seq.push_back(p1);
841                                 }
842                         } else {
843                                 seq.reserve(2);
844                                 if (cmpval<0) {
845                                         seq.push_back(p1);
846                                         seq.push_back(p2);
847                                 } else {
848                                         seq.push_back(p2);
849                                         seq.push_back(p1);
850                                 }
851                         }
852                 }
853         }
854 }
855
856 void expairseq::construct_from_2_expairseq(const expairseq &s1,
857                                                                                    const expairseq &s2)
858 {
859         combine_overall_coeff(s1.overall_coeff);
860         combine_overall_coeff(s2.overall_coeff);
861
862         epvector::const_iterator first1 = s1.seq.begin();
863         epvector::const_iterator last1 = s1.seq.end();
864         epvector::const_iterator first2 = s2.seq.begin();
865         epvector::const_iterator last2 = s2.seq.end();
866
867         seq.reserve(s1.seq.size()+s2.seq.size());
868
869         bool needs_further_processing=false;
870         
871         while (first1!=last1 && first2!=last2) {
872                 int cmpval = (*first1).rest.compare((*first2).rest);
873                 if (cmpval==0) {
874                         // combine terms
875                         const numeric &newcoeff = ex_to<numeric>(first1->coeff).
876                                                    add(ex_to<numeric>(first2->coeff));
877                         if (!newcoeff.is_zero()) {
878                                 seq.push_back(expair(first1->rest,newcoeff));
879                                 if (expair_needs_further_processing(seq.end()-1)) {
880                                         needs_further_processing = true;
881                                 }
882                         }
883                         ++first1;
884                         ++first2;
885                 } else if (cmpval<0) {
886                         seq.push_back(*first1);
887                         ++first1;
888                 } else {
889                         seq.push_back(*first2);
890                         ++first2;
891                 }
892         }
893         
894         while (first1!=last1) {
895                 seq.push_back(*first1);
896                 ++first1;
897         }
898         while (first2!=last2) {
899                 seq.push_back(*first2);
900                 ++first2;
901         }
902         
903         if (needs_further_processing) {
904                 epvector v = seq;
905                 seq.clear();
906                 construct_from_epvector(v);
907         }
908 }
909
910 void expairseq::construct_from_expairseq_ex(const expairseq &s,
911                                                                                         const ex &e)
912 {
913         combine_overall_coeff(s.overall_coeff);
914         if (is_exactly_a<numeric>(e)) {
915                 combine_overall_coeff(e);
916                 seq = s.seq;
917                 return;
918         }
919         
920         epvector::const_iterator first = s.seq.begin();
921         epvector::const_iterator last = s.seq.end();
922         expair p = split_ex_to_pair(e);
923         
924         seq.reserve(s.seq.size()+1);
925         bool p_pushed = false;
926         
927         bool needs_further_processing=false;
928         
929         // merge p into s.seq
930         while (first!=last) {
931                 int cmpval = (*first).rest.compare(p.rest);
932                 if (cmpval==0) {
933                         // combine terms
934                         const numeric &newcoeff = ex_to<numeric>(first->coeff).
935                                                    add(ex_to<numeric>(p.coeff));
936                         if (!newcoeff.is_zero()) {
937                                 seq.push_back(expair(first->rest,newcoeff));
938                                 if (expair_needs_further_processing(seq.end()-1))
939                                         needs_further_processing = true;
940                         }
941                         ++first;
942                         p_pushed = true;
943                         break;
944                 } else if (cmpval<0) {
945                         seq.push_back(*first);
946                         ++first;
947                 } else {
948                         seq.push_back(p);
949                         p_pushed = true;
950                         break;
951                 }
952         }
953         
954         if (p_pushed) {
955                 // while loop exited because p was pushed, now push rest of s.seq
956                 while (first!=last) {
957                         seq.push_back(*first);
958                         ++first;
959                 }
960         } else {
961                 // while loop exited because s.seq was pushed, now push p
962                 seq.push_back(p);
963         }
964
965         if (needs_further_processing) {
966                 epvector v = seq;
967                 seq.clear();
968                 construct_from_epvector(v);
969         }
970 }
971
972 void expairseq::construct_from_exvector(const exvector &v)
973 {
974         // simplifications: +(a,+(b,c),d) -> +(a,b,c,d) (associativity)
975         //                  +(d,b,c,a) -> +(a,b,c,d) (canonicalization)
976         //                  +(...,x,*(x,c1),*(x,c2)) -> +(...,*(x,1+c1+c2)) (c1, c2 numeric())
977         //                  (same for (+,*) -> (*,^)
978
979         make_flat(v);
980 #if EXPAIRSEQ_USE_HASHTAB
981         combine_same_terms();
982 #else
983         canonicalize();
984         combine_same_terms_sorted_seq();
985 #endif // EXPAIRSEQ_USE_HASHTAB
986 }
987
988 void expairseq::construct_from_epvector(const epvector &v)
989 {
990         // simplifications: +(a,+(b,c),d) -> +(a,b,c,d) (associativity)
991         //                  +(d,b,c,a) -> +(a,b,c,d) (canonicalization)
992         //                  +(...,x,*(x,c1),*(x,c2)) -> +(...,*(x,1+c1+c2)) (c1, c2 numeric())
993         //                  (same for (+,*) -> (*,^)
994
995         make_flat(v);
996 #if EXPAIRSEQ_USE_HASHTAB
997         combine_same_terms();
998 #else
999         canonicalize();
1000         combine_same_terms_sorted_seq();
1001 #endif // EXPAIRSEQ_USE_HASHTAB
1002 }
1003
1004 /** Combine this expairseq with argument exvector.
1005  *  It cares for associativity as well as for special handling of numerics. */
1006 void expairseq::make_flat(const exvector &v)
1007 {
1008         exvector::const_iterator cit;
1009         
1010         // count number of operands which are of same expairseq derived type
1011         // and their cumulative number of operands
1012         int nexpairseqs = 0;
1013         int noperands = 0;
1014         
1015         cit = v.begin();
1016         while (cit!=v.end()) {
1017                 if (ex_to<basic>(*cit).tinfo()==this->tinfo()) {
1018                         ++nexpairseqs;
1019                         noperands += ex_to<expairseq>(*cit).seq.size();
1020                 }
1021                 ++cit;
1022         }
1023         
1024         // reserve seq and coeffseq which will hold all operands
1025         seq.reserve(v.size()+noperands-nexpairseqs);
1026         
1027         // copy elements and split off numerical part
1028         cit = v.begin();
1029         while (cit!=v.end()) {
1030                 if (ex_to<basic>(*cit).tinfo()==this->tinfo()) {
1031                         const expairseq &subseqref = ex_to<expairseq>(*cit);
1032                         combine_overall_coeff(subseqref.overall_coeff);
1033                         epvector::const_iterator cit_s = subseqref.seq.begin();
1034                         while (cit_s!=subseqref.seq.end()) {
1035                                 seq.push_back(*cit_s);
1036                                 ++cit_s;
1037                         }
1038                 } else {
1039                         if (is_exactly_a<numeric>(*cit))
1040                                 combine_overall_coeff(*cit);
1041                         else
1042                                 seq.push_back(split_ex_to_pair(*cit));
1043                 }
1044                 ++cit;
1045         }
1046 }
1047
1048 /** Combine this expairseq with argument epvector.
1049  *  It cares for associativity as well as for special handling of numerics. */
1050 void expairseq::make_flat(const epvector &v)
1051 {
1052         epvector::const_iterator cit;
1053         
1054         // count number of operands which are of same expairseq derived type
1055         // and their cumulative number of operands
1056         int nexpairseqs = 0;
1057         int noperands = 0;
1058         
1059         cit = v.begin();
1060         while (cit!=v.end()) {
1061                 if (ex_to<basic>(cit->rest).tinfo()==this->tinfo()) {
1062                         ++nexpairseqs;
1063                         noperands += ex_to<expairseq>(cit->rest).seq.size();
1064                 }
1065                 ++cit;
1066         }
1067         
1068         // reserve seq and coeffseq which will hold all operands
1069         seq.reserve(v.size()+noperands-nexpairseqs);
1070         
1071         // copy elements and split off numerical part
1072         cit = v.begin();
1073         while (cit!=v.end()) {
1074                 if (ex_to<basic>(cit->rest).tinfo()==this->tinfo() &&
1075                     this->can_make_flat(*cit)) {
1076                         const expairseq &subseqref = ex_to<expairseq>(cit->rest);
1077                         combine_overall_coeff(ex_to<numeric>(subseqref.overall_coeff),
1078                                                             ex_to<numeric>(cit->coeff));
1079                         epvector::const_iterator cit_s = subseqref.seq.begin();
1080                         while (cit_s!=subseqref.seq.end()) {
1081                                 seq.push_back(expair(cit_s->rest,
1082                                                      ex_to<numeric>(cit_s->coeff).mul_dyn(ex_to<numeric>(cit->coeff))));
1083                                 //seq.push_back(combine_pair_with_coeff_to_pair(*cit_s,
1084                                 //                                              (*cit).coeff));
1085                                 ++cit_s;
1086                         }
1087                 } else {
1088                         if (cit->is_canonical_numeric())
1089                                 combine_overall_coeff(cit->rest);
1090                         else
1091                                 seq.push_back(*cit);
1092                 }
1093                 ++cit;
1094         }
1095 }
1096
1097 /** Brings this expairseq into a sorted (canonical) form. */
1098 void expairseq::canonicalize()
1099 {
1100         std::sort(seq.begin(), seq.end(), expair_rest_is_less());
1101 }
1102
1103
1104 /** Compact a presorted expairseq by combining all matching expairs to one
1105  *  each.  On an add object, this is responsible for 2*x+3*x+y -> 5*x+y, for
1106  *  instance. */
1107 void expairseq::combine_same_terms_sorted_seq()
1108 {
1109         if (seq.size()<2)
1110                 return;
1111
1112         bool needs_further_processing = false;
1113
1114         epvector::iterator itin1 = seq.begin();
1115         epvector::iterator itin2 = itin1+1;
1116         epvector::iterator itout = itin1;
1117         epvector::iterator last = seq.end();
1118         // must_copy will be set to true the first time some combination is 
1119         // possible from then on the sequence has changed and must be compacted
1120         bool must_copy = false;
1121         while (itin2!=last) {
1122                 if (itin1->rest.compare(itin2->rest)==0) {
1123                         itin1->coeff = ex_to<numeric>(itin1->coeff).
1124                                        add_dyn(ex_to<numeric>(itin2->coeff));
1125                         if (expair_needs_further_processing(itin1))
1126                                 needs_further_processing = true;
1127                         must_copy = true;
1128                 } else {
1129                         if (!ex_to<numeric>(itin1->coeff).is_zero()) {
1130                                 if (must_copy)
1131                                         *itout = *itin1;
1132                                 ++itout;
1133                         }
1134                         itin1 = itin2;
1135                 }
1136                 ++itin2;
1137         }
1138         if (!ex_to<numeric>(itin1->coeff).is_zero()) {
1139                 if (must_copy)
1140                         *itout = *itin1;
1141                 ++itout;
1142         }
1143         if (itout!=last)
1144                 seq.erase(itout,last);
1145
1146         if (needs_further_processing) {
1147                 epvector v = seq;
1148                 seq.clear();
1149                 construct_from_epvector(v);
1150         }
1151 }
1152
1153 #if EXPAIRSEQ_USE_HASHTAB
1154
1155 unsigned expairseq::calc_hashtabsize(unsigned sz) const
1156 {
1157         unsigned size;
1158         unsigned nearest_power_of_2 = 1 << log2(sz);
1159         // if (nearest_power_of_2 < maxhashtabsize/hashtabfactor) {
1160         //  size = nearest_power_of_2*hashtabfactor;
1161         size = nearest_power_of_2/hashtabfactor;
1162         if (size<minhashtabsize)
1163                 return 0;
1164
1165         // hashtabsize must be a power of 2
1166         GINAC_ASSERT((1U << log2(size))==size);
1167         return size;
1168 }
1169
1170 unsigned expairseq::calc_hashindex(const ex &e) const
1171 {
1172         // calculate hashindex
1173         unsigned hashindex;
1174         if (is_a<numeric>(e)) {
1175                 hashindex = hashmask;
1176         } else {
1177                 hashindex = e.gethash() & hashmask;
1178                 // last hashtab entry is reserved for numerics
1179                 if (hashindex==hashmask) hashindex = 0;
1180         }
1181         GINAC_ASSERT((hashindex<hashtabsize)||(hashtabsize==0));
1182         return hashindex;
1183 }
1184
1185 void expairseq::shrink_hashtab()
1186 {
1187         unsigned new_hashtabsize;
1188         while (hashtabsize!=(new_hashtabsize=calc_hashtabsize(seq.size()))) {
1189                 GINAC_ASSERT(new_hashtabsize<hashtabsize);
1190                 if (new_hashtabsize==0) {
1191                         hashtab.clear();
1192                         hashtabsize = 0;
1193                         canonicalize();
1194                         return;
1195                 }
1196                 
1197                 // shrink by a factor of 2
1198                 unsigned half_hashtabsize = hashtabsize/2;
1199                 for (unsigned i=0; i<half_hashtabsize-1; ++i)
1200                         hashtab[i].merge(hashtab[i+half_hashtabsize],epp_is_less());
1201                 // special treatment for numeric hashes
1202                 hashtab[0].merge(hashtab[half_hashtabsize-1],epp_is_less());
1203                 hashtab[half_hashtabsize-1] = hashtab[hashtabsize-1];
1204                 hashtab.resize(half_hashtabsize);
1205                 hashtabsize = half_hashtabsize;
1206                 hashmask = hashtabsize-1;
1207         }
1208 }
1209
1210 void expairseq::remove_hashtab_entry(epvector::const_iterator element)
1211 {
1212         if (hashtabsize==0)
1213                 return; // nothing to do
1214         
1215         // calculate hashindex of element to be deleted
1216         unsigned hashindex = calc_hashindex((*element).rest);
1217
1218         // find it in hashtab and remove it
1219         epplist &eppl = hashtab[hashindex];
1220         epplist::iterator epplit = eppl.begin();
1221         bool erased = false;
1222         while (epplit!=eppl.end()) {
1223                 if (*epplit == element) {
1224                         eppl.erase(epplit);
1225                         erased = true;
1226                         break;
1227                 }
1228                 ++epplit;
1229         }
1230         if (!erased) {
1231                 std::cout << "tried to erase " << element-seq.begin() << std::endl;
1232                 std::cout << "size " << seq.end()-seq.begin() << std::endl;
1233
1234                 unsigned hashindex = calc_hashindex(element->rest);
1235                 epplist &eppl = hashtab[hashindex];
1236                 epplist::iterator epplit = eppl.begin();
1237                 bool erased = false;
1238                 while (epplit!=eppl.end()) {
1239                         if (*epplit == element) {
1240                                 eppl.erase(epplit);
1241                                 erased = true;
1242                                 break;
1243                         }
1244                         ++epplit;
1245                 }
1246                 GINAC_ASSERT(erased);
1247         }
1248         GINAC_ASSERT(erased);
1249 }
1250
1251 void expairseq::move_hashtab_entry(epvector::const_iterator oldpos,
1252                                    epvector::iterator newpos)
1253 {
1254         GINAC_ASSERT(hashtabsize!=0);
1255         
1256         // calculate hashindex of element which was moved
1257         unsigned hashindex=calc_hashindex((*newpos).rest);
1258
1259         // find it in hashtab and modify it
1260         epplist &eppl = hashtab[hashindex];
1261         epplist::iterator epplit = eppl.begin();
1262         while (epplit!=eppl.end()) {
1263                 if (*epplit == oldpos) {
1264                         *epplit = newpos;
1265                         break;
1266                 }
1267                 ++epplit;
1268         }
1269         GINAC_ASSERT(epplit!=eppl.end());
1270 }
1271
1272 void expairseq::sorted_insert(epplist &eppl, epvector::const_iterator elem)
1273 {
1274         epplist::const_iterator current = eppl.begin();
1275         while ((current!=eppl.end()) && ((*current)->is_less(*elem))) {
1276                 ++current;
1277         }
1278         eppl.insert(current,elem);
1279 }    
1280
1281 void expairseq::build_hashtab_and_combine(epvector::iterator &first_numeric,
1282                                           epvector::iterator &last_non_zero,
1283                                           std::vector<bool> &touched,
1284                                           unsigned &number_of_zeroes)
1285 {
1286         epp current = seq.begin();
1287
1288         while (current!=first_numeric) {
1289                 if (is_exactly_a<numeric>(current->rest)) {
1290                         --first_numeric;
1291                         iter_swap(current,first_numeric);
1292                 } else {
1293                         // calculate hashindex
1294                         unsigned currenthashindex = calc_hashindex(current->rest);
1295
1296                         // test if there is already a matching expair in the hashtab-list
1297                         epplist &eppl=hashtab[currenthashindex];
1298                         epplist::iterator epplit = eppl.begin();
1299                         while (epplit!=eppl.end()) {
1300                                 if (current->rest.is_equal((*epplit)->rest))
1301                                         break;
1302                                 ++epplit;
1303                         }
1304                         if (epplit==eppl.end()) {
1305                                 // no matching expair found, append this to end of list
1306                                 sorted_insert(eppl,current);
1307                                 ++current;
1308                         } else {
1309                                 // epplit points to a matching expair, combine it with current
1310                                 (*epplit)->coeff = ex_to<numeric>((*epplit)->coeff).
1311                                                    add_dyn(ex_to<numeric>(current->coeff));
1312                                 
1313                                 // move obsolete current expair to end by swapping with last_non_zero element
1314                                 // if this was a numeric, it is swapped with the expair before first_numeric 
1315                                 iter_swap(current,last_non_zero);
1316                                 --first_numeric;
1317                                 if (first_numeric!=last_non_zero) iter_swap(first_numeric,current);
1318                                 --last_non_zero;
1319                                 ++number_of_zeroes;
1320                                 // test if combined term has coeff 0 and can be removed is done later
1321                                 touched[(*epplit)-seq.begin()] = true;
1322                         }
1323                 }
1324         }
1325 }
1326
1327 void expairseq::drop_coeff_0_terms(epvector::iterator &first_numeric,
1328                                    epvector::iterator &last_non_zero,
1329                                    std::vector<bool> &touched,
1330                                    unsigned &number_of_zeroes)
1331 {
1332         // move terms with coeff 0 to end and remove them from hashtab
1333         // check only those elements which have been touched
1334         epp current = seq.begin();
1335         size_t i = 0;
1336         while (current!=first_numeric) {
1337                 if (!touched[i]) {
1338                         ++current;
1339                         ++i;
1340                 } else if (!ex_to<numeric>((*current).coeff).is_zero()) {
1341                         ++current;
1342                         ++i;
1343                 } else {
1344                         remove_hashtab_entry(current);
1345                         
1346                         // move element to the end, unless it is already at the end
1347                         if (current!=last_non_zero) {
1348                                 iter_swap(current,last_non_zero);
1349                                 --first_numeric;
1350                                 bool numeric_swapped = first_numeric!=last_non_zero;
1351                                 if (numeric_swapped)
1352                                         iter_swap(first_numeric,current);
1353                                 epvector::iterator changed_entry;
1354
1355                                 if (numeric_swapped)
1356                                         changed_entry = first_numeric;
1357                                 else
1358                                         changed_entry = last_non_zero;
1359                                 
1360                                 --last_non_zero;
1361                                 ++number_of_zeroes;
1362
1363                                 if (first_numeric!=current) {
1364
1365                                         // change entry in hashtab which referred to first_numeric or last_non_zero to current
1366                                         move_hashtab_entry(changed_entry,current);
1367                                         touched[current-seq.begin()] = touched[changed_entry-seq.begin()];
1368                                 }
1369                         } else {
1370                                 --first_numeric;
1371                                 --last_non_zero;
1372                                 ++number_of_zeroes;
1373                         }
1374                 }
1375         }
1376         GINAC_ASSERT(i==current-seq.begin());
1377 }
1378
1379 /** True if one of the coeffs vanishes, otherwise false.
1380  *  This would be an invariant violation, so this should only be used for
1381  *  debugging purposes. */
1382 bool expairseq::has_coeff_0() const
1383 {
1384         epvector::const_iterator i = seq.begin(), end = seq.end();
1385         while (i != end) {
1386                 if (i->coeff.is_zero())
1387                         return true;
1388                 ++i;
1389         }
1390         return false;
1391 }
1392
1393 void expairseq::add_numerics_to_hashtab(epvector::iterator first_numeric,
1394                                                                                 epvector::const_iterator last_non_zero)
1395 {
1396         if (first_numeric == seq.end()) return; // no numerics
1397         
1398         epvector::const_iterator current = first_numeric, last = last_non_zero + 1;
1399         while (current != last) {
1400                 sorted_insert(hashtab[hashmask], current);
1401                 ++current;
1402         }
1403 }
1404
1405 void expairseq::combine_same_terms()
1406 {
1407         // combine same terms, drop term with coeff 0, move numerics to end
1408         
1409         // calculate size of hashtab
1410         hashtabsize = calc_hashtabsize(seq.size());
1411         
1412         // hashtabsize is a power of 2
1413         hashmask = hashtabsize-1;
1414         
1415         // allocate hashtab
1416         hashtab.clear();
1417         hashtab.resize(hashtabsize);
1418         
1419         if (hashtabsize==0) {
1420                 canonicalize();
1421                 combine_same_terms_sorted_seq();
1422                 GINAC_ASSERT(!has_coeff_0());
1423                 return;
1424         }
1425         
1426         // iterate through seq, move numerics to end,
1427         // fill hashtab and combine same terms
1428         epvector::iterator first_numeric = seq.end();
1429         epvector::iterator last_non_zero = seq.end()-1;
1430         
1431         size_t num = seq.size();
1432         std::vector<bool> touched(num);
1433         
1434         unsigned number_of_zeroes = 0;
1435         
1436         GINAC_ASSERT(!has_coeff_0());
1437         build_hashtab_and_combine(first_numeric,last_non_zero,touched,number_of_zeroes);
1438         
1439         // there should not be any terms with coeff 0 from the beginning,
1440         // so it should be safe to skip this step
1441         if (number_of_zeroes!=0) {
1442                 drop_coeff_0_terms(first_numeric,last_non_zero,touched,number_of_zeroes);
1443         }
1444         
1445         add_numerics_to_hashtab(first_numeric,last_non_zero);
1446         
1447         // pop zero elements
1448         for (unsigned i=0; i<number_of_zeroes; ++i) {
1449                 seq.pop_back();
1450         }
1451         
1452         // shrink hashtabsize to calculated value
1453         GINAC_ASSERT(!has_coeff_0());
1454         
1455         shrink_hashtab();
1456         
1457         GINAC_ASSERT(!has_coeff_0());
1458 }
1459
1460 #endif // EXPAIRSEQ_USE_HASHTAB
1461
1462 /** Check if this expairseq is in sorted (canonical) form.  Useful mainly for
1463  *  debugging or in assertions since being sorted is an invariance. */
1464 bool expairseq::is_canonical() const
1465 {
1466         if (seq.size() <= 1)
1467                 return 1;
1468         
1469 #if EXPAIRSEQ_USE_HASHTAB
1470         if (hashtabsize > 0) return 1; // not canoncalized
1471 #endif // EXPAIRSEQ_USE_HASHTAB
1472         
1473         epvector::const_iterator it = seq.begin(), itend = seq.end();
1474         epvector::const_iterator it_last = it;
1475         for (++it; it!=itend; it_last=it, ++it) {
1476                 if (!(it_last->is_less(*it) || it_last->is_equal(*it))) {
1477                         if (!is_exactly_a<numeric>(it_last->rest) ||
1478                                 !is_exactly_a<numeric>(it->rest)) {
1479                                 // double test makes it easier to set a breakpoint...
1480                                 if (!is_exactly_a<numeric>(it_last->rest) ||
1481                                         !is_exactly_a<numeric>(it->rest)) {
1482                                         printpair(std::clog, *it_last, 0);
1483                                         std::clog << ">";
1484                                         printpair(std::clog, *it, 0);
1485                                         std::clog << "\n";
1486                                         std::clog << "pair1:" << std::endl;
1487                                         it_last->rest.print(print_tree(std::clog));
1488                                         it_last->coeff.print(print_tree(std::clog));
1489                                         std::clog << "pair2:" << std::endl;
1490                                         it->rest.print(print_tree(std::clog));
1491                                         it->coeff.print(print_tree(std::clog));
1492                                         return 0;
1493                                 }
1494                         }
1495                 }
1496         }
1497         return 1;
1498 }
1499
1500
1501 /** Member-wise expand the expairs in this sequence.
1502  *
1503  *  @see expairseq::expand()
1504  *  @return pointer to epvector containing expanded pairs or zero pointer,
1505  *  if no members were changed. */
1506 std::auto_ptr<epvector> expairseq::expandchildren(unsigned options) const
1507 {
1508         const epvector::const_iterator last = seq.end();
1509         epvector::const_iterator cit = seq.begin();
1510         while (cit!=last) {
1511                 const ex &expanded_ex = cit->rest.expand(options);
1512                 if (!are_ex_trivially_equal(cit->rest,expanded_ex)) {
1513                         
1514                         // something changed, copy seq, eval and return it
1515                         std::auto_ptr<epvector> s(new epvector);
1516                         s->reserve(seq.size());
1517                         
1518                         // copy parts of seq which are known not to have changed
1519                         epvector::const_iterator cit2 = seq.begin();
1520                         while (cit2!=cit) {
1521                                 s->push_back(*cit2);
1522                                 ++cit2;
1523                         }
1524
1525                         // copy first changed element
1526                         s->push_back(combine_ex_with_coeff_to_pair(expanded_ex,
1527                                                                    cit2->coeff));
1528                         ++cit2;
1529
1530                         // copy rest
1531                         while (cit2!=last) {
1532                                 s->push_back(combine_ex_with_coeff_to_pair(cit2->rest.expand(options),
1533                                                                            cit2->coeff));
1534                                 ++cit2;
1535                         }
1536                         return s;
1537                 }
1538                 ++cit;
1539         }
1540         
1541         return std::auto_ptr<epvector>(0); // signalling nothing has changed
1542 }
1543
1544
1545 /** Member-wise evaluate the expairs in this sequence.
1546  *
1547  *  @see expairseq::eval()
1548  *  @return pointer to epvector containing evaluated pairs or zero pointer,
1549  *  if no members were changed. */
1550 std::auto_ptr<epvector> expairseq::evalchildren(int level) const
1551 {
1552         // returns a NULL pointer if nothing had to be evaluated
1553         // returns a pointer to a newly created epvector otherwise
1554         // (which has to be deleted somewhere else)
1555
1556         if (level==1)
1557                 return std::auto_ptr<epvector>(0);
1558         
1559         if (level == -max_recursion_level)
1560                 throw(std::runtime_error("max recursion level reached"));
1561         
1562         --level;
1563         epvector::const_iterator last = seq.end();
1564         epvector::const_iterator cit = seq.begin();
1565         while (cit!=last) {
1566                 const ex &evaled_ex = cit->rest.eval(level);
1567                 if (!are_ex_trivially_equal(cit->rest,evaled_ex)) {
1568                         
1569                         // something changed, copy seq, eval and return it
1570                         std::auto_ptr<epvector> s(new epvector);
1571                         s->reserve(seq.size());
1572                         
1573                         // copy parts of seq which are known not to have changed
1574                         epvector::const_iterator cit2=seq.begin();
1575                         while (cit2!=cit) {
1576                                 s->push_back(*cit2);
1577                                 ++cit2;
1578                         }
1579
1580                         // copy first changed element
1581                         s->push_back(combine_ex_with_coeff_to_pair(evaled_ex,
1582                                                                    cit2->coeff));
1583                         ++cit2;
1584
1585                         // copy rest
1586                         while (cit2!=last) {
1587                                 s->push_back(combine_ex_with_coeff_to_pair(cit2->rest.eval(level),
1588                                                                            cit2->coeff));
1589                                 ++cit2;
1590                         }
1591                         return s;
1592                 }
1593                 ++cit;
1594         }
1595         
1596         return std::auto_ptr<epvector>(0); // signalling nothing has changed
1597 }
1598
1599
1600 /** Member-wise substitute in this sequence.
1601  *
1602  *  @see expairseq::subs()
1603  *  @return pointer to epvector containing pairs after application of subs,
1604  *    or NULL pointer if no members were changed. */
1605 std::auto_ptr<epvector> expairseq::subschildren(const exmap & m, unsigned options) const
1606 {
1607         // When any of the objects to be substituted is a product or power
1608         // we have to recombine the pairs because the numeric coefficients may
1609         // be part of the search pattern.
1610         if (!(options & (subs_options::pattern_is_product | subs_options::pattern_is_not_product))) {
1611
1612                 // Search the list of substitutions and cache our findings
1613                 for (exmap::const_iterator it = m.begin(); it != m.end(); ++it) {
1614                         if (is_exactly_a<mul>(it->first) || is_exactly_a<power>(it->first)) {
1615                                 options |= subs_options::pattern_is_product;
1616                                 break;
1617                         }
1618                 }
1619                 if (!(options & subs_options::pattern_is_product))
1620                         options |= subs_options::pattern_is_not_product;
1621         }
1622
1623         if (options & subs_options::pattern_is_product) {
1624
1625                 // Substitute in the recombined pairs
1626                 epvector::const_iterator cit = seq.begin(), last = seq.end();
1627                 while (cit != last) {
1628
1629                         const ex &orig_ex = recombine_pair_to_ex(*cit);
1630                         const ex &subsed_ex = orig_ex.subs(m, options);
1631                         if (!are_ex_trivially_equal(orig_ex, subsed_ex)) {
1632
1633                                 // Something changed, copy seq, subs and return it
1634                                 std::auto_ptr<epvector> s(new epvector);
1635                                 s->reserve(seq.size());
1636
1637                                 // Copy parts of seq which are known not to have changed
1638                                 s->insert(s->begin(), seq.begin(), cit);
1639
1640                                 // Copy first changed element
1641                                 s->push_back(split_ex_to_pair(subsed_ex));
1642                                 ++cit;
1643
1644                                 // Copy rest
1645                                 while (cit != last) {
1646                                         s->push_back(split_ex_to_pair(recombine_pair_to_ex(*cit).subs(m, options)));
1647                                         ++cit;
1648                                 }
1649                                 return s;
1650                         }
1651
1652                         ++cit;
1653                 }
1654
1655         } else {
1656
1657                 // Substitute only in the "rest" part of the pairs
1658                 epvector::const_iterator cit = seq.begin(), last = seq.end();
1659                 while (cit != last) {
1660
1661                         const ex &subsed_ex = cit->rest.subs(m, options);
1662                         if (!are_ex_trivially_equal(cit->rest, subsed_ex)) {
1663                         
1664                                 // Something changed, copy seq, subs and return it
1665                                 std::auto_ptr<epvector> s(new epvector);
1666                                 s->reserve(seq.size());
1667
1668                                 // Copy parts of seq which are known not to have changed
1669                                 s->insert(s->begin(), seq.begin(), cit);
1670                         
1671                                 // Copy first changed element
1672                                 s->push_back(combine_ex_with_coeff_to_pair(subsed_ex, cit->coeff));
1673                                 ++cit;
1674
1675                                 // Copy rest
1676                                 while (cit != last) {
1677                                         s->push_back(combine_ex_with_coeff_to_pair(cit->rest.subs(m, options),
1678                                                                                    cit->coeff));
1679                                         ++cit;
1680                                 }
1681                                 return s;
1682                         }
1683
1684                         ++cit;
1685                 }
1686         }
1687         
1688         // Nothing has changed
1689         return std::auto_ptr<epvector>(0);
1690 }
1691
1692 //////////
1693 // static member variables
1694 //////////
1695
1696 #if EXPAIRSEQ_USE_HASHTAB
1697 unsigned expairseq::maxhashtabsize = 0x4000000U;
1698 unsigned expairseq::minhashtabsize = 0x1000U;
1699 unsigned expairseq::hashtabfactor = 1;
1700 #endif // EXPAIRSEQ_USE_HASHTAB
1701
1702 } // namespace GiNaC