Univariate Hensel lifting now uses upoly.
[ginac.git] / ginac / expairseq.cpp
1 /** @file expairseq.cpp
2  *
3  *  Implementation of sequences of expression pairs. */
4
5 /*
6  *  GiNaC Copyright (C) 1999-2008 Johannes Gutenberg University Mainz, Germany
7  *
8  *  This program is free software; you can redistribute it and/or modify
9  *  it under the terms of the GNU General Public License as published by
10  *  the Free Software Foundation; either version 2 of the License, or
11  *  (at your option) any later version.
12  *
13  *  This program is distributed in the hope that it will be useful,
14  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
15  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  *  GNU General Public License for more details.
17  *
18  *  You should have received a copy of the GNU General Public License
19  *  along with this program; if not, write to the Free Software
20  *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
21  */
22
23 #include <iostream>
24 #include <algorithm>
25 #include <string>
26 #include <stdexcept>
27 #include <iterator>
28
29 #include "expairseq.h"
30 #include "lst.h"
31 #include "add.h"
32 #include "mul.h"
33 #include "power.h"
34 #include "relational.h"
35 #include "wildcard.h"
36 #include "archive.h"
37 #include "operators.h"
38 #include "utils.h"
39 #include "indexed.h"
40
41 #if EXPAIRSEQ_USE_HASHTAB
42 #include <cmath>
43 #endif // EXPAIRSEQ_USE_HASHTAB
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         const void* this_tinfo = (const void*)typeid(*this).name();
616         unsigned v = golden_ratio_hash((p_int)this_tinfo);
617         epvector::const_iterator i = seq.begin();
618         const epvector::const_iterator end = seq.end();
619         while (i != end) {
620                 v ^= i->rest.gethash();
621 #if !EXPAIRSEQ_USE_HASHTAB
622                 // rotation spoils commutativity!
623                 v = rotate_left(v);
624                 v ^= i->coeff.gethash();
625 #endif // !EXPAIRSEQ_USE_HASHTAB
626                 ++i;
627         }
628
629         v ^= overall_coeff.gethash();
630
631         // store calculated hash value only if object is already evaluated
632         if (flags &status_flags::evaluated) {
633                 setflag(status_flags::hash_calculated);
634                 hashvalue = v;
635         }
636         
637         return v;
638 }
639
640 ex expairseq::expand(unsigned options) const
641 {
642         std::auto_ptr<epvector> vp = expandchildren(options);
643         if (vp.get())
644                 return thisexpairseq(vp, overall_coeff);
645         else {
646                 // The terms have not changed, so it is safe to declare this expanded
647                 return (options == 0) ? setflag(status_flags::expanded) : *this;
648         }
649 }
650
651 //////////
652 // new virtual functions which can be overridden by derived classes
653 //////////
654
655 // protected
656
657 /** Create an object of this type.
658  *  This method works similar to a constructor.  It is useful because expairseq
659  *  has (at least) two possible different semantics but we want to inherit
660  *  methods thus avoiding code duplication.  Sometimes a method in expairseq
661  *  has to create a new one of the same semantics, which cannot be done by a
662  *  ctor because the name (add, mul,...) is unknown on the expaiseq level.  In
663  *  order for this trick to work a derived class must of course override this
664  *  definition. */
665 ex expairseq::thisexpairseq(const epvector &v, const ex &oc, bool do_index_renaming) const
666 {
667         return expairseq(v, oc, do_index_renaming);
668 }
669
670 ex expairseq::thisexpairseq(std::auto_ptr<epvector> vp, const ex &oc, bool do_index_renaming) const
671 {
672         return expairseq(vp, oc, do_index_renaming);
673 }
674
675 void expairseq::printpair(const print_context & c, const expair & p, unsigned upper_precedence) const
676 {
677         c.s << "[[";
678         p.rest.print(c, precedence());
679         c.s << ",";
680         p.coeff.print(c, precedence());
681         c.s << "]]";
682 }
683
684 void expairseq::printseq(const print_context & c, char delim,
685                          unsigned this_precedence,
686                          unsigned upper_precedence) const
687 {
688         if (this_precedence <= upper_precedence)
689                 c.s << "(";
690         epvector::const_iterator it, it_last = seq.end() - 1;
691         for (it=seq.begin(); it!=it_last; ++it) {
692                 printpair(c, *it, this_precedence);
693                 c.s << delim;
694         }
695         printpair(c, *it, this_precedence);
696         if (!overall_coeff.is_equal(default_overall_coeff())) {
697                 c.s << delim;
698                 overall_coeff.print(c, this_precedence);
699         }
700         
701         if (this_precedence <= upper_precedence)
702                 c.s << ")";
703 }
704
705
706 /** Form an expair from an ex, using the corresponding semantics.
707  *  @see expairseq::recombine_pair_to_ex() */
708 expair expairseq::split_ex_to_pair(const ex &e) const
709 {
710         return expair(e,_ex1);
711 }
712
713
714 expair expairseq::combine_ex_with_coeff_to_pair(const ex &e,
715                                                 const ex &c) const
716 {
717         GINAC_ASSERT(is_exactly_a<numeric>(c));
718         
719         return expair(e,c);
720 }
721
722
723 expair expairseq::combine_pair_with_coeff_to_pair(const expair &p,
724                                                   const ex &c) const
725 {
726         GINAC_ASSERT(is_exactly_a<numeric>(p.coeff));
727         GINAC_ASSERT(is_exactly_a<numeric>(c));
728         
729         return expair(p.rest,ex_to<numeric>(p.coeff).mul_dyn(ex_to<numeric>(c)));
730 }
731
732
733 /** Form an ex out of an expair, using the corresponding semantics.
734  *  @see expairseq::split_ex_to_pair() */
735 ex expairseq::recombine_pair_to_ex(const expair &p) const
736 {
737         return lst(p.rest,p.coeff);
738 }
739
740 bool expairseq::expair_needs_further_processing(epp it)
741 {
742 #if EXPAIRSEQ_USE_HASHTAB
743         //#  error "FIXME: expair_needs_further_processing not yet implemented for hashtabs, sorry. A.F."
744 #endif // EXPAIRSEQ_USE_HASHTAB
745         return false;
746 }
747
748 ex expairseq::default_overall_coeff() const
749 {
750         return _ex0;
751 }
752
753 void expairseq::combine_overall_coeff(const ex &c)
754 {
755         GINAC_ASSERT(is_exactly_a<numeric>(overall_coeff));
756         GINAC_ASSERT(is_exactly_a<numeric>(c));
757         overall_coeff = ex_to<numeric>(overall_coeff).add_dyn(ex_to<numeric>(c));
758 }
759
760 void expairseq::combine_overall_coeff(const ex &c1, const ex &c2)
761 {
762         GINAC_ASSERT(is_exactly_a<numeric>(overall_coeff));
763         GINAC_ASSERT(is_exactly_a<numeric>(c1));
764         GINAC_ASSERT(is_exactly_a<numeric>(c2));
765         overall_coeff = ex_to<numeric>(overall_coeff).
766                         add_dyn(ex_to<numeric>(c1).mul(ex_to<numeric>(c2)));
767 }
768
769 bool expairseq::can_make_flat(const expair &p) const
770 {
771         return true;
772 }
773
774
775 //////////
776 // non-virtual functions in this class
777 //////////
778
779 void expairseq::construct_from_2_ex_via_exvector(const ex &lh, const ex &rh)
780 {
781         exvector v;
782         v.reserve(2);
783         v.push_back(lh);
784         v.push_back(rh);
785         construct_from_exvector(v);
786 #if EXPAIRSEQ_USE_HASHTAB
787         GINAC_ASSERT((hashtabsize==0)||(hashtabsize>=minhashtabsize));
788         GINAC_ASSERT(hashtabsize==calc_hashtabsize(seq.size()));
789 #endif // EXPAIRSEQ_USE_HASHTAB
790 }
791
792 void expairseq::construct_from_2_ex(const ex &lh, const ex &rh)
793 {
794         if (typeid(ex_to<basic>(lh)) == typeid(*this)) {
795                 if (typeid(ex_to<basic>(rh)) == typeid(*this)) {
796 #if EXPAIRSEQ_USE_HASHTAB
797                         unsigned totalsize = ex_to<expairseq>(lh).seq.size() +
798                                              ex_to<expairseq>(rh).seq.size();
799                         if (calc_hashtabsize(totalsize)!=0) {
800                                 construct_from_2_ex_via_exvector(lh,rh);
801                         } else {
802 #endif // EXPAIRSEQ_USE_HASHTAB
803                                 if (is_a<mul>(lh) && lh.info(info_flags::has_indices) && 
804                                         rh.info(info_flags::has_indices)) {
805                                         ex newrh=rename_dummy_indices_uniquely(lh, rh);
806                                         construct_from_2_expairseq(ex_to<expairseq>(lh),
807                                                                    ex_to<expairseq>(newrh));
808                                 }
809                                 else
810                                         construct_from_2_expairseq(ex_to<expairseq>(lh),
811                                                                    ex_to<expairseq>(rh));
812 #if EXPAIRSEQ_USE_HASHTAB
813                         }
814 #endif // EXPAIRSEQ_USE_HASHTAB
815                         return;
816                 } else {
817 #if EXPAIRSEQ_USE_HASHTAB
818                         unsigned totalsize = ex_to<expairseq>(lh).seq.size()+1;
819                         if (calc_hashtabsize(totalsize)!=0) {
820                                 construct_from_2_ex_via_exvector(lh, rh);
821                         } else {
822 #endif // EXPAIRSEQ_USE_HASHTAB
823                                 construct_from_expairseq_ex(ex_to<expairseq>(lh), rh);
824 #if EXPAIRSEQ_USE_HASHTAB
825                         }
826 #endif // EXPAIRSEQ_USE_HASHTAB
827                         return;
828                 }
829         } else if (typeid(ex_to<basic>(rh)) == typeid(*this)) {
830 #if EXPAIRSEQ_USE_HASHTAB
831                 unsigned totalsize=ex_to<expairseq>(rh).seq.size()+1;
832                 if (calc_hashtabsize(totalsize)!=0) {
833                         construct_from_2_ex_via_exvector(lh,rh);
834                 } else {
835 #endif // EXPAIRSEQ_USE_HASHTAB
836                         construct_from_expairseq_ex(ex_to<expairseq>(rh),lh);
837 #if EXPAIRSEQ_USE_HASHTAB
838                 }
839 #endif // EXPAIRSEQ_USE_HASHTAB
840                 return;
841         }
842         
843 #if EXPAIRSEQ_USE_HASHTAB
844         if (calc_hashtabsize(2)!=0) {
845                 construct_from_2_ex_via_exvector(lh,rh);
846                 return;
847         }
848         hashtabsize = 0;
849 #endif // EXPAIRSEQ_USE_HASHTAB
850         
851         if (is_exactly_a<numeric>(lh)) {
852                 if (is_exactly_a<numeric>(rh)) {
853                         combine_overall_coeff(lh);
854                         combine_overall_coeff(rh);
855                 } else {
856                         combine_overall_coeff(lh);
857                         seq.push_back(split_ex_to_pair(rh));
858                 }
859         } else {
860                 if (is_exactly_a<numeric>(rh)) {
861                         combine_overall_coeff(rh);
862                         seq.push_back(split_ex_to_pair(lh));
863                 } else {
864                         expair p1 = split_ex_to_pair(lh);
865                         expair p2 = split_ex_to_pair(rh);
866                         
867                         int cmpval = p1.rest.compare(p2.rest);
868                         if (cmpval==0) {
869                                 p1.coeff = ex_to<numeric>(p1.coeff).add_dyn(ex_to<numeric>(p2.coeff));
870                                 if (!ex_to<numeric>(p1.coeff).is_zero()) {
871                                         // no further processing is necessary, since this
872                                         // one element will usually be recombined in eval()
873                                         seq.push_back(p1);
874                                 }
875                         } else {
876                                 seq.reserve(2);
877                                 if (cmpval<0) {
878                                         seq.push_back(p1);
879                                         seq.push_back(p2);
880                                 } else {
881                                         seq.push_back(p2);
882                                         seq.push_back(p1);
883                                 }
884                         }
885                 }
886         }
887 }
888
889 void expairseq::construct_from_2_expairseq(const expairseq &s1,
890                                                                                    const expairseq &s2)
891 {
892         combine_overall_coeff(s1.overall_coeff);
893         combine_overall_coeff(s2.overall_coeff);
894
895         epvector::const_iterator first1 = s1.seq.begin();
896         epvector::const_iterator last1 = s1.seq.end();
897         epvector::const_iterator first2 = s2.seq.begin();
898         epvector::const_iterator last2 = s2.seq.end();
899
900         seq.reserve(s1.seq.size()+s2.seq.size());
901
902         bool needs_further_processing=false;
903         
904         while (first1!=last1 && first2!=last2) {
905                 int cmpval = (*first1).rest.compare((*first2).rest);
906
907                 if (cmpval==0) {
908                         // combine terms
909                         const numeric &newcoeff = ex_to<numeric>(first1->coeff).
910                                                    add(ex_to<numeric>(first2->coeff));
911                         if (!newcoeff.is_zero()) {
912                                 seq.push_back(expair(first1->rest,newcoeff));
913                                 if (expair_needs_further_processing(seq.end()-1)) {
914                                         needs_further_processing = true;
915                                 }
916                         }
917                         ++first1;
918                         ++first2;
919                 } else if (cmpval<0) {
920                         seq.push_back(*first1);
921                         ++first1;
922                 } else {
923                         seq.push_back(*first2);
924                         ++first2;
925                 }
926         }
927         
928         while (first1!=last1) {
929                 seq.push_back(*first1);
930                 ++first1;
931         }
932         while (first2!=last2) {
933                 seq.push_back(*first2);
934                 ++first2;
935         }
936         
937         if (needs_further_processing) {
938                 epvector v = seq;
939                 seq.clear();
940                 construct_from_epvector(v);
941         }
942 }
943
944 void expairseq::construct_from_expairseq_ex(const expairseq &s,
945                                                                                         const ex &e)
946 {
947         combine_overall_coeff(s.overall_coeff);
948         if (is_exactly_a<numeric>(e)) {
949                 combine_overall_coeff(e);
950                 seq = s.seq;
951                 return;
952         }
953         
954         epvector::const_iterator first = s.seq.begin();
955         epvector::const_iterator last = s.seq.end();
956         expair p = split_ex_to_pair(e);
957         
958         seq.reserve(s.seq.size()+1);
959         bool p_pushed = false;
960         
961         bool needs_further_processing=false;
962         
963         // merge p into s.seq
964         while (first!=last) {
965                 int cmpval = (*first).rest.compare(p.rest);
966                 if (cmpval==0) {
967                         // combine terms
968                         const numeric &newcoeff = ex_to<numeric>(first->coeff).
969                                                    add(ex_to<numeric>(p.coeff));
970                         if (!newcoeff.is_zero()) {
971                                 seq.push_back(expair(first->rest,newcoeff));
972                                 if (expair_needs_further_processing(seq.end()-1))
973                                         needs_further_processing = true;
974                         }
975                         ++first;
976                         p_pushed = true;
977                         break;
978                 } else if (cmpval<0) {
979                         seq.push_back(*first);
980                         ++first;
981                 } else {
982                         seq.push_back(p);
983                         p_pushed = true;
984                         break;
985                 }
986         }
987         
988         if (p_pushed) {
989                 // while loop exited because p was pushed, now push rest of s.seq
990                 while (first!=last) {
991                         seq.push_back(*first);
992                         ++first;
993                 }
994         } else {
995                 // while loop exited because s.seq was pushed, now push p
996                 seq.push_back(p);
997         }
998
999         if (needs_further_processing) {
1000                 epvector v = seq;
1001                 seq.clear();
1002                 construct_from_epvector(v);
1003         }
1004 }
1005
1006 void expairseq::construct_from_exvector(const exvector &v)
1007 {
1008         // simplifications: +(a,+(b,c),d) -> +(a,b,c,d) (associativity)
1009         //                  +(d,b,c,a) -> +(a,b,c,d) (canonicalization)
1010         //                  +(...,x,*(x,c1),*(x,c2)) -> +(...,*(x,1+c1+c2)) (c1, c2 numeric())
1011         //                  (same for (+,*) -> (*,^)
1012
1013         make_flat(v);
1014 #if EXPAIRSEQ_USE_HASHTAB
1015         combine_same_terms();
1016 #else
1017         canonicalize();
1018         combine_same_terms_sorted_seq();
1019 #endif // EXPAIRSEQ_USE_HASHTAB
1020 }
1021
1022 void expairseq::construct_from_epvector(const epvector &v, bool do_index_renaming)
1023 {
1024         // simplifications: +(a,+(b,c),d) -> +(a,b,c,d) (associativity)
1025         //                  +(d,b,c,a) -> +(a,b,c,d) (canonicalization)
1026         //                  +(...,x,*(x,c1),*(x,c2)) -> +(...,*(x,1+c1+c2)) (c1, c2 numeric())
1027         //                  (same for (+,*) -> (*,^)
1028
1029         make_flat(v, do_index_renaming);
1030 #if EXPAIRSEQ_USE_HASHTAB
1031         combine_same_terms();
1032 #else
1033         canonicalize();
1034         combine_same_terms_sorted_seq();
1035 #endif // EXPAIRSEQ_USE_HASHTAB
1036 }
1037
1038 /** Combine this expairseq with argument exvector.
1039  *  It cares for associativity as well as for special handling of numerics. */
1040 void expairseq::make_flat(const exvector &v)
1041 {
1042         exvector::const_iterator cit;
1043         
1044         // count number of operands which are of same expairseq derived type
1045         // and their cumulative number of operands
1046         int nexpairseqs = 0;
1047         int noperands = 0;
1048         bool do_idx_rename = false;
1049         
1050         cit = v.begin();
1051         while (cit!=v.end()) {
1052                 if (typeid(ex_to<basic>(*cit)) == typeid(*this)) {
1053                         ++nexpairseqs;
1054                         noperands += ex_to<expairseq>(*cit).seq.size();
1055                 }
1056                 if (is_a<mul>(*this) && (!do_idx_rename) &&
1057                                 cit->info(info_flags::has_indices))
1058                         do_idx_rename = true;
1059                 ++cit;
1060         }
1061         
1062         // reserve seq and coeffseq which will hold all operands
1063         seq.reserve(v.size()+noperands-nexpairseqs);
1064         
1065         // copy elements and split off numerical part
1066         make_flat_inserter mf(v, do_idx_rename);
1067         cit = v.begin();
1068         while (cit!=v.end()) {
1069                 if (typeid(ex_to<basic>(*cit)) == typeid(*this)) {
1070                         ex newfactor = mf.handle_factor(*cit, _ex1);
1071                         const expairseq &subseqref = ex_to<expairseq>(newfactor);
1072                         combine_overall_coeff(subseqref.overall_coeff);
1073                         epvector::const_iterator cit_s = subseqref.seq.begin();
1074                         while (cit_s!=subseqref.seq.end()) {
1075                                 seq.push_back(*cit_s);
1076                                 ++cit_s;
1077                         }
1078                 } else {
1079                         if (is_exactly_a<numeric>(*cit))
1080                                 combine_overall_coeff(*cit);
1081                         else {
1082                                 ex newfactor = mf.handle_factor(*cit, _ex1);
1083                                 seq.push_back(split_ex_to_pair(newfactor));
1084                         }
1085                 }
1086                 ++cit;
1087         }
1088 }
1089
1090 /** Combine this expairseq with argument epvector.
1091  *  It cares for associativity as well as for special handling of numerics. */
1092 void expairseq::make_flat(const epvector &v, bool do_index_renaming)
1093 {
1094         epvector::const_iterator cit;
1095         
1096         // count number of operands which are of same expairseq derived type
1097         // and their cumulative number of operands
1098         int nexpairseqs = 0;
1099         int noperands = 0;
1100         bool really_need_rename_inds = false;
1101         
1102         cit = v.begin();
1103         while (cit!=v.end()) {
1104                 if (typeid(ex_to<basic>(cit->rest)) == typeid(*this)) {
1105                         ++nexpairseqs;
1106                         noperands += ex_to<expairseq>(cit->rest).seq.size();
1107                 }
1108                 if ((!really_need_rename_inds) && is_a<mul>(*this) &&
1109                                 cit->rest.info(info_flags::has_indices))
1110                         really_need_rename_inds = true;
1111                 ++cit;
1112         }
1113         do_index_renaming = do_index_renaming && really_need_rename_inds;
1114         
1115         // reserve seq and coeffseq which will hold all operands
1116         seq.reserve(v.size()+noperands-nexpairseqs);
1117         make_flat_inserter mf(v, do_index_renaming);
1118         
1119         // copy elements and split off numerical part
1120         cit = v.begin();
1121         while (cit!=v.end()) {
1122                 if ((typeid(ex_to<basic>(cit->rest)) == typeid(*this)) &&
1123                     this->can_make_flat(*cit)) {
1124                         ex newrest = mf.handle_factor(cit->rest, cit->coeff);
1125                         const expairseq &subseqref = ex_to<expairseq>(newrest);
1126                         combine_overall_coeff(ex_to<numeric>(subseqref.overall_coeff),
1127                                                             ex_to<numeric>(cit->coeff));
1128                         epvector::const_iterator cit_s = subseqref.seq.begin();
1129                         while (cit_s!=subseqref.seq.end()) {
1130                                 seq.push_back(expair(cit_s->rest,
1131                                                      ex_to<numeric>(cit_s->coeff).mul_dyn(ex_to<numeric>(cit->coeff))));
1132                                 //seq.push_back(combine_pair_with_coeff_to_pair(*cit_s,
1133                                 //                                              (*cit).coeff));
1134                                 ++cit_s;
1135                         }
1136                 } else {
1137                         if (cit->is_canonical_numeric())
1138                                 combine_overall_coeff(mf.handle_factor(cit->rest, _ex1));
1139                         else {
1140                                 ex rest = cit->rest;
1141                                 ex newrest = mf.handle_factor(rest, cit->coeff);
1142                                 if (are_ex_trivially_equal(newrest, rest))
1143                                         seq.push_back(*cit);
1144                                 else
1145                                         seq.push_back(expair(newrest, cit->coeff));
1146                         }
1147                 }
1148                 ++cit;
1149         }
1150 }
1151
1152 /** Brings this expairseq into a sorted (canonical) form. */
1153 void expairseq::canonicalize()
1154 {
1155         std::sort(seq.begin(), seq.end(), expair_rest_is_less());
1156 }
1157
1158
1159 /** Compact a presorted expairseq by combining all matching expairs to one
1160  *  each.  On an add object, this is responsible for 2*x+3*x+y -> 5*x+y, for
1161  *  instance. */
1162 void expairseq::combine_same_terms_sorted_seq()
1163 {
1164         if (seq.size()<2)
1165                 return;
1166
1167         bool needs_further_processing = false;
1168
1169         epvector::iterator itin1 = seq.begin();
1170         epvector::iterator itin2 = itin1+1;
1171         epvector::iterator itout = itin1;
1172         epvector::iterator last = seq.end();
1173         // must_copy will be set to true the first time some combination is 
1174         // possible from then on the sequence has changed and must be compacted
1175         bool must_copy = false;
1176         while (itin2!=last) {
1177                 if (itin1->rest.compare(itin2->rest)==0) {
1178                         itin1->coeff = ex_to<numeric>(itin1->coeff).
1179                                        add_dyn(ex_to<numeric>(itin2->coeff));
1180                         if (expair_needs_further_processing(itin1))
1181                                 needs_further_processing = true;
1182                         must_copy = true;
1183                 } else {
1184                         if (!ex_to<numeric>(itin1->coeff).is_zero()) {
1185                                 if (must_copy)
1186                                         *itout = *itin1;
1187                                 ++itout;
1188                         }
1189                         itin1 = itin2;
1190                 }
1191                 ++itin2;
1192         }
1193         if (!ex_to<numeric>(itin1->coeff).is_zero()) {
1194                 if (must_copy)
1195                         *itout = *itin1;
1196                 ++itout;
1197         }
1198         if (itout!=last)
1199                 seq.erase(itout,last);
1200
1201         if (needs_further_processing) {
1202                 epvector v = seq;
1203                 seq.clear();
1204                 construct_from_epvector(v);
1205         }
1206 }
1207
1208 #if EXPAIRSEQ_USE_HASHTAB
1209
1210 unsigned expairseq::calc_hashtabsize(unsigned sz) const
1211 {
1212         unsigned size;
1213         unsigned nearest_power_of_2 = 1 << log2(sz);
1214         // if (nearest_power_of_2 < maxhashtabsize/hashtabfactor) {
1215         //  size = nearest_power_of_2*hashtabfactor;
1216         size = nearest_power_of_2/hashtabfactor;
1217         if (size<minhashtabsize)
1218                 return 0;
1219
1220         // hashtabsize must be a power of 2
1221         GINAC_ASSERT((1U << log2(size))==size);
1222         return size;
1223 }
1224
1225 unsigned expairseq::calc_hashindex(const ex &e) const
1226 {
1227         // calculate hashindex
1228         unsigned hashindex;
1229         if (is_a<numeric>(e)) {
1230                 hashindex = hashmask;
1231         } else {
1232                 hashindex = e.gethash() & hashmask;
1233                 // last hashtab entry is reserved for numerics
1234                 if (hashindex==hashmask) hashindex = 0;
1235         }
1236         GINAC_ASSERT((hashindex<hashtabsize)||(hashtabsize==0));
1237         return hashindex;
1238 }
1239
1240 void expairseq::shrink_hashtab()
1241 {
1242         unsigned new_hashtabsize;
1243         while (hashtabsize!=(new_hashtabsize=calc_hashtabsize(seq.size()))) {
1244                 GINAC_ASSERT(new_hashtabsize<hashtabsize);
1245                 if (new_hashtabsize==0) {
1246                         hashtab.clear();
1247                         hashtabsize = 0;
1248                         canonicalize();
1249                         return;
1250                 }
1251                 
1252                 // shrink by a factor of 2
1253                 unsigned half_hashtabsize = hashtabsize/2;
1254                 for (unsigned i=0; i<half_hashtabsize-1; ++i)
1255                         hashtab[i].merge(hashtab[i+half_hashtabsize],epp_is_less());
1256                 // special treatment for numeric hashes
1257                 hashtab[0].merge(hashtab[half_hashtabsize-1],epp_is_less());
1258                 hashtab[half_hashtabsize-1] = hashtab[hashtabsize-1];
1259                 hashtab.resize(half_hashtabsize);
1260                 hashtabsize = half_hashtabsize;
1261                 hashmask = hashtabsize-1;
1262         }
1263 }
1264
1265 void expairseq::remove_hashtab_entry(epvector::const_iterator element)
1266 {
1267         if (hashtabsize==0)
1268                 return; // nothing to do
1269         
1270         // calculate hashindex of element to be deleted
1271         unsigned hashindex = calc_hashindex((*element).rest);
1272
1273         // find it in hashtab and remove it
1274         epplist &eppl = hashtab[hashindex];
1275         epplist::iterator epplit = eppl.begin();
1276         bool erased = false;
1277         while (epplit!=eppl.end()) {
1278                 if (*epplit == element) {
1279                         eppl.erase(epplit);
1280                         erased = true;
1281                         break;
1282                 }
1283                 ++epplit;
1284         }
1285         if (!erased) {
1286                 std::cout << "tried to erase " << element-seq.begin() << std::endl;
1287                 std::cout << "size " << seq.end()-seq.begin() << std::endl;
1288
1289                 unsigned hashindex = calc_hashindex(element->rest);
1290                 epplist &eppl = hashtab[hashindex];
1291                 epplist::iterator epplit = eppl.begin();
1292                 bool erased = false;
1293                 while (epplit!=eppl.end()) {
1294                         if (*epplit == element) {
1295                                 eppl.erase(epplit);
1296                                 erased = true;
1297                                 break;
1298                         }
1299                         ++epplit;
1300                 }
1301                 GINAC_ASSERT(erased);
1302         }
1303         GINAC_ASSERT(erased);
1304 }
1305
1306 void expairseq::move_hashtab_entry(epvector::const_iterator oldpos,
1307                                    epvector::iterator newpos)
1308 {
1309         GINAC_ASSERT(hashtabsize!=0);
1310         
1311         // calculate hashindex of element which was moved
1312         unsigned hashindex=calc_hashindex((*newpos).rest);
1313
1314         // find it in hashtab and modify it
1315         epplist &eppl = hashtab[hashindex];
1316         epplist::iterator epplit = eppl.begin();
1317         while (epplit!=eppl.end()) {
1318                 if (*epplit == oldpos) {
1319                         *epplit = newpos;
1320                         break;
1321                 }
1322                 ++epplit;
1323         }
1324         GINAC_ASSERT(epplit!=eppl.end());
1325 }
1326
1327 void expairseq::sorted_insert(epplist &eppl, epvector::const_iterator elem)
1328 {
1329         epplist::const_iterator current = eppl.begin();
1330         while ((current!=eppl.end()) && ((*current)->is_less(*elem))) {
1331                 ++current;
1332         }
1333         eppl.insert(current,elem);
1334 }    
1335
1336 void expairseq::build_hashtab_and_combine(epvector::iterator &first_numeric,
1337                                           epvector::iterator &last_non_zero,
1338                                           std::vector<bool> &touched,
1339                                           unsigned &number_of_zeroes)
1340 {
1341         epp current = seq.begin();
1342
1343         while (current!=first_numeric) {
1344                 if (is_exactly_a<numeric>(current->rest)) {
1345                         --first_numeric;
1346                         iter_swap(current,first_numeric);
1347                 } else {
1348                         // calculate hashindex
1349                         unsigned currenthashindex = calc_hashindex(current->rest);
1350
1351                         // test if there is already a matching expair in the hashtab-list
1352                         epplist &eppl=hashtab[currenthashindex];
1353                         epplist::iterator epplit = eppl.begin();
1354                         while (epplit!=eppl.end()) {
1355                                 if (current->rest.is_equal((*epplit)->rest))
1356                                         break;
1357                                 ++epplit;
1358                         }
1359                         if (epplit==eppl.end()) {
1360                                 // no matching expair found, append this to end of list
1361                                 sorted_insert(eppl,current);
1362                                 ++current;
1363                         } else {
1364                                 // epplit points to a matching expair, combine it with current
1365                                 (*epplit)->coeff = ex_to<numeric>((*epplit)->coeff).
1366                                                    add_dyn(ex_to<numeric>(current->coeff));
1367                                 
1368                                 // move obsolete current expair to end by swapping with last_non_zero element
1369                                 // if this was a numeric, it is swapped with the expair before first_numeric 
1370                                 iter_swap(current,last_non_zero);
1371                                 --first_numeric;
1372                                 if (first_numeric!=last_non_zero) iter_swap(first_numeric,current);
1373                                 --last_non_zero;
1374                                 ++number_of_zeroes;
1375                                 // test if combined term has coeff 0 and can be removed is done later
1376                                 touched[(*epplit)-seq.begin()] = true;
1377                         }
1378                 }
1379         }
1380 }
1381
1382 void expairseq::drop_coeff_0_terms(epvector::iterator &first_numeric,
1383                                    epvector::iterator &last_non_zero,
1384                                    std::vector<bool> &touched,
1385                                    unsigned &number_of_zeroes)
1386 {
1387         // move terms with coeff 0 to end and remove them from hashtab
1388         // check only those elements which have been touched
1389         epp current = seq.begin();
1390         size_t i = 0;
1391         while (current!=first_numeric) {
1392                 if (!touched[i]) {
1393                         ++current;
1394                         ++i;
1395                 } else if (!ex_to<numeric>((*current).coeff).is_zero()) {
1396                         ++current;
1397                         ++i;
1398                 } else {
1399                         remove_hashtab_entry(current);
1400                         
1401                         // move element to the end, unless it is already at the end
1402                         if (current!=last_non_zero) {
1403                                 iter_swap(current,last_non_zero);
1404                                 --first_numeric;
1405                                 bool numeric_swapped = first_numeric!=last_non_zero;
1406                                 if (numeric_swapped)
1407                                         iter_swap(first_numeric,current);
1408                                 epvector::iterator changed_entry;
1409
1410                                 if (numeric_swapped)
1411                                         changed_entry = first_numeric;
1412                                 else
1413                                         changed_entry = last_non_zero;
1414                                 
1415                                 --last_non_zero;
1416                                 ++number_of_zeroes;
1417
1418                                 if (first_numeric!=current) {
1419
1420                                         // change entry in hashtab which referred to first_numeric or last_non_zero to current
1421                                         move_hashtab_entry(changed_entry,current);
1422                                         touched[current-seq.begin()] = touched[changed_entry-seq.begin()];
1423                                 }
1424                         } else {
1425                                 --first_numeric;
1426                                 --last_non_zero;
1427                                 ++number_of_zeroes;
1428                         }
1429                 }
1430         }
1431         GINAC_ASSERT(i==current-seq.begin());
1432 }
1433
1434 /** True if one of the coeffs vanishes, otherwise false.
1435  *  This would be an invariant violation, so this should only be used for
1436  *  debugging purposes. */
1437 bool expairseq::has_coeff_0() const
1438 {
1439         epvector::const_iterator i = seq.begin(), end = seq.end();
1440         while (i != end) {
1441                 if (i->coeff.is_zero())
1442                         return true;
1443                 ++i;
1444         }
1445         return false;
1446 }
1447
1448 void expairseq::add_numerics_to_hashtab(epvector::iterator first_numeric,
1449                                                                                 epvector::const_iterator last_non_zero)
1450 {
1451         if (first_numeric == seq.end()) return; // no numerics
1452         
1453         epvector::const_iterator current = first_numeric, last = last_non_zero + 1;
1454         while (current != last) {
1455                 sorted_insert(hashtab[hashmask], current);
1456                 ++current;
1457         }
1458 }
1459
1460 void expairseq::combine_same_terms()
1461 {
1462         // combine same terms, drop term with coeff 0, move numerics to end
1463         
1464         // calculate size of hashtab
1465         hashtabsize = calc_hashtabsize(seq.size());
1466         
1467         // hashtabsize is a power of 2
1468         hashmask = hashtabsize-1;
1469         
1470         // allocate hashtab
1471         hashtab.clear();
1472         hashtab.resize(hashtabsize);
1473         
1474         if (hashtabsize==0) {
1475                 canonicalize();
1476                 combine_same_terms_sorted_seq();
1477                 GINAC_ASSERT(!has_coeff_0());
1478                 return;
1479         }
1480         
1481         // iterate through seq, move numerics to end,
1482         // fill hashtab and combine same terms
1483         epvector::iterator first_numeric = seq.end();
1484         epvector::iterator last_non_zero = seq.end()-1;
1485         
1486         size_t num = seq.size();
1487         std::vector<bool> touched(num);
1488         
1489         unsigned number_of_zeroes = 0;
1490         
1491         GINAC_ASSERT(!has_coeff_0());
1492         build_hashtab_and_combine(first_numeric,last_non_zero,touched,number_of_zeroes);
1493         
1494         // there should not be any terms with coeff 0 from the beginning,
1495         // so it should be safe to skip this step
1496         if (number_of_zeroes!=0) {
1497                 drop_coeff_0_terms(first_numeric,last_non_zero,touched,number_of_zeroes);
1498         }
1499         
1500         add_numerics_to_hashtab(first_numeric,last_non_zero);
1501         
1502         // pop zero elements
1503         for (unsigned i=0; i<number_of_zeroes; ++i) {
1504                 seq.pop_back();
1505         }
1506         
1507         // shrink hashtabsize to calculated value
1508         GINAC_ASSERT(!has_coeff_0());
1509         
1510         shrink_hashtab();
1511         
1512         GINAC_ASSERT(!has_coeff_0());
1513 }
1514
1515 #endif // EXPAIRSEQ_USE_HASHTAB
1516
1517 /** Check if this expairseq is in sorted (canonical) form.  Useful mainly for
1518  *  debugging or in assertions since being sorted is an invariance. */
1519 bool expairseq::is_canonical() const
1520 {
1521         if (seq.size() <= 1)
1522                 return 1;
1523         
1524 #if EXPAIRSEQ_USE_HASHTAB
1525         if (hashtabsize > 0) return 1; // not canoncalized
1526 #endif // EXPAIRSEQ_USE_HASHTAB
1527         
1528         epvector::const_iterator it = seq.begin(), itend = seq.end();
1529         epvector::const_iterator it_last = it;
1530         for (++it; it!=itend; it_last=it, ++it) {
1531                 if (!(it_last->is_less(*it) || it_last->is_equal(*it))) {
1532                         if (!is_exactly_a<numeric>(it_last->rest) ||
1533                                 !is_exactly_a<numeric>(it->rest)) {
1534                                 // double test makes it easier to set a breakpoint...
1535                                 if (!is_exactly_a<numeric>(it_last->rest) ||
1536                                         !is_exactly_a<numeric>(it->rest)) {
1537                                         printpair(std::clog, *it_last, 0);
1538                                         std::clog << ">";
1539                                         printpair(std::clog, *it, 0);
1540                                         std::clog << "\n";
1541                                         std::clog << "pair1:" << std::endl;
1542                                         it_last->rest.print(print_tree(std::clog));
1543                                         it_last->coeff.print(print_tree(std::clog));
1544                                         std::clog << "pair2:" << std::endl;
1545                                         it->rest.print(print_tree(std::clog));
1546                                         it->coeff.print(print_tree(std::clog));
1547                                         return 0;
1548                                 }
1549                         }
1550                 }
1551         }
1552         return 1;
1553 }
1554
1555
1556 /** Member-wise expand the expairs in this sequence.
1557  *
1558  *  @see expairseq::expand()
1559  *  @return pointer to epvector containing expanded pairs or zero pointer,
1560  *  if no members were changed. */
1561 std::auto_ptr<epvector> expairseq::expandchildren(unsigned options) const
1562 {
1563         const epvector::const_iterator last = seq.end();
1564         epvector::const_iterator cit = seq.begin();
1565         while (cit!=last) {
1566                 const ex &expanded_ex = cit->rest.expand(options);
1567                 if (!are_ex_trivially_equal(cit->rest,expanded_ex)) {
1568                         
1569                         // something changed, copy seq, eval and return it
1570                         std::auto_ptr<epvector> s(new epvector);
1571                         s->reserve(seq.size());
1572                         
1573                         // copy parts of seq which are known not to have changed
1574                         epvector::const_iterator cit2 = seq.begin();
1575                         while (cit2!=cit) {
1576                                 s->push_back(*cit2);
1577                                 ++cit2;
1578                         }
1579
1580                         // copy first changed element
1581                         s->push_back(combine_ex_with_coeff_to_pair(expanded_ex,
1582                                                                    cit2->coeff));
1583                         ++cit2;
1584
1585                         // copy rest
1586                         while (cit2!=last) {
1587                                 s->push_back(combine_ex_with_coeff_to_pair(cit2->rest.expand(options),
1588                                                                            cit2->coeff));
1589                                 ++cit2;
1590                         }
1591                         return s;
1592                 }
1593                 ++cit;
1594         }
1595         
1596         return std::auto_ptr<epvector>(0); // signalling nothing has changed
1597 }
1598
1599
1600 /** Member-wise evaluate the expairs in this sequence.
1601  *
1602  *  @see expairseq::eval()
1603  *  @return pointer to epvector containing evaluated pairs or zero pointer,
1604  *  if no members were changed. */
1605 std::auto_ptr<epvector> expairseq::evalchildren(int level) const
1606 {
1607         // returns a NULL pointer if nothing had to be evaluated
1608         // returns a pointer to a newly created epvector otherwise
1609         // (which has to be deleted somewhere else)
1610
1611         if (level==1)
1612                 return std::auto_ptr<epvector>(0);
1613         
1614         if (level == -max_recursion_level)
1615                 throw(std::runtime_error("max recursion level reached"));
1616         
1617         --level;
1618         epvector::const_iterator last = seq.end();
1619         epvector::const_iterator cit = seq.begin();
1620         while (cit!=last) {
1621                 const ex &evaled_ex = cit->rest.eval(level);
1622                 if (!are_ex_trivially_equal(cit->rest,evaled_ex)) {
1623                         
1624                         // something changed, copy seq, eval and return it
1625                         std::auto_ptr<epvector> s(new epvector);
1626                         s->reserve(seq.size());
1627                         
1628                         // copy parts of seq which are known not to have changed
1629                         epvector::const_iterator cit2=seq.begin();
1630                         while (cit2!=cit) {
1631                                 s->push_back(*cit2);
1632                                 ++cit2;
1633                         }
1634
1635                         // copy first changed element
1636                         s->push_back(combine_ex_with_coeff_to_pair(evaled_ex,
1637                                                                    cit2->coeff));
1638                         ++cit2;
1639
1640                         // copy rest
1641                         while (cit2!=last) {
1642                                 s->push_back(combine_ex_with_coeff_to_pair(cit2->rest.eval(level),
1643                                                                            cit2->coeff));
1644                                 ++cit2;
1645                         }
1646                         return s;
1647                 }
1648                 ++cit;
1649         }
1650         
1651         return std::auto_ptr<epvector>(0); // signalling nothing has changed
1652 }
1653
1654 /** Member-wise substitute in this sequence.
1655  *
1656  *  @see expairseq::subs()
1657  *  @return pointer to epvector containing pairs after application of subs,
1658  *    or NULL pointer if no members were changed. */
1659 std::auto_ptr<epvector> expairseq::subschildren(const exmap & m, unsigned options) const
1660 {
1661         // When any of the objects to be substituted is a product or power
1662         // we have to recombine the pairs because the numeric coefficients may
1663         // be part of the search pattern.
1664         if (!(options & (subs_options::pattern_is_product | subs_options::pattern_is_not_product))) {
1665
1666                 // Search the list of substitutions and cache our findings
1667                 for (exmap::const_iterator it = m.begin(); it != m.end(); ++it) {
1668                         if (is_exactly_a<mul>(it->first) || is_exactly_a<power>(it->first)) {
1669                                 options |= subs_options::pattern_is_product;
1670                                 break;
1671                         }
1672                 }
1673                 if (!(options & subs_options::pattern_is_product))
1674                         options |= subs_options::pattern_is_not_product;
1675         }
1676
1677         if (options & subs_options::pattern_is_product) {
1678
1679                 // Substitute in the recombined pairs
1680                 epvector::const_iterator cit = seq.begin(), last = seq.end();
1681                 while (cit != last) {
1682
1683                         const ex &orig_ex = recombine_pair_to_ex(*cit);
1684                         const ex &subsed_ex = orig_ex.subs(m, options);
1685                         if (!are_ex_trivially_equal(orig_ex, subsed_ex)) {
1686
1687                                 // Something changed, copy seq, subs and return it
1688                                 std::auto_ptr<epvector> s(new epvector);
1689                                 s->reserve(seq.size());
1690
1691                                 // Copy parts of seq which are known not to have changed
1692                                 s->insert(s->begin(), seq.begin(), cit);
1693
1694                                 // Copy first changed element
1695                                 s->push_back(split_ex_to_pair(subsed_ex));
1696                                 ++cit;
1697
1698                                 // Copy rest
1699                                 while (cit != last) {
1700                                         s->push_back(split_ex_to_pair(recombine_pair_to_ex(*cit).subs(m, options)));
1701                                         ++cit;
1702                                 }
1703                                 return s;
1704                         }
1705
1706                         ++cit;
1707                 }
1708
1709         } else {
1710
1711                 // Substitute only in the "rest" part of the pairs
1712                 epvector::const_iterator cit = seq.begin(), last = seq.end();
1713                 while (cit != last) {
1714
1715                         const ex &subsed_ex = cit->rest.subs(m, options);
1716                         if (!are_ex_trivially_equal(cit->rest, subsed_ex)) {
1717                         
1718                                 // Something changed, copy seq, subs and return it
1719                                 std::auto_ptr<epvector> s(new epvector);
1720                                 s->reserve(seq.size());
1721
1722                                 // Copy parts of seq which are known not to have changed
1723                                 s->insert(s->begin(), seq.begin(), cit);
1724                         
1725                                 // Copy first changed element
1726                                 s->push_back(combine_ex_with_coeff_to_pair(subsed_ex, cit->coeff));
1727                                 ++cit;
1728
1729                                 // Copy rest
1730                                 while (cit != last) {
1731                                         s->push_back(combine_ex_with_coeff_to_pair(cit->rest.subs(m, options), cit->coeff));
1732                                         ++cit;
1733                                 }
1734                                 return s;
1735                         }
1736
1737                         ++cit;
1738                 }
1739         }
1740         
1741         // Nothing has changed
1742         return std::auto_ptr<epvector>(0);
1743 }
1744
1745 //////////
1746 // static member variables
1747 //////////
1748
1749 #if EXPAIRSEQ_USE_HASHTAB
1750 unsigned expairseq::maxhashtabsize = 0x4000000U;
1751 unsigned expairseq::minhashtabsize = 0x1000U;
1752 unsigned expairseq::hashtabfactor = 1;
1753 #endif // EXPAIRSEQ_USE_HASHTAB
1754
1755 } // namespace GiNaC