]> www.ginac.de Git - ginac.git/blob - ginac/expairseq.cpp
Remove useless code in add::eval().
[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 <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 (epvector::const_iterator 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_via_exvector(const ex &lh, const ex &rh)
603 {
604         const exvector v = {lh, rh};
605         construct_from_exvector(std::move(v));
606 }
607
608 void expairseq::construct_from_2_ex(const ex &lh, const ex &rh)
609 {
610         if (typeid(ex_to<basic>(lh)) == typeid(*this)) {
611                 if (typeid(ex_to<basic>(rh)) == typeid(*this)) {
612                         if (is_a<mul>(lh) && lh.info(info_flags::has_indices) && 
613                                 rh.info(info_flags::has_indices)) {
614                                 ex newrh=rename_dummy_indices_uniquely(lh, rh);
615                                 construct_from_2_expairseq(ex_to<expairseq>(lh),
616                                                            ex_to<expairseq>(newrh));
617                         }
618                         else
619                                 construct_from_2_expairseq(ex_to<expairseq>(lh),
620                                                            ex_to<expairseq>(rh));
621                         return;
622                 } else {
623                         construct_from_expairseq_ex(ex_to<expairseq>(lh), rh);
624                         return;
625                 }
626         } else if (typeid(ex_to<basic>(rh)) == typeid(*this)) {
627                 construct_from_expairseq_ex(ex_to<expairseq>(rh),lh);
628                 return;
629         }
630         
631         if (is_exactly_a<numeric>(lh)) {
632                 if (is_exactly_a<numeric>(rh)) {
633                         combine_overall_coeff(lh);
634                         combine_overall_coeff(rh);
635                 } else {
636                         combine_overall_coeff(lh);
637                         seq.push_back(split_ex_to_pair(rh));
638                 }
639         } else {
640                 if (is_exactly_a<numeric>(rh)) {
641                         combine_overall_coeff(rh);
642                         seq.push_back(split_ex_to_pair(lh));
643                 } else {
644                         expair p1 = split_ex_to_pair(lh);
645                         expair p2 = split_ex_to_pair(rh);
646                         
647                         int cmpval = p1.rest.compare(p2.rest);
648                         if (cmpval==0) {
649                                 p1.coeff = ex_to<numeric>(p1.coeff).add_dyn(ex_to<numeric>(p2.coeff));
650                                 if (!ex_to<numeric>(p1.coeff).is_zero()) {
651                                         // no further processing is necessary, since this
652                                         // one element will usually be recombined in eval()
653                                         seq.push_back(p1);
654                                 }
655                         } else {
656                                 seq.reserve(2);
657                                 if (cmpval<0) {
658                                         seq.push_back(p1);
659                                         seq.push_back(p2);
660                                 } else {
661                                         seq.push_back(p2);
662                                         seq.push_back(p1);
663                                 }
664                         }
665                 }
666         }
667 }
668
669 void expairseq::construct_from_2_expairseq(const expairseq &s1,
670                                            const expairseq &s2)
671 {
672         combine_overall_coeff(s1.overall_coeff);
673         combine_overall_coeff(s2.overall_coeff);
674
675         auto first1 = s1.seq.begin(), last1 = s1.seq.end();
676         auto first2 = s2.seq.begin(), last2 = s2.seq.end();
677
678         seq.reserve(s1.seq.size()+s2.seq.size());
679
680         bool needs_further_processing=false;
681         
682         while (first1!=last1 && first2!=last2) {
683                 int cmpval = (*first1).rest.compare((*first2).rest);
684
685                 if (cmpval==0) {
686                         // combine terms
687                         const numeric &newcoeff = ex_to<numeric>(first1->coeff).
688                                                    add(ex_to<numeric>(first2->coeff));
689                         if (!newcoeff.is_zero()) {
690                                 seq.push_back(expair(first1->rest,newcoeff));
691                                 if (expair_needs_further_processing(seq.end()-1)) {
692                                         needs_further_processing = true;
693                                 }
694                         }
695                         ++first1;
696                         ++first2;
697                 } else if (cmpval<0) {
698                         seq.push_back(*first1);
699                         ++first1;
700                 } else {
701                         seq.push_back(*first2);
702                         ++first2;
703                 }
704         }
705         
706         while (first1!=last1) {
707                 seq.push_back(*first1);
708                 ++first1;
709         }
710         while (first2!=last2) {
711                 seq.push_back(*first2);
712                 ++first2;
713         }
714         
715         if (needs_further_processing) {
716                 // Clear seq and start over.
717                 epvector v = std::move(seq);
718                 construct_from_epvector(std::move(v));
719         }
720 }
721
722 void expairseq::construct_from_expairseq_ex(const expairseq &s,
723                                             const ex &e)
724 {
725         combine_overall_coeff(s.overall_coeff);
726         if (is_exactly_a<numeric>(e)) {
727                 combine_overall_coeff(e);
728                 seq = s.seq;
729                 return;
730         }
731         
732         auto first = s.seq.begin(), last = s.seq.end();
733         expair p = split_ex_to_pair(e);
734         
735         seq.reserve(s.seq.size()+1);
736         bool p_pushed = false;
737         
738         bool needs_further_processing=false;
739         
740         // merge p into s.seq
741         while (first!=last) {
742                 int cmpval = (*first).rest.compare(p.rest);
743                 if (cmpval==0) {
744                         // combine terms
745                         const numeric &newcoeff = ex_to<numeric>(first->coeff).
746                                                    add(ex_to<numeric>(p.coeff));
747                         if (!newcoeff.is_zero()) {
748                                 seq.push_back(expair(first->rest,newcoeff));
749                                 if (expair_needs_further_processing(seq.end()-1))
750                                         needs_further_processing = true;
751                         }
752                         ++first;
753                         p_pushed = true;
754                         break;
755                 } else if (cmpval<0) {
756                         seq.push_back(*first);
757                         ++first;
758                 } else {
759                         seq.push_back(p);
760                         p_pushed = true;
761                         break;
762                 }
763         }
764         
765         if (p_pushed) {
766                 // while loop exited because p was pushed, now push rest of s.seq
767                 while (first!=last) {
768                         seq.push_back(*first);
769                         ++first;
770                 }
771         } else {
772                 // while loop exited because s.seq was pushed, now push p
773                 seq.push_back(p);
774         }
775
776         if (needs_further_processing) {
777                 // Clear seq and start over.
778                 epvector v = std::move(seq);
779                 construct_from_epvector(std::move(v));
780         }
781 }
782
783 void expairseq::construct_from_exvector(const exvector &v)
784 {
785         // simplifications: +(a,+(b,c),d) -> +(a,b,c,d) (associativity)
786         //                  +(d,b,c,a) -> +(a,b,c,d) (canonicalization)
787         //                  +(...,x,*(x,c1),*(x,c2)) -> +(...,*(x,1+c1+c2)) (c1, c2 numeric)
788         //                  (same for (+,*) -> (*,^)
789
790         make_flat(v);
791         canonicalize();
792         combine_same_terms_sorted_seq();
793 }
794
795 void expairseq::construct_from_epvector(const epvector &v, bool do_index_renaming)
796 {
797         // simplifications: +(a,+(b,c),d) -> +(a,b,c,d) (associativity)
798         //                  +(d,b,c,a) -> +(a,b,c,d) (canonicalization)
799         //                  +(...,x,*(x,c1),*(x,c2)) -> +(...,*(x,1+c1+c2)) (c1, c2 numeric)
800         //                  same for (+,*) -> (*,^)
801
802         make_flat(v, do_index_renaming);
803         canonicalize();
804         combine_same_terms_sorted_seq();
805 }
806
807 void expairseq::construct_from_epvector(epvector &&v, bool do_index_renaming)
808 {
809         // simplifications: +(a,+(b,c),d) -> +(a,b,c,d) (associativity)
810         //                  +(d,b,c,a) -> +(a,b,c,d) (canonicalization)
811         //                  +(...,x,*(x,c1),*(x,c2)) -> +(...,*(x,1+c1+c2)) (c1, c2 numeric)
812         //                  same for (+,*) -> (*,^)
813
814         make_flat(std::move(v), do_index_renaming);
815         canonicalize();
816         combine_same_terms_sorted_seq();
817 }
818
819 /** Combine this expairseq with argument exvector.
820  *  It cares for associativity as well as for special handling of numerics. */
821 void expairseq::make_flat(const exvector &v)
822 {
823         // count number of operands which are of same expairseq derived type
824         // and their cumulative number of operands
825         int nexpairseqs = 0;
826         int noperands = 0;
827         bool do_idx_rename = false;
828         
829         for (auto & cit : v) {
830                 if (typeid(ex_to<basic>(cit)) == typeid(*this)) {
831                         ++nexpairseqs;
832                         noperands += ex_to<expairseq>(cit).seq.size();
833                 }
834                 if (is_a<mul>(*this) && (!do_idx_rename) &&
835                     cit.info(info_flags::has_indices))
836                         do_idx_rename = true;
837         }
838         
839         // reserve seq and coeffseq which will hold all operands
840         seq.reserve(v.size()+noperands-nexpairseqs);
841         
842         // copy elements and split off numerical part
843         make_flat_inserter mf(v, do_idx_rename);
844         for (auto & cit : v) {
845                 if (typeid(ex_to<basic>(cit)) == typeid(*this)) {
846                         ex newfactor = mf.handle_factor(cit, _ex1);
847                         const expairseq &subseqref = ex_to<expairseq>(newfactor);
848                         combine_overall_coeff(subseqref.overall_coeff);
849                         for (auto & cit_s : subseqref.seq) {
850                                 seq.push_back(cit_s);
851                         }
852                 } else {
853                         if (is_exactly_a<numeric>(cit))
854                                 combine_overall_coeff(cit);
855                         else {
856                                 ex newfactor = mf.handle_factor(cit, _ex1);
857                                 seq.push_back(split_ex_to_pair(newfactor));
858                         }
859                 }
860         }
861 }
862
863 /** Combine this expairseq with argument epvector.
864  *  It cares for associativity as well as for special handling of numerics. */
865 void expairseq::make_flat(const epvector &v, bool do_index_renaming)
866 {
867         // count number of operands which are of same expairseq derived type
868         // and their cumulative number of operands
869         int nexpairseqs = 0;
870         int noperands = 0;
871         bool really_need_rename_inds = false;
872         
873         for (auto & cit : v) {
874                 if (typeid(ex_to<basic>(cit.rest)) == typeid(*this)) {
875                         ++nexpairseqs;
876                         noperands += ex_to<expairseq>(cit.rest).seq.size();
877                 }
878                 if ((!really_need_rename_inds) && is_a<mul>(*this) &&
879                     cit.rest.info(info_flags::has_indices))
880                         really_need_rename_inds = true;
881         }
882         do_index_renaming = do_index_renaming && really_need_rename_inds;
883         
884         // reserve seq and coeffseq which will hold all operands
885         seq.reserve(v.size()+noperands-nexpairseqs);
886         make_flat_inserter mf(v, do_index_renaming);
887         
888         // copy elements and split off numerical part
889         for (auto & cit : v) {
890                 if (typeid(ex_to<basic>(cit.rest)) == typeid(*this) &&
891                     this->can_make_flat(cit)) {
892                         ex newrest = mf.handle_factor(cit.rest, cit.coeff);
893                         const expairseq &subseqref = ex_to<expairseq>(newrest);
894                         combine_overall_coeff(ex_to<numeric>(subseqref.overall_coeff),
895                                               ex_to<numeric>(cit.coeff));
896                         for (auto & cit_s : subseqref.seq) {
897                                 seq.push_back(expair(cit_s.rest,
898                                                      ex_to<numeric>(cit_s.coeff).mul_dyn(ex_to<numeric>(cit.coeff))));
899                         }
900                 } else {
901                         if (cit.is_canonical_numeric())
902                                 combine_overall_coeff(mf.handle_factor(cit.rest, _ex1));
903                         else {
904                                 ex rest = cit.rest;
905                                 ex newrest = mf.handle_factor(rest, cit.coeff);
906                                 if (are_ex_trivially_equal(newrest, rest))
907                                         seq.push_back(cit);
908                                 else
909                                         seq.push_back(expair(newrest, cit.coeff));
910                         }
911                 }
912         }
913 }
914
915 /** Brings this expairseq into a sorted (canonical) form. */
916 void expairseq::canonicalize()
917 {
918         std::sort(seq.begin(), seq.end(), expair_rest_is_less());
919 }
920
921
922 /** Compact a presorted expairseq by combining all matching expairs to one
923  *  each.  On an add object, this is responsible for 2*x+3*x+y -> 5*x+y, for
924  *  instance. */
925 void expairseq::combine_same_terms_sorted_seq()
926 {
927         if (seq.size()<2)
928                 return;
929
930         bool needs_further_processing = false;
931
932         auto itin1 = seq.begin();
933         auto itin2 = itin1 + 1;
934         auto itout = itin1;
935         auto last = seq.end();
936         // must_copy will be set to true the first time some combination is 
937         // possible from then on the sequence has changed and must be compacted
938         bool must_copy = false;
939         while (itin2!=last) {
940                 if (itin1->rest.compare(itin2->rest)==0) {
941                         itin1->coeff = ex_to<numeric>(itin1->coeff).
942                                        add_dyn(ex_to<numeric>(itin2->coeff));
943                         if (expair_needs_further_processing(itin1))
944                                 needs_further_processing = true;
945                         must_copy = true;
946                 } else {
947                         if (!ex_to<numeric>(itin1->coeff).is_zero()) {
948                                 if (must_copy)
949                                         *itout = *itin1;
950                                 ++itout;
951                         }
952                         itin1 = itin2;
953                 }
954                 ++itin2;
955         }
956         if (!ex_to<numeric>(itin1->coeff).is_zero()) {
957                 if (must_copy)
958                         *itout = *itin1;
959                 ++itout;
960         }
961         if (itout!=last)
962                 seq.erase(itout,last);
963
964         if (needs_further_processing) {
965                 // Clear seq and start over.
966                 epvector v = std::move(seq);
967                 construct_from_epvector(std::move(v));
968         }
969 }
970
971 /** Check if this expairseq is in sorted (canonical) form.  Useful mainly for
972  *  debugging or in assertions since being sorted is an invariance. */
973 bool expairseq::is_canonical() const
974 {
975         if (seq.size() <= 1)
976                 return 1;
977         
978         auto it = seq.begin(), itend = seq.end();
979         auto it_last = it;
980         for (++it; it!=itend; it_last=it, ++it) {
981                 if (!(it_last->is_less(*it) || it_last->is_equal(*it))) {
982                         if (!is_exactly_a<numeric>(it_last->rest) ||
983                                 !is_exactly_a<numeric>(it->rest)) {
984                                 // double test makes it easier to set a breakpoint...
985                                 if (!is_exactly_a<numeric>(it_last->rest) ||
986                                         !is_exactly_a<numeric>(it->rest)) {
987                                         printpair(std::clog, *it_last, 0);
988                                         std::clog << ">";
989                                         printpair(std::clog, *it, 0);
990                                         std::clog << "\n";
991                                         std::clog << "pair1:" << std::endl;
992                                         it_last->rest.print(print_tree(std::clog));
993                                         it_last->coeff.print(print_tree(std::clog));
994                                         std::clog << "pair2:" << std::endl;
995                                         it->rest.print(print_tree(std::clog));
996                                         it->coeff.print(print_tree(std::clog));
997                                         return 0;
998                                 }
999                         }
1000                 }
1001         }
1002         return 1;
1003 }
1004
1005 /** Member-wise expand the expairs in this sequence.
1006  *
1007  *  @see expairseq::expand()
1008  *  @return epvector containing expanded pairs, empty if no members
1009  *    had to be changed. */
1010 epvector expairseq::expandchildren(unsigned options) const
1011 {
1012         auto cit = seq.begin(), last = seq.end();
1013         while (cit!=last) {
1014                 const ex expanded_ex = cit->rest.expand(options);
1015                 if (!are_ex_trivially_equal(cit->rest,expanded_ex)) {
1016                         
1017                         // something changed, copy seq, eval and return it
1018                         epvector s;
1019                         s.reserve(seq.size());
1020                         
1021                         // copy parts of seq which are known not to have changed
1022                         s.insert(s.begin(), seq.begin(), cit);
1023
1024                         // copy first changed element
1025                         s.push_back(expair(expanded_ex, cit->coeff));
1026                         ++cit;
1027
1028                         // copy rest
1029                         while (cit != last) {
1030                                 s.push_back(expair(cit->rest.expand(options), cit->coeff));
1031                                 ++cit;
1032                         }
1033                         return s;
1034                 }
1035
1036                 ++cit;
1037         }
1038         
1039         return epvector(); // empty signalling nothing has changed
1040 }
1041
1042
1043 /** Member-wise evaluate the expairs in this sequence.
1044  *
1045  *  @see expairseq::eval()
1046  *  @return epvector containing evaluated pairs, empty if no members
1047  *    had to be changed. */
1048 epvector expairseq::evalchildren() const
1049 {
1050         auto cit = seq.begin(), last = seq.end();
1051         while (cit!=last) {
1052                 const expair evaled_pair = combine_ex_with_coeff_to_pair(cit->rest, cit->coeff);
1053                 if (unlikely(!evaled_pair.is_equal(*cit))) {
1054
1055                         // something changed: copy seq, eval and return it
1056                         epvector s;
1057                         s.reserve(seq.size());
1058
1059                         // copy parts of seq which are known not to have changed
1060                         s.insert(s.begin(), seq.begin(), cit);
1061
1062                         // copy first changed element
1063                         s.push_back(evaled_pair);
1064                         ++cit;
1065
1066                         // copy rest
1067                         while (cit != last) {
1068                                 s.push_back(combine_ex_with_coeff_to_pair(cit->rest, cit->coeff));
1069                                 ++cit;
1070                         }
1071                         return s;
1072                 }
1073
1074                 ++cit;
1075         }
1076
1077         return epvector(); // signalling nothing has changed
1078 }
1079
1080 /** Member-wise substitute in this sequence.
1081  *
1082  *  @see expairseq::subs()
1083  *  @return epvector containing expanded pairs, empty if no members
1084  *    had to be changed. */
1085 epvector expairseq::subschildren(const exmap & m, unsigned options) const
1086 {
1087         // When any of the objects to be substituted is a product or power
1088         // we have to recombine the pairs because the numeric coefficients may
1089         // be part of the search pattern.
1090         if (!(options & (subs_options::pattern_is_product | subs_options::pattern_is_not_product))) {
1091
1092                 // Search the list of substitutions and cache our findings
1093                 for (auto & it : m) {
1094                         if (is_exactly_a<mul>(it.first) || is_exactly_a<power>(it.first)) {
1095                                 options |= subs_options::pattern_is_product;
1096                                 break;
1097                         }
1098                 }
1099                 if (!(options & subs_options::pattern_is_product))
1100                         options |= subs_options::pattern_is_not_product;
1101         }
1102
1103         if (options & subs_options::pattern_is_product) {
1104
1105                 // Substitute in the recombined pairs
1106                 auto cit = seq.begin(), last = seq.end();
1107                 while (cit != last) {
1108
1109                         const ex &orig_ex = recombine_pair_to_ex(*cit);
1110                         const ex &subsed_ex = orig_ex.subs(m, options);
1111                         if (!are_ex_trivially_equal(orig_ex, subsed_ex)) {
1112
1113                                 // Something changed: copy seq, subs and return it
1114                                 epvector s;
1115                                 s.reserve(seq.size());
1116
1117                                 // Copy parts of seq which are known not to have changed
1118                                 s.insert(s.begin(), seq.begin(), cit);
1119
1120                                 // Copy first changed element
1121                                 s.push_back(split_ex_to_pair(subsed_ex));
1122                                 ++cit;
1123
1124                                 // Copy rest
1125                                 while (cit != last) {
1126                                         s.push_back(split_ex_to_pair(recombine_pair_to_ex(*cit).subs(m, options)));
1127                                         ++cit;
1128                                 }
1129                                 return s;
1130                         }
1131
1132                         ++cit;
1133                 }
1134
1135         } else {
1136
1137                 // Substitute only in the "rest" part of the pairs
1138                 auto cit = seq.begin(), last = seq.end();
1139                 while (cit != last) {
1140
1141                         const ex subsed_rest = cit->rest.subs(m, options);
1142                         const expair subsed_pair = combine_ex_with_coeff_to_pair(subsed_rest, cit->coeff);
1143                         if (!subsed_pair.is_equal(*cit)) {
1144                         
1145                                 // Something changed: copy seq, subs and return it
1146                                 epvector s;
1147                                 s.reserve(seq.size());
1148
1149                                 // Copy parts of seq which are known not to have changed
1150                                 s.insert(s.begin(), seq.begin(), cit);
1151                         
1152                                 // Copy first changed element
1153                                 s.push_back(subsed_pair);
1154                                 ++cit;
1155
1156                                 // Copy rest
1157                                 while (cit != last) {
1158                                         s.push_back(combine_ex_with_coeff_to_pair(cit->rest.subs(m, options), cit->coeff));
1159                                         ++cit;
1160                                 }
1161                                 return s;
1162                         }
1163
1164                         ++cit;
1165                 }
1166         }
1167         
1168         // Nothing has changed
1169         return epvector();
1170 }
1171
1172 //////////
1173 // static member variables
1174 //////////
1175
1176 } // namespace GiNaC