127 if (
coeff.csgn() == -1)
131 if (
coeff.is_rational()) {
132 if (
coeff.is_negative())
137 if (
coeff.csgn() == -1)
154 for (
auto & it :
seq) {
176 for (
auto & it :
seq) {
178 if (ex_to<numeric>(it.coeff).is_negative())
184 if (!neg_powers.empty()) {
196 for (
auto & vit : others) {
221 auto it =
seq.begin(), itend =
seq.end();
222 while (it != itend) {
225 bool needclosingparenthesis =
false;
227 if (is_a<print_csrc_cl_N>(
c)) {
229 needclosingparenthesis =
true;
235 if (it->coeff.is_equal(
_ex1) || it->coeff.is_equal(
_ex_1))
238 ex(
power(it->rest, -ex_to<numeric>(it->coeff))).
print(
c, level);
240 ex(
power(it->rest, ex_to<numeric>(it->coeff))).
print(
c, level);
242 if (needclosingparenthesis)
261 c.s << class_name() <<
'(';
263 for (
size_t i=1; i<
nops(); ++i) {
285 for (
auto & it :
seq) {
303 for (
auto & it :
seq) {
321 for (
auto & it :
seq) {
335 for (
auto & it :
seq) {
352 for (
auto & it :
seq) {
372 for (
auto & it :
seq) {
381 return inherited::info(inf);
386 for (
auto & it :
seq) {
387 if (!it.rest.is_polynomial(var) ||
399 for (
auto & it :
seq) {
400 if (ex_to<numeric>(it.coeff).is_integer())
404 throw std::runtime_error(
"mul::degree() undefined degree because of non-integer exponent");
414 for (
auto & it :
seq) {
415 if (ex_to<numeric>(it.coeff).is_integer())
419 throw std::runtime_error(
"mul::ldegree() undefined degree because of non-integer exponent");
428 coeffseq.reserve(
seq.size()+1);
433 for (
auto & it :
seq)
436 return dynallocate<mul>(coeffseq);
439 bool coeff_found =
false;
440 for (
auto & it :
seq) {
444 coeffseq.push_back(
c);
447 coeffseq.push_back(t);
452 return dynallocate<mul>(coeffseq);
480 size_t seq_size =
seq.size();
484 }
else if (seq_size==0) {
490 }
else if ((seq_size==1) &&
491 is_exactly_a<add>((*
seq.begin()).rest) &&
492 ex_to<numeric>((*
seq.begin()).coeff).is_equal(*
_num1_p)) {
494 const add & addref = ex_to<add>((*
seq.begin()).rest);
496 distrseq.reserve(addref.
seq.size());
497 for (
auto & it : addref.
seq) {
500 return dynallocate<add>(std::move(distrseq),
508 auto j =
seq.begin();
511 bool something_changed =
false;
513 if (
likely(! (is_a<add>(i->rest) && i->coeff.is_equal(
_ex1)))) {
522 ex_to<numeric>(ex_to<add>(i->rest).seq.begin()->coeff).
div(
c);
523 const bool canonicalizable = lead_coeff.
is_integer();
530 if (
likely((
c == *
_num1_p) && ((! canonicalizable) || unit_normal))) {
535 if (! something_changed) {
537 something_changed =
true;
540 while ((j!=i) && (j!=
last)) {
551 const add& addref = ex_to<add>(i->rest);
552 add & primitive = dynallocate<add>(addref);
555 for (
auto & ai : primitive.
seq)
556 ai.
coeff = ex_to<numeric>(ai.coeff).div_dyn(
c);
563 if (something_changed) {
568 return dynallocate<mul>(std::move(s), ex_to<numeric>(
overall_coeff).mul_dyn(oc));
578 s.reserve(
seq.size());
580 for (
auto & it :
seq)
581 s.push_back(
expair(it.rest.evalf(), it.coeff));
589 for (
auto & it :
seq) {
597 ex temp = rp*new_rp - ip*new_ip;
598 ip = ip*new_rp + rp*new_ip;
623 if (
seq.size() == 1 &&
seq[0].coeff.is_equal(
_ex1)
624 && is_a<matrix>(
seq[0].rest))
631 s.reserve(
seq.size());
633 bool have_matrix =
false;
634 epvector::iterator the_matrix;
636 for (
auto & it :
seq) {
639 if (is_a<matrix>(
m)) {
641 the_matrix = s.
end() - 1;
649 matrix m = ex_to<matrix>(the_matrix->rest);
652 return m.mul_scalar(scalar);
661 return inherited::eval_ncmul(v);
664 for (
auto & it :
seq)
666 return it.rest.eval_ncmul(v);
667 return inherited::eval_ncmul(v);
677 origbase = origfactor.
op(0);
678 int expon = ex_to<numeric>(origfactor.
op(1)).to_int();
679 origexponent = expon > 0 ? expon : -expon;
680 origexpsign = expon > 0 ? 1 : -1;
682 origbase = origfactor;
692 patternbase = patternfactor.
op(0);
693 int expon = ex_to<numeric>(patternfactor.
op(1)).to_int();
694 patternexponent = expon > 0 ? expon : -expon;
695 patternexpsign = expon > 0 ? 1 : -1;
697 patternbase = patternfactor;
702 exmap saverepls = repls;
703 if (origexponent < patternexponent || origexpsign != patternexpsign || !origbase.
match(patternbase,saverepls))
707 int newnummatches = origexponent / patternexponent;
708 if (newnummatches < nummatches)
709 nummatches = newnummatches;
722 int factor,
int &nummatches,
const std::vector<bool> &subsed,
723 std::vector<bool> &matched)
731 for (
size_t i=0; i<e.
nops(); ++i) {
732 if(subsed[i] || matched[i])
734 exmap newrepls = repls;
735 int newnummatches = nummatches;
739 newnummatches, subsed, matched)) {
741 nummatches = newnummatches;
756 if(is_a<mul>(pattern)) {
758 int nummatches = std::numeric_limits<int>::max();
759 std::vector<bool> subsed(
nops(),
false);
760 std::vector<bool> matched(
nops(),
false);
770 std::vector<bool> subsed(
nops(),
false);
774 for (
auto & it :
m) {
776 if (is_exactly_a<mul>(it.first)) {
778 int nummatches = std::numeric_limits<int>::max();
779 std::vector<bool> currsubsed(
nops(),
false);
785 for (
size_t j=0; j<subsed.size(); j++)
790 divide_by *=
pow(subsed_pattern, nummatches);
793 multiply_by *=
pow(subsed_result, nummatches);
798 for (
size_t j=0; j<this->
nops(); j++) {
799 int nummatches = std::numeric_limits<int>::max();
801 if (!subsed[j] &&
tryfactsubs(
op(j), it.first, nummatches, repls)){
805 divide_by *=
pow(subsed_pattern, nummatches);
808 multiply_by *=
pow(subsed_result, nummatches);
814 bool subsfound =
false;
815 for (
size_t i=0; i<subsed.size(); i++) {
824 return ((*
this)/divide_by)*multiply_by;
831 std::unique_ptr<epvector> newepv(
nullptr);
832 for (
auto i=
seq.begin(); i!=
seq.end(); ++i) {
843 newepv->reserve(
seq.size());
844 for (
auto j=
seq.begin(); j!=i; ++j) {
845 newepv->push_back(*j);
863 size_t num =
seq.size();
870 auto i2 = mulseq.begin();
879 return dynallocate<add>(addseq);
884 return inherited::compare_same_type(other);
894 bool all_commutative =
true;
895 epvector::const_iterator noncommutative_element;
897 epvector::const_iterator i =
seq.begin(), end =
seq.end();
899 unsigned rt = i->rest.return_type();
904 noncommutative_element = i;
905 all_commutative =
false;
909 if (noncommutative_element->rest.return_type_tinfo() != i->rest.return_type_tinfo()) {
923 return make_return_type_t<mul>();
926 for (
auto & it :
seq)
928 return it.rest.return_type_tinfo();
931 return make_return_type_t<mul>();
936 return dynallocate<mul>(v, oc, do_index_renaming);
941 return dynallocate<mul>(std::move(vp), oc, do_index_renaming);
946 if (is_exactly_a<power>(e)) {
947 const power & powerref = ex_to<power>(e);
948 if (is_exactly_a<numeric>(powerref.
exponent))
960 if (is_exactly_a<symbol>(e))
964 if (
c.is_equal(
_ex1))
981 if (is_exactly_a<symbol>(p.
rest))
985 if (
c.is_equal(
_ex1))
1002 return dynallocate<power>(p.
rest, p.
coeff);
1007 if (is_exactly_a<mul>(it->rest) &&
1008 ex_to<numeric>(it->coeff).is_integer()) {
1013 if (is_exactly_a<numeric>(it->rest)) {
1014 if (it->coeff.is_equal(
_ex1)) {
1058 if (is_exactly_a<mul>(e)) {
1059 for (
auto & it : ex_to<mul>(e).seq) {
1063 }
else if (is_exactly_a<power>(e)) {
1073 bool monomial_case =
true;
1074 for (
const auto & i :
seq) {
1076 monomial_case =
false;
1080 if (monomial_case) {
1094 const epvector & expanded_seq = (expanded.empty() ?
seq : expanded);
1102 non_adds.reserve(expanded_seq.size());
1104 for (
const auto & cit : expanded_seq) {
1105 if (is_exactly_a<add>(cit.rest) &&
1106 (cit.coeff.is_equal(
_ex1))) {
1107 if (is_exactly_a<add>(last_expanded)) {
1113 const int sizedifference = ex_to<add>(last_expanded).seq.size()-ex_to<add>(cit.rest).seq.size();
1116 const add& add1 = (sizedifference<0 ? ex_to<add>(last_expanded) : ex_to<add>(cit.rest));
1117 const add& add2 = (sizedifference<0 ? ex_to<add>(cit.rest) : ex_to<add>(last_expanded));
1119 distrseq.reserve(add1.
seq.size()+add2.
seq.size());
1124 distrseq.insert(distrseq.end(), add2.
seq.begin(), add2.
seq.end());
1126 for (
const auto & i : add2.
seq)
1127 distrseq.push_back(
expair(i.rest, ex_to<numeric>(i.coeff).mul_dyn(ex_to<numeric>(add1.
overall_coeff))));
1133 distrseq.insert(distrseq.end(), add1.
seq.begin(), add1.
seq.end());
1135 for (
const auto & i : add1.
seq)
1136 distrseq.push_back(
expair(i.rest, ex_to<numeric>(i.coeff).mul_dyn(ex_to<numeric>(add2.
overall_coeff))));
1142 exvector add1_dummy_indices, add2_dummy_indices, add_indices;
1145 if (!skip_idx_rename) {
1146 for (
const auto & i : add1.
seq) {
1148 add1_dummy_indices.insert(add1_dummy_indices.end(), add_indices.begin(), add_indices.end());
1150 for (
const auto & i : add2.
seq) {
1152 add2_dummy_indices.insert(add2_dummy_indices.end(), add_indices.begin(), add_indices.end());
1155 sort(add1_dummy_indices.begin(), add1_dummy_indices.end(),
ex_is_less());
1156 sort(add2_dummy_indices.begin(), add2_dummy_indices.end(),
ex_is_less());
1161 for (
const auto & i2 : add2.
seq) {
1166 distrseq2.reserve(add1.
seq.size());
1167 const ex i2_new = (skip_idx_rename || (dummy_subs.
op(0).
nops() == 0) ?
1169 i2.rest.subs(ex_to<lst>(dummy_subs.
op(0)),
1171 for (
const auto & i1 : add1.
seq) {
1174 const ex rest = dynallocate<mul>(i1.rest, i2_new);
1175 if (is_exactly_a<numeric>(rest)) {
1176 oc += ex_to<numeric>(rest).
mul(ex_to<numeric>(i1.coeff).mul(ex_to<numeric>(i2.coeff)));
1178 distrseq2.push_back(
expair(rest, ex_to<numeric>(i1.coeff).mul_dyn(ex_to<numeric>(i2.coeff))));
1181 tmp_accu += dynallocate<add>(std::move(distrseq2), oc);
1183 last_expanded = tmp_accu;
1187 last_expanded = cit.rest;
1191 non_adds.push_back(cit);
1197 if (is_exactly_a<add>(last_expanded)) {
1198 size_t n = last_expanded.
nops();
1200 distrseq.reserve(
n);
1202 if (! skip_idx_rename) {
1207 for (
size_t i=0; i<
n; ++i) {
1209 if (skip_idx_rename)
1215 distrseq.push_back(term.
expand());
1219 distrseq.push_back(term);
1266 s.reserve(
seq.size());
1280 while (cit2!=
last) {
Interface to GiNaC's sums of expressions.
Archiving of GiNaC expressions.
#define GINAC_ASSERT(X)
Assertion macro for checking invariances.
expair combine_pair_with_coeff_to_pair(const expair &p, const ex &c) const override
This class is the ABC (abstract base class) of GiNaC's class hierarchy.
const basic & clearflag(unsigned f) const
Clear some status_flags.
const basic & setflag(unsigned f) const
Set some status_flags.
ex diff(const symbol &s, unsigned nth=1) const
Default interface of nth derivative ex::diff(s, n).
virtual bool has(const ex &other, unsigned options=0) const
Test for occurrence of a pattern.
unsigned flags
of type status_flags
virtual void print(const print_context &c, unsigned level=0) const
Output to stream.
ex subs_one_level(const exmap &m, unsigned options) const
Helper function for subs().
const basic & hold() const
Stop further evaluation.
virtual int compare_same_type(const basic &other) const
Returns order relation between two objects of same type.
void do_print_tree(const print_tree &c, unsigned level) const
Tree output to stream.
Wrapper template for making GiNaC classes out of STL containers.
ex op(size_t i) const override
Return operand/member at position i.
Lightweight wrapper for GiNaC's symbolic objects.
bool match(const ex &pattern) const
Check whether expression matches a specified pattern.
const_iterator begin() const noexcept
ex expand(unsigned options=0) const
Expand an expression.
bool is_equal(const ex &other) const
int degree(const ex &s) const
const_iterator end() const noexcept
ex subs(const exmap &m, unsigned options=0) const
bool info(unsigned inf) const
void print(const print_context &c, unsigned level=0) const
Print expression to stream.
int ldegree(const ex &s) const
ex coeff(const ex &s, int n=1) const
void swap(expair &other)
Swap contents with other expair.
ex rest
first member of pair, an arbitrary expression
ex coeff
second member of pair, must be numeric
bool is_equal(const expair &other) const
Member-wise check for canonical ordering equality.
A sequence of class expair.
size_t nops() const override
Number of operands/members.
void construct_from_epvector(const epvector &v, bool do_index_renaming=false)
void construct_from_2_ex(const ex &lh, const ex &rh)
bool is_canonical() const
Check if this expairseq is in sorted (canonical) form.
void construct_from_exvector(const exvector &v)
epvector evalchildren() const
Member-wise evaluate the expairs in this sequence.
ex op(size_t i) const override
Return operand/member at position i.
@ expand_rename_idx
used internally by mul::expand()
@ algebraic
enable algebraic matching
ex thisexpairseq(const epvector &v, const ex &oc, bool do_index_renaming=false) const override
Create an object of this type.
bool info(unsigned inf) const override
Information about the object.
ex real_part() const override
bool expair_needs_further_processing(epp it) override
ex evalf() const override
Evaluate object numerically.
epvector expandchildren(unsigned options) const
Member-wise expand the expairs representing this sequence.
unsigned precedence() const override
Return relative operator precedence (for parenthezing output).
bool is_polynomial(const ex &var) const override
Check whether this is a polynomial in the given variables.
return_type_t return_type_tinfo() const override
ex default_overall_coeff() const override
void do_print_csrc(const print_csrc &c, unsigned level) const
unsigned return_type() const override
void do_print(const print_context &c, unsigned level) const
void do_print_python_repr(const print_python_repr &c, unsigned level) const
ex conjugate() const override
bool can_make_flat(const expair &p) const override
ex imag_part() const override
expair combine_ex_with_coeff_to_pair(const ex &e, const ex &c) const override
void combine_overall_coeff(const ex &c) override
int ldegree(const ex &s) const override
Return degree of lowest power in object s.
ex eval() const override
Perform automatic term rewriting rules in this class.
expair split_ex_to_pair(const ex &e) const override
Form an expair from an ex, using the corresponding semantics.
ex expand(unsigned options=0) const override
Expand expression, i.e.
int degree(const ex &s) const override
Return degree of highest power in object s.
void do_print_latex(const print_latex &c, unsigned level) const
static bool can_be_further_expanded(const ex &e)
ex derivative(const symbol &s) const override
Implementation of ex::diff() for a product.
void find_real_imag(ex &, ex &) const
ex coeff(const ex &s, int n=1) const override
Return coefficient of degree n in object s.
ex recombine_pair_to_ex(const expair &p) const override
Form an ex out of an expair, using the corresponding semantics.
ex evalm() const override
Evaluate sums, products and integer powers of matrices.
void print_overall_coeff(const print_context &c, const char *mul_sym) const
expair combine_pair_with_coeff_to_pair(const expair &p, const ex &c) const override
ex algebraic_subs_mul(const exmap &m, unsigned options) const
ex eval_ncmul(const exvector &v) const override
bool has(const ex &other, unsigned options=0) const override
Test for occurrence of a pattern.
mul(const ex &lh, const ex &rh)
This class is a wrapper around CLN-numbers within the GiNaC class hierarchy.
bool is_pos_integer() const
True if object is an exact integer greater than zero.
numeric integer_content() const override
bool is_integer() const
True if object is a non-complex integer.
const numeric mul(const numeric &other) const
Numerical multiplication method.
const numeric div(const numeric &other) const
Numerical division method.
This class holds a two-component object, a basis and and exponent representing exponentiation.
Base class for print_contexts.
Base context for C source output.
Context for latex-parsable output.
Context for python-parsable output.
@ noncommutative_composite
@ expanded
.expand(0) has already done its job (other expand() options ignore this flag)
@ evaluated
.eval() has already done its job
@ hash_calculated
.calchash() has already done its job
@ no_pattern
disable pattern matching
@ algebraic
enable algebraic substitutions
Definition of optimizing macros.
Interface to GiNaC's indexed expressions.
Definition of GiNaC's lst.
Interface to symbolic matrices.
Interface to GiNaC's products of expressions.
const numeric pow(const numeric &x, const numeric &y)
std::map< ex, ex, ex_is_less > exmap
std::vector< expair > epvector
expair-vector
bool are_ex_trivially_equal(const ex &e1, const ex &e2)
Compare two objects of class quickly without doing a deep tree traversal.
bool algebraic_match_mul_with_mul(const mul &e, const ex &pat, exmap &repls, int factor, int &nummatches, const std::vector< bool > &subsed, std::vector< bool > &matched)
Checks whether e matches to the pattern pat and the (possibly to be updated) list of replacements rep...
print_func< print_context >(&varidx::do_print). print_func< print_latex >(&varidx
epvector::iterator epp
expair-vector pointer
ex factor(const ex &poly, unsigned options)
Interface function to the outside world.
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...
GINAC_IMPLEMENT_REGISTERED_CLASS_OPT_T(lst, basic, print_func< print_context >(&lst::do_print). print_func< print_tree >(&lst::do_print_tree)) template<> bool lst GINAC_BIND_UNARCHIVER(lst)
Specialization of container::info() for lst.
bool tryfactsubs(const ex &origfactor, const ex &patternfactor, int &nummatches, exmap &repls)
std::vector< ex > exvector
exvector get_all_dummy_indices_safely(const ex &e)
More reliable version of the form.
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.
To distinguish between different kinds of non-commutative objects.
Interface to GiNaC's symbolic objects.
Interface to several small and furry utilities needed within GiNaC but not of any interest to the use...