[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
4.14.3 Symmetries
Indexed objects can have certain symmetry properties with respect to their
indices. Symmetries are specified as a tree of objects of class symmetry
that is constructed with the helper functions
symmetry sy_none(...); symmetry sy_symm(...); symmetry sy_anti(...); symmetry sy_cycl(...); |
sy_none()
stands for no symmetry, sy_symm()
and sy_anti()
specify fully symmetric or antisymmetric, respectively, and sy_cycl()
represents a cyclic symmetry. Each of these functions accepts up to four
arguments which can be either symmetry objects themselves or unsigned integer
numbers that represent an index position (counting from 0). A symmetry
specification that consists of only a single sy_symm()
, sy_anti()
or sy_cycl()
with no arguments specifies the respective symmetry for
all indices.
Here are some examples of symmetry definitions:
... // No symmetry: e = indexed(A, i, j); e = indexed(A, sy_none(), i, j); // equivalent e = indexed(A, sy_none(0, 1), i, j); // equivalent // Symmetric in all three indices: e = indexed(A, sy_symm(), i, j, k); e = indexed(A, sy_symm(0, 1, 2), i, j, k); // equivalent e = indexed(A, sy_symm(2, 0, 1), i, j, k); // same symmetry, but yields a // different canonical order // Symmetric in the first two indices only: e = indexed(A, sy_symm(0, 1), i, j, k); e = indexed(A, sy_none(sy_symm(0, 1), 2), i, j, k); // equivalent // Antisymmetric in the first and last index only (index ranges need not // be contiguous): e = indexed(A, sy_anti(0, 2), i, j, k); e = indexed(A, sy_none(sy_anti(0, 2), 1), i, j, k); // equivalent // An example of a mixed symmetry: antisymmetric in the first two and // last two indices, symmetric when swapping the first and last index // pairs (like the Riemann curvature tensor): e = indexed(A, sy_symm(sy_anti(0, 1), sy_anti(2, 3)), i, j, k, l); // Cyclic symmetry in all three indices: e = indexed(A, sy_cycl(), i, j, k); e = indexed(A, sy_cycl(0, 1, 2), i, j, k); // equivalent // The following examples are invalid constructions that will throw // an exception at run time. // An index may not appear multiple times: e = indexed(A, sy_symm(0, 0, 1), i, j, k); // ERROR e = indexed(A, sy_none(sy_symm(0, 1), sy_anti(0, 2)), i, j, k); // ERROR // Every child of sy_symm(), sy_anti() and sy_cycl() must refer to the // same number of indices: e = indexed(A, sy_symm(sy_anti(0, 1), 2), i, j, k); // ERROR // And of course, you cannot specify indices which are not there: e = indexed(A, sy_symm(0, 1, 2, 3), i, j, k); // ERROR ... |
If you need to specify more than four indices, you have to use the
.add()
method of the symmetry
class. For example, to specify
full symmetry in the first six indices you would write
sy_symm(0, 1, 2, 3).add(4).add(5)
.
If an indexed object has a symmetry, GiNaC will automatically bring the indices into a canonical order which allows for some immediate simplifications:
... cout << indexed(A, sy_symm(), i, j) + indexed(A, sy_symm(), j, i) << endl; // -> 2*A.j.i cout << indexed(B, sy_anti(), i, j) + indexed(B, sy_anti(), j, i) << endl; // -> 0 cout << indexed(B, sy_anti(), i, j, k) - indexed(B, sy_anti(), j, k, i) << endl; // -> 0 ... |
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |