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