GiNaC 1.8.10
ncmul.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 "ncmul.h"
23#include "ex.h"
24#include "add.h"
25#include "mul.h"
26#include "clifford.h"
27#include "matrix.h"
28#include "archive.h"
29#include "indexed.h"
30#include "utils.h"
31
32#include <algorithm>
33#include <stdexcept>
34
35namespace GiNaC {
36
39 print_func<print_tree>(&ncmul::do_print_tree).
40 print_func<print_csrc>(&ncmul::do_print_csrc).
41 print_func<print_python_repr>(&ncmul::do_print_csrc))
42
43
44
45// default constructor
47
49{
50}
51
53// other constructors
55
56// public
57
58ncmul::ncmul(const ex & lh, const ex & rh) : inherited{lh,rh}
59{
60}
61
62ncmul::ncmul(const ex & f1, const ex & f2, const ex & f3) : inherited{f1,f2,f3}
63{
64}
65
66ncmul::ncmul(const ex & f1, const ex & f2, const ex & f3,
67 const ex & f4) : inherited{f1,f2,f3,f4}
68{
69}
70
71ncmul::ncmul(const ex & f1, const ex & f2, const ex & f3,
72 const ex & f4, const ex & f5) : inherited{f1,f2,f3,f4,f5}
73{
74}
75
76ncmul::ncmul(const ex & f1, const ex & f2, const ex & f3,
77 const ex & f4, const ex & f5, const ex & f6) : inherited{f1,f2,f3,f4,f5,f6}
78{
79}
80
81ncmul::ncmul(const exvector & v) : inherited(v)
82{
83}
84
85ncmul::ncmul(exvector && v) : inherited(std::move(v))
86{
87}
88
90// archiving
92
93
95// functions overriding virtual functions from base classes
97
98// public
99
100void ncmul::do_print(const print_context & c, unsigned level) const
101{
102 printseq(c, '(', '*', ')', precedence(), level);
103}
104
105void ncmul::do_print_csrc(const print_context & c, unsigned level) const
106{
107 c.s << class_name();
108 printseq(c, '(', ',', ')', precedence(), precedence());
109}
110
111bool ncmul::info(unsigned inf) const
112{
113 return inherited::info(inf);
114}
115
116typedef std::vector<std::size_t> uintvector;
117
118ex ncmul::expand(unsigned options) const
119{
120 // First, expand the children
122 const exvector &expanded_seq = v.empty() ? this->seq : v;
123
124 // Now, look for all the factors that are sums and remember their
125 // position and number of terms.
126 uintvector positions_of_adds(expanded_seq.size());
127 uintvector number_of_add_operands(expanded_seq.size());
128
129 size_t number_of_adds = 0;
130 size_t number_of_expanded_terms = 1;
131
132 size_t current_position = 0;
133 for (auto & it : expanded_seq) {
134 if (is_exactly_a<add>(it)) {
135 positions_of_adds[number_of_adds] = current_position;
136 size_t num_ops = it.nops();
137 number_of_add_operands[number_of_adds] = num_ops;
138 number_of_expanded_terms *= num_ops;
139 number_of_adds++;
140 }
141 ++current_position;
142 }
143
144 // If there are no sums, we are done
145 if (number_of_adds == 0) {
146 if (!v.empty())
147 return dynallocate<ncmul>(std::move(v)).setflag(options == 0 ? status_flags::expanded : 0);
148 else
149 return *this;
150 }
151
152 // Now, form all possible products of the terms of the sums with the
153 // remaining factors, and add them together
154 exvector distrseq;
155 distrseq.reserve(number_of_expanded_terms);
156
157 uintvector k(number_of_adds);
158
159 /* Rename indices in the static members of the product */
160 exvector expanded_seq_mod;
161 size_t j = 0;
162 exvector va;
163
164 for (size_t i=0; i<expanded_seq.size(); i++) {
165 if (i == positions_of_adds[j]) {
166 expanded_seq_mod.push_back(_ex1);
167 j++;
168 } else {
169 expanded_seq_mod.push_back(rename_dummy_indices_uniquely(va, expanded_seq[i], true));
170 }
171 }
172
173 while (true) {
174 exvector term = expanded_seq_mod;
175 for (size_t i=0; i<number_of_adds; i++) {
176 term[positions_of_adds[i]] = rename_dummy_indices_uniquely(va, expanded_seq[positions_of_adds[i]].op(k[i]), true);
177 }
178
179 distrseq.push_back(dynallocate<ncmul>(std::move(term)).setflag(options == 0 ? status_flags::expanded : 0));
180
181 // increment k[]
182 int l = number_of_adds-1;
183 while ((l>=0) && ((++k[l]) >= number_of_add_operands[l])) {
184 k[l] = 0;
185 l--;
186 }
187 if (l<0)
188 break;
189 }
190
191 return dynallocate<add>(distrseq).setflag(options == 0 ? status_flags::expanded : 0);
192}
193
194int ncmul::degree(const ex & s) const
195{
196 if (is_equal(ex_to<basic>(s)))
197 return 1;
198
199 // Sum up degrees of factors
200 int deg_sum = 0;
201 for (auto & i : seq)
202 deg_sum += i.degree(s);
203 return deg_sum;
204}
205
206int ncmul::ldegree(const ex & s) const
207{
208 if (is_equal(ex_to<basic>(s)))
209 return 1;
210
211 // Sum up degrees of factors
212 int deg_sum = 0;
213 for (auto & i : seq)
214 deg_sum += i.degree(s);
215 return deg_sum;
216}
217
218ex ncmul::coeff(const ex & s, int n) const
219{
220 if (is_equal(ex_to<basic>(s)))
221 return n==1 ? _ex1 : _ex0;
222
223 exvector coeffseq;
224 coeffseq.reserve(seq.size());
225
226 if (n == 0) {
227 // product of individual coeffs
228 // if a non-zero power of s is found, the resulting product will be 0
229 for (auto & it : seq)
230 coeffseq.push_back(it.coeff(s,n));
231 return dynallocate<ncmul>(std::move(coeffseq));
232 }
233
234 bool coeff_found = false;
235 for (auto & i : seq) {
236 ex c = i.coeff(s,n);
237 if (c.is_zero()) {
238 coeffseq.push_back(i);
239 } else {
240 coeffseq.push_back(c);
241 coeff_found = true;
242 }
243 }
244
245 if (coeff_found)
246 return dynallocate<ncmul>(std::move(coeffseq));
247
248 return _ex0;
249}
250
251size_t ncmul::count_factors(const ex & e) const
252{
253 if ((is_exactly_a<mul>(e)&&(e.return_type()!=return_types::commutative))||
254 (is_exactly_a<ncmul>(e))) {
255 size_t factors=0;
256 for (size_t i=0; i<e.nops(); i++)
257 factors += count_factors(e.op(i));
258
259 return factors;
260 }
261 return 1;
262}
263
264void ncmul::append_factors(exvector & v, const ex & e) const
265{
266 if ((is_exactly_a<mul>(e)&&(e.return_type()!=return_types::commutative))||
267 (is_exactly_a<ncmul>(e))) {
268 for (size_t i=0; i<e.nops(); i++)
269 append_factors(v, e.op(i));
270 } else
271 v.push_back(e);
272}
273
274typedef std::vector<unsigned> unsignedvector;
275typedef std::vector<exvector> exvectorvector;
276
288{
289 // The following additional rule would be nice, but produces a recursion,
290 // which must be trapped by introducing a flag that the sub-ncmuls()
291 // are already evaluated (maybe later...)
292 // ncmul(x1,x2,...,X,y1,y2,...) ->
293 // ncmul(ncmul(x1,x2,...),X,ncmul(y1,y2,...)
294 // (X noncommutative_composite)
295
297 return *this;
298 }
299
300 // ncmul(...,*(x1,x2),...,ncmul(x3,x4),...) ->
301 // ncmul(...,x1,x2,...,x3,x4,...) (associativity)
302 size_t factors = 0;
303 for (auto & it : seq)
304 factors += count_factors(it);
305
306 exvector assocseq;
307 assocseq.reserve(factors);
308 make_flat_inserter mf(seq, true);
309 for (auto & it : seq) {
310 ex factor = mf.handle_factor(it, 1);
311 append_factors(assocseq, factor);
312 }
313
314 // ncmul(x) -> x
315 if (assocseq.size()==1) return *(seq.begin());
316
317 // ncmul() -> 1
318 if (assocseq.empty()) return _ex1;
319
320 // determine return types
321 unsignedvector rettypes(assocseq.size());
322 size_t i = 0;
323 size_t count_commutative=0;
324 size_t count_noncommutative=0;
325 size_t count_noncommutative_composite=0;
326 for (auto & it : assocseq) {
327 rettypes[i] = it.return_type();
328 switch (rettypes[i]) {
330 count_commutative++;
331 break;
333 count_noncommutative++;
334 break;
336 count_noncommutative_composite++;
337 break;
338 default:
339 throw(std::logic_error("ncmul::eval(): invalid return type"));
340 }
341 ++i;
342 }
343 GINAC_ASSERT(count_commutative+count_noncommutative+count_noncommutative_composite==assocseq.size());
344
345 // ncmul(...,c1,...,c2,...) ->
346 // *(c1,c2,ncmul(...)) (pull out commutative elements)
347 if (count_commutative!=0) {
348 exvector commutativeseq;
349 commutativeseq.reserve(count_commutative+1);
350 exvector noncommutativeseq;
351 noncommutativeseq.reserve(assocseq.size()-count_commutative);
352 size_t num = assocseq.size();
353 for (size_t i=0; i<num; ++i) {
354 if (rettypes[i]==return_types::commutative)
355 commutativeseq.push_back(assocseq[i]);
356 else
357 noncommutativeseq.push_back(assocseq[i]);
358 }
359 commutativeseq.push_back(dynallocate<ncmul>(std::move(noncommutativeseq)));
360 return dynallocate<mul>(std::move(commutativeseq));
361 }
362
363 // ncmul(x1,y1,x2,y2) -> *(ncmul(x1,x2),ncmul(y1,y2))
364 // (collect elements of same type)
365
366 if (count_noncommutative_composite==0) {
367 // there are neither commutative nor noncommutative_composite
368 // elements in assocseq
369 GINAC_ASSERT(count_commutative==0);
370
371 size_t assoc_num = assocseq.size();
372 exvectorvector evv;
373 std::vector<return_type_t> rttinfos;
374 evv.reserve(assoc_num);
375 rttinfos.reserve(assoc_num);
376
377 for (auto & it : assocseq) {
378 return_type_t ti = it.return_type_tinfo();
379 size_t rtt_num = rttinfos.size();
380 // search type in vector of known types
381 for (i=0; i<rtt_num; ++i) {
382 if(ti == rttinfos[i]) {
383 evv[i].push_back(it);
384 break;
385 }
386 }
387 if (i >= rtt_num) {
388 // new type
389 rttinfos.push_back(ti);
390 evv.push_back(exvector());
391 (evv.end()-1)->reserve(assoc_num);
392 (evv.end()-1)->push_back(it);
393 }
394 }
395
396 size_t evv_num = evv.size();
397#ifdef DO_GINAC_ASSERT
398 GINAC_ASSERT(evv_num == rttinfos.size());
399 GINAC_ASSERT(evv_num > 0);
400 size_t s=0;
401 for (i=0; i<evv_num; ++i)
402 s += evv[i].size();
403 GINAC_ASSERT(s == assoc_num);
404#endif // def DO_GINAC_ASSERT
405
406 // if all elements are of same type, simplify the string
407 if (evv_num == 1) {
408 return evv[0][0].eval_ncmul(evv[0]);
409 }
410
411 exvector splitseq;
412 splitseq.reserve(evv_num);
413 for (i=0; i<evv_num; ++i)
414 splitseq.push_back(dynallocate<ncmul>(evv[i]));
415
416 return dynallocate<mul>(splitseq);
417 }
418
419 return dynallocate<ncmul>(assocseq).setflag(status_flags::evaluated);
420}
421
423{
424 // Evaluate children first
425 exvector s;
426 s.reserve(seq.size());
427 for (auto & it : seq)
428 s.push_back(it.evalm());
429
430 // If there are only matrices, simply multiply them
431 auto it = s.begin(), itend = s.end();
432 if (is_a<matrix>(*it)) {
433 matrix prod(ex_to<matrix>(*it));
434 it++;
435 while (it != itend) {
436 if (!is_a<matrix>(*it))
437 goto no_matrix;
438 prod = prod.mul(ex_to<matrix>(*it));
439 it++;
440 }
441 return prod;
442 }
443
444no_matrix:
445 return dynallocate<ncmul>(std::move(s));
446}
447
449{
450 return dynallocate<ncmul>(v);
451}
452
454{
455 return dynallocate<ncmul>(std::move(v));
456}
457
459{
461 return exprseq::conjugate();
462 }
463
465 return exprseq::conjugate();
466 }
467
468 exvector ev;
469 ev.reserve(nops());
470 for (auto i=end(); i!=begin();) {
471 --i;
472 ev.push_back(i->conjugate());
473 }
474 return dynallocate<ncmul>(std::move(ev));
475}
476
478{
479 return basic::real_part();
480}
481
483{
484 return basic::imag_part();
485}
486
487// protected
488
493{
494 size_t num = seq.size();
495 exvector addseq;
496 addseq.reserve(num);
497
498 // D(a*b*c) = D(a)*b*c + a*D(b)*c + a*b*D(c)
499 exvector ncmulseq = seq;
500 for (size_t i=0; i<num; ++i) {
501 ex e = seq[i].diff(s);
502 e.swap(ncmulseq[i]);
503 addseq.push_back(dynallocate<ncmul>(ncmulseq));
504 e.swap(ncmulseq[i]);
505 }
506 return dynallocate<add>(addseq);
507}
508
509int ncmul::compare_same_type(const basic & other) const
510{
511 return inherited::compare_same_type(other);
512}
513
514unsigned ncmul::return_type() const
515{
516 if (seq.empty())
518
519 bool all_commutative = true;
520 exvector::const_iterator noncommutative_element; // point to first found nc element
521
522 auto i = seq.begin(), end = seq.end();
523 while (i != end) {
524 unsigned rt = i->return_type();
526 return rt; // one ncc -> mul also ncc
527 if ((rt == return_types::noncommutative) && (all_commutative)) {
528 // first nc element found, remember position
529 noncommutative_element = i;
530 all_commutative = false;
531 }
532 if ((rt == return_types::noncommutative) && (!all_commutative)) {
533 // another nc element found, compare type_infos
534 if(noncommutative_element->return_type_tinfo() != i->return_type_tinfo())
536 }
537 ++i;
538 }
539 // all factors checked
540 GINAC_ASSERT(!all_commutative); // not all factors should commutate, because this is a ncmul();
542}
543
545{
546 if (seq.empty())
547 return make_return_type_t<ncmul>();
548
549 // return type_info of first noncommutative element
550 for (auto & i : seq)
551 if (i.return_type() == return_types::noncommutative)
552 return i.return_type_tinfo();
553
554 // no noncommutative element found, should not happen
555 return make_return_type_t<ncmul>();
556}
557
559// new virtual functions which can be overridden by derived classes
561
562// none
563
565// non-virtual functions in this class
567
569{
570 auto cit = this->seq.begin(), end = this->seq.end();
571 while (cit != end) {
572 const ex & expanded_ex = cit->expand(options);
573 if (!are_ex_trivially_equal(*cit, expanded_ex)) {
574
575 // copy first part of seq which hasn't changed
576 exvector s(this->seq.begin(), cit);
577 s.reserve(this->seq.size());
578
579 // insert changed element
580 s.push_back(expanded_ex);
581 ++cit;
582
583 // copy rest
584 while (cit != end) {
585 s.push_back(cit->expand(options));
586 ++cit;
587 }
588
589 return s;
590 }
591
592 ++cit;
593 }
594
595 return exvector(); // nothing has changed
596}
597
599{
600 return seq;
601}
602
604// friend functions
606
608{
609 return dynallocate<ncmul>(v);
610}
611
613{
614 if (v.empty())
615 return _ex1;
616 else if (v.size() == 1)
617 return v[0];
618 else
619 return dynallocate<ncmul>(v).setflag(status_flags::evaluated);
620}
621
623
624} // 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
This class is the ABC (abstract base class) of GiNaC's class hierarchy.
Definition basic.h:104
virtual ex imag_part() const
Definition basic.cpp:680
const basic & setflag(unsigned f) const
Set some status_flags.
Definition basic.h:287
unsigned flags
of type status_flags
Definition basic.h:301
bool is_equal(const basic &other) const
Test for syntactic equality.
Definition basic.cpp:862
virtual ex real_part() const
Definition basic.cpp:675
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
Wrapper template for making GiNaC classes out of STL containers.
Definition container.h:72
virtual void printseq(const print_context &c, char openbracket, char delim, char closebracket, unsigned this_precedence, unsigned upper_precedence=0) const
Print sequence of contained elements.
Definition container.h:450
const_iterator end() const
Definition container.h:239
ex conjugate() const override
Definition container.h:146
const_iterator begin() const
Definition container.h:238
size_t nops() const override
Number of operands/members.
Definition container.h:117
ex op(size_t i) const override
Return operand/member at position i.
Definition container.h:294
Lightweight wrapper for GiNaC's symbolic objects.
Definition ex.h:72
const_iterator begin() const noexcept
Definition ex.h:662
ex diff(const symbol &s, unsigned nth=1) const
Compute partial derivative of an expression.
Definition ex.cpp:86
ex expand(unsigned options=0) const
Expand an expression.
Definition ex.cpp:73
unsigned return_type() const
Definition ex.h:230
void swap(ex &other) noexcept
Efficiently swap the contents of two expressions.
Definition ex.h:104
size_t nops() const
Definition ex.h:135
ex op(size_t i) const
Definition ex.h:136
ex coeff(const ex &s, int n=1) const
Definition ex.h:175
Class to handle the renaming of dummy indices.
Definition expairseq.h:135
ex handle_factor(const ex &x, const ex &coeff)
Definition expairseq.h:152
Symbolic matrices.
Definition matrix.h:37
matrix mul(const matrix &other) const
Product of matrices.
Definition matrix.cpp:586
Non-commutative product of expressions.
Definition ncmul.h:32
unsigned precedence() const override
Return relative operator precedence (for parenthezing output).
Definition ncmul.h:56
int ldegree(const ex &s) const override
Return degree of lowest power in object s.
Definition ncmul.cpp:206
int degree(const ex &s) const override
Return degree of highest power in object s.
Definition ncmul.cpp:194
void append_factors(exvector &v, const ex &e) const
Definition ncmul.cpp:264
ex coeff(const ex &s, int n=1) const override
Return coefficient of degree n in object s.
Definition ncmul.cpp:218
return_type_t return_type_tinfo() const override
Definition ncmul.cpp:544
void do_print(const print_context &c, unsigned level) const
Definition ncmul.cpp:100
ex expand(unsigned options=0) const override
Expand expression, i.e.
Definition ncmul.cpp:118
exvector expandchildren(unsigned options) const
Definition ncmul.cpp:568
ex imag_part() const override
Definition ncmul.cpp:482
ncmul(const ex &lh, const ex &rh)
Definition ncmul.cpp:58
ex real_part() const override
Definition ncmul.cpp:477
void do_print_csrc(const print_context &c, unsigned level) const
Definition ncmul.cpp:105
ex eval() const override
Perform automatic term rewriting rules in this class.
Definition ncmul.cpp:287
ex evalm() const override
Evaluate sums, products and integer powers of matrices.
Definition ncmul.cpp:422
ex derivative(const symbol &s) const override
Implementation of ex::diff() for a non-commutative product.
Definition ncmul.cpp:492
unsigned return_type() const override
Definition ncmul.cpp:514
bool info(unsigned inf) const override
Information about the object.
Definition ncmul.cpp:111
const exvector & get_factors() const
Definition ncmul.cpp:598
size_t count_factors(const ex &e) const
Definition ncmul.cpp:251
ex thiscontainer(const exvector &v) const override
Definition ncmul.cpp:448
ex conjugate() const override
Definition ncmul.cpp:458
Base class for print_contexts.
Definition print.h:101
@ 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
Basic CAS symbol.
Definition symbol.h:38
Interface to GiNaC's clifford algebra (Dirac gamma) objects.
Interface to GiNaC's light-weight expression handles.
upvec factors
Definition factor.cpp:1429
unsigned options
Definition factor.cpp:2473
vector< int > k
Definition factor.cpp:1434
size_t n
Definition factor.cpp:1431
size_t c
Definition factor.cpp:756
Interface to GiNaC's indexed expressions.
Interface to symbolic matrices.
Interface to GiNaC's products of expressions.
Definition add.cpp:35
ex hold_ncmul(const exvector &v)
Definition ncmul.cpp:612
bool is_clifford_tinfo(const return_type_t &ti)
Check whether a given return_type_t object (as returned by return_type_tinfo() is that of a clifford ...
Definition clifford.h:193
ex reeval_ncmul(const exvector &v)
Definition ncmul.cpp:607
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
std::vector< exvector > exvectorvector
Definition ncmul.cpp:275
std::vector< std::size_t > uintvector
Definition ncmul.cpp:116
print_func< print_context >(&varidx::do_print). print_func< print_latex >(&varidx
Definition idx.cpp:43
ex factor(const ex &poly, unsigned options)
Interface function to the outside world.
Definition factor.cpp:2574
std::vector< unsigned > unsignedvector
Definition ncmul.cpp:274
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...
Definition indexed.cpp:1460
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
Definition ex.h:987
Interface to GiNaC's non-commutative products of expressions.
#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.