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