# Permute association key and generate a sparse array

Imagine having an Association

Av = <|{1, 4, 2, 3} -> a, {2, 4, 2, 4} -> b|>


It can be much longer. I am searching for an idiomatic and transparent way to construct a SparseArray out of it: Sv=buildSA[Av] The caveat is that each value corresponds to 8 possible permutation of indices. In particular, given the entry {i,j,k,l}->v, the sparse array should also contain

{i,j,k,l}->v
{l,j,k,i}->v
{l,k,j,i}->v
{i,k,j,l}->v
{j,i,l,k}->v
{k,i,l,j}->v
{k,l,i,j}->v
{j,l,i,k}->v


These symmetry properties come from the underlying definition

Sv[[i,j,k,l]]=Integrate[f[i][x] f[j][y] f[k][y] f[l][x] v[x,y],{x,...},{y,...}]

and the fact that v[x,y]==v[y,x].

I have a way to do that,

buildSA[a_] := Module[{b, ki, vi},
b = <||>;
Do[
vi = a[ki];
AssociateTo[b, ki[[{1, 2, 3, 4}]] -> vi];
AssociateTo[b, ki[[{4, 2, 3, 1}]] -> vi];
AssociateTo[b, ki[[{4, 3, 2, 1}]] -> vi];
AssociateTo[b, ki[[{1, 3, 2, 4}]] -> vi];
AssociateTo[b, ki[[{2, 1, 4, 3}]] -> vi];
AssociateTo[b, ki[[{3, 1, 4, 2}]] -> vi];
AssociateTo[b, ki[[{3, 4, 1, 2}]] -> vi];
AssociateTo[b, ki[[{2, 4, 1, 3}]] -> vi];
,
{ki, Keys[a]}];
SparseArray[b // Normal]
]


but it looks very artificial. What would be the natural way to do it?

• Why specifically these 8 permutations? Sep 18, 2020 at 8:01
• @Szabolcs The elements of the sparse array I am constructing are essentially integrals of the product of 4 functions. The permutation symmetry comes from the symmetry of integrals with respect to the permutation of functions. Sep 18, 2020 at 8:14
• @Szabolcs I have updated the post with the explanation of the reason for symmetries and my own messy implementation. Sep 18, 2020 at 8:22

Maybe with SymmetrizedArray?

size = 4;
rank = 4;
Av = <|{1, 4, 2, 3} -> a, {2, 4, 2, 4} -> b|>;
symmetries = {
{{4, 2, 3, 1}, 1},
{{4, 3, 2, 1}, 1},
{{1, 3, 2, 4}, 1},
{{2, 1, 4, 3}, 1},
{{3, 1, 4, 2}, 1},
{{3, 4, 1, 2}, 1},
{{2, 4, 1, 3}, 1}
};
A = SparseArray[
SymmetrizedArray[Normal[Av], ConstantArray[n, rank], symmetries]
]


In the list symmetries, each entry is a pair {p,s} of a permutation p that can be applied and a sign s (1, -1) that tells us whether the array is meant to be symmetric (s = 1 means symmetric, s = -1 means antisymmetric).

In fact, it suffices to provide only a set of generators of the symmetry group. For example,

symmetries = {
{{4, 2, 3, 1}, 1},
{{1, 3, 2, 4}, 1},
{{2, 4, 1, 3}, 1}
};


would lead to the same result

• Very nice! Especially appealing is the possibility to only provide a list of generators. Sep 18, 2020 at 8:48
• Thank you very much! =) Sep 18, 2020 at 9:19
pg = PermutationGroup[{{1, 2, 3, 4}, {4, 2, 3, 1}, {4, 3, 2, 1}, {1,
3, 2, 4}, {2, 1, 4, 3}, {3, 1, 4, 2}, {3, 4, 1, 2}, {2, 4, 1, 3}}];

ClearAll[sAbuild]
sAbuild = SparseArray[KeyValueMap[Alternatives @@
GroupOrbits[pg, {#}, Permute][[1]] -> #2 &]@#, #2] &;

dims = {4, 4, 4, 4};

sAbuild[Av, dims]


Based on Henrik's answer, we can use a smaller set of generators to get the same result:

pg = PermutationGroup @ {{4, 2, 3, 1}, {1, 3, 2, 4}, {2, 4, 1, 3}};

• Thank you, I was thinking in this direction, but could not figure it out the KeyValueMap with Alternatives construction. I guess the group should be possible to build from the constructors somehow. Sep 18, 2020 at 8:47