GiNaC 1.8.10
add.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 "add.h"
23#include "mul.h"
24#include "archive.h"
25#include "operators.h"
26#include "matrix.h"
27#include "utils.h"
28#include "clifford.h"
29#include "ncmul.h"
30#include "compiler.h"
31
32#include <limits>
33#include <stdexcept>
34
35namespace GiNaC {
36
39 print_func<print_latex>(&add::do_print_latex).
40 print_func<print_csrc>(&add::do_print_csrc).
41 print_func<print_tree>(&add::do_print_tree).
42 print_func<print_python_repr>(&add::do_print_python_repr))
43
44
45// default constructor
47
49{
50}
51
53// other constructors
55
56// public
57
58add::add(const ex & lh, const ex & rh)
59{
63}
64
71
78
79add::add(const epvector & v, const ex & oc)
80{
81 overall_coeff = oc;
84}
85
92
93add::add(epvector && vp, const ex & oc)
94{
95 overall_coeff = oc;
96 construct_from_epvector(std::move(vp));
98}
99
101// archiving
103
105
107// functions overriding virtual functions from base classes
109
110// public
111
112void add::print_add(const print_context & c, const char *openbrace, const char *closebrace, const char *mul_sym, unsigned level) const
113{
114 if (precedence() <= level)
115 c.s << openbrace << '(';
116
118 bool first = true;
119
120 // First print the overall numeric coefficient, if present
121 if (!overall_coeff.is_zero()) {
123 first = false;
124 }
125
126 // Then proceed with the remaining factors
127 for (auto & it : seq) {
128 coeff = ex_to<numeric>(it.coeff);
129 if (!first) {
130 if (coeff.csgn() == -1) c.s << '-'; else c.s << '+';
131 } else {
132 if (coeff.csgn() == -1) c.s << '-';
133 first = false;
134 }
135 if (!coeff.is_equal(*_num1_p) &&
137 if (coeff.is_rational()) {
138 if (coeff.is_negative())
139 (-coeff).print(c);
140 else
141 coeff.print(c);
142 } else {
143 if (coeff.csgn() == -1)
144 (-coeff).print(c, precedence());
145 else
147 }
148 c.s << mul_sym;
149 }
150 it.rest.print(c, precedence());
151 }
152
153 if (precedence() <= level)
154 c.s << ')' << closebrace;
155}
156
157void add::do_print(const print_context & c, unsigned level) const
158{
159 print_add(c, "", "", "*", level);
160}
161
162void add::do_print_latex(const print_latex & c, unsigned level) const
163{
164 print_add(c, "{", "}", " ", level);
165}
166
167void add::do_print_csrc(const print_csrc & c, unsigned level) const
168{
169 if (precedence() <= level)
170 c.s << "(";
171
172 // Print arguments, separated by "+" or "-"
173 char separator = ' ';
174 for (auto & it : seq) {
175
176 // If the coefficient is negative, separator is "-"
177 if (it.coeff.is_equal(_ex_1) ||
178 ex_to<numeric>(it.coeff).numer().is_equal(*_num_1_p))
179 separator = '-';
180 c.s << separator;
181 if (it.coeff.is_equal(_ex1) || it.coeff.is_equal(_ex_1)) {
182 it.rest.print(c, precedence());
183 } else if (ex_to<numeric>(it.coeff).numer().is_equal(*_num1_p) ||
184 ex_to<numeric>(it.coeff).numer().is_equal(*_num_1_p))
185 {
186 it.rest.print(c, precedence());
187 c.s << '/';
188 ex_to<numeric>(it.coeff).denom().print(c, precedence());
189 } else {
190 it.coeff.print(c, precedence());
191 c.s << '*';
192 it.rest.print(c, precedence());
193 }
194
195 separator = '+';
196 }
197
198 if (!overall_coeff.is_zero()) {
200 || is_a<print_csrc_cl_N>(c) || !overall_coeff.info(info_flags::real)) // sign inside ctor argument
201 c.s << '+';
203 }
204
205 if (precedence() <= level)
206 c.s << ")";
207}
208
209void add::do_print_python_repr(const print_python_repr & c, unsigned level) const
210{
211 c.s << class_name() << '(';
212 op(0).print(c);
213 for (size_t i=1; i<nops(); ++i) {
214 c.s << ',';
215 op(i).print(c);
216 }
217 c.s << ')';
218}
219
220bool add::info(unsigned inf) const
221{
222 switch (inf) {
227 case info_flags::real:
236 case info_flags::even:
239 for (auto & i : seq) {
240 if (!(recombine_pair_to_ex(i).info(inf)))
241 return false;
242 }
244 return true;
245 return overall_coeff.info(inf);
246 }
247 }
248 return inherited::info(inf);
249}
250
251bool add::is_polynomial(const ex & var) const
252{
253 for (auto & i : seq) {
254 if (!i.rest.is_polynomial(var)) {
255 return false;
256 }
257 }
258 return true;
259}
260
261int add::degree(const ex & s) const
262{
263 int deg = std::numeric_limits<int>::min();
264 if (!overall_coeff.is_zero())
265 deg = 0;
266
267 // Find maximum of degrees of individual terms
268 for (auto & i : seq) {
269 int cur_deg = i.rest.degree(s);
270 if (cur_deg > deg)
271 deg = cur_deg;
272 }
273 return deg;
274}
275
276int add::ldegree(const ex & s) const
277{
278 int deg = std::numeric_limits<int>::max();
279 if (!overall_coeff.is_zero())
280 deg = 0;
281
282 // Find minimum of degrees of individual terms
283 for (auto & i : seq) {
284 int cur_deg = i.rest.ldegree(s);
285 if (cur_deg < deg)
286 deg = cur_deg;
287 }
288 return deg;
289}
290
291ex add::coeff(const ex & s, int n) const
292{
293 epvector coeffseq;
294 epvector coeffseq_cliff;
295 int rl = clifford_max_label(s);
296 bool do_clifford = (rl != -1);
297 bool nonscalar = false;
298
299 // Calculate sum of coefficients in each term
300 for (auto & i : seq) {
301 ex restcoeff = i.rest.coeff(s, n);
302 if (!restcoeff.is_zero()) {
303 if (do_clifford) {
304 if (clifford_max_label(restcoeff) == -1) {
305 coeffseq_cliff.push_back(expair(ncmul(restcoeff, dirac_ONE(rl)), i.coeff));
306 } else {
307 coeffseq_cliff.push_back(expair(restcoeff, i.coeff));
308 nonscalar = true;
309 }
310 }
311 coeffseq.push_back(expair(restcoeff, i.coeff));
312 }
313 }
314
315 return dynallocate<add>(nonscalar ? std::move(coeffseq_cliff) : std::move(coeffseq),
316 n==0 ? overall_coeff : _ex0);
317}
318
326{
328 GINAC_ASSERT(seq.size()>0);
329 GINAC_ASSERT(seq.size()>1 || !overall_coeff.is_zero());
330 return *this;
331 }
332
333 const epvector evaled = evalchildren();
334 if (unlikely(!evaled.empty())) {
335 // start over evaluating a new object
336 return dynallocate<add>(std::move(evaled), overall_coeff);
337 }
338
339#ifdef DO_GINAC_ASSERT
340 for (auto & i : seq) {
341 GINAC_ASSERT(!is_exactly_a<add>(i.rest));
342 }
343#endif // def DO_GINAC_ASSERT
344
345 size_t seq_size = seq.size();
346 if (seq_size == 0) {
347 // +(;c) -> c
348 return overall_coeff;
349 } else if (seq_size == 1 && overall_coeff.is_zero()) {
350 // +(x;0) -> x
351 return recombine_pair_to_ex(*(seq.begin()));
352 } else if (!overall_coeff.is_zero() && seq[0].rest.return_type() != return_types::commutative) {
353 throw (std::logic_error("add::eval(): sum of non-commutative objects has non-zero numeric term"));
354 }
355
356 return this->hold();
357}
358
360{
361 // Evaluate children first and add up all matrices. Stop if there's one
362 // term that is not a matrix.
363 epvector s;
364 s.reserve(seq.size());
365
366 bool all_matrices = true;
367 bool first_term = true;
368 matrix sum;
369
370 for (auto & it : seq) {
371 const ex &m = recombine_pair_to_ex(it).evalm();
372 s.push_back(split_ex_to_pair(m));
373 if (is_a<matrix>(m)) {
374 if (first_term) {
375 sum = ex_to<matrix>(m);
376 first_term = false;
377 } else
378 sum = sum.add(ex_to<matrix>(m));
379 } else
380 all_matrices = false;
381 }
382
383 if (all_matrices)
384 return sum + overall_coeff;
385 else
386 return dynallocate<add>(std::move(s), overall_coeff);
387}
388
390{
391 std::unique_ptr<exvector> v(nullptr);
392 for (size_t i=0; i<nops(); ++i) {
393 if (v) {
394 v->push_back(op(i).conjugate());
395 continue;
396 }
397 ex term = op(i);
398 ex ccterm = term.conjugate();
399 if (are_ex_trivially_equal(term, ccterm))
400 continue;
401 v.reset(new exvector);
402 v->reserve(nops());
403 for (size_t j=0; j<i; ++j)
404 v->push_back(op(j));
405 v->push_back(ccterm);
406 }
407 if (v) {
408 return add(std::move(*v));
409 }
410 return *this;
411}
412
414{
415 epvector v;
416 v.reserve(seq.size());
417 for (auto & it : seq)
418 if (it.coeff.info(info_flags::real)) {
419 ex rp = it.rest.real_part();
420 if (!rp.is_zero())
421 v.push_back(expair(rp, it.coeff));
422 } else {
424 if (!rp.is_zero())
425 v.push_back(split_ex_to_pair(rp));
426 }
427 return dynallocate<add>(std::move(v), overall_coeff.real_part());
428}
429
431{
432 epvector v;
433 v.reserve(seq.size());
434 for (auto & it : seq)
435 if (it.coeff.info(info_flags::real)) {
436 ex ip = it.rest.imag_part();
437 if (!ip.is_zero())
438 v.push_back(expair(ip, it.coeff));
439 } else {
441 if (!ip.is_zero())
442 v.push_back(split_ex_to_pair(ip));
443 }
444 return dynallocate<add>(std::move(v), overall_coeff.imag_part());
445}
446
448{
449 if (seq.empty())
450 return inherited::eval_ncmul(v);
451 else
452 return seq.begin()->rest.eval_ncmul(v);
453}
454
455// protected
456
459ex add::derivative(const symbol & y) const
460{
461 epvector s;
462 s.reserve(seq.size());
463
464 // Only differentiate the "rest" parts of the expairs. This is faster
465 // than the default implementation in basic::derivative() although
466 // if performs the same function (differentiate each term).
467 for (auto & it : seq)
468 s.push_back(expair(it.rest.diff(y), it.coeff));
469
470 return dynallocate<add>(std::move(s));
471}
472
473int add::compare_same_type(const basic & other) const
474{
475 return inherited::compare_same_type(other);
476}
477
478unsigned add::return_type() const
479{
480 if (seq.empty())
482 else
483 return seq.begin()->rest.return_type();
484}
485
487{
488 if (seq.empty())
489 return make_return_type_t<add>();
490 else
491 return seq.begin()->rest.return_type_tinfo();
492}
493
494// Note: do_index_renaming is ignored because it makes no sense for an add.
495ex add::thisexpairseq(const epvector & v, const ex & oc, bool do_index_renaming) const
496{
497 return dynallocate<add>(v, oc);
498}
499
500// Note: do_index_renaming is ignored because it makes no sense for an add.
501ex add::thisexpairseq(epvector && vp, const ex & oc, bool do_index_renaming) const
502{
503 return dynallocate<add>(std::move(vp), oc);
504}
505
507{
508 if (is_exactly_a<mul>(e)) {
509 const mul &mulref(ex_to<mul>(e));
510 const ex &numfactor = mulref.overall_coeff;
511 if (numfactor.is_equal(_ex1))
512 return expair(e, _ex1);
513 mul & mulcopy = dynallocate<mul>(mulref);
514 mulcopy.overall_coeff = _ex1;
516 return expair(mulcopy, numfactor);
517 }
518 return expair(e,_ex1);
519}
520
522 const ex & c) const
523{
524 GINAC_ASSERT(is_exactly_a<numeric>(c));
525 if (is_exactly_a<mul>(e)) {
526 const mul &mulref(ex_to<mul>(e));
527 const ex &numfactor = mulref.overall_coeff;
528 if (likely(numfactor.is_equal(_ex1)))
529 return expair(e, c);
530 mul & mulcopy = dynallocate<mul>(mulref);
531 mulcopy.overall_coeff = _ex1;
533 if (c.is_equal(_ex1))
534 return expair(mulcopy, numfactor);
535 else
536 return expair(mulcopy, ex_to<numeric>(numfactor).mul_dyn(ex_to<numeric>(c)));
537 } else if (is_exactly_a<numeric>(e)) {
538 if (c.is_equal(_ex1))
539 return expair(e, _ex1);
540 if (e.is_equal(_ex1))
541 return expair(c, _ex1);
542 return expair(ex_to<numeric>(e).mul_dyn(ex_to<numeric>(c)), _ex1);
543 }
544 return expair(e, c);
545}
546
548 const ex & c) const
549{
550 GINAC_ASSERT(is_exactly_a<numeric>(p.coeff));
551 GINAC_ASSERT(is_exactly_a<numeric>(c));
552
553 if (is_exactly_a<numeric>(p.rest)) {
554 GINAC_ASSERT(ex_to<numeric>(p.coeff).is_equal(*_num1_p)); // should be normalized
555 return expair(ex_to<numeric>(p.rest).mul_dyn(ex_to<numeric>(c)),_ex1);
556 }
557
558 return expair(p.rest,ex_to<numeric>(p.coeff).mul_dyn(ex_to<numeric>(c)));
559}
560
562{
563 if (ex_to<numeric>(p.coeff).is_equal(*_num1_p))
564 return p.rest;
565 else
566 return dynallocate<mul>(p.rest, p.coeff);
567}
568
569ex add::expand(unsigned options) const
570{
571 epvector expanded = expandchildren(options);
572 if (expanded.empty())
573 return (options == 0) ? setflag(status_flags::expanded) : *this;
574
575 return dynallocate<add>(std::move(expanded), overall_coeff).setflag(options == 0 ? status_flags::expanded : 0);
576}
577
578} // 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
add(const ex &lh, const ex &rh)
Definition add.cpp:58
unsigned return_type() const override
Definition add.cpp:478
ex derivative(const symbol &s) const override
Implementation of ex::diff() for a sum.
Definition add.cpp:459
ex coeff(const ex &s, int n=1) const override
Return coefficient of degree n in object s.
Definition add.cpp:291
void print_add(const print_context &c, const char *openbrace, const char *closebrace, const char *mul_sym, unsigned level) const
Definition add.cpp:112
ex eval() const override
Perform automatic term rewriting rules in this class.
Definition add.cpp:325
void do_print(const print_context &c, unsigned level) const
Definition add.cpp:157
ex real_part() const override
Definition add.cpp:413
int degree(const ex &s) const override
Return degree of highest power in object s.
Definition add.cpp:261
void do_print_python_repr(const print_python_repr &c, unsigned level) const
Definition add.cpp:209
bool is_polynomial(const ex &var) const override
Check whether this is a polynomial in the given variables.
Definition add.cpp:251
bool info(unsigned inf) const override
Information about the object.
Definition add.cpp:220
int ldegree(const ex &s) const override
Return degree of lowest power in object s.
Definition add.cpp:276
ex eval_ncmul(const exvector &v) const override
Definition add.cpp:447
ex thisexpairseq(const epvector &v, const ex &oc, bool do_index_renaming=false) const override
Create an object of this type.
Definition add.cpp:495
void do_print_latex(const print_latex &c, unsigned level) const
Definition add.cpp:162
ex conjugate() const override
Definition add.cpp:389
ex expand(unsigned options=0) const override
Expand expression, i.e.
Definition add.cpp:569
expair combine_ex_with_coeff_to_pair(const ex &e, const ex &c) const override
Definition add.cpp:521
ex evalm() const override
Evaluate sums, products and integer powers of matrices.
Definition add.cpp:359
return_type_t return_type_tinfo() const override
Definition add.cpp:486
expair split_ex_to_pair(const ex &e) const override
Form an expair from an ex, using the corresponding semantics.
Definition add.cpp:506
ex imag_part() const override
Definition add.cpp:430
ex recombine_pair_to_ex(const expair &p) const override
Form an ex out of an expair, using the corresponding semantics.
Definition add.cpp:561
expair combine_pair_with_coeff_to_pair(const expair &p, const ex &c) const override
Definition add.cpp:547
void do_print_csrc(const print_csrc &c, unsigned level) const
Definition add.cpp:167
unsigned precedence() const override
Return relative operator precedence (for parenthezing output).
Definition add.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 flags
of type status_flags
Definition basic.h:301
virtual void print(const print_context &c, unsigned level=0) const
Output to stream.
Definition basic.cpp:115
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
void do_print_tree(const print_tree &c, unsigned level) const
Tree output to stream.
Definition basic.cpp:174
Lightweight wrapper for GiNaC's symbolic objects.
Definition ex.h:72
bool is_equal(const ex &other) const
Definition ex.h:345
ex conjugate() const
Definition ex.h:146
ex imag_part() const
Definition ex.h:148
bool info(unsigned inf) const
Definition ex.h:132
bool is_zero() const
Definition ex.h:213
void print(const print_context &c, unsigned level=0) const
Print expression to stream.
Definition ex.cpp:54
ex real_part() const
Definition ex.h:147
ex evalm() const
Definition ex.h:122
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
A sequence of class expair.
Definition expairseq.h:49
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.
epvector expandchildren(unsigned options) const
Member-wise expand the expairs in this sequence.
Symbolic matrices.
Definition matrix.h:37
matrix add(const matrix &other) const
Sum of matrices.
Definition matrix.cpp:552
Product of expressions.
Definition mul.h:31
Non-commutative product of expressions.
Definition ncmul.h:32
ex coeff(const ex &s, int n=1) const override
Return coefficient of degree n in object s.
Definition ncmul.cpp:218
This class is a wrapper around CLN-numbers within the GiNaC class hierarchy.
Definition numeric.h:81
Base class for print_contexts.
Definition print.h:101
Base context for C source output.
Definition print.h:156
Context for latex-parsable output.
Definition print.h:121
Context for python-parsable output.
Definition print.h:137
@ 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
Basic CAS symbol.
Definition symbol.h:38
Interface to GiNaC's clifford algebra (Dirac gamma) objects.
Definition of optimizing macros.
#define likely(cond)
Definition compiler.h:31
#define unlikely(cond)
Definition compiler.h:30
unsigned options
Definition factor.cpp:2473
size_t n
Definition factor.cpp:1431
size_t c
Definition factor.cpp:756
mvec m
Definition factor.cpp:757
Interface to symbolic matrices.
Interface to GiNaC's products of expressions.
Definition add.cpp:35
const numeric * _num_1_p
Definition utils.cpp:350
int clifford_max_label(const ex &e, bool ignore_ONE)
Returns the maximal representation label of a clifford object if e contains at least one,...
std::vector< expair > epvector
expair-vector
Definition expairseq.h:32
ex dirac_ONE(unsigned char rl)
Create a Clifford unity object.
Definition clifford.cpp:722
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
const ex _ex_1
Definition utils.cpp:351
print_func< print_context >(&varidx::do_print). print_func< print_latex >(&varidx
Definition idx.cpp:43
const numeric * _num1_p
Definition utils.cpp:383
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.
Definition lst.cpp:41
const ex _ex0
Definition utils.cpp:368
std::vector< ex > exvector
Definition basic.h:47
Interface to GiNaC's non-commutative products of expressions.
Interface to GiNaC's overloaded operators.
#define GINAC_IMPLEMENT_REGISTERED_CLASS_OPT(classname, supername, options)
Macro for inclusion in the implementation of each registered class.
Definition registrar.h:183
To distinguish between different kinds of non-commutative objects.
Definition registrar.h:42
Interface to several small and furry utilities needed within GiNaC but not of any interest to the use...

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