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