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