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