Action of Permutation Group S7 on Octonion Triads

The C code below sets up an octonion multiplication table (without signs), for a specified set of triads comprising a quaternionic grouping; then each permutation of the indices of the imaginary units is applied to a second (possibly the same) triad set, and the resulting multiplication table is constructed and compared to the original - if the same, the permutation has mapped the second triad set to the first, and is printed.

Input

Input is in a 2-line file, each line specifying a quaternionic grouping as a list of 7 indices in the lexically ordered list of triplets of unit elements, e.g. the input file containing:
0,9,14,20,23,27,28
1,8,12,16,24,26,32
has line 1 specifying the XOR representation, and line 2 specifying triads (1,2,4), (2,3,5), (3,4,6), (4,5,7), (5,6,1), (6,7,2), (7,1,3). The program will list all permutations of {1,2,...,7} which transform the latter quaternionic grouping into the XOR grouping.

Likewise, if the input file contains
0,9,14,20,23,27,28
0,9,14,20,23,27,28
the permutations listed will map the XOR triads onto themselves.

Some Observations

Consider the action of the permutation group S7 on quaternionic groupings of the 7 imaginary unit elements, e.g. for the XOR grouping
X = {(e1,e2,e3),(e1,e4,e5),(e1,e6,e7),(e2,e4,e6),(e2,e5,e7),(e3,e4,e7),(e3,e5,e6)},
the action of σ ∈ S7 on X is given by
σ(X) = {(eσ(1),eσ(2),eσ(3)),(eσ(1),eσ(4),eσ(5)),(eσ(1),eσ(6),eσ(7)),(eσ(2),eσ(4),eσ(6)),(eσ(2),eσ(5),eσ(7)),(eσ(3),eσ(4),eσ(7)),(eσ(3),eσ(5),eσ(6))},
Let SG represent the set of permutations preserving a given quaternionic grouping G. SG is easily seen to be a subgroup of the permutation group S7. If H represents a different quaternionic grouping, and g ∈ S7 maps H to G, then SGg is a set of o(SG) distinct elements of S7 mapping H to G, and SH = g-1SGg.

Hence, the number Q of distinct quaternionic groupings obtainable by permutation of a given grouping is given by the number of distinct cosets of any SG, i.e.
Q = o(S7)/o(SG) = 7!/168 = 30

(where 168 is found by the code below), or more generally, for N imaginary units, Q = N!/o(SG).

The Code for 7 Imaginaries

The following C code constructs a list of permutations in S7 which map the first of 2 given quaternionic groupings into the second (which quaternionic groupings are specified in an input file, as described in comments in the body of the code). Similar code is available for the 9-dimensional case (in which o(SG) is found to be 432), and for the sedenions, where o(SG)=8!/2.
#include <stdio.h>

int main() {
	int N=7, i, j, k, dif, *perm, *next, n;
	int triplets[35][3]; // lexically ordered list of all possible triplets of distinct elements
	FILE *fp;
	int triads[7];
	int M0[8][8], Mp[8][8];
	char filnam[50], line[50];
// create lexically ordered list of triplets of distinct elements
	for(i=1, n=0; i<=N; i++) {
		for(j=i+1; j<=N; j++) {
			for(k=j+1;k<=N;k++) {	
				triplets[n][0] = i;
				triplets[n][1] = j;
				triplets[n++][2] = k;
			}
		}
	}
	
// specify file containing lists of source triads and image triads
	printf("Read triad lists from: "); // 2 lines, each line giving list of 7 comma-separated indices in triplets[] to specify a triad set 
	scanf("%s", filnam);
	fp = fopen(filnam, "r");
// first line's triad set generates M0, the looked-for image of permutation acting on multiplication table from line 2
	fgets(line, 50, fp); 
	sscanf(line,"%d,%d,%d,%d,%d,%d,%d", &triads[0],  &triads[1],  &triads[2],  &triads[3],  &triads[4],  &triads[5],  &triads[6]); 
// make basic mult table, for comparison with permuted one
	M0[0][0] = Mp[0][0] = 0; 
	for(i=1; i< 8; i++) 
	{
		M0[0][i] = M0[i][0] = Mp[0][i] = Mp[i][0] = i;
		M0[i][i] = Mp[i][i] = -1;
	}
	for(i=0; i< 7; i++)
		for(j=0; j< 3; j++)
		{
			M0[triplets[triads[i]][j]][triplets[triads[i]][(j+1)%3]] = triplets[triads[i]][(j+2)%3];
			M0[triplets[triads[i]][(j+1)%3]][triplets[triads[i]][j]] = triplets[triads[i]][(j+2)%3];
		}
// 2nd line's triad set will be permuted and the result compared to the sought image M0
	fgets(line, 50, fp); // 2nd line's triad set generates multiplication table to be acted upon by permutations, image then compared to M0
	sscanf(line,"%d,%d,%d,%d,%d,%d,%d", &triads[0],  &triads[1],  &triads[2],  &triads[3],  &triads[4],  &triads[5],  &triads[6]); 
	fclose(fp);
	perm = (int *) malloc((N+1)*sizeof(int));
	perm[0] = N;
	for(i=1; i< N+1; i++)
		perm[i] = i;
	next = (int *) malloc((N+1)*sizeof(int));
	n = 0;
	while((k = nextp(perm, next))>0)
	{
		n++;
		for(i=0; i< 7; i++)
		for(j=0; j< 3; j++)
// create multiplication table Mp from permuted 2nd quaternionic grouping
		{
			Mp[perm[triplets[triads[i]][j]]][perm[triplets[triads[i]][(j+1)%3]]] = perm[triplets[triads[i]][(j+2)%3]];
			Mp[perm[triplets[triads[i]][(j+1)%3]]][perm[triplets[triads[i]][j]]] = perm[triplets[triads[i]][(j+2)%3]];
		}
		for(i=1, dif=0; i< 8 && dif==0; i++)
// compare Mp to M0 and record permutation if Mp = M0
			for(j=1;j< 8 && dif==0;j++)
				if(M0[i][j] != Mp[i][j]) dif = 1;
			for(j=1; j< N+1; j++)
			{
				if(dif==0)
					printf("%d ", perm[j]);
				perm[j] = next[j];
			}
			if(dif==0)
				printf(" #%d\n", n);
	}
}
int nextp(int *perm, int *next)
// check all permutations by stepping through them in natural lexical order
{
	int i, j, k, N;
	N = perm[0];
	for(i=0; i<=N; i++) next[i] = perm[i];
	for(i=N-1; i>0 && perm[i+1]< perm[i];i--); // i will point to 1st breaker of monotonic increase from right
	if(i==0) return 0;
	for(j=i+1; perm[i]< perm[j] && j< N+1; j++); // j-1 will point to elt to swap w i
	next[i] = perm[j-1];
	next[j-1] = perm[i];
	for(j=1; j<=(N-i)/2; j++) 
	{
		k = next[i+j];
		next[i+j] = next[N-j+1];
		next[N-j+1] = k;
	}
	return i;
}

Sample Outputs

Here are some resulting permutation sets for quaternionic groupings within the octonions:

Code for 9 Imaginaries

The following C program finds the permutations in S9 which leave invariant a particular quaternionic grouping for the 9-dimensional Steiner triples system, using a method similar to the octonion code above:
#include <stdio.h>

int main() {
	int N=9, i, j, k, dif, *perm, *next, n;
	int triads[12][3] = {{1,2,3},{1,4,5},{1,6,7},{1,8,9},{2,4,6},{2,5,8},{2,7,9},{3,4,9},{3,5,7},{3,6,8},{4,7,8},{5,6,9}};
	int M0[10][10], Mp[10][10];
// make basic mult table, for comparison with permuted one
	M0[0][0] = Mp[0][0] = 0;
	for(i=1; i< 10; i++) 
	{
		M0[0][i] = M0[i][0] = Mp[0][i] = Mp[i][0] = i;
		M0[i][i] = Mp[i][i] = -1;
	}
	for(i=0; i< 12; i++)
		for(j=0; j< 3; j++)
		{
			M0[triads[i][j]][triads[i][(j+1)%3]] = triads[i][(j+2)%3];
			M0[triads[i][(j+1)%3]][triads[i][j]] = triads[i][(j+2)%3];
		}
	perm = (int *) malloc((N+1)*sizeof(int));
	perm[0] = N;
	for(i=1; i<= N; i++)
		perm[i] = i;
	next = (int *) malloc((N+1)*sizeof(int));
	n = 0;
	while((k = nextp(perm, next))>0)
	{
		n++;
		for(i=0; i< 12; i++)
		for(j=0; j< 3; j++)
		{
			Mp[perm[triads[i][j]]][perm[triads[i][(j+1)%3]]] = perm[triads[i][(j+2)%3]];
			Mp[perm[triads[i][(j+1)%3]]][perm[triads[i][j]]] = perm[triads[i][(j+2)%3]];
		}
		for(i=1, dif=0; i< 8 && dif==0; i++)
			for(j=1;j< 8 && dif==0;j++)
				if(M0[i][j] != Mp[i][j]) dif = 1;
			for(j=1; j< N+1; j++)
			{
				if(dif==0)
					printf("%d ", perm[j]);
				perm[j] = next[j];
			}
			if(dif==0)
				printf(" #%d\n", n);
	}
}
int nextp(int *perm, int *next)
{
	int i, j, k, N;
	N = perm[0];
	for(i=0; i<= N; i++) next[i] = perm[i];
	for(i=N-1; i>0 && perm[i+1]< perm[i];i--); // i will point to 1st breaker of monotonic increase from right
	if(i==0) return 0;
	for(j=i+1; perm[i]< perm[j] && j< N+1; j++); // j-1 will point to elt to swap w i
	next[i] = perm[j-1];
	next[j-1] = perm[i];
	for(j=1; j<= (N-i)/2; j++) 
	{
		k = next[i+j];
		next[i+j] = next[N-j+1];
		next[N-j+1] = k;
	}
	return i;
}