128 if (
coeff.csgn() == -1)
132 if (
coeff.is_rational()) {
133 if (
coeff.is_negative())
138 if (
coeff.csgn() == -1)
155 for (
auto & it :
seq) {
177 for (
auto & it :
seq) {
179 if (ex_to<numeric>(it.coeff).is_negative())
185 if (!neg_powers.empty()) {
197 for (
auto & vit : others) {
222 auto it =
seq.begin(), itend =
seq.end();
223 while (it != itend) {
226 bool needclosingparenthesis =
false;
228 if (is_a<print_csrc_cl_N>(
c)) {
230 needclosingparenthesis =
true;
236 if (it->coeff.is_equal(
_ex1) || it->coeff.is_equal(
_ex_1))
239 ex(
power(it->rest, -ex_to<numeric>(it->coeff))).
print(
c, level);
241 ex(
power(it->rest, ex_to<numeric>(it->coeff))).
print(
c, level);
243 if (needclosingparenthesis)
262 c.s << class_name() <<
'(';
264 for (
size_t i=1; i<
nops(); ++i) {
286 for (
auto & it :
seq) {
304 for (
auto & it :
seq) {
322 for (
auto & it :
seq) {
336 for (
auto & it :
seq) {
353 for (
auto & it :
seq) {
373 for (
auto & it :
seq) {
382 return inherited::info(inf);
387 for (
auto & it :
seq) {
388 if (!it.rest.is_polynomial(var) ||
400 for (
auto & it :
seq) {
401 if (ex_to<numeric>(it.coeff).is_integer())
405 throw std::runtime_error(
"mul::degree() undefined degree because of non-integer exponent");
415 for (
auto & it :
seq) {
416 if (ex_to<numeric>(it.coeff).is_integer())
420 throw std::runtime_error(
"mul::ldegree() undefined degree because of non-integer exponent");
429 coeffseq.reserve(
seq.size()+1);
434 for (
auto & it :
seq)
437 return dynallocate<mul>(coeffseq);
440 bool coeff_found =
false;
441 for (
auto & it :
seq) {
445 coeffseq.push_back(
c);
448 coeffseq.push_back(t);
453 return dynallocate<mul>(coeffseq);
481 size_t seq_size =
seq.size();
485 }
else if (seq_size==0) {
491 }
else if ((seq_size==1) &&
492 is_exactly_a<add>((*
seq.begin()).rest) &&
493 ex_to<numeric>((*
seq.begin()).coeff).is_equal(*
_num1_p)) {
495 const add & addref = ex_to<add>((*
seq.begin()).rest);
497 distrseq.reserve(addref.
seq.size());
498 for (
auto & it : addref.
seq) {
501 return dynallocate<add>(std::move(distrseq),
509 auto j =
seq.begin();
512 bool something_changed =
false;
514 if (
likely(! (is_a<add>(i->rest) && i->coeff.is_equal(
_ex1)))) {
523 ex_to<numeric>(ex_to<add>(i->rest).seq.begin()->coeff).
div(
c);
524 const bool canonicalizable = lead_coeff.
is_integer();
531 if (
likely((
c == *
_num1_p) && ((! canonicalizable) || unit_normal))) {
536 if (! something_changed) {
538 something_changed =
true;
541 while ((j!=i) && (j!=
last)) {
552 const add& addref = ex_to<add>(i->rest);
553 add & primitive = dynallocate<add>(addref);
556 for (
auto & ai : primitive.
seq)
557 ai.
coeff = ex_to<numeric>(ai.coeff).div_dyn(
c);
564 if (something_changed) {
569 return dynallocate<mul>(std::move(s), ex_to<numeric>(
overall_coeff).mul_dyn(oc));
579 s.reserve(
seq.size());
581 for (
auto & it :
seq)
582 s.push_back(
expair(it.rest.evalf(), it.coeff));
590 for (
auto & it :
seq) {
598 ex temp = rp*new_rp - ip*new_ip;
599 ip = ip*new_rp + rp*new_ip;
624 if (
seq.size() == 1 &&
seq[0].coeff.is_equal(
_ex1)
625 && is_a<matrix>(
seq[0].rest))
632 s.reserve(
seq.size());
634 bool have_matrix =
false;
635 epvector::iterator the_matrix;
637 for (
auto & it :
seq) {
640 if (is_a<matrix>(
m)) {
642 the_matrix = s.
end() - 1;
650 matrix m = ex_to<matrix>(the_matrix->rest);
653 return m.mul_scalar(scalar);
662 return inherited::eval_ncmul(v);
665 for (
auto & it :
seq)
667 return it.rest.eval_ncmul(v);
668 return inherited::eval_ncmul(v);
678 origbase = origfactor.
op(0);
679 int expon = ex_to<numeric>(origfactor.
op(1)).to_int();
680 origexponent = expon > 0 ? expon : -expon;
681 origexpsign = expon > 0 ? 1 : -1;
683 origbase = origfactor;
693 patternbase = patternfactor.
op(0);
694 int expon = ex_to<numeric>(patternfactor.
op(1)).to_int();
695 patternexponent = expon > 0 ? expon : -expon;
696 patternexpsign = expon > 0 ? 1 : -1;
698 patternbase = patternfactor;
703 exmap saverepls = repls;
704 if (origexponent < patternexponent || origexpsign != patternexpsign || !origbase.
match(patternbase,saverepls))
708 int newnummatches = origexponent / patternexponent;
709 if (newnummatches < nummatches)
710 nummatches = newnummatches;
723 int factor,
int &nummatches,
const std::vector<bool> &subsed,
724 std::vector<bool> &matched)
732 for (
size_t i=0; i<e.
nops(); ++i) {
733 if(subsed[i] || matched[i])
735 exmap newrepls = repls;
736 int newnummatches = nummatches;
740 newnummatches, subsed, matched)) {
742 nummatches = newnummatches;
757 if(is_a<mul>(pattern)) {
759 int nummatches = std::numeric_limits<int>::max();
760 std::vector<bool> subsed(
nops(),
false);
761 std::vector<bool> matched(
nops(),
false);
771 std::vector<bool> subsed(
nops(),
false);
775 for (
auto & it :
m) {
777 if (is_exactly_a<mul>(it.first)) {
779 int nummatches = std::numeric_limits<int>::max();
780 std::vector<bool> currsubsed(
nops(),
false);
786 for (
size_t j=0; j<subsed.size(); j++)
791 divide_by *=
pow(subsed_pattern, nummatches);
794 multiply_by *=
pow(subsed_result, nummatches);
799 for (
size_t j=0; j<this->
nops(); j++) {
800 int nummatches = std::numeric_limits<int>::max();
802 if (!subsed[j] &&
tryfactsubs(
op(j), it.first, nummatches, repls)){
806 divide_by *=
pow(subsed_pattern, nummatches);
809 multiply_by *=
pow(subsed_result, nummatches);
815 bool subsfound =
false;
816 for (
size_t i=0; i<subsed.size(); i++) {
825 return ((*
this)/divide_by)*multiply_by;
832 std::unique_ptr<epvector> newepv(
nullptr);
833 for (
auto i=
seq.begin(); i!=
seq.end(); ++i) {
844 newepv->reserve(
seq.size());
845 for (
auto j=
seq.begin(); j!=i; ++j) {
846 newepv->push_back(*j);
864 size_t num =
seq.size();
871 auto i2 = mulseq.begin();
880 return dynallocate<add>(addseq);
885 return inherited::compare_same_type(other);
895 bool all_commutative =
true;
896 epvector::const_iterator noncommutative_element;
898 epvector::const_iterator i =
seq.begin(), end =
seq.end();
900 unsigned rt = i->rest.return_type();
905 noncommutative_element = i;
906 all_commutative =
false;
910 if (noncommutative_element->rest.return_type_tinfo() != i->rest.return_type_tinfo()) {
924 return make_return_type_t<mul>();
927 for (
auto & it :
seq)
929 return it.rest.return_type_tinfo();
932 return make_return_type_t<mul>();
937 return dynallocate<mul>(v, oc, do_index_renaming);
942 return dynallocate<mul>(std::move(vp), oc, do_index_renaming);
947 if (is_exactly_a<power>(e)) {
948 const power & powerref = ex_to<power>(e);
949 if (is_exactly_a<numeric>(powerref.
exponent))
961 if (is_exactly_a<symbol>(e))
965 if (
c.is_equal(
_ex1))
982 if (is_exactly_a<symbol>(p.
rest))
986 if (
c.is_equal(
_ex1))
1003 return dynallocate<power>(p.
rest, p.
coeff);
1008 if (is_exactly_a<mul>(it->rest) &&
1009 ex_to<numeric>(it->coeff).is_integer()) {
1014 if (is_exactly_a<numeric>(it->rest)) {
1015 if (it->coeff.is_equal(
_ex1)) {
1059 if (is_exactly_a<mul>(e)) {
1060 for (
auto & it : ex_to<mul>(e).seq) {
1064 }
else if (is_exactly_a<power>(e)) {
1074 bool monomial_case =
true;
1075 for (
const auto & i :
seq) {
1077 monomial_case =
false;
1081 if (monomial_case) {
1095 const epvector & expanded_seq = (expanded.empty() ?
seq : expanded);
1103 non_adds.reserve(expanded_seq.size());
1105 for (
const auto & cit : expanded_seq) {
1106 if (is_exactly_a<add>(cit.rest) &&
1107 (cit.coeff.is_equal(
_ex1))) {
1108 if (is_exactly_a<add>(last_expanded)) {
1114 const int sizedifference = ex_to<add>(last_expanded).seq.size()-ex_to<add>(cit.rest).seq.size();
1117 const add& add1 = (sizedifference<0 ? ex_to<add>(last_expanded) : ex_to<add>(cit.rest));
1118 const add& add2 = (sizedifference<0 ? ex_to<add>(cit.rest) : ex_to<add>(last_expanded));
1120 distrseq.reserve(add1.
seq.size()+add2.
seq.size());
1125 distrseq.insert(distrseq.end(), add2.
seq.begin(), add2.
seq.end());
1127 for (
const auto & i : add2.
seq)
1128 distrseq.push_back(
expair(i.rest, ex_to<numeric>(i.coeff).mul_dyn(ex_to<numeric>(add1.
overall_coeff))));
1134 distrseq.insert(distrseq.end(), add1.
seq.begin(), add1.
seq.end());
1136 for (
const auto & i : add1.
seq)
1137 distrseq.push_back(
expair(i.rest, ex_to<numeric>(i.coeff).mul_dyn(ex_to<numeric>(add2.
overall_coeff))));
1143 exvector add1_dummy_indices, add2_dummy_indices, add_indices;
1146 if (!skip_idx_rename) {
1147 for (
const auto & i : add1.
seq) {
1149 add1_dummy_indices.insert(add1_dummy_indices.end(), add_indices.begin(), add_indices.end());
1151 for (
const auto & i : add2.
seq) {
1153 add2_dummy_indices.insert(add2_dummy_indices.end(), add_indices.begin(), add_indices.end());
1156 sort(add1_dummy_indices.begin(), add1_dummy_indices.end(),
ex_is_less());
1157 sort(add2_dummy_indices.begin(), add2_dummy_indices.end(),
ex_is_less());
1162 for (
const auto & i2 : add2.
seq) {
1167 distrseq2.reserve(add1.
seq.size());
1168 const ex i2_new = (skip_idx_rename || (dummy_subs.
op(0).
nops() == 0) ?
1170 i2.rest.subs(ex_to<lst>(dummy_subs.
op(0)),
1172 for (
const auto & i1 : add1.
seq) {
1175 const ex rest = dynallocate<mul>(i1.rest, i2_new);
1176 if (is_exactly_a<numeric>(rest)) {
1177 oc += ex_to<numeric>(rest).
mul(ex_to<numeric>(i1.coeff).mul(ex_to<numeric>(i2.coeff)));
1179 distrseq2.push_back(
expair(rest, ex_to<numeric>(i1.coeff).mul_dyn(ex_to<numeric>(i2.coeff))));
1182 tmp_accu += dynallocate<add>(std::move(distrseq2), oc);
1184 last_expanded = tmp_accu;
1188 last_expanded = cit.rest;
1192 non_adds.push_back(cit);
1198 if (is_exactly_a<add>(last_expanded)) {
1199 size_t n = last_expanded.
nops();
1201 distrseq.reserve(
n);
1203 if (! skip_idx_rename) {
1208 for (
size_t i=0; i<
n; ++i) {
1210 if (skip_idx_rename)
1216 distrseq.push_back(term.
expand());
1220 distrseq.push_back(term);
1267 s.reserve(
seq.size());
1281 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...