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