C
introduction
Comme l'a commenté David Carraher, le moyen le plus simple d'analyser le pavage hexagonal semblait être de tirer parti de son isomorphisme avec le diagramme de Young tridimensionnel, essentiellement un carré x, y rempli de barres de hauteur entière dont la hauteur z doit rester la même ou augmenter. lorsque l’axe z est approché.
J'ai commencé avec un algorithme permettant de trouver les totaux, plus facile à adapter pour le comptage de symétrie que l'algorithme publié, basé sur un biais par rapport à l'un des trois axes cartésiens.
Algorithme
Je commence par remplir les cellules des plans x, y et z avec des 1, tandis que le reste de la zone contient des zéros. Une fois cela fait, je construis le motif couche par couche, chaque couche contenant les cellules qui ont une distance de manhattan 3D commune à l'origine. Une cellule ne peut contenir un 1 que si les trois cellules en dessous contiennent également un 1. Si l'une d'entre elles contient un 0, la cellule doit être un 0.
L'avantage de construire le motif de cette manière est que chaque couche est symétrique autour de la ligne x = y = z. Cela signifie que chaque couche peut être vérifiée indépendamment pour sa symétrie.
Vérification de la symétrie
Les symétries du solide sont les suivantes: Rotation 3 fois autour de la ligne x = y = z -> Rotation 3 fois autour du centre de l'hexagone; et 3 réflexions x autour des 3 plans contenant la ligne x = y = z et chacun des axes x, y, z -> réflexion autour des lignes passant par les angles hexagonaux.
Cela ne fait qu'ajouter une symétrie 6 fois. Pour obtenir la symétrie complète de l'hexagone, un autre type de symétrie doit être envisagé. Chaque solide (construit à partir de 1) a un solide complémentaire (construit à partir de 0). Lorsque N est impair, le solide complémentaire doit être différent du solide d'origine (car il ne leur est pas possible d'avoir le même nombre de cubes). Pourtant, lorsque le solide complémentaire est retourné, on constate que sa représentation 2D sous forme de mosaïque de diamant est identique (à l’exception d’une opération à symétrie double) au solide initial. Lorsque N est pair, il est possible que le solide soit auto-inverse.
Cela se voit dans les exemples pour N = 2 dans la question. Vu de gauche, le premier hexagone ressemble à un cube solide avec 8 petits cubes, tandis que le dernier hexagone ressemble à une coque vide avec 0 petit cube. Si vu de la droite, l'inverse est vrai. Les 3ème, 4ème et 5ème hexagones et les 16ème, 17ème et 18ème hexagones semblent contenir 2 ou 6 cubes et se complètent donc en 3 dimensions. Ils sont reliés les uns aux autres en 2 dimensions par une opération de symétrie 2 (rotation 2 fois, ou réflexion autour d'un axe passant par les arêtes de l'hexagone). D'autre part, les 9ème, 10ème, 11ème et 12ème hexagones montrent des motifs 3D qui sont leurs propres compléments et ont donc une symétrie plus élevée (ce sont donc les seuls modèles avec une multiplicité impaire).
Notez qu'avoir (N ^ 3) / 2 cubes est une condition nécessaire pour être auto-complémentaire, mais en général, il ne suffit pas si N> 2. Le résultat de tout cela est que pour les N impairs, les pavages apparaissent toujours par paires (N ^ 3) / 2 cubes doivent être soigneusement inspectés.
Code actuel (génère le total correct pour N = 1,2,3,5. Erreur comme indiqué pour N = 4.)
int n; //side length
char t[11][11][11]; //grid sized for N up to 10
int q[29][192], r[29]; //tables of coordinates for up to 10*3-2=28 layers
int c[9]; //counts arrangements found by symmetry class. c[8] contains total.
//recursive layer counting function. m= manhattan distance, e= number of cells in previous layers, s=symmetry class.
void f(int m,int e,int s){
int u[64], v[64], w[64]; //shortlists for x,y,z coordinates of cells in this layer
int j=0;
int x,y,z;
for (int i=r[m]*3; i; i-=3){
// get a set of coordinates for a cell in the current layer.
x=q[m][i-3]; y= q[m][i-2]; z= q[m][i-1];
// if the three cells in the previous layer are filled, add it to the shortlist u[],v[],w[]. j indicates the length of the shortlist.
if (t[x][y][z-1] && t[x][y-1][z] && t[x-1][y][z]) u[j]=x, v[j]=y, w[j++]=z ;
}
// there are 1<<j possible arrangements for this layer.
for (int i = 1 << j; i--;) {
int d = 0;
// for each value of i, set the 1's bits of t[] to the 1's bits of i. Count the number of 1's into d as we go.
for (int k = j; k--;) d+=(t[u[k]][v[k]][w[k]]=(i>>k)&1);
// we have no interest in i=0 as it is the empty layer and therefore the same as the previous recursion step.
// Still we loop through it to ensure t[] is properly cleared.
if(i>0){
int s1=s; //local copy of symmetry class. 1's bit for 3 fold rotation, 2's bit for reflection in y axis.
int sc=0; //symmetry of self-complement.
//if previous layers were symmetrical, test if the symmetry has been reduced by the current layer
if (s1) for (int k = j; k--;) s1 &= (t[u[k]][v[k]][w[k]]==t[w[k]][u[k]][v[k]]) | (t[u[k]][v[k]][w[k]]==t[w[k]][v[k]][u[k]])<<1;
//if exactly half the cells are filled, test for self complement
if ((e+d)*2==n*n*n){
sc=1;
for(int A=1; A<=(n>>1); A++)for(int B=1; B<=n; B++)for(int C=1; C<=n; C++) sc&=t[A][B][C]^t[n+1-A][n+1-B][n+1-C];
}
//increment counters for total and for symmetry class.
c[8]++; c[s1+(sc<<2)]++;
//uncomment for graphic display of each block stacking with metadata. not recommended for n>3.
//printf("m=%d j=%d i=%d c1=%d-2*%d=%d c3=%d cy=%d(cs=%d) c3v=%d ctot=%d\n",m,j,i,c[0],c[2],c[0]-2*c[2],c[1],c[2],c[2]*3,c[3],c[8]);
//printf("m=%d j=%d i=%d C1=%d-2*%d=%d C3=%d CY=%d(CS=%d) C3V=%d ctot=%d\n",m,j,i,c[4],c[6],c[4]-2*c[6],c[5],c[6],c[6]*3,c[7],c[8]);
//for (int A = 0; A<4; A++, puts(""))for (int B = 0; B<4; B++, printf(" "))for (int C = 0; C<4; C++) printf("%c",34+t[A][B][C]);
//recurse to next level.
if(m<n*3-2)f(m + 1,e+d,s1);
}
}
}
main()
{
scanf("%d",&n);
int x,y,z;
// Fill x,y and z planes of t[] with 1's
for (int a=0; a<9; a++) for (int b=0; b<9; b++) t[a][b][0]= t[0][a][b]= t[b][0][a]= 1;
// Build table of coordinates for each manhattan layer
for (int m=1; m < n*3-1; m++){
printf("m=%d : ",m);
int j=0;
for (x = 1; x <= n; x++) for (y = 1; y <= n; y++) {
z=m+2-x-y;
if (z>0 && z <= n) q[m][j++] = x, q[m][j++] = y, q[m][j++]=z, printf(" %d%d%d ",x,y,z);
r[m]=j/3;
}
printf(" : r=%d\n",r[m]);
}
// Set count to 1 representing the empty box (symmetry c3v)
c[8]=1; c[3]=1;
// Start searching at f=1, with 0 cells occupied and symmetry 3=c3v
f(1,0,3);
// c[2 and 6] only contain reflections in y axis, therefore must be multiplied by 3.
// Similarly the reflections in x and z axis must be subtracted from c[0] and c[4].
c[0]-=c[2]*2; c[2]*=3;
c[4]-=c[6]*2; c[6]*=3;
int cr[9];cr[8]=0;
printf("non self-complement self-complement\n");
printf("c1 %9d/12=%9d C1 %9d/6=%9d\n", c[0], cr[0]=c[0]/12, c[4], cr[4]=c[4]/6);
if(cr[0]*12!=c[0])puts("c1 division error");if(cr[4]*6!=c[4])puts("C1 division error");
printf("c3 %9d/4 =%9d C3 %9d/2=%9d\n", c[1], cr[1]=c[1]/4, c[5], cr[5]=c[5]/2);
if(cr[1]*4!=c[1])puts("c3 division error");if(cr[5]*2!=c[5])puts("C3 division error");
printf("cs %9d/6 =%9d CS %9d/3=%9d\n", c[2], cr[2]=c[2]/6, c[6], cr[6]=c[6]/3);
if(cr[2]*6!=c[2])puts("cs division error");if(cr[6]*3!=c[6])puts("CS division error");
printf("c3v %9d/2 =%9d C3V %9d/1=%9d\n", c[3], cr[3]=c[3]/2, c[7], cr[7]=c[7]);
if(cr[3]*2!=c[3])puts("c3v division error");
for(int i=8;i--;)cr[8]+=cr[i];
printf("total =%d unique =%d",c[8],cr[8]);
}
Sortie
Le programme génère une table de sortie de 8 entrées, conformément aux 8 symétries du solide. Le solide peut avoir l’une des 4 symétries suivantes (notation Schoenflies)
c1: no symmetry
c3: 3-fold axis of rotation (produces 3-fold axis of rotation in hexagon tiling)
cs: plane of reflection (produces line of reflection in hexagon tiling)
c3v both of the above (produces 3-fold axis of rotation and three lines of reflection through the hexagon corners)
De plus, lorsque le solide a exactement la moitié des cellules avec 1 et l'autre avec 0, il est possible d'inverser tous les 1 et les 0, puis d'inverser les coordonnées par le centre de l'espace du cube. C'est ce que j'appelle l'auto-complément, mais un terme plus mathématique serait "antisymétrique par rapport à un centre d'inversion".
Cette opération de symétrie donne un axe de rotation de 2 fois dans le pavage hexagonal.
Les motifs qui ont cette symétrie sont listés dans une colonne séparée. Ils ne se produisent que lorsque N est pair.
Mon compte semble être légèrement en retrait pour N = 4. En discutant avec Peter Taylor, il apparaît que je ne détecte pas de pavages présentant uniquement une symétrie d'une ligne sur les arêtes de l'hexagone. Ceci est probablement dû au fait que je n'ai pas testé l'auto-complément (antisymétrie) pour des opérations autres que (inversion) x (identité.). ) peut découvrir les symétries manquantes. Je m'attendrais alors à ce que la première ligne des données pour N = 4 ressemble à ceci (16 de moins en c1 et 32 de plus en C1):
c1 224064/12=18672 C1 534/6=89
Cela alignerait les totaux sur la réponse de Peter et sur https://oeis.org/A066931/a066931.txt.
la sortie actuelle est la suivante.
N=1
non self-complement self-complement
c1 0/12= 0 C1 0/6= 0
c3 0/4 = 0 C3 0/2= 0
cs 0/6 = 0 CS 0/3= 0
c3v 2/2 = 1 C3V 0/1= 0
total =2 unique =1
non self-complement self-complement
N=2
c1 0/12= 0 C1 0/6= 0
c3 0/4 = 0 C3 0/2= 0
cs 12/6 = 2 CS 3/3= 1
c3v 4/2 = 2 C3V 1/1= 1
total =20 unique =6
N=3
non self-complement self-complement
c1 672/12=56 C1 0/6= 0
c3 4/4 = 1 C3 0/2= 0
cs 288/6 =48 CS 0/3= 0
c3v 16/2 = 8 C3V 0/1= 0
total =980 unique =113
N=4 (errors as discussed)
non self-complement self-complement
c1 224256/12=18688 C1 342/6=57
c3 64/4 =16 C3 2/2= 1
cs 8064/6 =1344 CS 54/3=18
c3v 64/2 =32 C3V 2/1= 2
total =232848 unique =20158
N=5
non self-complement self-complement
c1 266774112/12=22231176 C1 0/6= 0
c3 1100/4 =275 C3 0/2= 0
cs 451968/6 =75328 CS 0/3= 0
c3v 352/2 =176 C3V 0/1= 0
total =267227532 unique =22306955
Liste de tâches (mise à jour)
Ranger le code actuel.
Fait plus ou moins
Implémentez la vérification de symétrie pour la couche en cours et transmettez un paramètre pour la symétrie de la couche précédente (cela ne sert à rien de vérifier si la dernière couche était asymétrique.)
Fait, les résultats pour N impair correspondent aux données publiées.
Ajoute une option pour supprimer le comptage des figures asymétriques (devrait courir beaucoup plus vite)
Cela peut être fait en ajoutant une autre condition à l'appel récursif: if(s1 && m<n*3-2)f(m + 1,e+d,s1)
Cela réduit le temps d'exécution pour N = 5 de 5 minutes à environ une seconde. En conséquence, la première ligne de la sortie devient le total des déchets (tout comme les totaux globaux), mais si le total est déjà connu d’OEIS, le nombre de pavages asymétriques peut être reconstitué, au moins pour les N. impairs.
Mais même pour N, le nombre de solides asymétriques (selon les symétries c3v) qui s'auto-complétaient serait perdu. Dans ce cas, un programme séparé dédié aux solides avec exactement (N ** 3) / 2 cellules avec un 1 peut être utile. Avec cette option disponible (et en comptant correctement), il peut être possible d’essayer N = 6, mais l’exécution prendra beaucoup de temps.
Implémentez le comptage des cellules pour réduire la recherche à (N ^ 3) / 2 cubes.
Non fait, les économies devraient être marginales
Implémentez la vérification de symétrie (solide complémentaire) pour les motifs contenant exactement (N ^ 3) / 2 cubes.
Fait, mais semble avoir des omissions, voir N = 4.
Trouvez un moyen de choisir le chiffre lexical le plus bas parmi un chiffre asymétrique.
Les économies ne devraient pas être aussi bonnes. Supprimer les figures asymétriques élimine la plupart de cela. La seule réflexion vérifiée est le plan passant par l’axe des y (x et z sont calculés ultérieurement en les multipliant par 3.). Peut-être que cela courrait presque deux fois plus vite si on n'en comptait qu'un.
Pour faciliter ceci, améliorez éventuellement la façon dont les coordonnées dans chaque couche sont listées (elles forment des groupes dégénérés de 6 ou 3, avec éventuellement un groupe de 1 au centre exact de la couche.)
Intéressant, mais il y a probablement d'autres questions sur le site à explorer.
N = 6
sortie de plus de 10 ^ 12, une solution non constructive est presque certainement nécessaire pour aller aussi loin.