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