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