GiNaC  1.8.3
add.cpp
Go to the documentation of this file.
1 
5 /*
6  * GiNaC Copyright (C) 1999-2022 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 
38 namespace 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 // default constructor
50 
51 add::add()
52 {
53 }
54 
56 // other constructors
58 
59 // public
60 
61 add::add(const ex & lh, const ex & rh)
62 {
64  construct_from_2_ex(lh,rh);
66 }
67 
68 add::add(const exvector & v)
69 {
73 }
74 
75 add::add(const epvector & v)
76 {
80 }
81 
82 add::add(const epvector & v, const ex & oc)
83 {
84  overall_coeff = oc;
87 }
88 
90 {
92  construct_from_epvector(std::move(vp));
94 }
95 
96 add::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 
115 void 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 
120  numeric coeff;
121  bool first = true;
122 
123  // First print the overall numeric coefficient, if present
124  if (!overall_coeff.is_zero()) {
125  overall_coeff.print(c, 0);
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) &&
139  !coeff.is_equal(*_num_1_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
149  coeff.print(c, precedence());
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 
160 void add::do_print(const print_context & c, unsigned level) const
161 {
162  print_add(c, "", "", "*", level);
163 }
164 
165 void add::do_print_latex(const print_latex & c, unsigned level) const
166 {
167  print_add(c, "{", "}", " ", level);
168 }
169 
170 void 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 
212 void 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 
223 bool add::info(unsigned inf) const
224 {
225  switch (inf) {
230  case info_flags::real:
232  case info_flags::integer:
237  case info_flags::posint:
239  case info_flags::even:
242  for (auto & i : seq) {
243  if (!(recombine_pair_to_ex(i).info(inf)))
244  return false;
245  }
246  if (overall_coeff.is_zero() && (inf == info_flags::positive || inf == info_flags::posint))
247  return true;
248  return overall_coeff.info(inf);
249  }
250  }
251  return inherited::info(inf);
252 }
253 
254 bool 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 
264 int 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 
279 int 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 
294 ex 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 
328 ex add::eval() const
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 
362 ex add::evalm() const
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 {
426  ex rp = recombine_pair_to_ex(it).real_part();
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 {
443  ex ip = recombine_pair_to_ex(it).imag_part();
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 
450 ex add::eval_ncmul(const exvector & v) const
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 
462 ex 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 
476 int add::compare_same_type(const basic & other) const
477 {
478  return inherited::compare_same_type(other);
479 }
480 
481 unsigned 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.
498 ex 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.
504 ex 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 
572 ex 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
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
Definition: add.cpp:509
ex imag_part() const override
Definition: add.cpp:433
ex recombine_pair_to_ex(const expair &p) const override
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
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
const basic & setflag(unsigned f) const
Set some status_flags.
Definition: basic.h:288
virtual int compare_same_type(const basic &other) const
Returns order relation between two objects of same type.
Definition: basic.cpp:719
const basic & clearflag(unsigned f) const
Clear some status_flags.
Definition: basic.h:291
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.
epvector seq
Definition: expairseq.h:127
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
void construct_from_exvector(const exvector &v)
epvector evalchildren() const
ex op(size_t i) const override
Return operand/member at position i.
void do_print_tree(const print_tree &c, unsigned level) const
epvector expandchildren(unsigned options) const
@ 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:2480
size_t n
Definition: factor.cpp:1463
size_t c
Definition: factor.cpp:770
mvec m
Definition: factor.cpp:771
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:684
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
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 numeric * _num1_p
Definition: utils.cpp:384
const ex _ex0
Definition: utils.cpp:369
std::vector< ex > exvector
Definition: basic.h:46
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.