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