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