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