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