GiNaC 1.8.10
symmetry.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 "symmetry.h"
23#include "lst.h"
24#include "add.h"
25#include "numeric.h" // for factorial()
26#include "operators.h"
27#include "archive.h"
28#include "utils.h"
29#include "hash_seed.h"
30
31#include <functional>
32#include <limits>
33#include <stdexcept>
34
35namespace GiNaC {
36
39 print_func<print_tree>(&symmetry::do_print_tree))
40
41/*
42 Some notes about the structure of a symmetry tree:
43 - The leaf nodes of the tree are of type "none", have one index, and no
44 children (of course). They are constructed by the symmetry(unsigned)
45 constructor.
46 - Leaf nodes are the only nodes that only have one index.
47 - Container nodes contain two or more children. The "indices" set member
48 is the set union of the index sets of all children, and the "children"
49 vector stores the children themselves.
50 - The index set of each child of a "symm", "anti" or "cycl" node must
51 have the same size. It follows that the children of such a node are
52 either all leaf nodes, or all container nodes with two or more indices.
53*/
54
55
56// default constructor
58
59symmetry::symmetry() : type(none)
60{
62}
63
65// other constructors
67
68symmetry::symmetry(unsigned i) : type(none)
69{
70 indices.insert(i);
72}
73
74symmetry::symmetry(symmetry_type t, const symmetry &c1, const symmetry &c2) : type(t)
75{
76 add(c1); add(c2);
78}
79
81// archiving
83
86{
87 inherited::read_archive(n, sym_lst);
88 unsigned t;
89 if (!(n.find_unsigned("type", t)))
90 throw (std::runtime_error("unknown symmetry type in archive"));
92
93 unsigned i = 0;
94 while (true) {
95 ex e;
96 if (n.find_ex("child", e, sym_lst, i))
97 add(ex_to<symmetry>(e));
98 else
99 break;
100 i++;
101 }
102
103 if (i == 0) {
104 while (true) {
105 unsigned u;
106 if (n.find_unsigned("index", u, i))
107 indices.insert(u);
108 else
109 break;
110 i++;
111 }
112 }
113}
115
118{
119 inherited::archive(n);
120
121 n.add_unsigned("type", type);
122
123 if (children.empty()) {
124 for (auto & i : indices) {
125 n.add_unsigned("index", i);
126 }
127 } else {
128 for (auto & i : children) {
129 n.add_ex("child", i);
130 }
131 }
132}
133
135// functions overriding virtual functions from base classes
137
138int symmetry::compare_same_type(const basic & other) const
139{
140 GINAC_ASSERT(is_a<symmetry>(other));
141
142 // For archiving purposes we need to have an ordering of symmetries.
143 const symmetry &othersymm = ex_to<symmetry>(other);
144
145 // Compare type.
146 if (type > othersymm.type)
147 return 1;
148 if (type < othersymm.type)
149 return -1;
150
151 // Compare the index set.
152 size_t this_size = indices.size();
153 size_t that_size = othersymm.indices.size();
154 if (this_size > that_size)
155 return 1;
156 if (this_size < that_size)
157 return -1;
158 auto end = indices.end();
159 for (auto i=indices.begin(),j=othersymm.indices.begin(); i!=end; ++i,++j) {
160 if(*i < *j)
161 return 1;
162 if(*i > *j)
163 return -1;
164 }
165
166 // Compare the children.
167 if (children.size() > othersymm.children.size())
168 return 1;
169 if (children.size() < othersymm.children.size())
170 return -1;
171 for (size_t i=0; i<children.size(); ++i) {
172 int cmpval = ex_to<symmetry>(children[i])
173 .compare_same_type(ex_to<symmetry>(othersymm.children[i]));
174 if (cmpval)
175 return cmpval;
176 }
177
178 return 0;
179}
180
181unsigned symmetry::calchash() const
182{
183 unsigned v = make_hash_seed(typeid(*this));
184
185 if (type == none) {
186 v = rotate_left(v);
187 if (!indices.empty())
188 v ^= *(indices.begin());
189 } else {
190 for (auto & i : children) {
191 v = rotate_left(v);
192 v ^= i.gethash();
193 }
194 }
195
198 hashvalue = v;
199 }
200
201 return v;
202}
203
204void symmetry::do_print(const print_context & c, unsigned level) const
205{
206 if (children.empty()) {
207 if (indices.size() > 0)
208 c.s << *(indices.begin());
209 else
210 c.s << "none";
211 } else {
212 switch (type) {
213 case none: c.s << '!'; break;
214 case symmetric: c.s << '+'; break;
215 case antisymmetric: c.s << '-'; break;
216 case cyclic: c.s << '@'; break;
217 default: c.s << '?'; break;
218 }
219 c.s << '(';
220 size_t num = children.size();
221 for (size_t i=0; i<num; i++) {
222 children[i].print(c);
223 if (i != num - 1)
224 c.s << ",";
225 }
226 c.s << ')';
227 }
228}
229
230void symmetry::do_print_tree(const print_tree & c, unsigned level) const
231{
232 c.s << std::string(level, ' ') << class_name() << " @" << this
233 << std::hex << ", hash=0x" << hashvalue << ", flags=0x" << flags << std::dec
234 << ", type=";
235
236 switch (type) {
237 case none: c.s << "none"; break;
238 case symmetric: c.s << "symm"; break;
239 case antisymmetric: c.s << "anti"; break;
240 case cyclic: c.s << "cycl"; break;
241 default: c.s << "<unknown>"; break;
242 }
243
244 c.s << ", indices=(";
245 if (!indices.empty()) {
246 auto i = indices.begin(), end = indices.end();
247 --end;
248 while (i != end)
249 c.s << *i++ << ",";
250 c.s << *i;
251 }
252 c.s << ")\n";
253
254 for (auto & i : children) {
255 i.print(c, level + c.delta_indent);
256 }
257}
258
260// non-virtual functions in this class
262
264{
265 if (type == antisymmetric || type == cyclic)
266 return true;
267
268 for (auto & i : children)
269 if (ex_to<symmetry>(i).has_nonsymmetric())
270 return true;
271
272 return false;
273}
274
276{
277 if (type == cyclic)
278 return true;
279
280 for (auto & i : children)
281 if (ex_to<symmetry>(i).has_cyclic())
282 return true;
283
284 return false;
285}
286
288{
289 // All children must have the same number of indices
290 if (type != none && !children.empty()) {
291 GINAC_ASSERT(is_exactly_a<symmetry>(children[0]));
292 if (ex_to<symmetry>(children[0]).indices.size() != c.indices.size())
293 throw (std::logic_error("symmetry:add(): children must have same number of indices"));
294 }
295
296 // Compute union of indices and check whether the two sets are disjoint
297 std::set<unsigned> un;
298 set_union(indices.begin(), indices.end(), c.indices.begin(), c.indices.end(), inserter(un, un.begin()));
299 if (un.size() != indices.size() + c.indices.size())
300 throw (std::logic_error("symmetry::add(): the same index appears in more than one child"));
301
302 // Set new index set
303 indices.swap(un);
304
305 // Add child node
306 children.push_back(c);
307 return *this;
308}
309
310void symmetry::validate(unsigned n)
311{
312 if (indices.upper_bound(n - 1) != indices.end())
313 throw (std::range_error("symmetry::verify(): index values are out of range"));
314 if (type != none && indices.empty()) {
315 for (unsigned i=0; i<n; i++)
316 add(i);
317 }
318}
319
321// global functions
323
324static const symmetry & index0()
325{
326 static ex s = dynallocate<symmetry>(0);
327 return ex_to<symmetry>(s);
328}
329
330static const symmetry & index1()
331{
332 static ex s = dynallocate<symmetry>(1);
333 return ex_to<symmetry>(s);
334}
335
336static const symmetry & index2()
337{
338 static ex s = dynallocate<symmetry>(2);
339 return ex_to<symmetry>(s);
340}
341
342static const symmetry & index3()
343{
344 static ex s = dynallocate<symmetry>(3);
345 return ex_to<symmetry>(s);
346}
347
349{
350 static ex s = dynallocate<symmetry>();
351 return ex_to<symmetry>(s);
352}
353
355{
356 static ex s = dynallocate<symmetry>(symmetry::symmetric, index0(), index1());
357 return ex_to<symmetry>(s);
358}
359
361{
362 static ex s = dynallocate<symmetry>(symmetry::symmetric, index0(), index1()).add(index2());
363 return ex_to<symmetry>(s);
364}
365
367{
368 static ex s = dynallocate<symmetry>(symmetry::symmetric, index0(), index1()).add(index2()).add(index3());
369 return ex_to<symmetry>(s);
370}
371
373{
374 static ex s = dynallocate<symmetry>(symmetry::antisymmetric, index0(), index1());
375 return ex_to<symmetry>(s);
376}
377
379{
380 static ex s = dynallocate<symmetry>(symmetry::antisymmetric, index0(), index1()).add(index2());
381 return ex_to<symmetry>(s);
382}
383
385{
386 static ex s = dynallocate<symmetry>(symmetry::antisymmetric, index0(), index1()).add(index2()).add(index3());
387 return ex_to<symmetry>(s);
388}
389
391 exvector::iterator v;
392
393public:
394 sy_is_less(exvector::iterator v_) : v(v_) {}
395
396 bool operator() (const ex &lh, const ex &rh) const
397 {
398 GINAC_ASSERT(is_exactly_a<symmetry>(lh));
399 GINAC_ASSERT(is_exactly_a<symmetry>(rh));
400 GINAC_ASSERT(ex_to<symmetry>(lh).indices.size() == ex_to<symmetry>(rh).indices.size());
401 auto ait = ex_to<symmetry>(lh).indices.begin(), aitend = ex_to<symmetry>(lh).indices.end(), bit = ex_to<symmetry>(rh).indices.begin();
402 while (ait != aitend) {
403 int cmpval = v[*ait].compare(v[*bit]);
404 if (cmpval < 0)
405 return true;
406 else if (cmpval > 0)
407 return false;
408 ++ait; ++bit;
409 }
410 return false;
411 }
412};
413
414class sy_swap {
415 exvector::iterator v;
416
417public:
418 bool &swapped;
419
420 sy_swap(exvector::iterator v_, bool &s) : v(v_), swapped(s) {}
421
422 void operator() (const ex &lh, const ex &rh)
423 {
424 GINAC_ASSERT(is_exactly_a<symmetry>(lh));
425 GINAC_ASSERT(is_exactly_a<symmetry>(rh));
426 GINAC_ASSERT(ex_to<symmetry>(lh).indices.size() == ex_to<symmetry>(rh).indices.size());
427 auto ait = ex_to<symmetry>(lh).indices.begin(), aitend = ex_to<symmetry>(lh).indices.end(), bit = ex_to<symmetry>(rh).indices.begin();
428 while (ait != aitend) {
429 v[*ait].swap(v[*bit]);
430 ++ait; ++bit;
431 }
432 swapped = true;
433 }
434};
435
436int canonicalize(exvector::iterator v, const symmetry &symm)
437{
438 // Less than two elements? Then do nothing
439 if (symm.indices.size() < 2)
440 return std::numeric_limits<int>::max();
441
442 // Canonicalize children first
443 bool something_changed = false;
444 int sign = 1;
445 auto first = symm.children.begin(), last = symm.children.end();
446 while (first != last) {
447 GINAC_ASSERT(is_exactly_a<symmetry>(*first));
448 int child_sign = canonicalize(v, ex_to<symmetry>(*first));
449 if (child_sign == 0)
450 return 0;
451 if (child_sign != std::numeric_limits<int>::max()) {
452 something_changed = true;
453 sign *= child_sign;
454 }
455 first++;
456 }
457
458 // Now reorder the children
459 first = symm.children.begin();
460 switch (symm.type) {
462 // Sort the children in ascending order
463 shaker_sort(first, last, sy_is_less(v), sy_swap(v, something_changed));
464 break;
466 // Sort the children in ascending order, keeping track of the signum
467 sign *= permutation_sign(first, last, sy_is_less(v), sy_swap(v, something_changed));
468 if (sign == 0)
469 return 0;
470 break;
471 case symmetry::cyclic:
472 // Permute the smallest child to the front
473 cyclic_permutation(first, last, min_element(first, last, sy_is_less(v)), sy_swap(v, something_changed));
474 break;
475 default:
476 break;
477 }
478 return something_changed ? sign : std::numeric_limits<int>::max();
479}
480
481
482// Symmetrize/antisymmetrize over a vector of objects
483static ex symm(const ex & e, exvector::const_iterator first, exvector::const_iterator last, bool asymmetric)
484{
485 // Need at least 2 objects for this operation
486 unsigned num = last - first;
487 if (num < 2)
488 return e;
489
490 // Transform object vector to a lst (for subs())
491 lst orig_lst(first, last);
492
493 // Create index vectors for permutation
494 unsigned *iv = new unsigned[num], *iv2;
495 for (unsigned i=0; i<num; i++)
496 iv[i] = i;
497 iv2 = (asymmetric ? new unsigned[num] : nullptr);
498
499 // Loop over all permutations (the first permutation, which is the
500 // identity, is unrolled)
501 exvector sum_v;
502 sum_v.push_back(e);
503 while (std::next_permutation(iv, iv + num)) {
504 lst new_lst;
505 for (unsigned i=0; i<num; i++)
506 new_lst.append(orig_lst.op(iv[i]));
508 if (asymmetric) {
509 memcpy(iv2, iv, num * sizeof(unsigned));
510 term *= permutation_sign(iv2, iv2 + num);
511 }
512 sum_v.push_back(term);
513 }
514 ex sum = dynallocate<add>(sum_v);
515
516 delete[] iv;
517 delete[] iv2;
518
519 return sum / factorial(numeric(num));
520}
521
522ex symmetrize(const ex & e, exvector::const_iterator first, exvector::const_iterator last)
523{
524 return symm(e, first, last, false);
525}
526
527ex antisymmetrize(const ex & e, exvector::const_iterator first, exvector::const_iterator last)
528{
529 return symm(e, first, last, true);
530}
531
532ex symmetrize_cyclic(const ex & e, exvector::const_iterator first, exvector::const_iterator last)
533{
534 // Need at least 2 objects for this operation
535 unsigned num = last - first;
536 if (num < 2)
537 return e;
538
539 // Transform object vector to a lst (for subs())
540 lst orig_lst(first, last);
541 lst new_lst = orig_lst;
542
543 // Loop over all cyclic permutations (the first permutation, which is
544 // the identity, is unrolled)
545 ex sum = e;
546 for (unsigned i=0; i<num-1; i++) {
547 ex perm = new_lst.op(0);
548 new_lst.remove_first().append(perm);
550 }
551 return sum / num;
552}
553
555ex ex::symmetrize(const lst & l) const
556{
557 exvector v(l.begin(), l.end());
558 return symm(*this, v.begin(), v.end(), false);
559}
560
562ex ex::antisymmetrize(const lst & l) const
563{
564 exvector v(l.begin(), l.end());
565 return symm(*this, v.begin(), v.end(), true);
566}
567
571{
572 exvector v(l.begin(), l.end());
573 return GiNaC::symmetrize_cyclic(*this, v.begin(), v.end());
574}
575
576} // 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
Sum of expressions.
Definition add.h:31
This class stores all properties needed to record/retrieve the state of one object of class basic (or...
Definition archive.h:48
This class is the ABC (abstract base class) of GiNaC's class hierarchy.
Definition basic.h:104
const basic & setflag(unsigned f) const
Set some status_flags.
Definition basic.h:287
unsigned hashvalue
hash value
Definition basic.h:302
unsigned flags
of type status_flags
Definition basic.h:301
virtual int compare_same_type(const basic &other) const
Returns order relation between two objects of same type.
Definition basic.cpp:718
Wrapper template for making GiNaC classes out of STL containers.
Definition container.h:72
const_iterator end() const
Definition container.h:239
const_iterator begin() const
Definition container.h:238
ex op(size_t i) const override
Return operand/member at position i.
Definition container.h:294
container & remove_first()
Remove first element.
Definition container.h:399
container & append(const ex &b)
Add element at back.
Definition container.h:390
Lightweight wrapper for GiNaC's symbolic objects.
Definition ex.h:72
const_iterator begin() const noexcept
Definition ex.h:662
ex symmetrize_cyclic() const
Symmetrize expression by cyclic permutation over its free indices.
Definition indexed.cpp:1290
const_iterator end() const noexcept
Definition ex.h:667
ex subs(const exmap &m, unsigned options=0) const
Definition ex.h:841
ex symmetrize() const
Symmetrize expression over its free indices.
Definition indexed.cpp:1278
ex antisymmetrize() const
Antisymmetrize expression over its free indices.
Definition indexed.cpp:1284
This class is a wrapper around CLN-numbers within the GiNaC class hierarchy.
Definition numeric.h:81
Base class for print_contexts.
Definition print.h:101
Context for tree-like output for debugging.
Definition print.h:145
@ 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
@ hash_calculated
.calchash() has already done its job
Definition flags.h:204
@ no_pattern
disable pattern matching
Definition flags.h:50
sy_is_less(exvector::iterator v_)
Definition symmetry.cpp:394
exvector::iterator v
Definition symmetry.cpp:391
bool operator()(const ex &lh, const ex &rh) const
Definition symmetry.cpp:396
exvector::iterator v
Definition symmetry.cpp:415
sy_swap(exvector::iterator v_, bool &s)
Definition symmetry.cpp:420
void operator()(const ex &lh, const ex &rh)
Definition symmetry.cpp:422
This class describes the symmetry of a group of indices.
Definition symmetry.h:38
void read_archive(const archive_node &n, lst &syms) override
Read (a.k.a.
Definition symmetry.cpp:85
void validate(unsigned n)
Verify that all indices of this node are in the range [0..n-1].
Definition symmetry.cpp:310
symmetry_type
Type of symmetry.
Definition symmetry.h:48
@ symmetric
totally symmetric
Definition symmetry.h:50
@ antisymmetric
totally antisymmetric
Definition symmetry.h:51
@ none
no symmetry properties
Definition symmetry.h:49
@ cyclic
cyclic symmetry
Definition symmetry.h:52
bool has_nonsymmetric() const
Check whether this node involves anything non symmetric.
Definition symmetry.cpp:263
symmetry & add(const symmetry &c)
Add child node, check index sets for consistency.
Definition symmetry.cpp:287
symmetry_type type
Type of symmetry described by this node.
Definition symmetry.h:102
void do_print(const print_context &c, unsigned level) const
Definition symmetry.cpp:204
exvector children
Vector of child nodes.
Definition symmetry.h:108
bool has_cyclic() const
Check whether this node involves a cyclic symmetry.
Definition symmetry.cpp:275
std::set< unsigned > indices
Sorted union set of all indices handled by this node.
Definition symmetry.h:105
symmetry(unsigned i)
Create leaf node that represents one index.
Definition symmetry.cpp:68
unsigned calchash() const override
Compute the hash value of an object and if it makes sense to store it in the objects status_flags,...
Definition symmetry.cpp:181
void do_print_tree(const print_tree &c, unsigned level) const
Definition symmetry.cpp:230
void archive(archive_node &n) const override
Save (a.k.a.
Definition symmetry.cpp:117
size_t n
Definition factor.cpp:1431
size_t c
Definition factor.cpp:756
size_t last
Definition factor.cpp:1433
Type-specific hash seed.
Definition of GiNaC's lst.
Definition add.cpp:35
const symmetry & antisymmetric4()
Definition symmetry.cpp:384
const symmetry & symmetric3()
Definition symmetry.cpp:360
const symmetry & not_symmetric()
Definition symmetry.cpp:348
ex symmetrize(const ex &thisex)
Definition ex.h:808
const symmetry & antisymmetric3()
Definition symmetry.cpp:378
const symmetry & antisymmetric2()
Definition symmetry.cpp:372
static const symmetry & index1()
Definition symmetry.cpp:330
const symmetry & symmetric2()
Definition symmetry.cpp:354
const numeric factorial(const numeric &n)
Factorial combinatorial function.
Definition numeric.cpp:2112
static const symmetry & index2()
Definition symmetry.cpp:336
print_func< print_context >(&varidx::do_print). print_func< print_latex >(&varidx
Definition idx.cpp:43
static const symmetry & index3()
Definition symmetry.cpp:342
static unsigned make_hash_seed(const std::type_info &tinfo)
We need a hash function which gives different values for objects of different types.
Definition hash_seed.h:36
unsigned rotate_left(unsigned n)
Rotate bits of unsigned value by one bit to the left.
Definition utils.h:47
ex antisymmetrize(const ex &thisex)
Definition ex.h:814
static const symmetry & index0()
Definition symmetry.cpp:324
const symmetry & symmetric4()
Definition symmetry.cpp:366
void shaker_sort(It first, It last, Cmp comp, Swap swapit)
Definition utils.h:192
void cyclic_permutation(It first, It last, It new_first, Swap swapit)
Definition utils.h:243
static ex symm(const ex &e, exvector::const_iterator first, exvector::const_iterator last, bool asymmetric)
Definition symmetry.cpp:483
int canonicalize(exvector::iterator v, const symmetry &symm)
Canonicalize the order of elements of an expression vector, according to the symmetry properties defi...
Definition symmetry.cpp:436
ex symmetrize_cyclic(const ex &thisex)
Definition ex.h:820
int permutation_sign(It first, It last)
Definition utils.h:76
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
std::vector< ex > exvector
Definition basic.h:47
Makes the interface to the underlying bignum package available.
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:183
Interface to GiNaC's symmetry definitions.
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.