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