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