GiNaC 1.8.10
expairseq.cpp
Go to the documentation of this file.
1
5/*
6 * GiNaC Copyright (C) 1999-2026 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, see <https://www.gnu.org/licenses/>.
20 */
21
22#include "expairseq.h"
23#include "lst.h"
24#include "add.h"
25#include "mul.h"
26#include "power.h"
27#include "relational.h"
28#include "wildcard.h"
29#include "archive.h"
30#include "operators.h"
31#include "utils.h"
32#include "hash_seed.h"
33#include "indexed.h"
34#include "compiler.h"
35
36#include <algorithm>
37#include <iostream>
38#include <iterator>
39#include <memory>
40#include <stdexcept>
41#include <string>
42
43namespace GiNaC {
44
45
48 print_func<print_tree>(&expairseq::do_print_tree))
49
50
51
52// helper classes
54
55class epp_is_less
56{
57public:
58 bool operator()(const epp &lh, const epp &rh) const
59 {
60 return (*lh).is_less(*rh);
61 }
62};
63
65// default constructor
67
68// public
69
71{}
72
73// protected
74
76// other constructors
78
79expairseq::expairseq(const ex &lh, const ex &rh)
80{
83}
84
90
91expairseq::expairseq(const epvector &v, const ex &oc, bool do_index_renaming)
92 : overall_coeff(oc)
93{
94 GINAC_ASSERT(is_a<numeric>(oc));
95 construct_from_epvector(v, do_index_renaming);
97}
98
99expairseq::expairseq(epvector && vp, const ex &oc, bool do_index_renaming)
100 : overall_coeff(oc)
101{
102 GINAC_ASSERT(is_a<numeric>(oc));
103 construct_from_epvector(std::move(vp), do_index_renaming);
105}
106
108// archiving
110
112{
113 inherited::read_archive(n, sym_lst);
114 auto range = n.find_property_range("rest", "coeff");
115 seq.reserve((range.end-range.begin)/2);
116
117 for (auto loc = range.begin; loc < range.end;) {
118 ex rest;
119 ex coeff;
120 n.find_ex_by_loc(loc++, rest, sym_lst);
121 n.find_ex_by_loc(loc++, coeff, sym_lst);
122 seq.emplace_back(expair(rest, coeff));
123 }
124
125 n.find_ex("overall_coeff", overall_coeff, sym_lst);
126
127 canonicalize();
129}
130
132{
133 inherited::archive(n);
134 for (auto & i : seq) {
135 n.add_ex("rest", i.rest);
136 n.add_ex("coeff", i.coeff);
137 }
138 n.add_ex("overall_coeff", overall_coeff);
139}
140
141
143// functions overriding virtual functions from base classes
145
146// public
147
148void expairseq::do_print(const print_context & c, unsigned level) const
149{
150 c.s << "[[";
151 printseq(c, ',', precedence(), level);
152 c.s << "]]";
153}
154
155void expairseq::do_print_tree(const print_tree & c, unsigned level) const
156{
157 c.s << std::string(level, ' ') << class_name() << " @" << this
158 << std::hex << ", hash=0x" << hashvalue << ", flags=0x" << flags << std::dec
159 << ", nops=" << nops()
160 << std::endl;
161 size_t num = seq.size();
162 for (size_t i=0; i<num; ++i) {
163 seq[i].rest.print(c, level + c.delta_indent);
164 seq[i].coeff.print(c, level + c.delta_indent);
165 if (i != num - 1)
166 c.s << std::string(level + c.delta_indent, ' ') << "-----" << std::endl;
167 }
169 c.s << std::string(level + c.delta_indent, ' ') << "-----" << std::endl
170 << std::string(level + c.delta_indent, ' ') << "overall_coeff" << std::endl;
171 overall_coeff.print(c, level + c.delta_indent);
172 }
173 c.s << std::string(level + c.delta_indent,' ') << "=====" << std::endl;
174}
175
176bool expairseq::info(unsigned inf) const
177{
178 switch(inf) {
180 return (flags & status_flags::expanded);
183 return true;
185 return false;
186 for (auto & i : seq) {
187 if (i.rest.info(info_flags::has_indices)) {
188 this->setflag(status_flags::has_indices);
189 this->clearflag(status_flags::has_no_indices);
190 return true;
191 }
192 }
193 this->clearflag(status_flags::has_indices);
194 this->setflag(status_flags::has_no_indices);
195 return false;
196 }
197 }
198 return inherited::info(inf);
199}
200
201size_t expairseq::nops() const
202{
204 return seq.size();
205 else
206 return seq.size()+1;
207}
208
209ex expairseq::op(size_t i) const
210{
211 if (i < seq.size())
212 return recombine_pair_to_ex(seq[i]);
214 return overall_coeff;
215}
216
218{
219 epvector v;
220 v.reserve(seq.size()+1);
221
222 for (auto & it : seq)
223 v.push_back(split_ex_to_pair(f(recombine_pair_to_ex(it))));
224
226 return thisexpairseq(std::move(v), default_overall_coeff(), true);
227 else {
228 ex newcoeff = f(overall_coeff);
229 if(is_a<numeric>(newcoeff))
230 return thisexpairseq(std::move(v), newcoeff, true);
231 else {
232 v.push_back(split_ex_to_pair(newcoeff));
233 return thisexpairseq(std::move(v), default_overall_coeff(), true);
234 }
235 }
236}
237
240{
242 return *this;
243
244 const epvector evaled = evalchildren();
245 if (!evaled.empty())
246 return dynallocate<expairseq>(std::move(evaled), overall_coeff).setflag(status_flags::evaluated);
247 else
248 return this->hold();
249}
250
252{
253 epvector *newepv = nullptr;
254 for (auto i=epv.begin(); i!=epv.end(); ++i) {
255 if (newepv) {
256 newepv->push_back(i->conjugate());
257 continue;
258 }
259 expair x = i->conjugate();
260 if (x.is_equal(*i)) {
261 continue;
262 }
263 newepv = new epvector;
264 newepv->reserve(epv.size());
265 for (auto j=epv.begin(); j!=i; ++j) {
266 newepv->push_back(*j);
267 }
268 newepv->push_back(x);
269 }
270 return newepv;
271}
272
274{
275 std::unique_ptr<epvector> newepv(conjugateepvector(seq));
277 if (newepv) {
278 return thisexpairseq(std::move(*newepv), x);
279 }
281 return *this;
282 }
283 return thisexpairseq(seq, x);
284}
285
286bool expairseq::match(const ex & pattern, exmap & repl_lst) const
287{
288 // This differs from basic::match() because we want "a+b+c+d" to
289 // match "d+*+b" with "*" being "a+c", and we want to honor commutativity
290
291 if (typeid(*this) == typeid(ex_to<basic>(pattern))) {
292
293 // Check whether global wildcard (one that matches the "rest of the
294 // expression", like "*" above) is present
295 bool has_global_wildcard = false;
296 ex global_wildcard;
297 for (size_t i=0; i<pattern.nops(); i++) {
298 if (is_exactly_a<wildcard>(pattern.op(i))) {
299 has_global_wildcard = true;
300 global_wildcard = pattern.op(i);
301 break;
302 }
303 }
304
305 // Even if the expression does not match the pattern, some of
306 // its subexpressions could match it. For example, x^5*y^(-1)
307 // does not match the pattern $0^5, but its subexpression x^5
308 // does. So, save repl_lst in order to not add bogus entries.
309 exmap tmp_repl = repl_lst;
310
311 // Unfortunately, this is an O(N^2) operation because we can't
312 // sort the pattern in a useful way...
313
314 // Chop into terms
315 exvector ops;
316 ops.reserve(nops());
317 for (size_t i=0; i<nops(); i++)
318 ops.push_back(op(i));
319
320 // Now, for every term of the pattern, look for a matching term in
321 // the expression and remove the match
322 for (size_t i=0; i<pattern.nops(); i++) {
323 ex p = pattern.op(i);
324 if (has_global_wildcard && p.is_equal(global_wildcard))
325 continue;
326 auto it = ops.begin(), itend = ops.end();
327 while (it != itend) {
328 if (it->match(p, tmp_repl)) {
329 ops.erase(it);
330 goto found;
331 }
332 ++it;
333 }
334 return false; // no match found
335found: ;
336 }
337
338 if (has_global_wildcard) {
339
340 // Assign all the remaining terms to the global wildcard (unless
341 // it has already been matched before, in which case the matches
342 // must be equal)
343 size_t num = ops.size();
344 epvector vp;
345 vp.reserve(num);
346 for (size_t i=0; i<num; i++)
347 vp.push_back(split_ex_to_pair(ops[i]));
348 ex rest = thisexpairseq(std::move(vp), default_overall_coeff());
349 for (auto & it : tmp_repl) {
350 if (it.first.is_equal(global_wildcard)) {
351 if (rest.is_equal(it.second)) {
352 repl_lst = tmp_repl;
353 return true;
354 }
355 return false;
356 }
357 }
358 repl_lst = tmp_repl;
359 repl_lst[global_wildcard] = rest;
360 return true;
361
362 } else {
363
364 // No global wildcard, then the match fails if there are any
365 // unmatched terms left
366 if (ops.empty()) {
367 repl_lst = tmp_repl;
368 return true;
369 }
370 return false;
371 }
372 }
373 return inherited::match(pattern, repl_lst);
374}
375
376ex expairseq::subs(const exmap & m, unsigned options) const
377{
378 epvector subsed = subschildren(m, options);
379 if (!subsed.empty())
380 return ex_to<basic>(thisexpairseq(std::move(subsed), overall_coeff, (options & subs_options::no_index_renaming) == 0));
381 else if ((options & subs_options::algebraic) && is_exactly_a<mul>(*this))
382 return static_cast<const mul *>(this)->algebraic_subs_mul(m, options);
383 else
384 return subs_one_level(m, options);
385}
386
387// protected
388
389int expairseq::compare_same_type(const basic &other) const
390{
391 GINAC_ASSERT(is_a<expairseq>(other));
392 const expairseq &o = static_cast<const expairseq &>(other);
393
394 int cmpval;
395
396 // compare number of elements
397 if (seq.size() != o.seq.size())
398 return (seq.size()<o.seq.size()) ? -1 : 1;
399
400 // compare overall_coeff
402 if (cmpval!=0)
403 return cmpval;
404
405 auto cit1 = seq.begin(), last1 = seq.end();
406 auto cit2 = o.seq.begin(), last2 = o.seq.end();
407 for (; (cit1!=last1) && (cit2!=last2); ++cit1, ++cit2) {
408 cmpval = (*cit1).compare(*cit2);
409 if (cmpval!=0) return cmpval;
410 }
411
412 GINAC_ASSERT(cit1==last1);
413 GINAC_ASSERT(cit2==last2);
414
415 return 0;
416}
417
418bool expairseq::is_equal_same_type(const basic &other) const
419{
420 const expairseq &o = static_cast<const expairseq &>(other);
421
422 // compare number of elements
423 if (seq.size()!=o.seq.size())
424 return false;
425
426 // compare overall_coeff
428 return false;
429
430 auto cit2 = o.seq.begin();
431 for (auto & cit1 : seq) {
432 if (!cit1.is_equal(*cit2))
433 return false;
434 ++cit2;
435 }
436
437 return true;
438}
439
444
445unsigned expairseq::calchash() const
446{
447 unsigned v = make_hash_seed(typeid(*this));
448 for (auto & i : seq) {
449 v ^= i.rest.gethash();
450 v = rotate_left(v);
451 v ^= i.coeff.gethash();
452 }
453
454 v ^= overall_coeff.gethash();
455
456 // store calculated hash value only if object is already evaluated
459 hashvalue = v;
460 }
461
462 return v;
463}
464
466{
467 epvector expanded = expandchildren(options);
468 if (!expanded.empty()) {
469 return thisexpairseq(std::move(expanded), overall_coeff);
470 }
471 return (options == 0) ? setflag(status_flags::expanded) : *this;
472}
473
475// new virtual functions which can be overridden by derived classes
477
478// protected
479
488ex expairseq::thisexpairseq(const epvector &v, const ex &oc, bool do_index_renaming) const
489{
490 return expairseq(v, oc, do_index_renaming);
491}
492
493ex expairseq::thisexpairseq(epvector && vp, const ex &oc, bool do_index_renaming) const
494{
495 return expairseq(std::move(vp), oc, do_index_renaming);
496}
497
498void expairseq::printpair(const print_context & c, const expair & p, unsigned upper_precedence) const
499{
500 c.s << "[[";
501 p.rest.print(c, precedence());
502 c.s << ",";
503 p.coeff.print(c, precedence());
504 c.s << "]]";
505}
506
507void expairseq::printseq(const print_context & c, char delim,
508 unsigned this_precedence,
509 unsigned upper_precedence) const
510{
511 if (this_precedence <= upper_precedence)
512 c.s << "(";
513 auto it = seq.begin(), it_last = seq.end() - 1;
514 for (; it!=it_last; ++it) {
515 printpair(c, *it, this_precedence);
516 c.s << delim;
517 }
518 printpair(c, *it, this_precedence);
520 c.s << delim;
521 overall_coeff.print(c, this_precedence);
522 }
523
524 if (this_precedence <= upper_precedence)
525 c.s << ")";
526}
527
528
532{
533 return expair(e,_ex1);
534}
535
536
538 const ex &c) const
539{
540 GINAC_ASSERT(is_exactly_a<numeric>(c));
541
542 return expair(e,c);
543}
544
545
547 const ex &c) const
548{
549 GINAC_ASSERT(is_exactly_a<numeric>(p.coeff));
550 GINAC_ASSERT(is_exactly_a<numeric>(c));
551
552 return expair(p.rest,ex_to<numeric>(p.coeff).mul_dyn(ex_to<numeric>(c)));
553}
554
555
559{
560 return lst{p.rest, p.coeff};
561}
562
564{
565 if (is_exactly_a<numeric>(it->rest) &&
566 it->coeff.is_equal(_ex1)) {
567 // the pair {<n>, 1} has yet to be absorbed into overall_coeff
568 return true;
569 }
570 return false;
571}
572
574{
575 return _ex0;
576}
577
579{
580 GINAC_ASSERT(is_exactly_a<numeric>(overall_coeff));
581 GINAC_ASSERT(is_exactly_a<numeric>(c));
582 overall_coeff = ex_to<numeric>(overall_coeff).add_dyn(ex_to<numeric>(c));
583}
584
585void expairseq::combine_overall_coeff(const ex &c1, const ex &c2)
586{
587 GINAC_ASSERT(is_exactly_a<numeric>(overall_coeff));
588 GINAC_ASSERT(is_exactly_a<numeric>(c1));
589 GINAC_ASSERT(is_exactly_a<numeric>(c2));
590 overall_coeff = ex_to<numeric>(overall_coeff).
591 add_dyn(ex_to<numeric>(c1).mul(ex_to<numeric>(c2)));
592}
593
595{
596 return true;
597}
598
599
601// non-virtual functions in this class
603
604void expairseq::construct_from_2_ex(const ex &lh, const ex &rh)
605{
606 const std::type_info& typeid_this = typeid(*this);
607 if (typeid(ex_to<basic>(lh)) == typeid_this) {
608 if (typeid(ex_to<basic>(rh)) == typeid_this) {
609 if (is_a<mul>(lh) && lh.info(info_flags::has_indices) &&
611 ex newrh=rename_dummy_indices_uniquely(lh, rh);
612 construct_from_2_expairseq(ex_to<expairseq>(lh),
613 ex_to<expairseq>(newrh));
614 }
615 else
616 construct_from_2_expairseq(ex_to<expairseq>(lh),
617 ex_to<expairseq>(rh));
618 return;
619 } else {
620 construct_from_expairseq_ex(ex_to<expairseq>(lh), rh);
621 return;
622 }
623 } else if (typeid(ex_to<basic>(rh)) == typeid_this) {
624 construct_from_expairseq_ex(ex_to<expairseq>(rh),lh);
625 return;
626 }
627
628 if (is_exactly_a<numeric>(lh)) {
629 if (is_exactly_a<numeric>(rh)) {
632 } else {
634 seq.push_back(split_ex_to_pair(rh));
635 }
636 } else {
637 if (is_exactly_a<numeric>(rh)) {
639 seq.push_back(split_ex_to_pair(lh));
640 } else {
641 expair p1 = split_ex_to_pair(lh);
642 expair p2 = split_ex_to_pair(rh);
643
644 int cmpval = p1.rest.compare(p2.rest);
645 if (cmpval==0) {
646 p1.coeff = ex_to<numeric>(p1.coeff).add_dyn(ex_to<numeric>(p2.coeff));
647 if (!ex_to<numeric>(p1.coeff).is_zero()) {
648 // no further processing is necessary, since this
649 // one element will usually be recombined in eval()
650 seq.push_back(p1);
651 }
652 } else {
653 seq.reserve(2);
654 if (cmpval<0) {
655 seq.push_back(p1);
656 seq.push_back(p2);
657 } else {
658 seq.push_back(p2);
659 seq.push_back(p1);
660 }
661 }
662 }
663 }
664}
665
667 const expairseq &s2)
668{
671
672 auto first1 = s1.seq.begin(), last1 = s1.seq.end();
673 auto first2 = s2.seq.begin(), last2 = s2.seq.end();
674
675 seq.reserve(s1.seq.size()+s2.seq.size());
676
677 bool needs_further_processing=false;
678
679 while (first1!=last1 && first2!=last2) {
680 int cmpval = (*first1).rest.compare((*first2).rest);
681
682 if (cmpval==0) {
683 // combine terms
684 const numeric &newcoeff = ex_to<numeric>(first1->coeff).
685 add(ex_to<numeric>(first2->coeff));
686 if (!newcoeff.is_zero()) {
687 seq.push_back(expair(first1->rest,newcoeff));
689 needs_further_processing = true;
690 }
691 }
692 ++first1;
693 ++first2;
694 } else if (cmpval<0) {
695 seq.push_back(*first1);
696 ++first1;
697 } else {
698 seq.push_back(*first2);
699 ++first2;
700 }
701 }
702
703 while (first1!=last1) {
704 seq.push_back(*first1);
705 ++first1;
706 }
707 while (first2!=last2) {
708 seq.push_back(*first2);
709 ++first2;
710 }
711
712 if (needs_further_processing) {
713 // Clear seq and start over.
714 epvector v = std::move(seq);
715 construct_from_epvector(std::move(v));
716 }
717}
718
720 const ex &e)
721{
723 if (is_exactly_a<numeric>(e)) {
725 seq = s.seq;
726 return;
727 }
728
729 auto first = s.seq.begin(), last = s.seq.end();
731
732 seq.reserve(s.seq.size()+1);
733 bool p_pushed = false;
734
735 bool needs_further_processing=false;
736
737 // merge p into s.seq
738 while (first!=last) {
739 int cmpval = (*first).rest.compare(p.rest);
740 if (cmpval==0) {
741 // combine terms
742 const numeric &newcoeff = ex_to<numeric>(first->coeff).
743 add(ex_to<numeric>(p.coeff));
744 if (!newcoeff.is_zero()) {
745 seq.push_back(expair(first->rest,newcoeff));
747 needs_further_processing = true;
748 }
749 ++first;
750 p_pushed = true;
751 break;
752 } else if (cmpval<0) {
753 seq.push_back(*first);
754 ++first;
755 } else {
756 seq.push_back(p);
757 p_pushed = true;
758 break;
759 }
760 }
761
762 if (p_pushed) {
763 // while loop exited because p was pushed, now push rest of s.seq
764 while (first!=last) {
765 seq.push_back(*first);
766 ++first;
767 }
768 } else {
769 // while loop exited because s.seq was pushed, now push p
770 seq.push_back(p);
771 }
772
773 if (needs_further_processing) {
774 // Clear seq and start over.
775 epvector v = std::move(seq);
776 construct_from_epvector(std::move(v));
777 }
778}
779
781{
782 // simplifications: +(a,+(b,c),d) -> +(a,b,c,d) (associativity)
783 // +(d,b,c,a) -> +(a,b,c,d) (canonicalization)
784 // +(...,x,*(x,c1),*(x,c2)) -> +(...,*(x,1+c1+c2)) (c1, c2 numeric)
785 // (same for (+,*) -> (*,^)
786
787 make_flat(v);
788 canonicalize();
790}
791
792void expairseq::construct_from_epvector(const epvector &v, bool do_index_renaming)
793{
794 // simplifications: +(a,+(b,c),d) -> +(a,b,c,d) (associativity)
795 // +(d,b,c,a) -> +(a,b,c,d) (canonicalization)
796 // +(...,x,*(x,c1),*(x,c2)) -> +(...,*(x,1+c1+c2)) (c1, c2 numeric)
797 // same for (+,*) -> (*,^)
798
799 make_flat(v, do_index_renaming);
800 canonicalize();
802}
803
804void expairseq::construct_from_epvector(epvector &&v, bool do_index_renaming)
805{
806 // simplifications: +(a,+(b,c),d) -> +(a,b,c,d) (associativity)
807 // +(d,b,c,a) -> +(a,b,c,d) (canonicalization)
808 // +(...,x,*(x,c1),*(x,c2)) -> +(...,*(x,1+c1+c2)) (c1, c2 numeric)
809 // same for (+,*) -> (*,^)
810
811 make_flat(std::move(v), do_index_renaming);
812 canonicalize();
814}
815
819{
820 // count number of operands which are of same expairseq derived type
821 // and their cumulative number of operands
822 int nexpairseqs = 0;
823 int noperands = 0;
824 bool do_idx_rename = false;
825
826 const std::type_info& typeid_this = typeid(*this);
827 for (auto & cit : v) {
828 if (typeid(ex_to<basic>(cit)) == typeid_this) {
829 ++nexpairseqs;
830 noperands += ex_to<expairseq>(cit).seq.size();
831 }
832 if (is_a<mul>(*this) && (!do_idx_rename) &&
833 cit.info(info_flags::has_indices))
834 do_idx_rename = true;
835 }
836
837 // reserve seq and coeffseq which will hold all operands
838 seq.reserve(v.size()+noperands-nexpairseqs);
839
840 // copy elements and split off numerical part
841 make_flat_inserter mf(v, do_idx_rename);
842 for (auto & cit : v) {
843 if (typeid(ex_to<basic>(cit)) == typeid_this) {
844 ex newfactor = mf.handle_factor(cit, _ex1);
845 const expairseq &subseqref = ex_to<expairseq>(newfactor);
847 for (auto & cit_s : subseqref.seq) {
848 seq.push_back(cit_s);
849 }
850 } else {
851 if (is_exactly_a<numeric>(cit))
853 else {
854 ex newfactor = mf.handle_factor(cit, _ex1);
855 seq.push_back(split_ex_to_pair(newfactor));
856 }
857 }
858 }
859}
860
863void expairseq::make_flat(const epvector &v, bool do_index_renaming)
864{
865 // count number of operands which are of same expairseq derived type
866 // and their cumulative number of operands
867 int nexpairseqs = 0;
868 int noperands = 0;
869 bool really_need_rename_inds = false;
870
871 const std::type_info& typeid_this = typeid(*this);
872 for (auto & cit : v) {
873 if (typeid(ex_to<basic>(cit.rest)) == typeid_this) {
874 ++nexpairseqs;
875 noperands += ex_to<expairseq>(cit.rest).seq.size();
876 }
877 if ((!really_need_rename_inds) && is_a<mul>(*this) &&
878 cit.rest.info(info_flags::has_indices))
879 really_need_rename_inds = true;
880 }
881 do_index_renaming = do_index_renaming && really_need_rename_inds;
882
883 // reserve seq and coeffseq which will hold all operands
884 seq.reserve(v.size()+noperands-nexpairseqs);
885 make_flat_inserter mf(v, do_index_renaming);
886
887 // copy elements and split off numerical part
888 for (auto & cit : v) {
889 if (typeid(ex_to<basic>(cit.rest)) == typeid_this &&
890 this->can_make_flat(cit)) {
891 ex newrest = mf.handle_factor(cit.rest, cit.coeff);
892 const expairseq &subseqref = ex_to<expairseq>(newrest);
894 for (auto & cit_s : subseqref.seq) {
895 seq.push_back(expair(cit_s.rest,
896 ex_to<numeric>(cit_s.coeff).mul_dyn(ex_to<numeric>(cit.coeff))));
897 }
898 } else {
899 if (cit.is_canonical_numeric())
901 else {
902 ex rest = cit.rest;
903 ex newrest = mf.handle_factor(rest, cit.coeff);
904 if (are_ex_trivially_equal(newrest, rest))
905 seq.push_back(cit);
906 else
907 seq.push_back(expair(newrest, cit.coeff));
908 }
909 }
910 }
911}
912
915{
916 std::sort(seq.begin(), seq.end(), expair_rest_is_less());
917}
918
919
924{
925 if (seq.size()<2)
926 return;
927
928 bool needs_further_processing = false;
929
930 auto itin1 = seq.begin();
931 auto itin2 = itin1 + 1;
932 auto itout = itin1;
933 auto last = seq.end();
934 // must_copy will be set to true the first time some combination is
935 // possible from then on the sequence has changed and must be compacted
936 bool must_copy = false;
937 while (itin2!=last) {
938 if (itin1->rest.compare(itin2->rest)==0) {
939 itin1->coeff = ex_to<numeric>(itin1->coeff).
940 add_dyn(ex_to<numeric>(itin2->coeff));
942 needs_further_processing = true;
943 must_copy = true;
944 } else {
945 if (!ex_to<numeric>(itin1->coeff).is_zero()) {
946 if (must_copy)
947 *itout = *itin1;
948 ++itout;
949 }
950 itin1 = itin2;
951 }
952 ++itin2;
953 }
954 if (!ex_to<numeric>(itin1->coeff).is_zero()) {
955 if (must_copy)
956 *itout = *itin1;
957 ++itout;
958 }
959 if (itout!=last)
960 seq.erase(itout,last);
961
962 if (needs_further_processing) {
963 // Clear seq and start over.
964 epvector v = std::move(seq);
965 construct_from_epvector(std::move(v));
966 }
967}
968
972{
973 if (seq.size() <= 1)
974 return 1;
975
976 auto it = seq.begin(), itend = seq.end();
977 auto it_last = it;
978 for (++it; it!=itend; it_last=it, ++it) {
979 if (!(it_last->is_less(*it) || it_last->is_equal(*it))) {
980 if (!is_exactly_a<numeric>(it_last->rest) ||
981 !is_exactly_a<numeric>(it->rest)) {
982 // double test makes it easier to set a breakpoint...
983 if (!is_exactly_a<numeric>(it_last->rest) ||
984 !is_exactly_a<numeric>(it->rest)) {
985 printpair(std::clog, *it_last, 0);
986 std::clog << ">";
987 printpair(std::clog, *it, 0);
988 std::clog << "\n";
989 std::clog << "pair1:" << std::endl;
990 it_last->rest.print(print_tree(std::clog));
991 it_last->coeff.print(print_tree(std::clog));
992 std::clog << "pair2:" << std::endl;
993 it->rest.print(print_tree(std::clog));
994 it->coeff.print(print_tree(std::clog));
995 return 0;
996 }
997 }
998 }
999 }
1000 return 1;
1001}
1002
1009{
1010 auto cit = seq.begin(), last = seq.end();
1011 while (cit!=last) {
1012 const ex expanded_ex = cit->rest.expand(options);
1013 if (!are_ex_trivially_equal(cit->rest,expanded_ex)) {
1014
1015 // something changed, copy seq, eval and return it
1016 epvector s;
1017 s.reserve(seq.size());
1018
1019 // copy parts of seq which are known not to have changed
1020 s.insert(s.begin(), seq.begin(), cit);
1021
1022 // copy first changed element
1023 s.push_back(expair(expanded_ex, cit->coeff));
1024 ++cit;
1025
1026 // copy rest
1027 while (cit != last) {
1028 s.push_back(expair(cit->rest.expand(options), cit->coeff));
1029 ++cit;
1030 }
1031 return s;
1032 }
1033
1034 ++cit;
1035 }
1036
1037 return epvector(); // empty signalling nothing has changed
1038}
1039
1040
1047{
1048 auto cit = seq.begin(), last = seq.end();
1049 while (cit!=last) {
1050 const expair evaled_pair = combine_ex_with_coeff_to_pair(cit->rest, cit->coeff);
1051 if (unlikely(!evaled_pair.is_equal(*cit))) {
1052
1053 // something changed: copy seq, eval and return it
1054 epvector s;
1055 s.reserve(seq.size());
1056
1057 // copy parts of seq which are known not to have changed
1058 s.insert(s.begin(), seq.begin(), cit);
1059
1060 // copy first changed element
1061 s.push_back(evaled_pair);
1062 ++cit;
1063
1064 // copy rest
1065 while (cit != last) {
1066 s.push_back(combine_ex_with_coeff_to_pair(cit->rest, cit->coeff));
1067 ++cit;
1068 }
1069 return s;
1070 }
1071
1072 ++cit;
1073 }
1074
1075 return epvector(); // signalling nothing has changed
1076}
1077
1084{
1085 // When any of the objects to be substituted is a product or power
1086 // we have to recombine the pairs because the numeric coefficients may
1087 // be part of the search pattern.
1089
1090 // Search the list of substitutions and cache our findings
1091 for (auto & it : m) {
1092 if (is_exactly_a<mul>(it.first) || is_exactly_a<power>(it.first)) {
1094 break;
1095 }
1096 }
1099 }
1100
1102
1103 // Substitute in the recombined pairs
1104 auto cit = seq.begin(), last = seq.end();
1105 while (cit != last) {
1106
1107 const ex &orig_ex = recombine_pair_to_ex(*cit);
1108 const ex &subsed_ex = orig_ex.subs(m, options);
1109 if (!are_ex_trivially_equal(orig_ex, subsed_ex)) {
1110
1111 // Something changed: copy seq, subs and return it
1112 epvector s;
1113 s.reserve(seq.size());
1114
1115 // Copy parts of seq which are known not to have changed
1116 s.insert(s.begin(), seq.begin(), cit);
1117
1118 // Copy first changed element
1119 s.push_back(split_ex_to_pair(subsed_ex));
1120 ++cit;
1121
1122 // Copy rest
1123 while (cit != last) {
1124 s.push_back(split_ex_to_pair(recombine_pair_to_ex(*cit).subs(m, options)));
1125 ++cit;
1126 }
1127 return s;
1128 }
1129
1130 ++cit;
1131 }
1132
1133 } else {
1134
1135 // Substitute only in the "rest" part of the pairs
1136 auto cit = seq.begin(), last = seq.end();
1137 while (cit != last) {
1138
1139 const ex subsed_rest = cit->rest.subs(m, options);
1140 const expair subsed_pair = combine_ex_with_coeff_to_pair(subsed_rest, cit->coeff);
1141 if (!subsed_pair.is_equal(*cit)) {
1142
1143 // Something changed: copy seq, subs and return it
1144 epvector s;
1145 s.reserve(seq.size());
1146
1147 // Copy parts of seq which are known not to have changed
1148 s.insert(s.begin(), seq.begin(), cit);
1149
1150 // Copy first changed element
1151 s.push_back(subsed_pair);
1152 ++cit;
1153
1154 // Copy rest
1155 while (cit != last) {
1156 s.push_back(combine_ex_with_coeff_to_pair(cit->rest.subs(m, options), cit->coeff));
1157 ++cit;
1158 }
1159 return s;
1160 }
1161
1162 ++cit;
1163 }
1164 }
1165
1166 // Nothing has changed
1167 return epvector();
1168}
1169
1171// static member variables
1173
1174} // namespace GiNaC
Interface to GiNaC's sums of expressions.
Archiving of GiNaC expressions.
#define GINAC_ASSERT(X)
Assertion macro for checking invariances.
Definition assertion.h:32
Sum of expressions.
Definition add.h:31
This class stores all properties needed to record/retrieve the state of one object of class basic (or...
Definition archive.h:48
This class is the ABC (abstract base class) of GiNaC's class hierarchy.
Definition basic.h:104
const basic & clearflag(unsigned f) const
Clear some status_flags.
Definition basic.h:290
const basic & setflag(unsigned f) const
Set some status_flags.
Definition basic.h:287
unsigned hashvalue
hash value
Definition basic.h:302
unsigned flags
of type status_flags
Definition basic.h:301
ex subs_one_level(const exmap &m, unsigned options) const
Helper function for subs().
Definition basic.cpp:584
const basic & hold() const
Stop further evaluation.
Definition basic.cpp:886
virtual int compare_same_type(const basic &other) const
Returns order relation between two objects of same type.
Definition basic.cpp:718
virtual ex coeff(const ex &s, int n=1) const
Return coefficient of degree n in object s.
Definition basic.cpp:336
Wrapper template for making GiNaC classes out of STL containers.
Definition container.h:72
Lightweight wrapper for GiNaC's symbolic objects.
Definition ex.h:72
unsigned gethash() const
Definition ex.h:233
const_iterator begin() const noexcept
Definition ex.h:662
ex expand(unsigned options=0) const
Expand an expression.
Definition ex.cpp:73
bool is_equal(const ex &other) const
Definition ex.h:345
ex conjugate() const
Definition ex.h:146
size_t nops() const
Definition ex.h:135
ex subs(const exmap &m, unsigned options=0) const
Definition ex.h:841
bool info(unsigned inf) const
Definition ex.h:132
int compare(const ex &other) const
Definition ex.h:322
void print(const print_context &c, unsigned level=0) const
Print expression to stream.
Definition ex.cpp:54
ex op(size_t i) const
Definition ex.h:136
ex coeff(const ex &s, int n=1) const
Definition ex.h:175
A pair of expressions.
Definition expair.h:37
ex rest
first member of pair, an arbitrary expression
Definition expair.h:89
ex coeff
second member of pair, must be numeric
Definition expair.h:90
bool is_equal(const expair &other) const
Member-wise check for canonical ordering equality.
Definition expair.h:48
A sequence of class expair.
Definition expairseq.h:49
ex eval() const override
Perform coefficient-wise automatic term rewriting rules in this class.
epvector subschildren(const exmap &m, unsigned options=0) const
Member-wise substitute in this sequence.
void combine_same_terms_sorted_seq()
Compact a presorted expairseq by combining all matching expairs to one each.
size_t nops() const override
Number of operands/members.
bool is_equal_same_type(const basic &other) const override
Returns true if two objects of same type are equal.
expairseq(const ex &lh, const ex &rh)
Definition expairseq.cpp:79
virtual bool expair_needs_further_processing(epp it)
ex conjugate() const override
void construct_from_2_expairseq(const expairseq &s1, const expairseq &s2)
bool match(const ex &pattern, exmap &repl_lst) const override
Check whether the expression matches a given pattern.
ex subs(const exmap &m, unsigned options=0) const override
Substitute a set of objects by arbitrary expressions.
unsigned return_type() const override
void construct_from_epvector(const epvector &v, bool do_index_renaming=false)
void construct_from_2_ex(const ex &lh, const ex &rh)
virtual ex default_overall_coeff() const
void archive(archive_node &n) const override
Save (serialize) the object into archive node.
virtual void printpair(const print_context &c, const expair &p, unsigned upper_precedence) const
bool is_canonical() const
Check if this expairseq is in sorted (canonical) form.
unsigned precedence() const override
Return relative operator precedence (for parenthezing output).
Definition expairseq.h:61
virtual ex thisexpairseq(const epvector &v, const ex &oc, bool do_index_renaming=false) const
Create an object of this type.
virtual expair combine_pair_with_coeff_to_pair(const expair &p, const ex &c) const
bool info(unsigned inf) const override
Information about the object.
void construct_from_exvector(const exvector &v)
void read_archive(const archive_node &n, lst &syms) override
Load (deserialize) the object from an archive node.
virtual expair combine_ex_with_coeff_to_pair(const ex &e, const ex &c) const
void make_flat(const exvector &v)
Combine this expairseq with argument exvector.
virtual void printseq(const print_context &c, char delim, unsigned this_precedence, unsigned upper_precedence) const
virtual bool can_make_flat(const expair &p) const
ex expand(unsigned options=0) const override
Expand expression, i.e.
void construct_from_expairseq_ex(const expairseq &s, const ex &e)
void do_print(const print_context &c, unsigned level) const
epvector evalchildren() const
Member-wise evaluate the expairs in this sequence.
ex op(size_t i) const override
Return operand/member at position i.
virtual ex recombine_pair_to_ex(const expair &p) const
Form an ex out of an expair, using the corresponding semantics.
void do_print_tree(const print_tree &c, unsigned level) const
virtual void combine_overall_coeff(const ex &c)
ex map(map_function &f) const override
Construct new expression by applying the specified function to all sub-expressions (one level only,...
epvector expandchildren(unsigned options) const
Member-wise expand the expairs in this sequence.
void canonicalize()
Brings this expairseq into a sorted (canonical) form.
unsigned calchash() const override
Compute the hash value of an object and if it makes sense to store it in the objects status_flags,...
virtual expair split_ex_to_pair(const ex &e) const
Form an expair from an ex, using the corresponding semantics.
Class to handle the renaming of dummy indices.
Definition expairseq.h:135
ex handle_factor(const ex &x, const ex &coeff)
Definition expairseq.h:152
Product of expressions.
Definition mul.h:31
This class is a wrapper around CLN-numbers within the GiNaC class hierarchy.
Definition numeric.h:81
bool is_zero() const
True if object is zero.
Definition numeric.cpp:1128
Base class for print_contexts.
Definition print.h:101
Context for tree-like output for debugging.
Definition print.h:145
@ expanded
.expand(0) has already done its job (other expand() options ignore this flag)
Definition flags.h:203
@ evaluated
.eval() has already done its job
Definition flags.h:202
@ hash_calculated
.calchash() has already done its job
Definition flags.h:204
@ pattern_is_not_product
used internally by expairseq::subschildren()
Definition flags.h:55
@ pattern_is_product
used internally by expairseq::subschildren()
Definition flags.h:54
@ algebraic
enable algebraic substitutions
Definition flags.h:52
Definition of optimizing macros.
#define unlikely(cond)
Definition compiler.h:30
Interface to sequences of expression pairs.
unsigned options
Definition factor.cpp:2473
size_t n
Definition factor.cpp:1431
size_t c
Definition factor.cpp:756
ex x
Definition factor.cpp:1609
mvec m
Definition factor.cpp:757
size_t last
Definition factor.cpp:1433
Type-specific hash seed.
Interface to GiNaC's indexed expressions.
Definition of GiNaC's lst.
Interface to GiNaC's products of expressions.
Definition add.cpp:35
std::map< ex, ex, ex_is_less > exmap
Definition basic.h:49
std::vector< expair > epvector
expair-vector
Definition expairseq.h:32
epvector * conjugateepvector(const epvector &epv)
Complex conjugate every element of an epvector.
const ex _ex1
Definition utils.cpp:384
bool are_ex_trivially_equal(const ex &e1, const ex &e2)
Compare two objects of class quickly without doing a deep tree traversal.
Definition ex.h:699
print_func< print_context >(&varidx::do_print). print_func< print_latex >(&varidx
Definition idx.cpp:43
static unsigned make_hash_seed(const std::type_info &tinfo)
We need a hash function which gives different values for objects of different types.
Definition hash_seed.h:36
unsigned rotate_left(unsigned n)
Rotate bits of unsigned value by one bit to the left.
Definition utils.h:47
epvector::iterator epp
expair-vector pointer
Definition expairseq.h:33
lst rename_dummy_indices_uniquely(const exvector &va, const exvector &vb)
Similar to above, where va and vb are the same and the return value is a list of two lists for substi...
Definition indexed.cpp:1460
const ex _ex0
Definition utils.cpp:368
std::vector< ex > exvector
Definition basic.h:47
Interface to GiNaC's overloaded operators.
Interface to GiNaC's symbolic exponentiation (basis^exponent).
#define GINAC_IMPLEMENT_REGISTERED_CLASS_OPT(classname, supername, options)
Macro for inclusion in the implementation of each registered class.
Definition registrar.h:183
Interface to relations between expressions.
Function object not caring about the numerical coefficients for insertion into third argument of STL'...
Definition expair.h:102
Function object for map().
Definition basic.h:84
Interface to several small and furry utilities needed within GiNaC but not of any interest to the use...
Interface to GiNaC's wildcard objects.

This page is part of the GiNaC developer's reference. It was generated automatically by doxygen. For an introduction, see the tutorial.