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