59 bool operator()(
const epp &lh,
const epp &rh)
const 61 return (*lh).is_less(*rh);
96 construct_from_epvector(v, do_index_renaming);
100 expairseq::expairseq(
epvector && vp,
const ex &oc,
bool do_index_renaming)
104 construct_from_epvector(std::move(vp), do_index_renaming);
112 void expairseq::read_archive(
const archive_node &
n,
lst &sym_lst)
114 inherited::read_archive(
n, sym_lst);
115 auto range =
n.find_property_range(
"rest",
"coeff");
116 seq.reserve((range.end-range.begin)/2);
118 for (
auto loc = range.begin; loc < range.end;) {
121 n.find_ex_by_loc(loc++, rest, sym_lst);
122 n.find_ex_by_loc(loc++,
coeff, sym_lst);
123 seq.emplace_back(expair(rest,
coeff));
126 n.find_ex(
"overall_coeff", overall_coeff, sym_lst);
132 void expairseq::archive(archive_node &
n)
const 134 inherited::archive(
n);
135 for (
auto & i : seq) {
136 n.add_ex(
"rest", i.rest);
137 n.add_ex(
"coeff", i.coeff);
139 n.add_ex(
"overall_coeff", overall_coeff);
149 void expairseq::do_print(
const print_context &
c,
unsigned level)
const 152 printseq(
c,
',', precedence(), level);
156 void expairseq::do_print_tree(
const print_tree &
c,
unsigned level)
const 158 c.s << std::string(level,
' ') << class_name() <<
" @" <<
this 159 << std::hex <<
", hash=0x" << hashvalue <<
", flags=0x" << flags << std::dec
160 <<
", nops=" <<
nops()
162 size_t num = seq.size();
163 for (
size_t i=0; i<num; ++i) {
164 seq[i].rest.print(
c, level +
c.delta_indent);
165 seq[i].coeff.print(
c, level +
c.delta_indent);
167 c.s << std::string(level +
c.delta_indent,
' ') <<
"-----" << std::endl;
169 if (!overall_coeff.is_equal(default_overall_coeff())) {
170 c.s << std::string(level +
c.delta_indent,
' ') <<
"-----" << std::endl
171 << std::string(level +
c.delta_indent,
' ') <<
"overall_coeff" << std::endl;
172 overall_coeff.print(
c, level +
c.delta_indent);
174 c.s << std::string(level +
c.delta_indent,
' ') <<
"=====" << std::endl;
177 bool expairseq::info(
unsigned inf)
const 180 case info_flags::expanded:
181 return (flags & status_flags::expanded);
182 case info_flags::has_indices: {
183 if (flags & status_flags::has_indices)
185 else if (flags & status_flags::has_no_indices)
187 for (
auto & i : seq) {
188 if (i.rest.info(info_flags::has_indices)) {
189 this->setflag(status_flags::has_indices);
190 this->clearflag(status_flags::has_no_indices);
194 this->clearflag(status_flags::has_indices);
195 this->setflag(status_flags::has_no_indices);
199 return inherited::info(inf);
204 if (overall_coeff.is_equal(default_overall_coeff()))
213 return recombine_pair_to_ex(seq[i]);
214 GINAC_ASSERT(!overall_coeff.is_equal(default_overall_coeff()));
215 return overall_coeff;
218 ex expairseq::map(map_function &f)
const 221 v.reserve(seq.size()+1);
223 for (
auto & it : seq)
224 v.push_back(split_ex_to_pair(f(recombine_pair_to_ex(it))));
226 if (overall_coeff.is_equal(default_overall_coeff()))
227 return thisexpairseq(std::move(v), default_overall_coeff(),
true);
229 ex newcoeff = f(overall_coeff);
230 if(is_a<numeric>(newcoeff))
231 return thisexpairseq(std::move(v), newcoeff,
true);
233 v.push_back(split_ex_to_pair(newcoeff));
234 return thisexpairseq(std::move(v), default_overall_coeff(),
true);
242 if (flags &status_flags::evaluated)
245 const epvector evaled = evalchildren();
247 return dynallocate<expairseq>(std::move(evaled), overall_coeff).setflag(status_flags::evaluated);
255 for (
auto i=epv.begin(); i!=epv.end(); ++i) {
257 newepv->push_back(i->conjugate());
260 expair
x = i->conjugate();
261 if (
x.is_equal(*i)) {
265 newepv->reserve(epv.size());
266 for (
auto j=epv.begin(); j!=i; ++j) {
267 newepv->push_back(*j);
269 newepv->push_back(
x);
277 ex
x = overall_coeff.conjugate();
279 return thisexpairseq(std::move(*newepv),
x);
284 return thisexpairseq(seq,
x);
292 if (
typeid(*
this) ==
typeid(ex_to<basic>(pattern))) {
296 bool has_global_wildcard =
false;
298 for (
size_t i=0; i<pattern.nops(); i++) {
299 if (is_exactly_a<wildcard>(pattern.op(i))) {
300 has_global_wildcard =
true;
301 global_wildcard = pattern.op(i);
310 exmap tmp_repl = repl_lst;
318 for (
size_t i=0; i<
nops(); i++)
319 ops.push_back(
op(i));
323 for (
size_t i=0; i<pattern.nops(); i++) {
324 ex p = pattern.op(i);
325 if (has_global_wildcard && p.is_equal(global_wildcard))
327 auto it = ops.begin(), itend = ops.end();
328 while (it != itend) {
329 if (it->match(p, tmp_repl)) {
339 if (has_global_wildcard) {
344 size_t num = ops.size();
347 for (
size_t i=0; i<num; i++)
348 vp.push_back(split_ex_to_pair(ops[i]));
349 ex rest = thisexpairseq(std::move(vp), default_overall_coeff());
350 for (
auto & it : tmp_repl) {
351 if (it.first.is_equal(global_wildcard)) {
352 if (rest.is_equal(it.second)) {
360 repl_lst[global_wildcard] = rest;
381 return ex_to<basic>(thisexpairseq(std::move(subsed), overall_coeff, (
options & subs_options::no_index_renaming) == 0));
382 else if ((
options & subs_options::algebraic) && is_exactly_a<mul>(*this))
383 return static_cast<const mul *>(
this)->algebraic_subs_mul(
m,
options);
390 int expairseq::compare_same_type(
const basic &other)
const 393 const expairseq &o =
static_cast<const expairseq &
>(other);
398 if (seq.size() != o.seq.size())
399 return (seq.size()<o.seq.size()) ? -1 : 1;
402 cmpval = overall_coeff.compare(o.overall_coeff);
406 auto cit1 = seq.begin(), last1 = seq.end();
407 auto cit2 = o.seq.begin(), last2 = o.seq.end();
408 for (; (cit1!=last1) && (cit2!=last2); ++cit1, ++cit2) {
409 cmpval = (*cit1).compare(*cit2);
410 if (cmpval!=0)
return cmpval;
419 bool expairseq::is_equal_same_type(
const basic &other)
const 421 const expairseq &o =
static_cast<const expairseq &
>(other);
424 if (seq.size()!=o.seq.size())
428 if (!overall_coeff.is_equal(o.overall_coeff))
431 auto cit2 = o.seq.begin();
432 for (
auto & cit1 : seq) {
433 if (!cit1.is_equal(*cit2))
441 unsigned expairseq::return_type()
const 443 return return_types::noncommutative_composite;
446 unsigned expairseq::calchash()
const 449 for (
auto & i : seq) {
450 v ^= i.rest.gethash();
452 v ^= i.coeff.gethash();
455 v ^= overall_coeff.gethash();
458 if (flags &status_flags::evaluated) {
459 setflag(status_flags::hash_calculated);
469 if (!expanded.empty()) {
470 return thisexpairseq(std::move(expanded), overall_coeff);
472 return (
options == 0) ? setflag(status_flags::expanded) : *this;
489 ex expairseq::thisexpairseq(
const epvector &v,
const ex &oc,
bool do_index_renaming)
const 491 return expairseq(v, oc, do_index_renaming);
494 ex expairseq::thisexpairseq(
epvector && vp,
const ex &oc,
bool do_index_renaming)
const 496 return expairseq(std::move(vp), oc, do_index_renaming);
499 void expairseq::printpair(
const print_context &
c,
const expair & p,
unsigned upper_precedence)
const 502 p.rest.print(
c, precedence());
504 p.coeff.print(
c, precedence());
508 void expairseq::printseq(
const print_context &
c,
char delim,
509 unsigned this_precedence,
510 unsigned upper_precedence)
const 512 if (this_precedence <= upper_precedence)
514 auto it = seq.begin(), it_last = seq.end() - 1;
515 for (; it!=it_last; ++it) {
516 printpair(
c, *it, this_precedence);
519 printpair(
c, *it, this_precedence);
520 if (!overall_coeff.is_equal(default_overall_coeff())) {
522 overall_coeff.print(
c, this_precedence);
525 if (this_precedence <= upper_precedence)
532 expair expairseq::split_ex_to_pair(
const ex &e)
const 534 return expair(e,
_ex1);
538 expair expairseq::combine_ex_with_coeff_to_pair(
const ex &e,
547 expair expairseq::combine_pair_with_coeff_to_pair(
const expair &p,
553 return expair(p.rest,ex_to<numeric>(p.coeff).mul_dyn(ex_to<numeric>(
c)));
559 ex expairseq::recombine_pair_to_ex(
const expair &p)
const 561 return lst{p.rest, p.coeff};
564 bool expairseq::expair_needs_further_processing(
epp it)
566 if (is_exactly_a<numeric>(it->rest) &&
567 it->coeff.is_equal(
_ex1)) {
574 ex expairseq::default_overall_coeff()
const 579 void expairseq::combine_overall_coeff(
const ex &
c)
583 overall_coeff = ex_to<numeric>(overall_coeff).add_dyn(ex_to<numeric>(
c));
586 void expairseq::combine_overall_coeff(
const ex &c1,
const ex &c2)
591 overall_coeff = ex_to<numeric>(overall_coeff).
592 add_dyn(ex_to<numeric>(c1).mul(ex_to<numeric>(c2)));
595 bool expairseq::can_make_flat(
const expair &p)
const 605 void expairseq::construct_from_2_ex(
const ex &lh,
const ex &rh)
607 const std::type_info& typeid_this =
typeid(*this);
608 if (
typeid(ex_to<basic>(lh)) == typeid_this) {
609 if (
typeid(ex_to<basic>(rh)) == typeid_this) {
610 if (is_a<mul>(lh) && lh.info(info_flags::has_indices) &&
611 rh.info(info_flags::has_indices)) {
613 construct_from_2_expairseq(ex_to<expairseq>(lh),
614 ex_to<expairseq>(newrh));
617 construct_from_2_expairseq(ex_to<expairseq>(lh),
618 ex_to<expairseq>(rh));
621 construct_from_expairseq_ex(ex_to<expairseq>(lh), rh);
624 }
else if (
typeid(ex_to<basic>(rh)) == typeid_this) {
625 construct_from_expairseq_ex(ex_to<expairseq>(rh),lh);
629 if (is_exactly_a<numeric>(lh)) {
630 if (is_exactly_a<numeric>(rh)) {
631 combine_overall_coeff(lh);
632 combine_overall_coeff(rh);
634 combine_overall_coeff(lh);
635 seq.push_back(split_ex_to_pair(rh));
638 if (is_exactly_a<numeric>(rh)) {
639 combine_overall_coeff(rh);
640 seq.push_back(split_ex_to_pair(lh));
642 expair p1 = split_ex_to_pair(lh);
643 expair p2 = split_ex_to_pair(rh);
645 int cmpval = p1.rest.compare(p2.rest);
647 p1.coeff = ex_to<numeric>(p1.coeff).add_dyn(ex_to<numeric>(p2.coeff));
648 if (!ex_to<numeric>(p1.coeff).is_zero()) {
667 void expairseq::construct_from_2_expairseq(
const expairseq &s1,
670 combine_overall_coeff(s1.overall_coeff);
671 combine_overall_coeff(s2.overall_coeff);
673 auto first1 = s1.seq.begin(), last1 = s1.seq.end();
674 auto first2 = s2.seq.begin(), last2 = s2.seq.end();
676 seq.reserve(s1.seq.size()+s2.seq.size());
678 bool needs_further_processing=
false;
680 while (first1!=last1 && first2!=last2) {
681 int cmpval = (*first1).rest.compare((*first2).rest);
685 const numeric &newcoeff = ex_to<numeric>(first1->coeff).
686 add(ex_to<numeric>(first2->coeff));
687 if (!newcoeff.is_zero()) {
688 seq.push_back(expair(first1->rest,newcoeff));
689 if (expair_needs_further_processing(seq.end()-1)) {
690 needs_further_processing =
true;
695 }
else if (cmpval<0) {
696 seq.push_back(*first1);
699 seq.push_back(*first2);
704 while (first1!=last1) {
705 seq.push_back(*first1);
708 while (first2!=last2) {
709 seq.push_back(*first2);
713 if (needs_further_processing) {
716 construct_from_epvector(std::move(v));
720 void expairseq::construct_from_expairseq_ex(
const expairseq &s,
723 combine_overall_coeff(s.overall_coeff);
724 if (is_exactly_a<numeric>(e)) {
725 combine_overall_coeff(e);
730 auto first = s.seq.begin(),
last = s.seq.end();
731 expair p = split_ex_to_pair(e);
733 seq.reserve(s.seq.size()+1);
734 bool p_pushed =
false;
736 bool needs_further_processing=
false;
739 while (first!=
last) {
740 int cmpval = (*first).rest.compare(p.rest);
743 const numeric &newcoeff = ex_to<numeric>(first->coeff).
744 add(ex_to<numeric>(p.coeff));
745 if (!newcoeff.is_zero()) {
746 seq.push_back(expair(first->rest,newcoeff));
747 if (expair_needs_further_processing(seq.end()-1))
748 needs_further_processing =
true;
753 }
else if (cmpval<0) {
754 seq.push_back(*first);
765 while (first!=
last) {
766 seq.push_back(*first);
774 if (needs_further_processing) {
777 construct_from_epvector(std::move(v));
781 void expairseq::construct_from_exvector(
const exvector &v)
790 combine_same_terms_sorted_seq();
793 void expairseq::construct_from_epvector(
const epvector &v,
bool do_index_renaming)
800 make_flat(v, do_index_renaming);
802 combine_same_terms_sorted_seq();
805 void expairseq::construct_from_epvector(
epvector &&v,
bool do_index_renaming)
812 make_flat(std::move(v), do_index_renaming);
814 combine_same_terms_sorted_seq();
819 void expairseq::make_flat(
const exvector &v)
825 bool do_idx_rename =
false;
827 const std::type_info& typeid_this =
typeid(*this);
828 for (
auto & cit : v) {
829 if (
typeid(ex_to<basic>(cit)) == typeid_this) {
831 noperands += ex_to<expairseq>(cit).seq.size();
833 if (is_a<mul>(*
this) && (!do_idx_rename) &&
834 cit.info(info_flags::has_indices))
835 do_idx_rename =
true;
839 seq.reserve(v.size()+noperands-nexpairseqs);
842 make_flat_inserter mf(v, do_idx_rename);
843 for (
auto & cit : v) {
844 if (
typeid(ex_to<basic>(cit)) == typeid_this) {
845 ex newfactor = mf.handle_factor(cit,
_ex1);
846 const expairseq &subseqref = ex_to<expairseq>(newfactor);
847 combine_overall_coeff(subseqref.overall_coeff);
848 for (
auto & cit_s : subseqref.seq) {
849 seq.push_back(cit_s);
852 if (is_exactly_a<numeric>(cit))
853 combine_overall_coeff(cit);
855 ex newfactor = mf.handle_factor(cit,
_ex1);
856 seq.push_back(split_ex_to_pair(newfactor));
864 void expairseq::make_flat(
const epvector &v,
bool do_index_renaming)
870 bool really_need_rename_inds =
false;
872 const std::type_info& typeid_this =
typeid(*this);
873 for (
auto & cit : v) {
874 if (
typeid(ex_to<basic>(cit.rest)) == typeid_this) {
876 noperands += ex_to<expairseq>(cit.rest).seq.size();
878 if ((!really_need_rename_inds) && is_a<mul>(*
this) &&
879 cit.rest.info(info_flags::has_indices))
880 really_need_rename_inds =
true;
882 do_index_renaming = do_index_renaming && really_need_rename_inds;
885 seq.reserve(v.size()+noperands-nexpairseqs);
886 make_flat_inserter mf(v, do_index_renaming);
889 for (
auto & cit : v) {
890 if (
typeid(ex_to<basic>(cit.rest)) == typeid_this &&
891 this->can_make_flat(cit)) {
892 ex newrest = mf.handle_factor(cit.rest, cit.coeff);
893 const expairseq &subseqref = ex_to<expairseq>(newrest);
894 combine_overall_coeff(subseqref.overall_coeff, cit.coeff);
895 for (
auto & cit_s : subseqref.seq) {
896 seq.push_back(expair(cit_s.rest,
897 ex_to<numeric>(cit_s.coeff).mul_dyn(ex_to<numeric>(cit.coeff))));
900 if (cit.is_canonical_numeric())
901 combine_overall_coeff(mf.handle_factor(cit.rest,
_ex1));
904 ex newrest = mf.handle_factor(rest, cit.coeff);
908 seq.push_back(expair(newrest, cit.coeff));
917 std::sort(seq.begin(), seq.end(), expair_rest_is_less());
924 void expairseq::combine_same_terms_sorted_seq()
929 bool needs_further_processing =
false;
931 auto itin1 = seq.begin();
932 auto itin2 = itin1 + 1;
934 auto last = seq.end();
937 bool must_copy =
false;
938 while (itin2!=
last) {
939 if (itin1->rest.compare(itin2->rest)==0) {
940 itin1->coeff = ex_to<numeric>(itin1->coeff).
941 add_dyn(ex_to<numeric>(itin2->coeff));
942 if (expair_needs_further_processing(itin1))
943 needs_further_processing =
true;
946 if (!ex_to<numeric>(itin1->coeff).is_zero()) {
955 if (!ex_to<numeric>(itin1->coeff).is_zero()) {
961 seq.erase(itout,
last);
963 if (needs_further_processing) {
966 construct_from_epvector(std::move(v));
972 bool expairseq::is_canonical()
const 977 auto it = seq.begin(), itend = seq.end();
979 for (++it; it!=itend; it_last=it, ++it) {
980 if (!(it_last->is_less(*it) || it_last->is_equal(*it))) {
981 if (!is_exactly_a<numeric>(it_last->rest) ||
982 !is_exactly_a<numeric>(it->rest)) {
984 if (!is_exactly_a<numeric>(it_last->rest) ||
985 !is_exactly_a<numeric>(it->rest)) {
986 printpair(std::clog, *it_last, 0);
988 printpair(std::clog, *it, 0);
990 std::clog <<
"pair1:" << std::endl;
991 it_last->rest.print(print_tree(std::clog));
992 it_last->coeff.print(print_tree(std::clog));
993 std::clog <<
"pair2:" << std::endl;
994 it->rest.print(print_tree(std::clog));
995 it->coeff.print(print_tree(std::clog));
1011 auto cit = seq.begin(),
last = seq.end();
1013 const ex expanded_ex = cit->rest.expand(
options);
1018 s.reserve(seq.size());
1021 s.insert(s.begin(), seq.begin(), cit);
1024 s.push_back(expair(expanded_ex, cit->coeff));
1028 while (cit !=
last) {
1029 s.push_back(expair(cit->rest.expand(
options), cit->coeff));
1047 epvector expairseq::evalchildren()
const 1049 auto cit = seq.begin(),
last = seq.end();
1051 const expair evaled_pair = combine_ex_with_coeff_to_pair(cit->rest, cit->coeff);
1052 if (
unlikely(!evaled_pair.is_equal(*cit))) {
1056 s.reserve(seq.size());
1059 s.insert(s.begin(), seq.begin(), cit);
1062 s.push_back(evaled_pair);
1066 while (cit !=
last) {
1067 s.push_back(combine_ex_with_coeff_to_pair(cit->rest, cit->coeff));
1089 if (!(
options & (subs_options::pattern_is_product | subs_options::pattern_is_not_product))) {
1092 for (
auto & it :
m) {
1093 if (is_exactly_a<mul>(it.first) || is_exactly_a<power>(it.first)) {
1094 options |= subs_options::pattern_is_product;
1098 if (!(
options & subs_options::pattern_is_product))
1099 options |= subs_options::pattern_is_not_product;
1102 if (
options & subs_options::pattern_is_product) {
1105 auto cit = seq.begin(),
last = seq.end();
1106 while (cit !=
last) {
1108 const ex &orig_ex = recombine_pair_to_ex(*cit);
1109 const ex &subsed_ex = orig_ex.subs(
m,
options);
1114 s.reserve(seq.size());
1117 s.insert(s.begin(), seq.begin(), cit);
1120 s.push_back(split_ex_to_pair(subsed_ex));
1124 while (cit !=
last) {
1125 s.push_back(split_ex_to_pair(recombine_pair_to_ex(*cit).subs(
m,
options)));
1137 auto cit = seq.begin(),
last = seq.end();
1138 while (cit !=
last) {
1140 const ex subsed_rest = cit->rest.subs(
m,
options);
1141 const expair subsed_pair = combine_ex_with_coeff_to_pair(subsed_rest, cit->coeff);
1142 if (!subsed_pair.is_equal(*cit)) {
1146 s.reserve(seq.size());
1149 s.insert(s.begin(), seq.begin(), cit);
1152 s.push_back(subsed_pair);
1156 while (cit !=
last) {
1157 s.push_back(combine_ex_with_coeff_to_pair(cit->rest.subs(
m,
options), cit->coeff));
size_t nops(const ex &thisex)
Interface to GiNaC's symbolic exponentiation (basis^exponent).
void do_print(const print_context &c, unsigned level) const
Interface to GiNaC's indexed expressions.
int canonicalize(exvector::iterator v, const symmetry &symm)
Canonicalize the order of elements of an expression vector, according to the symmetry properties defi...
Archiving of GiNaC expressions.
Interface to GiNaC's sums of expressions.
Interface to sequences of expression pairs.
void do_print_tree(const print_tree &c, unsigned level) const
bool are_ex_trivially_equal(const ex &e1, const ex &e2)
Compare two objects of class quickly without doing a deep tree traversal.
Interface to GiNaC's products of expressions.
Interface to GiNaC's wildcard objects.
container< std::list > lst
Interface to several small and furry utilities needed within GiNaC but not of any interest to the use...
Definition of optimizing macros.
ex conjugate(const ex &thisex)
print_func< print_context >(&varidx::do_print). print_func< print_latex >(&varidx
#define GINAC_ASSERT(X)
Assertion macro for checking invariances.
bool match(const ex &thisex, const ex &pattern, exmap &repl_lst)
static unsigned make_hash_seed(const std::type_info &tinfo)
We need a hash function which gives different values for objects of different types.
epvector * conjugateepvector(const epvector &)
Complex conjugate every element of an epvector.
void construct_from_2_ex(const ex &lh, const ex &rh)
GINAC_IMPLEMENT_REGISTERED_CLASS_OPT(add, expairseq, print_func< print_context >(&add::do_print). print_func< print_latex >(&add::do_print_latex). print_func< print_csrc >(&add::do_print_csrc). print_func< print_tree >(&add::do_print_tree). print_func< print_python_repr >(&add::do_print_python_repr)) add
ex op(const ex &thisex, size_t i)
std::vector< ex > exvector
std::map< ex, ex, ex_is_less > exmap
epvector::iterator epp
expair-vector pointer
Interface to GiNaC's overloaded operators.
Definition of GiNaC's lst.
unsigned rotate_left(unsigned n)
Rotate bits of unsigned value by one bit to the left.
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...
ex coeff(const ex &thisex, const ex &s, int n=1)
expairseq(const ex &lh, const ex &rh)
Interface to relations between expressions.
std::vector< expair > epvector
expair-vector
bool is_canonical() const
void construct_from_exvector(const exvector &v)
ex eval(const ex &thisex)
ex subs(const ex &thisex, const exmap &m, unsigned options=0)
ex expand(const ex &thisex, unsigned options=0)