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