]> www.ginac.de Git - ginac.git/blob - ginac/expairseq.cpp
Remove 'discardable' option from ctors of container and derived classes.
[ginac.git] / ginac / expairseq.cpp
1 /** @file expairseq.cpp
2  *
3  *  Implementation of sequences of expression pairs. */
4
5 /*
6  *  GiNaC Copyright (C) 1999-2015 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 "expairseq.h"
24 #include "lst.h"
25 #include "add.h"
26 #include "mul.h"
27 #include "power.h"
28 #include "relational.h"
29 #include "wildcard.h"
30 #include "archive.h"
31 #include "operators.h"
32 #include "utils.h"
33 #include "hash_seed.h"
34 #include "indexed.h"
35 #include "compiler.h"
36
37 #include <algorithm>
38 #include <iostream>
39 #include <iterator>
40 #include <stdexcept>
41 #include <string>
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() 
71 {}
72
73 // protected
74
75 //////////
76 // other constructors
77 //////////
78
79 expairseq::expairseq(const ex &lh, const ex &rh)
80 {
81         construct_from_2_ex(lh,rh);
82         GINAC_ASSERT(is_canonical());
83 }
84
85 expairseq::expairseq(const exvector &v)
86 {
87         construct_from_exvector(v);
88         GINAC_ASSERT(is_canonical());
89 }
90
91 expairseq::expairseq(const epvector &v, const ex &oc, bool do_index_renaming)
92   :  overall_coeff(oc)
93 {
94         GINAC_ASSERT(is_a<numeric>(oc));
95         construct_from_epvector(v, do_index_renaming);
96         GINAC_ASSERT(is_canonical());
97 }
98
99 expairseq::expairseq(epvector && vp, const ex &oc, bool do_index_renaming)
100   :  overall_coeff(oc)
101 {
102         GINAC_ASSERT(is_a<numeric>(oc));
103         construct_from_epvector(std::move(vp), do_index_renaming);
104         GINAC_ASSERT(is_canonical());
105 }
106
107 //////////
108 // archiving
109 //////////
110
111 void expairseq::read_archive(const archive_node &n, lst &sym_lst) 
112 {
113         inherited::read_archive(n, sym_lst);
114         auto first = n.find_first("rest");
115         auto last = n.find_last("coeff");
116         ++last;
117         seq.reserve((last-first)/2);
118
119         for (auto loc = first; loc < last;) {
120                 ex rest;
121                 ex coeff;
122                 n.find_ex_by_loc(loc++, rest, sym_lst);
123                 n.find_ex_by_loc(loc++, coeff, sym_lst);
124                 seq.push_back(expair(rest, coeff));
125         }
126
127         n.find_ex("overall_coeff", overall_coeff, sym_lst);
128
129         canonicalize();
130         GINAC_ASSERT(is_canonical());
131 }
132
133 void expairseq::archive(archive_node &n) const
134 {
135         inherited::archive(n);
136         for (auto & i : seq) {
137                 n.add_ex("rest", i.rest);
138                 n.add_ex("coeff", i.coeff);
139         }
140         n.add_ex("overall_coeff", overall_coeff);
141 }
142
143
144 //////////
145 // functions overriding virtual functions from base classes
146 //////////
147
148 // public
149
150 void expairseq::do_print(const print_context & c, unsigned level) const
151 {
152         c.s << "[[";
153         printseq(c, ',', precedence(), level);
154         c.s << "]]";
155 }
156
157 void expairseq::do_print_tree(const print_tree & c, unsigned level) const
158 {
159         c.s << std::string(level, ' ') << class_name() << " @" << this
160             << std::hex << ", hash=0x" << hashvalue << ", flags=0x" << flags << std::dec
161             << ", nops=" << nops()
162             << std::endl;
163         size_t num = seq.size();
164         for (size_t i=0; i<num; ++i) {
165                 seq[i].rest.print(c, level + c.delta_indent);
166                 seq[i].coeff.print(c, level + c.delta_indent);
167                 if (i != num - 1)
168                         c.s << std::string(level + c.delta_indent, ' ') << "-----" << std::endl;
169         }
170         if (!overall_coeff.is_equal(default_overall_coeff())) {
171                 c.s << std::string(level + c.delta_indent, ' ') << "-----" << std::endl
172                     << std::string(level + c.delta_indent, ' ') << "overall_coeff" << std::endl;
173                 overall_coeff.print(c, level + c.delta_indent);
174         }
175         c.s << std::string(level + c.delta_indent,' ') << "=====" << std::endl;
176 }
177
178 bool expairseq::info(unsigned inf) const
179 {
180         switch(inf) {
181                 case info_flags::expanded:
182                         return (flags & status_flags::expanded);
183                 case info_flags::has_indices: {
184                         if (flags & status_flags::has_indices)
185                                 return true;
186                         else if (flags & status_flags::has_no_indices)
187                                 return false;
188                         for (auto & i : seq) {
189                                 if (i.rest.info(info_flags::has_indices)) {
190                                         this->setflag(status_flags::has_indices);
191                                         this->clearflag(status_flags::has_no_indices);
192                                         return true;
193                                 }
194                         }
195                         this->clearflag(status_flags::has_indices);
196                         this->setflag(status_flags::has_no_indices);
197                         return false;
198                 }
199         }
200         return inherited::info(inf);
201 }
202
203 size_t expairseq::nops() const
204 {
205         if (overall_coeff.is_equal(default_overall_coeff()))
206                 return seq.size();
207         else
208                 return seq.size()+1;
209 }
210
211 ex expairseq::op(size_t i) const
212 {
213         if (i < seq.size())
214                 return recombine_pair_to_ex(seq[i]);
215         GINAC_ASSERT(!overall_coeff.is_equal(default_overall_coeff()));
216         return overall_coeff;
217 }
218
219 ex expairseq::map(map_function &f) const
220 {
221         epvector v;
222         v.reserve(seq.size()+1);
223
224         for (auto & it : seq)
225                 v.push_back(split_ex_to_pair(f(recombine_pair_to_ex(it))));
226
227         if (overall_coeff.is_equal(default_overall_coeff()))
228                 return thisexpairseq(std::move(v), default_overall_coeff(), true);
229         else {
230                 ex newcoeff = f(overall_coeff);
231                 if(is_a<numeric>(newcoeff))
232                         return thisexpairseq(std::move(v), newcoeff, true);
233                 else {
234                         v.push_back(split_ex_to_pair(newcoeff));
235                         return thisexpairseq(std::move(v), default_overall_coeff(), true);
236                 }
237         }
238 }
239
240 /** Perform coefficient-wise automatic term rewriting rules in this class. */
241 ex expairseq::eval(int level) const
242 {
243         if ((level==1) && (flags &status_flags::evaluated))
244                 return *this;
245
246         epvector evaled = evalchildren(level);
247         if (!evaled.empty())
248                 return (new expairseq(std::move(evaled), overall_coeff))->setflag(status_flags::dynallocated | status_flags::evaluated);
249         else
250                 return this->hold();
251 }
252
253 epvector* conjugateepvector(const epvector&epv)
254 {
255         epvector *newepv = nullptr;
256         for (auto i=epv.begin(); i!=epv.end(); ++i) {
257                 if (newepv) {
258                         newepv->push_back(i->conjugate());
259                         continue;
260                 }
261                 expair x = i->conjugate();
262                 if (x.is_equal(*i)) {
263                         continue;
264                 }
265                 newepv = new epvector;
266                 newepv->reserve(epv.size());
267                 for (epvector::const_iterator j=epv.begin(); j!=i; ++j) {
268                         newepv->push_back(*j);
269                 }
270                 newepv->push_back(x);
271         }
272         return newepv;
273 }
274
275 ex expairseq::conjugate() const
276 {
277         std::unique_ptr<epvector> newepv(conjugateepvector(seq));
278         ex x = overall_coeff.conjugate();
279         if (newepv) {
280                 return thisexpairseq(std::move(*newepv), x);
281         }
282         if (are_ex_trivially_equal(x, overall_coeff)) {
283                 return *this;
284         }
285         return thisexpairseq(seq, x);
286 }
287
288 bool expairseq::match(const ex & pattern, exmap & repl_lst) const
289 {
290         // This differs from basic::match() because we want "a+b+c+d" to
291         // match "d+*+b" with "*" being "a+c", and we want to honor commutativity
292
293         if (typeid(*this) == typeid(ex_to<basic>(pattern))) {
294
295                 // Check whether global wildcard (one that matches the "rest of the
296                 // expression", like "*" above) is present
297                 bool has_global_wildcard = false;
298                 ex global_wildcard;
299                 for (size_t i=0; i<pattern.nops(); i++) {
300                         if (is_exactly_a<wildcard>(pattern.op(i))) {
301                                 has_global_wildcard = true;
302                                 global_wildcard = pattern.op(i);
303                                 break;
304                         }
305                 }
306
307                 // Even if the expression does not match the pattern, some of
308                 // its subexpressions could match it. For example, x^5*y^(-1)
309                 // does not match the pattern $0^5, but its subexpression x^5
310                 // does. So, save repl_lst in order to not add bogus entries.
311                 exmap tmp_repl = repl_lst;
312
313                 // Unfortunately, this is an O(N^2) operation because we can't
314                 // sort the pattern in a useful way...
315
316                 // Chop into terms
317                 exvector ops;
318                 ops.reserve(nops());
319                 for (size_t i=0; i<nops(); i++)
320                         ops.push_back(op(i));
321
322                 // Now, for every term of the pattern, look for a matching term in
323                 // the expression and remove the match
324                 for (size_t i=0; i<pattern.nops(); i++) {
325                         ex p = pattern.op(i);
326                         if (has_global_wildcard && p.is_equal(global_wildcard))
327                                 continue;
328                         auto it = ops.begin(), itend = ops.end();
329                         while (it != itend) {
330                                 if (it->match(p, tmp_repl)) {
331                                         ops.erase(it);
332                                         goto found;
333                                 }
334                                 ++it;
335                         }
336                         return false; // no match found
337 found:          ;
338                 }
339
340                 if (has_global_wildcard) {
341
342                         // Assign all the remaining terms to the global wildcard (unless
343                         // it has already been matched before, in which case the matches
344                         // must be equal)
345                         size_t num = ops.size();
346                         epvector vp;
347                         vp.reserve(num);
348                         for (size_t i=0; i<num; i++)
349                                 vp.push_back(split_ex_to_pair(ops[i]));
350                         ex rest = thisexpairseq(std::move(vp), default_overall_coeff());
351                         for (auto & it : tmp_repl) {
352                                 if (it.first.is_equal(global_wildcard)) {
353                                         if (rest.is_equal(it.second)) {
354                                                 repl_lst = tmp_repl;
355                                                 return true;
356                                         }
357                                         return false;
358                                 }
359                         }
360                         repl_lst = tmp_repl;
361                         repl_lst[global_wildcard] = rest;
362                         return true;
363
364                 } else {
365
366                         // No global wildcard, then the match fails if there are any
367                         // unmatched terms left
368                         if (ops.empty()) {
369                                 repl_lst = tmp_repl;
370                                 return true;
371                         }
372                         return false;
373                 }
374         }
375         return inherited::match(pattern, repl_lst);
376 }
377
378 ex expairseq::subs(const exmap & m, unsigned options) const
379 {
380         epvector subsed = subschildren(m, options);
381         if (!subsed.empty())
382                 return ex_to<basic>(thisexpairseq(std::move(subsed), overall_coeff, (options & subs_options::no_index_renaming) == 0));
383         else if ((options & subs_options::algebraic) && is_exactly_a<mul>(*this))
384                 return static_cast<const mul *>(this)->algebraic_subs_mul(m, options);
385         else
386                 return subs_one_level(m, options);
387 }
388
389 // protected
390
391 int expairseq::compare_same_type(const basic &other) const
392 {
393         GINAC_ASSERT(is_a<expairseq>(other));
394         const expairseq &o = static_cast<const expairseq &>(other);
395         
396         int cmpval;
397         
398         // compare number of elements
399         if (seq.size() != o.seq.size())
400                 return (seq.size()<o.seq.size()) ? -1 : 1;
401         
402         // compare overall_coeff
403         cmpval = overall_coeff.compare(o.overall_coeff);
404         if (cmpval!=0)
405                 return cmpval;
406         
407         auto cit1 = seq.begin(), last1 = seq.end();
408         auto cit2 = o.seq.begin(), last2 = o.seq.end();
409         for (; (cit1!=last1) && (cit2!=last2); ++cit1, ++cit2) {
410                 cmpval = (*cit1).compare(*cit2);
411                 if (cmpval!=0) return cmpval;
412         }
413                 
414         GINAC_ASSERT(cit1==last1);
415         GINAC_ASSERT(cit2==last2);
416                 
417         return 0;
418 }
419
420 bool expairseq::is_equal_same_type(const basic &other) const
421 {
422         const expairseq &o = static_cast<const expairseq &>(other);
423         
424         // compare number of elements
425         if (seq.size()!=o.seq.size())
426                 return false;
427         
428         // compare overall_coeff
429         if (!overall_coeff.is_equal(o.overall_coeff))
430                 return false;
431         
432         auto cit2 = o.seq.begin();
433         for (auto & cit1 : seq) {
434                 if (!cit1.is_equal(*cit2))
435                         return false;
436                 ++cit2;
437         }
438
439         return true;
440 }
441
442 unsigned expairseq::return_type() const
443 {
444         return return_types::noncommutative_composite;
445 }
446
447 unsigned expairseq::calchash() const
448 {
449         unsigned v = make_hash_seed(typeid(*this));
450         for (auto & i : seq) {
451                 v ^= i.rest.gethash();
452                 v = rotate_left(v);
453                 v ^= i.coeff.gethash();
454         }
455
456         v ^= overall_coeff.gethash();
457
458         // store calculated hash value only if object is already evaluated
459         if (flags &status_flags::evaluated) {
460                 setflag(status_flags::hash_calculated);
461                 hashvalue = v;
462         }
463         
464         return v;
465 }
466
467 ex expairseq::expand(unsigned options) const
468 {
469         epvector expanded = expandchildren(options);
470         if (!expanded.empty()) {
471                 return thisexpairseq(std::move(expanded), overall_coeff);
472         }
473         return (options == 0) ? setflag(status_flags::expanded) : *this;
474 }
475
476 //////////
477 // new virtual functions which can be overridden by derived classes
478 //////////
479
480 // protected
481
482 /** Create an object of this type.
483  *  This method works similar to a constructor.  It is useful because expairseq
484  *  has (at least) two possible different semantics but we want to inherit
485  *  methods thus avoiding code duplication.  Sometimes a method in expairseq
486  *  has to create a new one of the same semantics, which cannot be done by a
487  *  ctor because the name (add, mul,...) is unknown on the expairseq level.  In
488  *  order for this trick to work a derived class must of course override this
489  *  definition. */
490 ex expairseq::thisexpairseq(const epvector &v, const ex &oc, bool do_index_renaming) const
491 {
492         return expairseq(v, oc, do_index_renaming);
493 }
494
495 ex expairseq::thisexpairseq(epvector && vp, const ex &oc, bool do_index_renaming) const
496 {
497         return expairseq(std::move(vp), oc, do_index_renaming);
498 }
499
500 void expairseq::printpair(const print_context & c, const expair & p, unsigned upper_precedence) const
501 {
502         c.s << "[[";
503         p.rest.print(c, precedence());
504         c.s << ",";
505         p.coeff.print(c, precedence());
506         c.s << "]]";
507 }
508
509 void expairseq::printseq(const print_context & c, char delim,
510                          unsigned this_precedence,
511                          unsigned upper_precedence) const
512 {
513         if (this_precedence <= upper_precedence)
514                 c.s << "(";
515         auto it = seq.begin(), it_last = seq.end() - 1;
516         for (; it!=it_last; ++it) {
517                 printpair(c, *it, this_precedence);
518                 c.s << delim;
519         }
520         printpair(c, *it, this_precedence);
521         if (!overall_coeff.is_equal(default_overall_coeff())) {
522                 c.s << delim;
523                 overall_coeff.print(c, this_precedence);
524         }
525         
526         if (this_precedence <= upper_precedence)
527                 c.s << ")";
528 }
529
530
531 /** Form an expair from an ex, using the corresponding semantics.
532  *  @see expairseq::recombine_pair_to_ex() */
533 expair expairseq::split_ex_to_pair(const ex &e) const
534 {
535         return expair(e,_ex1);
536 }
537
538
539 expair expairseq::combine_ex_with_coeff_to_pair(const ex &e,
540                                                 const ex &c) const
541 {
542         GINAC_ASSERT(is_exactly_a<numeric>(c));
543         
544         return expair(e,c);
545 }
546
547
548 expair expairseq::combine_pair_with_coeff_to_pair(const expair &p,
549                                                   const ex &c) const
550 {
551         GINAC_ASSERT(is_exactly_a<numeric>(p.coeff));
552         GINAC_ASSERT(is_exactly_a<numeric>(c));
553         
554         return expair(p.rest,ex_to<numeric>(p.coeff).mul_dyn(ex_to<numeric>(c)));
555 }
556
557
558 /** Form an ex out of an expair, using the corresponding semantics.
559  *  @see expairseq::split_ex_to_pair() */
560 ex expairseq::recombine_pair_to_ex(const expair &p) const
561 {
562         return lst(p.rest,p.coeff);
563 }
564
565 bool expairseq::expair_needs_further_processing(epp it)
566 {
567         return false;
568 }
569
570 ex expairseq::default_overall_coeff() const
571 {
572         return _ex0;
573 }
574
575 void expairseq::combine_overall_coeff(const ex &c)
576 {
577         GINAC_ASSERT(is_exactly_a<numeric>(overall_coeff));
578         GINAC_ASSERT(is_exactly_a<numeric>(c));
579         overall_coeff = ex_to<numeric>(overall_coeff).add_dyn(ex_to<numeric>(c));
580 }
581
582 void expairseq::combine_overall_coeff(const ex &c1, const ex &c2)
583 {
584         GINAC_ASSERT(is_exactly_a<numeric>(overall_coeff));
585         GINAC_ASSERT(is_exactly_a<numeric>(c1));
586         GINAC_ASSERT(is_exactly_a<numeric>(c2));
587         overall_coeff = ex_to<numeric>(overall_coeff).
588                         add_dyn(ex_to<numeric>(c1).mul(ex_to<numeric>(c2)));
589 }
590
591 bool expairseq::can_make_flat(const expair &p) const
592 {
593         return true;
594 }
595
596
597 //////////
598 // non-virtual functions in this class
599 //////////
600
601 void expairseq::construct_from_2_ex_via_exvector(const ex &lh, const ex &rh)
602 {
603         exvector v;
604         v.reserve(2);
605         v.push_back(lh);
606         v.push_back(rh);
607         construct_from_exvector(v);
608 }
609
610 void expairseq::construct_from_2_ex(const ex &lh, const ex &rh)
611 {
612         if (typeid(ex_to<basic>(lh)) == typeid(*this)) {
613                 if (typeid(ex_to<basic>(rh)) == typeid(*this)) {
614                         if (is_a<mul>(lh) && lh.info(info_flags::has_indices) && 
615                                 rh.info(info_flags::has_indices)) {
616                                 ex newrh=rename_dummy_indices_uniquely(lh, rh);
617                                 construct_from_2_expairseq(ex_to<expairseq>(lh),
618                                                            ex_to<expairseq>(newrh));
619                         }
620                         else
621                                 construct_from_2_expairseq(ex_to<expairseq>(lh),
622                                                            ex_to<expairseq>(rh));
623                         return;
624                 } else {
625                         construct_from_expairseq_ex(ex_to<expairseq>(lh), rh);
626                         return;
627                 }
628         } else if (typeid(ex_to<basic>(rh)) == typeid(*this)) {
629                 construct_from_expairseq_ex(ex_to<expairseq>(rh),lh);
630                 return;
631         }
632         
633         if (is_exactly_a<numeric>(lh)) {
634                 if (is_exactly_a<numeric>(rh)) {
635                         combine_overall_coeff(lh);
636                         combine_overall_coeff(rh);
637                 } else {
638                         combine_overall_coeff(lh);
639                         seq.push_back(split_ex_to_pair(rh));
640                 }
641         } else {
642                 if (is_exactly_a<numeric>(rh)) {
643                         combine_overall_coeff(rh);
644                         seq.push_back(split_ex_to_pair(lh));
645                 } else {
646                         expair p1 = split_ex_to_pair(lh);
647                         expair p2 = split_ex_to_pair(rh);
648                         
649                         int cmpval = p1.rest.compare(p2.rest);
650                         if (cmpval==0) {
651                                 p1.coeff = ex_to<numeric>(p1.coeff).add_dyn(ex_to<numeric>(p2.coeff));
652                                 if (!ex_to<numeric>(p1.coeff).is_zero()) {
653                                         // no further processing is necessary, since this
654                                         // one element will usually be recombined in eval()
655                                         seq.push_back(p1);
656                                 }
657                         } else {
658                                 seq.reserve(2);
659                                 if (cmpval<0) {
660                                         seq.push_back(p1);
661                                         seq.push_back(p2);
662                                 } else {
663                                         seq.push_back(p2);
664                                         seq.push_back(p1);
665                                 }
666                         }
667                 }
668         }
669 }
670
671 void expairseq::construct_from_2_expairseq(const expairseq &s1,
672                                            const expairseq &s2)
673 {
674         combine_overall_coeff(s1.overall_coeff);
675         combine_overall_coeff(s2.overall_coeff);
676
677         auto first1 = s1.seq.begin(), last1 = s1.seq.end();
678         auto first2 = s2.seq.begin(), last2 = s2.seq.end();
679
680         seq.reserve(s1.seq.size()+s2.seq.size());
681
682         bool needs_further_processing=false;
683         
684         while (first1!=last1 && first2!=last2) {
685                 int cmpval = (*first1).rest.compare((*first2).rest);
686
687                 if (cmpval==0) {
688                         // combine terms
689                         const numeric &newcoeff = ex_to<numeric>(first1->coeff).
690                                                    add(ex_to<numeric>(first2->coeff));
691                         if (!newcoeff.is_zero()) {
692                                 seq.push_back(expair(first1->rest,newcoeff));
693                                 if (expair_needs_further_processing(seq.end()-1)) {
694                                         needs_further_processing = true;
695                                 }
696                         }
697                         ++first1;
698                         ++first2;
699                 } else if (cmpval<0) {
700                         seq.push_back(*first1);
701                         ++first1;
702                 } else {
703                         seq.push_back(*first2);
704                         ++first2;
705                 }
706         }
707         
708         while (first1!=last1) {
709                 seq.push_back(*first1);
710                 ++first1;
711         }
712         while (first2!=last2) {
713                 seq.push_back(*first2);
714                 ++first2;
715         }
716         
717         if (needs_further_processing) {
718                 epvector v = seq;
719                 seq.clear();
720                 construct_from_epvector(std::move(v));
721         }
722 }
723
724 void expairseq::construct_from_expairseq_ex(const expairseq &s,
725                                             const ex &e)
726 {
727         combine_overall_coeff(s.overall_coeff);
728         if (is_exactly_a<numeric>(e)) {
729                 combine_overall_coeff(e);
730                 seq = s.seq;
731                 return;
732         }
733         
734         auto first = s.seq.begin(), last = s.seq.end();
735         expair p = split_ex_to_pair(e);
736         
737         seq.reserve(s.seq.size()+1);
738         bool p_pushed = false;
739         
740         bool needs_further_processing=false;
741         
742         // merge p into s.seq
743         while (first!=last) {
744                 int cmpval = (*first).rest.compare(p.rest);
745                 if (cmpval==0) {
746                         // combine terms
747                         const numeric &newcoeff = ex_to<numeric>(first->coeff).
748                                                    add(ex_to<numeric>(p.coeff));
749                         if (!newcoeff.is_zero()) {
750                                 seq.push_back(expair(first->rest,newcoeff));
751                                 if (expair_needs_further_processing(seq.end()-1))
752                                         needs_further_processing = true;
753                         }
754                         ++first;
755                         p_pushed = true;
756                         break;
757                 } else if (cmpval<0) {
758                         seq.push_back(*first);
759                         ++first;
760                 } else {
761                         seq.push_back(p);
762                         p_pushed = true;
763                         break;
764                 }
765         }
766         
767         if (p_pushed) {
768                 // while loop exited because p was pushed, now push rest of s.seq
769                 while (first!=last) {
770                         seq.push_back(*first);
771                         ++first;
772                 }
773         } else {
774                 // while loop exited because s.seq was pushed, now push p
775                 seq.push_back(p);
776         }
777
778         if (needs_further_processing) {
779                 epvector v = seq;
780                 seq.clear();
781                 construct_from_epvector(std::move(v));
782         }
783 }
784
785 void expairseq::construct_from_exvector(const exvector &v)
786 {
787         // simplifications: +(a,+(b,c),d) -> +(a,b,c,d) (associativity)
788         //                  +(d,b,c,a) -> +(a,b,c,d) (canonicalization)
789         //                  +(...,x,*(x,c1),*(x,c2)) -> +(...,*(x,1+c1+c2)) (c1, c2 numeric)
790         //                  (same for (+,*) -> (*,^)
791
792         make_flat(v);
793         canonicalize();
794         combine_same_terms_sorted_seq();
795 }
796
797 void expairseq::construct_from_epvector(const epvector &v, bool do_index_renaming)
798 {
799         // simplifications: +(a,+(b,c),d) -> +(a,b,c,d) (associativity)
800         //                  +(d,b,c,a) -> +(a,b,c,d) (canonicalization)
801         //                  +(...,x,*(x,c1),*(x,c2)) -> +(...,*(x,1+c1+c2)) (c1, c2 numeric)
802         //                  same for (+,*) -> (*,^)
803
804         make_flat(v, do_index_renaming);
805         canonicalize();
806         combine_same_terms_sorted_seq();
807 }
808
809 void expairseq::construct_from_epvector(epvector &&v, bool do_index_renaming)
810 {
811         // simplifications: +(a,+(b,c),d) -> +(a,b,c,d) (associativity)
812         //                  +(d,b,c,a) -> +(a,b,c,d) (canonicalization)
813         //                  +(...,x,*(x,c1),*(x,c2)) -> +(...,*(x,1+c1+c2)) (c1, c2 numeric)
814         //                  same for (+,*) -> (*,^)
815
816         make_flat(std::move(v), do_index_renaming);
817         canonicalize();
818         combine_same_terms_sorted_seq();
819 }
820
821 /** Combine this expairseq with argument exvector.
822  *  It cares for associativity as well as for special handling of numerics. */
823 void expairseq::make_flat(const exvector &v)
824 {
825         // count number of operands which are of same expairseq derived type
826         // and their cumulative number of operands
827         int nexpairseqs = 0;
828         int noperands = 0;
829         bool do_idx_rename = false;
830         
831         for (auto & cit : v) {
832                 if (typeid(ex_to<basic>(cit)) == typeid(*this)) {
833                         ++nexpairseqs;
834                         noperands += ex_to<expairseq>(cit).seq.size();
835                 }
836                 if (is_a<mul>(*this) && (!do_idx_rename) &&
837                     cit.info(info_flags::has_indices))
838                         do_idx_rename = true;
839         }
840         
841         // reserve seq and coeffseq which will hold all operands
842         seq.reserve(v.size()+noperands-nexpairseqs);
843         
844         // copy elements and split off numerical part
845         make_flat_inserter mf(v, do_idx_rename);
846         for (auto & cit : v) {
847                 if (typeid(ex_to<basic>(cit)) == typeid(*this)) {
848                         ex newfactor = mf.handle_factor(cit, _ex1);
849                         const expairseq &subseqref = ex_to<expairseq>(newfactor);
850                         combine_overall_coeff(subseqref.overall_coeff);
851                         for (auto & cit_s : subseqref.seq) {
852                                 seq.push_back(cit_s);
853                         }
854                 } else {
855                         if (is_exactly_a<numeric>(cit))
856                                 combine_overall_coeff(cit);
857                         else {
858                                 ex newfactor = mf.handle_factor(cit, _ex1);
859                                 seq.push_back(split_ex_to_pair(newfactor));
860                         }
861                 }
862         }
863 }
864
865 /** Combine this expairseq with argument epvector.
866  *  It cares for associativity as well as for special handling of numerics. */
867 void expairseq::make_flat(const epvector &v, bool do_index_renaming)
868 {
869         // count number of operands which are of same expairseq derived type
870         // and their cumulative number of operands
871         int nexpairseqs = 0;
872         int noperands = 0;
873         bool really_need_rename_inds = false;
874         
875         for (auto & cit : v) {
876                 if (typeid(ex_to<basic>(cit.rest)) == typeid(*this)) {
877                         ++nexpairseqs;
878                         noperands += ex_to<expairseq>(cit.rest).seq.size();
879                 }
880                 if ((!really_need_rename_inds) && is_a<mul>(*this) &&
881                     cit.rest.info(info_flags::has_indices))
882                         really_need_rename_inds = true;
883         }
884         do_index_renaming = do_index_renaming && really_need_rename_inds;
885         
886         // reserve seq and coeffseq which will hold all operands
887         seq.reserve(v.size()+noperands-nexpairseqs);
888         make_flat_inserter mf(v, do_index_renaming);
889         
890         // copy elements and split off numerical part
891         for (auto & cit : v) {
892                 if (typeid(ex_to<basic>(cit.rest)) == typeid(*this) &&
893                     this->can_make_flat(cit)) {
894                         ex newrest = mf.handle_factor(cit.rest, cit.coeff);
895                         const expairseq &subseqref = ex_to<expairseq>(newrest);
896                         combine_overall_coeff(ex_to<numeric>(subseqref.overall_coeff),
897                                               ex_to<numeric>(cit.coeff));
898                         for (auto & cit_s : subseqref.seq) {
899                                 seq.push_back(expair(cit_s.rest,
900                                                      ex_to<numeric>(cit_s.coeff).mul_dyn(ex_to<numeric>(cit.coeff))));
901                         }
902                 } else {
903                         if (cit.is_canonical_numeric())
904                                 combine_overall_coeff(mf.handle_factor(cit.rest, _ex1));
905                         else {
906                                 ex rest = cit.rest;
907                                 ex newrest = mf.handle_factor(rest, cit.coeff);
908                                 if (are_ex_trivially_equal(newrest, rest))
909                                         seq.push_back(cit);
910                                 else
911                                         seq.push_back(expair(newrest, cit.coeff));
912                         }
913                 }
914         }
915 }
916
917 /** Brings this expairseq into a sorted (canonical) form. */
918 void expairseq::canonicalize()
919 {
920         std::sort(seq.begin(), seq.end(), expair_rest_is_less());
921 }
922
923
924 /** Compact a presorted expairseq by combining all matching expairs to one
925  *  each.  On an add object, this is responsible for 2*x+3*x+y -> 5*x+y, for
926  *  instance. */
927 void expairseq::combine_same_terms_sorted_seq()
928 {
929         if (seq.size()<2)
930                 return;
931
932         bool needs_further_processing = false;
933
934         auto itin1 = seq.begin();
935         auto itin2 = itin1 + 1;
936         auto itout = itin1;
937         auto last = seq.end();
938         // must_copy will be set to true the first time some combination is 
939         // possible from then on the sequence has changed and must be compacted
940         bool must_copy = false;
941         while (itin2!=last) {
942                 if (itin1->rest.compare(itin2->rest)==0) {
943                         itin1->coeff = ex_to<numeric>(itin1->coeff).
944                                        add_dyn(ex_to<numeric>(itin2->coeff));
945                         if (expair_needs_further_processing(itin1))
946                                 needs_further_processing = true;
947                         must_copy = true;
948                 } else {
949                         if (!ex_to<numeric>(itin1->coeff).is_zero()) {
950                                 if (must_copy)
951                                         *itout = *itin1;
952                                 ++itout;
953                         }
954                         itin1 = itin2;
955                 }
956                 ++itin2;
957         }
958         if (!ex_to<numeric>(itin1->coeff).is_zero()) {
959                 if (must_copy)
960                         *itout = *itin1;
961                 ++itout;
962         }
963         if (itout!=last)
964                 seq.erase(itout,last);
965
966         if (needs_further_processing) {
967                 epvector v = seq;
968                 seq.clear();
969                 construct_from_epvector(std::move(v));
970         }
971 }
972
973 /** Check if this expairseq is in sorted (canonical) form.  Useful mainly for
974  *  debugging or in assertions since being sorted is an invariance. */
975 bool expairseq::is_canonical() const
976 {
977         if (seq.size() <= 1)
978                 return 1;
979         
980         auto it = seq.begin(), itend = seq.end();
981         auto it_last = it;
982         for (++it; it!=itend; it_last=it, ++it) {
983                 if (!(it_last->is_less(*it) || it_last->is_equal(*it))) {
984                         if (!is_exactly_a<numeric>(it_last->rest) ||
985                                 !is_exactly_a<numeric>(it->rest)) {
986                                 // double test makes it easier to set a breakpoint...
987                                 if (!is_exactly_a<numeric>(it_last->rest) ||
988                                         !is_exactly_a<numeric>(it->rest)) {
989                                         printpair(std::clog, *it_last, 0);
990                                         std::clog << ">";
991                                         printpair(std::clog, *it, 0);
992                                         std::clog << "\n";
993                                         std::clog << "pair1:" << std::endl;
994                                         it_last->rest.print(print_tree(std::clog));
995                                         it_last->coeff.print(print_tree(std::clog));
996                                         std::clog << "pair2:" << std::endl;
997                                         it->rest.print(print_tree(std::clog));
998                                         it->coeff.print(print_tree(std::clog));
999                                         return 0;
1000                                 }
1001                         }
1002                 }
1003         }
1004         return 1;
1005 }
1006
1007 /** Member-wise expand the expairs in this sequence.
1008  *
1009  *  @see expairseq::expand()
1010  *  @return epvector containing expanded pairs, empty if no members
1011  *    had to be changed. */
1012 epvector expairseq::expandchildren(unsigned options) const
1013 {
1014         auto cit = seq.begin(), last = seq.end();
1015         while (cit!=last) {
1016                 const ex &expanded_ex = cit->rest.expand(options);
1017                 if (!are_ex_trivially_equal(cit->rest,expanded_ex)) {
1018                         
1019                         // something changed, copy seq, eval and return it
1020                         epvector s;
1021                         s.reserve(seq.size());
1022                         
1023                         // copy parts of seq which are known not to have changed
1024                         auto cit2 = seq.begin();
1025                         while (cit2!=cit) {
1026                                 s.push_back(*cit2);
1027                                 ++cit2;
1028                         }
1029
1030                         // copy first changed element
1031                         s.push_back(combine_ex_with_coeff_to_pair(expanded_ex,
1032                                                                   cit2->coeff));
1033                         ++cit2;
1034
1035                         // copy rest
1036                         while (cit2!=last) {
1037                                 s.push_back(combine_ex_with_coeff_to_pair(cit2->rest.expand(options),
1038                                                                           cit2->coeff));
1039                                 ++cit2;
1040                         }
1041                         return s;
1042                 }
1043                 ++cit;
1044         }
1045         
1046         return epvector(); // empty signalling nothing has changed
1047 }
1048
1049
1050 /** Member-wise evaluate the expairs in this sequence.
1051  *
1052  *  @see expairseq::eval()
1053  *  @return epvector containing evaluated pairs, empty if no members
1054  *    had to be changed. */
1055 epvector expairseq::evalchildren(int level) const
1056 {
1057         if (likely(level==1))
1058                 return epvector();  // nothing had to be evaluated
1059         
1060         if (level == -max_recursion_level)
1061                 throw(std::runtime_error("max recursion level reached"));
1062         
1063         --level;
1064         auto cit = seq.begin(), last = seq.end();
1065         while (cit!=last) {
1066                 const ex evaled_ex = cit->rest.eval(level);
1067                 if (!are_ex_trivially_equal(cit->rest,evaled_ex)) {
1068                         
1069                         // something changed, copy seq, eval and return it
1070                         epvector s;
1071                         s.reserve(seq.size());
1072                         
1073                         // copy parts of seq which are known not to have changed
1074                         auto cit2 = seq.begin();
1075                         while (cit2!=cit) {
1076                                 s.push_back(*cit2);
1077                                 ++cit2;
1078                         }
1079
1080                         // copy first changed element
1081                         s.push_back(combine_ex_with_coeff_to_pair(evaled_ex,
1082                                                                   cit2->coeff));
1083                         ++cit2;
1084
1085                         // copy rest
1086                         while (cit2!=last) {
1087                                 s.push_back(combine_ex_with_coeff_to_pair(cit2->rest.eval(level),
1088                                                                           cit2->coeff));
1089                                 ++cit2;
1090                         }
1091                         return std::move(s);
1092                 }
1093                 ++cit;
1094         }
1095
1096         return epvector(); // signalling nothing has changed
1097 }
1098
1099 /** Member-wise substitute in this sequence.
1100  *
1101  *  @see expairseq::subs()
1102  *  @return epvector containing expanded pairs, empty if no members
1103  *    had to be changed. */
1104 epvector expairseq::subschildren(const exmap & m, unsigned options) const
1105 {
1106         // When any of the objects to be substituted is a product or power
1107         // we have to recombine the pairs because the numeric coefficients may
1108         // be part of the search pattern.
1109         if (!(options & (subs_options::pattern_is_product | subs_options::pattern_is_not_product))) {
1110
1111                 // Search the list of substitutions and cache our findings
1112                 for (auto & it : m) {
1113                         if (is_exactly_a<mul>(it.first) || is_exactly_a<power>(it.first)) {
1114                                 options |= subs_options::pattern_is_product;
1115                                 break;
1116                         }
1117                 }
1118                 if (!(options & subs_options::pattern_is_product))
1119                         options |= subs_options::pattern_is_not_product;
1120         }
1121
1122         if (options & subs_options::pattern_is_product) {
1123
1124                 // Substitute in the recombined pairs
1125                 auto cit = seq.begin(), last = seq.end();
1126                 while (cit != last) {
1127
1128                         const ex &orig_ex = recombine_pair_to_ex(*cit);
1129                         const ex &subsed_ex = orig_ex.subs(m, options);
1130                         if (!are_ex_trivially_equal(orig_ex, subsed_ex)) {
1131
1132                                 // Something changed, copy seq, subs and return it
1133                                 epvector s;
1134                                 s.reserve(seq.size());
1135
1136                                 // Copy parts of seq which are known not to have changed
1137                                 s.insert(s.begin(), seq.begin(), cit);
1138
1139                                 // Copy first changed element
1140                                 s.push_back(split_ex_to_pair(subsed_ex));
1141                                 ++cit;
1142
1143                                 // Copy rest
1144                                 while (cit != last) {
1145                                         s.push_back(split_ex_to_pair(recombine_pair_to_ex(*cit).subs(m, options)));
1146                                         ++cit;
1147                                 }
1148                                 return s;
1149                         }
1150
1151                         ++cit;
1152                 }
1153
1154         } else {
1155
1156                 // Substitute only in the "rest" part of the pairs
1157                 auto cit = seq.begin(), last = seq.end();
1158                 while (cit != last) {
1159
1160                         const ex &subsed_ex = cit->rest.subs(m, options);
1161                         if (!are_ex_trivially_equal(cit->rest, subsed_ex)) {
1162                         
1163                                 // Something changed, copy seq, subs and return it
1164                                 epvector s;
1165                                 s.reserve(seq.size());
1166
1167                                 // Copy parts of seq which are known not to have changed
1168                                 s.insert(s.begin(), seq.begin(), cit);
1169                         
1170                                 // Copy first changed element
1171                                 s.push_back(combine_ex_with_coeff_to_pair(subsed_ex, cit->coeff));
1172                                 ++cit;
1173
1174                                 // Copy rest
1175                                 while (cit != last) {
1176                                         s.push_back(combine_ex_with_coeff_to_pair(cit->rest.subs(m, options), cit->coeff));
1177                                         ++cit;
1178                                 }
1179                                 return s;
1180                         }
1181
1182                         ++cit;
1183                 }
1184         }
1185         
1186         // Nothing has changed
1187         return epvector();
1188 }
1189
1190 //////////
1191 // static member variables
1192 //////////
1193
1194 } // namespace GiNaC