Symmetrized Arrays

Symmetry plays a key role in the treatment of high-rank tensors. Most high-rank tensors of importance in physics and mathematics have symmetry, from the symmetric inertia tensors to the rank-4 stiffness and curvature tensors. Many of them have transposition symmetries, in some cases rather complicated. The Wolfram System implements a complete language for permutation symmetries of tensors of any rank or dimensions, and provides a specialized type of array that stores only the independent components with respect to symmetry. This frequently results in a substantial gain in storage space, though usually at the expense of slower manipulations, because more complex algorithms are required. See "Tensor Symmetries" for a description of the language of symmetries.

Representation of Arrays with Symmetry

Symmetrized arrays.

This is an array with symmetry:

array={{{18,-92,0},{-92,25,67},{0,67,-5}},{{-92,25,67},{25,46,-26},{67,-26,27}},{{0,67,-5},{67,-26,27},{-5,27,-82}}};

TensorSymmetry[array]

That means that the array stays invariant under all permutations of its slots:

Transpose[array,#]===array&/@Permutations[{1,2,3}]

It can be stored a simpler way, which better reflects the fact that some elements are repeated several times:

sarray=SymmetrizedArray[array]

The new representation contains the dimensions, the list of nonzero independent components, and the symmetry:

sarray//InputForm

Its normal form coincides with the original array:

Normal[sarray]===array

These are rules for the independent components of the array. The default rule at the end represents the fact that independent components not given here are taken to have value 0:

SymmetrizedArrayRules[sarray]

Symmetrized arrays offer a compact way to store some arrays with much symmetry. In particular, antisymmetry maximizes this gain. In the most extreme nonzero case, a fully antisymmetric rank-n array in dimension n has one independent component. Its sparse representation contains n! nonzero elements, and its normal form has (n^n) entries. On the other hand, manipulation of symmetrized arrays is usually slower because it requires more complex algorithms.

(RefLink[LeviCivitaTensor, paclet:ref/LeviCivitaTensor]) offers a sparse representation by default:

lc7=LeviCivitaTensor[7]

(RefLink[LeviCivitaTensor, paclet:ref/LeviCivitaTensor]) offers a symmetrized and normal represention:

lc7S=LeviCivitaTensor[7,SymmetrizedArray]

lc7N=LeviCivitaTensor[7,List];

Compare sizes of the different representations:

lc7S//ByteCount

lc7//ByteCount

lc7N//ByteCount

There are other highly symmetric arrays in the Wolfram System.

disk=DiskMatrix[{7,7,7,7,7}];

ByteCount[disk]

SymmetrizedArray[disk]//ByteCount

(RefLink[StructuredArray, paclet:ref/StructuredArray]) objects, in particular symmetrized arrays, are treated as atomic objects. Their information can be accessed using functions.

A symmetrized array is atomic:

AtomQ[sarray]

The information about the array can be obtained as follows:

SymmetrizedArrayRules[sarray]

Dimensions[sarray]

TensorSymmetry[sarray]

Extract components of the array, irrespectively of whether they are independent or not:

sarray[[1,2,3]]

sarray[[2,3,1]]

Extract subarrays, keeping their symmetry if possible:

sarray[[2]]

TensorSymmetry[%]

Individual elements can be changed. Note that the given rule is transformed into its corresponding independent component rule:

SymmetrizedReplacePart[sarray,{{3,2,1}->X}]

Normal[%]

Construction of Symmetrized Arrays

It has been shown that (RefLink[SymmetrizedArray, paclet:ref/SymmetrizedArray]) can be used to rewrite a normal array with symmetry in a more efficient form. Following (RefLink[SparseArray, paclet:ref/SparseArray]), (RefLink[SymmetrizedArray, paclet:ref/SymmetrizedArray]) can also construct the same efficient representation from a list of rules and a symmetry specification.

(RefLink[SymmetrizedArray, paclet:ref/SymmetrizedArray]) form of an antisymmetric matrix:

{{0,1,0},{-1,0,2},{0,-2,0}}//SymmetrizedArray

These are its independent components:

rules=SymmetrizedArrayRules[%]

Reconstruct the array from these rules and the symmetry:

SymmetrizedArray[rules,{3,3},Antisymmetric[{1,2}]]

Normal[%]

If the symmetry is not provided, then the identity symmetry is assumed. The result is effectively equivalent to using (RefLink[SparseArray, paclet:ref/SparseArray]) with the same rules:

SymmetrizedArray[rules,{3,3}]==SparseArray[rules,{3,3}]

Rules that are incompatible with the symmetry are discarded:

SymmetrizedArray[{{1,1}->x11,{1,2}->x12,{2,2}->x22},{2,2},Antisymmetric[{1,2}]]

Normal[%]

General patterns in rules can be used in the first argument of (RefLink[SymmetrizedArray, paclet:ref/SymmetrizedArray]). These rules are meant to be rules for the independent components only, as given by (RefLink[SymmetrizedIndependentComponents, paclet:ref/SymmetrizedIndependentComponents]), and not for all positions of the array, as (RefLink[SparseArray, paclet:ref/SparseArray]) would do. In particular, this is useful to generate symmetrized arrays with random entries.

A random rank-3 antisymmetric array in dimension 4:

SeedRandom[0]
sarray=SymmetrizedArray[_:>RandomInteger[10],{4,4,4},Antisymmetric[{1,2,3}]]

Normal[sarray]

Use indexed expression as components of the array:

sarray=SymmetrizedArray[pos_:>(Subscript[x, pos]),{4,4,4},Antisymmetric[All]]

Normal[sarray]

An alternative way to construct symmetrized arrays is by actual symmetrization of other arrays, using the function (RefLink[Symmetrize, paclet:ref/Symmetrize]).

Symmetrize a general matrix:

Symmetrize[{{a,b},{c,d}}]

Normal[%]

Symmetrized with other symmetries:

Symmetrize[{{a,b},{c,d}},Antisymmetric[{1,2}]]

Normal[%]

Antisymmetric Arrays

The antisymmetric tensors play a fundamental role in exterior algebra. The Wolfram System provides the basic operations of the wedge product of antisymmetric tensors and Hodge duality.

Take two antisymmetric arrays in dimension 5:

SeedRandom[0]
aa1=SymmetrizedArray[_:>RandomInteger[10],{5,5},Antisymmetric[All]];
aa2=SymmetrizedArray[_:>RandomInteger[10],{5,5},Antisymmetric[All]];

Their wedge product is the antisymmetrized tensor product, except for a multiplicative factor given by the multinomial of the ranks:

aa1\[TensorWedge]aa2

%===Multinomial[2,2]Symmetrize[aa1⊗aa2,Antisymmetric[All]]

When the total rank exceeds the dimension, the result vanishes:

aa1\[TensorWedge]aa2\[TensorWedge]aa1//SymmetrizedArrayRules

The (RefLink[SymmetrizedArray, paclet:ref/SymmetrizedArray]) representation allows working with high dimensions; that would not be possible otherwise with normal or sparse representations:

SeedRandom[0]
aa1=SymmetrizedArray[_:>RandomInteger[10],ConstantArray[15,6],Antisymmetric[All]];
aa2=SymmetrizedArray[_:>RandomInteger[10],ConstantArray[15,8],Antisymmetric[All]];

(aa12=aa1\[TensorWedge]aa2)//Timing

The result is more conveniently represented giving its Hodge dual:

HodgeDual[aa12]

%//Normal