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