* Implementation of sequences of expression pairs. */
/*
- * GiNaC Copyright (C) 1999-2015 Johannes Gutenberg University Mainz, Germany
+ * GiNaC Copyright (C) 1999-2024 Johannes Gutenberg University Mainz, Germany
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
#include <algorithm>
#include <iostream>
#include <iterator>
+#include <memory>
#include <stdexcept>
#include <string>
void expairseq::read_archive(const archive_node &n, lst &sym_lst)
{
inherited::read_archive(n, sym_lst);
- auto first = n.find_first("rest");
- auto last = n.find_last("coeff");
- ++last;
- seq.reserve((last-first)/2);
+ auto range = n.find_property_range("rest", "coeff");
+ seq.reserve((range.end-range.begin)/2);
- for (auto loc = first; loc < last;) {
+ for (auto loc = range.begin; loc < range.end;) {
ex rest;
ex coeff;
n.find_ex_by_loc(loc++, rest, sym_lst);
n.find_ex_by_loc(loc++, coeff, sym_lst);
- seq.push_back(expair(rest, coeff));
+ seq.emplace_back(expair(rest, coeff));
}
n.find_ex("overall_coeff", overall_coeff, sym_lst);
}
/** Perform coefficient-wise automatic term rewriting rules in this class. */
-ex expairseq::eval(int level) const
+ex expairseq::eval() const
{
- if ((level==1) && (flags &status_flags::evaluated))
+ if (flags &status_flags::evaluated)
return *this;
- epvector evaled = evalchildren(level);
+ const epvector evaled = evalchildren();
if (!evaled.empty())
- return (new expairseq(std::move(evaled), overall_coeff))->setflag(status_flags::dynallocated | status_flags::evaluated);
+ return dynallocate<expairseq>(std::move(evaled), overall_coeff).setflag(status_flags::evaluated);
else
return this->hold();
}
}
newepv = new epvector;
newepv->reserve(epv.size());
- for (epvector::const_iterator j=epv.begin(); j!=i; ++j) {
+ for (auto j=epv.begin(); j!=i; ++j) {
newepv->push_back(*j);
}
newepv->push_back(x);
* @see expairseq::split_ex_to_pair() */
ex expairseq::recombine_pair_to_ex(const expair &p) const
{
- return lst(p.rest,p.coeff);
+ return lst{p.rest, p.coeff};
}
bool expairseq::expair_needs_further_processing(epp it)
{
+ if (is_exactly_a<numeric>(it->rest) &&
+ it->coeff.is_equal(_ex1)) {
+ // the pair {<n>, 1} has yet to be absorbed into overall_coeff
+ return true;
+ }
return false;
}
// non-virtual functions in this class
//////////
-void expairseq::construct_from_2_ex_via_exvector(const ex &lh, const ex &rh)
-{
- exvector v;
- v.reserve(2);
- v.push_back(lh);
- v.push_back(rh);
- construct_from_exvector(v);
-}
-
void expairseq::construct_from_2_ex(const ex &lh, const ex &rh)
{
- if (typeid(ex_to<basic>(lh)) == typeid(*this)) {
- if (typeid(ex_to<basic>(rh)) == typeid(*this)) {
+ const std::type_info& typeid_this = typeid(*this);
+ if (typeid(ex_to<basic>(lh)) == typeid_this) {
+ if (typeid(ex_to<basic>(rh)) == typeid_this) {
if (is_a<mul>(lh) && lh.info(info_flags::has_indices) &&
rh.info(info_flags::has_indices)) {
ex newrh=rename_dummy_indices_uniquely(lh, rh);
construct_from_expairseq_ex(ex_to<expairseq>(lh), rh);
return;
}
- } else if (typeid(ex_to<basic>(rh)) == typeid(*this)) {
+ } else if (typeid(ex_to<basic>(rh)) == typeid_this) {
construct_from_expairseq_ex(ex_to<expairseq>(rh),lh);
return;
}
int nexpairseqs = 0;
int noperands = 0;
bool do_idx_rename = false;
-
+
+ const std::type_info& typeid_this = typeid(*this);
for (auto & cit : v) {
- if (typeid(ex_to<basic>(cit)) == typeid(*this)) {
+ if (typeid(ex_to<basic>(cit)) == typeid_this) {
++nexpairseqs;
noperands += ex_to<expairseq>(cit).seq.size();
}
// copy elements and split off numerical part
make_flat_inserter mf(v, do_idx_rename);
for (auto & cit : v) {
- if (typeid(ex_to<basic>(cit)) == typeid(*this)) {
+ if (typeid(ex_to<basic>(cit)) == typeid_this) {
ex newfactor = mf.handle_factor(cit, _ex1);
const expairseq &subseqref = ex_to<expairseq>(newfactor);
combine_overall_coeff(subseqref.overall_coeff);
int nexpairseqs = 0;
int noperands = 0;
bool really_need_rename_inds = false;
-
+
+ const std::type_info& typeid_this = typeid(*this);
for (auto & cit : v) {
- if (typeid(ex_to<basic>(cit.rest)) == typeid(*this)) {
+ if (typeid(ex_to<basic>(cit.rest)) == typeid_this) {
++nexpairseqs;
noperands += ex_to<expairseq>(cit.rest).seq.size();
}
// copy elements and split off numerical part
for (auto & cit : v) {
- if (typeid(ex_to<basic>(cit.rest)) == typeid(*this) &&
+ if (typeid(ex_to<basic>(cit.rest)) == typeid_this &&
this->can_make_flat(cit)) {
ex newrest = mf.handle_factor(cit.rest, cit.coeff);
const expairseq &subseqref = ex_to<expairseq>(newrest);
- combine_overall_coeff(ex_to<numeric>(subseqref.overall_coeff),
- ex_to<numeric>(cit.coeff));
+ combine_overall_coeff(subseqref.overall_coeff, cit.coeff);
for (auto & cit_s : subseqref.seq) {
seq.push_back(expair(cit_s.rest,
ex_to<numeric>(cit_s.coeff).mul_dyn(ex_to<numeric>(cit.coeff))));
{
auto cit = seq.begin(), last = seq.end();
while (cit!=last) {
- const ex &expanded_ex = cit->rest.expand(options);
+ const ex expanded_ex = cit->rest.expand(options);
if (!are_ex_trivially_equal(cit->rest,expanded_ex)) {
// something changed, copy seq, eval and return it
s.reserve(seq.size());
// copy parts of seq which are known not to have changed
- auto cit2 = seq.begin();
- while (cit2!=cit) {
- s.push_back(*cit2);
- ++cit2;
- }
+ s.insert(s.begin(), seq.begin(), cit);
// copy first changed element
- s.push_back(combine_ex_with_coeff_to_pair(expanded_ex,
- cit2->coeff));
- ++cit2;
+ s.push_back(expair(expanded_ex, cit->coeff));
+ ++cit;
// copy rest
- while (cit2!=last) {
- s.push_back(combine_ex_with_coeff_to_pair(cit2->rest.expand(options),
- cit2->coeff));
- ++cit2;
+ while (cit != last) {
+ s.push_back(expair(cit->rest.expand(options), cit->coeff));
+ ++cit;
}
return s;
}
+
++cit;
}
* @see expairseq::eval()
* @return epvector containing evaluated pairs, empty if no members
* had to be changed. */
-epvector expairseq::evalchildren(int level) const
+epvector expairseq::evalchildren() const
{
- if (likely(level==1))
- return epvector(); // nothing had to be evaluated
-
- if (level == -max_recursion_level)
- throw(std::runtime_error("max recursion level reached"));
-
- --level;
auto cit = seq.begin(), last = seq.end();
while (cit!=last) {
- const ex evaled_ex = cit->rest.eval(level);
- if (!are_ex_trivially_equal(cit->rest,evaled_ex)) {
-
- // something changed, copy seq, eval and return it
+ const expair evaled_pair = combine_ex_with_coeff_to_pair(cit->rest, cit->coeff);
+ if (unlikely(!evaled_pair.is_equal(*cit))) {
+
+ // something changed: copy seq, eval and return it
epvector s;
s.reserve(seq.size());
-
+
// copy parts of seq which are known not to have changed
- auto cit2 = seq.begin();
- while (cit2!=cit) {
- s.push_back(*cit2);
- ++cit2;
- }
+ s.insert(s.begin(), seq.begin(), cit);
// copy first changed element
- s.push_back(combine_ex_with_coeff_to_pair(evaled_ex,
- cit2->coeff));
- ++cit2;
+ s.push_back(evaled_pair);
+ ++cit;
// copy rest
- while (cit2!=last) {
- s.push_back(combine_ex_with_coeff_to_pair(cit2->rest.eval(level),
- cit2->coeff));
- ++cit2;
+ while (cit != last) {
+ s.push_back(combine_ex_with_coeff_to_pair(cit->rest, cit->coeff));
+ ++cit;
}
- return std::move(s);
+ return s;
}
+
++cit;
}
const ex &subsed_ex = orig_ex.subs(m, options);
if (!are_ex_trivially_equal(orig_ex, subsed_ex)) {
- // Something changed, copy seq, subs and return it
+ // Something changed: copy seq, subs and return it
epvector s;
s.reserve(seq.size());
auto cit = seq.begin(), last = seq.end();
while (cit != last) {
- const ex &subsed_ex = cit->rest.subs(m, options);
- if (!are_ex_trivially_equal(cit->rest, subsed_ex)) {
+ const ex subsed_rest = cit->rest.subs(m, options);
+ const expair subsed_pair = combine_ex_with_coeff_to_pair(subsed_rest, cit->coeff);
+ if (!subsed_pair.is_equal(*cit)) {
- // Something changed, copy seq, subs and return it
+ // Something changed: copy seq, subs and return it
epvector s;
s.reserve(seq.size());
s.insert(s.begin(), seq.begin(), cit);
// Copy first changed element
- s.push_back(combine_ex_with_coeff_to_pair(subsed_ex, cit->coeff));
+ s.push_back(subsed_pair);
++cit;
// Copy rest