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