Yakut
Arka fon
Sonsuz boyutlara uzanan üç düzenli politop ailesi vardır:
tetrahedronun üyesi olduğu simpleksler (simpleks terimi daha doğru olmasına rağmen, burada sık sık hipertetrahedra olarak anlatacağım.) Onların schlafi sembolleri formda {3,3,...,3,3}
küpün üyesi olduğu n küpleri. Schlafi sembolleri şu şekildedir{4,3,...,3,3}
oktahedronun üyesi olduğu ortopleksler (sık sık burada hyperoctahedra olarak bahsedeceğim) Schlafi sembolleri formdadır {3,3,...,3,4}
{m}Herhangi bir sayıda m kenarına sahip olabilen 2 boyutlu çokgenlerin sonsuz bir düzenli politop ailesi sembolü vardır .
Buna ek olarak, sadece beş özel düzenli politop vakası vardır: 3 boyutlu ikosahedron {3,5}ve dodekahedron {5,3}; bunların 4-boyutlu analogları 600-hücre {3,3,5}ve 120-hücre {5,3,3}; ve bir diğer 4 boyutlu politop, 24 hücreli {3,4,3}(3 boyuttaki en yakın analogları küboktahedron ve ikilisi eşkenar dodekahedron olan).
Ana işlev
Aşağıda polytopeschlafi sembolünü yorumlayan ana işlev bulunmaktadır. Bir sayı dizisi bekler ve aşağıdaki gibi bir dizi dizi içeren bir dizi döndürür:
Tüm köşelerin bir dizisi, her biri n öğeli bir koordinat dizisi olarak ifade edilir (burada n, boyut sayısıdır)
Her kenarın bir dizi köşe indeksleri olarak ifade edilen tüm kenarlardan oluşan bir dizi
Her yüzün, köşe indekslerinin bir m elemanı olarak ifade edildiği tüm yüzlerden oluşan bir dizi (burada m, yüz başına köşe sayısıdır)
ve böylece boyut sayısına uygun şekilde devam eder.
2d politoplarını kendisi hesaplar, 3 sonsuz boyutlu aile için işlevleri çağırır ve beş özel durum için arama tablolarını kullanır. Üzerinde belirtilen fonksiyonları ve tabloları bulmayı bekler.
include Math
#code in subsequent sections of this answer should be inserted here
polytope=->schl{
if schl.size==1 #if a single digit calculate and return a polygon
return [(1..schl[0]).map{|i|[sin(PI*2*i/schl[0]),cos(PI*2*i/schl[0])]},(1..schl[0]).map{|i|[i%schl[0],(i+1)%schl[0]]}]
elsif i=[[3,5],[5,3]].index(schl) #if a 3d special, lookup from tables
return [[vv,ee,ff],[uu,aa,bb]][i]
elsif i=[[3,3,5],[5,3,3],[3,4,3]].index(schl) #if a 4d special. lookup fromm tables
return [[v,e,f,g],[u,x,y,z],[o,p,q,r]][i]
elsif schl.size==schl.count(3) #if all threes, call tetr for a hypertetrahedron
return tetr[schl.size+1]
elsif schl.size-1==schl.count(3) #if all except one number 3
return cube[schl.size+1] if schl[0]==4 #and the 1st digit is 4, call cube for a hypercube
return octa[schl.size+1] if schl[-1]==4 #and the last digit is 4, call octa for a hyperoctahedron
end
return "error" #in any other case return an error
}
Tetrahedron, küp ve oktahedron familyaları için fonksiyonlar
https://en.wikipedia.org/wiki/Simplex
https://en.wikipedia.org/wiki/5-cell (4d simpleks)
http://mathworld.wolfram.com/Simplex.html
Tetrahedron ailesi açıklaması - koordinatlar
n-boyutlu bir simpleks / hipertetrahedron n + 1 puana sahiptir. N-boyutlu simpleks köşelerini n + 1 boyutlarında vermek çok kolaydır.
Böylece (1,0,0),(0,1,0),(0,0,1)3 boyutlu gömülü bir 2d üçgen ve (1,0,0,0),(0,1,0,0),(0,0,1,0),(0,0,0,1)4 boyutlu gömülü bir 3d tetrahedron açıklanmaktadır. Bu, köşeler arasındaki tüm mesafelerin sqrt (2) olduğunu doğrulayarak kolayca doğrulanabilir.
N-boyutlu uzayda n-boyutlu simpleks için köşeleri bulmak için internette çeşitli karmaşık algoritmalar verilmiştir. Https://mathoverflow.net/a/38725 adresindeki Will Jagy'nin yorumlarında oldukça basit bir tane buldum . Son nokta p=q=...=x=y=z, diğerlerinden sqrt (2) mesafede hatta yatıyor . Bu nedenle, yukarıda üçgen ya da bir noktaya eklenmesiyle bir tetrahedron dönüştürülebilir (-1/3,-1/3,-1/3)ya da (1,1,1). Son nokta için koordinatların bu 2 olası değeri (1-(1+n)**0.5)/nve(1+(1+n)**0.5)/n
Soru n-tope büyüklüğü önemli değil diyor, ben n tarafından aracılığıyla çarpın tercih ve koordinatları kullanmak (n,0,0..0)kadar (0..0,0,n)final noktası ile (t,t,..,t,t)t = uygulama 1-(1+n)**0.5basitlik için.
Bu tetrahedronun merkezi başlangıç noktasında olmadığından s.map!{|j|j-((1-(1+n)**0.5)+n)/(1+n)}, merkezin başlangıç noktasından ne kadar uzak olduğunu bulan ve onu çıkaran çizgi tarafından tüm koordinatlarda bir düzeltme yapılmalıdır . Bunu ayrı bir işlem olarak sakladım. Bununla birlikte , dizi tarafından başlatıldığında buraya doğru ofseti koyabileceğimize ve merkezleme düzeltmesini sondan ziyade başlangıçta yapabileceğimize değinmek için s[i]+=nnerede yaptım .s[i]=ns=[0]*n
Tetrahedron ailesi açıklaması - grafik topolojisi
Tek yönlü grafiğin tamamı grafiktir: her tepe noktası, diğer tepe noktalarına tam olarak bir kez bağlanır. Bir n simpleksimiz varsa, n-1 simpleks vermek için herhangi bir tepe noktasını, bir üçgene veya bir kenara sahip olduğumuz noktaya kadar kaldırabiliriz.
Bu nedenle, her biri bir ikili sayıyla temsil edilen toplam 2 ** (n + 1) öğeye sahibiz. Bu 0, hiçlik için tüm s'den, 1bir tepe 1için bir s ve bir kenar için iki s 1, tam politop için tüm s'ye kadar değişir .
Her boyuttaki öğeleri saklamak için bir dizi boş dizi ayarladık. Ardından, olası köşe alt kümelerinin her birini oluşturmak için sıfırdan (2 ** n + 1) döngüye girer ve her alt kümenin boyutuna göre bunları dizide saklarız.
Kenardan (tepe noktası veya sıfır) daha küçük bir şeyle veya tam politopla (sorudaki örnekte tam küp verilmediğinden) ilgilenmiyoruz, bu nedenle tg[2..n]bu istenmeyen öğeleri kaldırmaya geri dönüyoruz. Geri dönmeden önce, tepe koordinatlarını içeren [tv] 'yi başa yapıştırıyoruz.
kod
tetr=->n{
#Tetrahedron Family Vertices
tv=(0..n).map{|i|
s=[0]*n
if i==n
s.map!{(1-(1+n)**0.5)}
else
s[i]+=n
end
s.map!{|j|j-((1-(1+n)**0.5)+n)/(1+n)}
s}
#Tetrahedron Family Graph
tg=(0..n+1).map{[]}
(2**(n+1)).times{|i|
s=[]
(n+1).times{|j|s<<j if i>>j&1==1}
tg[s.size]<<s
}
return [tv]+tg[2..n]}
cube=->n{
#Cube Family Vertices
cv=(0..2**n-1).map{|i|s=[];n.times{|j|s<<(i>>j&1)*2-1};s}
#Cube Family Graph
cg=(0..n+1).map{[]}
(3**n).times{|i| #for each point
s=[]
cv.size.times{|j| #and each vertex
t=true #assume vertex goes with point
n.times{|k| #and each pair of opposite sides
t&&= (i/(3**k)%3-1)*cv[j][k]!=-1 #if the vertex has kingsmove distance >1 from point it does not belong
}
s<<j if t #add the vertex if it belongs
}
cg[log2(s.size)+1]<<s if s.size > 0
}
return [cv]+cg[2..n]}
octa=->n{
#Octahedron Family Vertices
ov=(0..n*2-1).map{|i|s=[0]*n;s[i/2]=(-1)**i;s}
#Octahedron Family Graph
og=(0..n).map{[]}
(3**n).times{|i| #for each point
s=[]
ov.size.times{|j| #and each vertex
n.times{|k| #and each pair of opposite sides
s<<j if (i/(3**k)%3-1)*ov[j][k]==1 #if the vertex is located in the side corresponding to the point, add the vertex to the list
}
}
og[s.size]<<s
}
return [ov]+og[2..n]}
küp ve oktahedron aileleri açıklama - koordinatlar
N-küp olan 2**nköşe, n, bir dizi ile temsil edilen her bir 1S ve -1(bütün olasılığı da mümkün olduğunda). Biz, yineleme dizinlerini s 0için 2**n-1tüm tepe noktaları listesinin ve bit yineleme ile her bir köşe için bir dizi oluşturmak dizin ve diziye -1veya ekleme 1(en az anlamlı bit en anlamlı bit.) Böylece İkili 11014d noktası olur [1,-1,1,1].
N-sekiz yüzlü veya n-orthoplex sahip 2ntüm koordinatlar bir olması olan, biri dışında sıfır ile, köşe 1ya da -1. Oluşturulan dizideki köşe noktalarının sırası [[1,0,0..],[-1,0,0..],[0,1,0..],[0,-1,0..],[0,0,1..],[0,0,-1..]...]. Oktahedron, küpün ikizi olduğu için, oktahedronun köşelerinin, küpü çevreleyen yüzlerin merkezleri tarafından tanımlandığını unutmayın.
küp ve oktahedron aileleri açıklama - grafik topolojisi
Hypercube taraflarından ve hiperoktahedronun hiperküpün ikili olması gerçeğinden biraz ilham alındı .
N-küp 3**niçin kataloglanacak öğeler var . Örneğin, 3 küp3**3 = 27 elemente sahiptir. Bu, 1 merkez, 6 yüz, 12 kenar ve 8 köşeye sahip bir rubik küpünü toplam 27 için inceleyerek görülebilir. 2x2x2'lik bir n-küpü n-küpünü tanımlayan tüm boyutlarda -1,0 ve -1 arasında yineleme yaparız. .. ve küpün karşı tarafında OLMAYAN tüm köşeleri döndürün. Böylece küpün merkez noktası 2 ** n köşelerin tümünü döndürür ve bir birimi merkezden herhangi bir eksen boyunca hareket ettirmek, köşe sayısını yarı yarıya azaltır.
Tetrahedron ailesinde olduğu gibi, boş bir dizi dizisi üreterek başlıyoruz ve onu element başına köşe sayısına göre dolduruyoruz. Kenarların, yüzlerin, küplerin vb. Yukarı doğru giderken köşe sayısı 2 ** n olarak değiştiğinden log2(s.size)+1, basitçe kullanmak yerine kullanacağımızı unutmayın s.size. Yine, fonksiyondan dönmeden önce hiper küpün kendisini ve 2'den az köşesi olan tüm elemanları kaldırmamız gerekir.
Oktahedron / ortopleks ailesi, küp ailesinin çiftidir, bu nedenle yine 3**nkataloglanacak öğeler vardır . Burada -1,0,1tüm boyutlar için yineleme yapıyoruz ve bir tepe noktasının sıfır olmayan koordinatı noktanın karşılık gelen koordinatına eşitse, tepe noktası o noktaya karşılık gelen listeye eklenir. Böylece bir kenar, sıfır olmayan iki koordinatı olan bir noktaya, bir üçgen sıfır olmayan 3 koordinatı olan bir noktaya ve bir tetrahedron, sıfır olmayan temasları olan bir noktaya (4d uzayda) karşılık gelir.
Her nokta için ortaya çıkan köşe dizileri, diğer durumlarda olduğu gibi büyük bir dizide saklanır ve geri dönmeden önce 2 köşeden az olan öğeleri kaldırmamız gerekir. Ancak bu durumda, algoritmanın kaydetmediği için n-tope üst öğesinin tamamını kaldırmamız gerekmez.
Küp kod uygulamaları mümkün olduğunca benzer olacak şekilde tasarlanmıştır. Bunun belirli bir zarafeti olsa da, aynı prensiplere dayanan daha verimli algoritmaların tasarlanması muhtemeldir.
https://en.wikipedia.org/wiki/Hypercube
http://mathworld.wolfram.com/Hypercube.html
https://en.wikipedia.org/wiki/Cross-polytope
http://mathworld.wolfram.com/CrossPolytope.html
3D özel durumlar için tablo oluşturma kodu
Parçaların en tutarlı etiketlemesi için yapıldığı gibi, son boyuta paralel beş kat simetri ekseni ile yönlendirilmiş ikosahedron / dodekahedron ile bir yönlendirme kullanılmıştır. İkosahedron için köşe ve yüzlerin numaralandırılması kod yorumlarındaki şemaya göre yapılır ve dodekahedron için tersine çevrilir.
Https://tr.wikipedia.org/wiki/Regular_icosahedron'a göre , ikosahedronun polar olmayan 10 köşesinin enlemi +/- arctan (1/2) 'dir. İkosahedronun ilk 10 köşesinin koordinatları, bu, xy düzleminden +/- 2 mesafede yarıçap 2'nin iki dairesinde. Bu, ortamın toplam yarıçapını (5) yapar, böylece son 2 köşe (0,0, + / - sqrt (2)) olur.
Dodekahedronun köşe noktalarının koordinatları, onları çevreleyen üç ikosahedron tepe noktasının koordinatlarının toplanmasıyla hesaplanır.
=begin
TABLE NAMES vertices edges faces
icosahedron vv ee ff
dodecahedron uu aa bb
10
/ \ / \ / \ / \ / \
/10 \ /12 \ /14 \ /16 \ /18 \
-----1-----3-----5-----7-----9
\ 0 / \ 2 / \ 4 / \ 6 / \ 8 / \
\ / 1 \ / 3 \ / 5 \ / 7 \ / 9 \
0-----2-----4-----6-----8-----
\11 / \13 / \15 / \17 / \19 /
\ / \ / \ / \ / \ /
11
=end
vv=[];ee=[];ff=[]
10.times{|i|
vv[i]=[2*sin(PI/5*i),2*cos(PI/5*i),(-1)**i]
ee[i]=[i,(i+1)%10];ee[i+10]=[i,(i+2)%10];ee[i+20]=[i,11-i%2]
ff[i]=[(i-1)%10,i,(i+1)%10];ff[i+10]=[(i-1)%10,10+i%2,(i+1)%10]
}
vv+=[[0,0,-5**0.5],[0,0,5**0.5]]
uu=[];aa=[];bb=[]
10.times{|i|
uu[i]=(0..2).map{|j|vv[ff[i][0]][j]+vv[ff[i][1]][j]+vv[ff[i][2]][j]}
uu[i+10]=(0..2).map{|j|vv[ff[i+10][0]][j]+vv[ff[i+10][1]][j]+vv[ff[i+10][2]][j]}
aa[i]=[i,(i+1)%10];aa[i+10]=[i,(i+10)%10];aa[i+20]=[(i-1)%10+10,(i+1)%10+10]
bb[i]=[(i-1)%10+10,(i-1)%10,i,(i+1)%10,(i+1)%10+10]
}
bb+=[[10,12,14,16,18],[11,13,15,17,19]]
4d özel durumlar için tablo oluşturma kodu
Bu biraz hack. Bu kodun çalışması birkaç saniye sürer. Çıktıyı bir dosyada saklamak ve gerektiğinde yüklemek daha iyi olur.
600 hücre için 120 tepe koordinatı listesi http://mathworld.wolfram.com/600-Cell.html adresinden alınmıştır . Altın oran içermeyen 24 tepe koordinatı, 24 hücrenin köşe noktalarını oluşturur. Vikipedi aynı şemaya sahiptir, ancak bu 24 koordinatın ve diğer 96'nın göreceli ölçeğinde bir hata vardır.
#TABLE NAMES vertices edges faces cells
#600 cell (analogue of icosahedron) v e f g
#120 cell (analogue of dodecahedron) u x y z
#24 cell o p q r
#600-CELL
# 120 vertices of 600cell. First 24 are also vertices of 24-cell
v=[[2,0,0,0],[0,2,0,0],[0,0,2,0],[0,0,0,2],[-2,0,0,0],[0,-2,0,0],[0,0,-2,0],[0,0,0,-2]]+
(0..15).map{|j|[(-1)**(j/8),(-1)**(j/4),(-1)**(j/2),(-1)**j]}+
(0..95).map{|i|j=i/12
a,b,c,d=1.618*(-1)**(j/4),(-1)**(j/2),0.618*(-1)**j,0
h=[[a,b,c,d],[b,a,d,c],[c,d,a,b],[d,c,b,a]][i%12/3]
(i%3).times{h[0],h[1],h[2]=h[1],h[2],h[0]}
h}
#720 edges of 600cell. Identified by minimum distance of 2/phi between them
e=[]
120.times{|i|120.times{|j|
e<<[i,j] if i<j && ((v[i][0]-v[j][0])**2+(v[i][1]-v[j][1])**2+(v[i][2]-v[j][2])**2+(v[i][3]-v[j][3])**2)**0.5<1.3
}}
#1200 faces of 600cell.
#If 2 edges share a common vertex and the other 2 vertices form an edge in the list, it is a valid triangle.
f=[]
720.times{|i|720.times{|j|
f<< [e[i][0],e[i][1],e[j][1]] if i<j && e[i][0]==e[j][0] && e.index([e[i][1],e[j][1]])
}}
#600 cells of 600cell.
#If 2 triangles share a common edge and the other 2 vertices form an edge in the list, it is a valid tetrahedron.
g=[]
1200.times{|i|1200.times{|j|
g<< [f[i][0],f[i][1],f[i][2],f[j][2]] if i<j && f[i][0]==f[j][0] && f[i][1]==f[j][1] && e.index([f[i][2],f[j][2]])
}}
#120 CELL (dual of 600 cell)
#600 vertices of 120cell, correspond to the centres of the cells of the 600cell
u=g.map{|i|s=[0,0,0,0];i.each{|j|4.times{|k|s[k]+=v[j][k]/4.0}};s}
#1200 edges of 120cell at centres of faces of 600-cell. Search for pairs of tetrahedra with common face
x=f.map{|i|s=[];600.times{|j|s<<j if i==(i & g[j])};s}
#720 pentagonal faces, surrounding edges of 600-cell. Search for sets of 5 tetrahedra with common edge
y=e.map{|i|s=[];600.times{|j|s<<j if i==(i & g[j])};s}
#120 dodecahedral cells surrounding vertices of 600-cell. Search for sets of 20 tetrahedra with common vertex
z=(0..119).map{|i|s=[];600.times{|j|s<<j if [i]==([i] & g[j])};s}
#24-CELL
#24 vertices, a subset of the 600cell
o=v[0..23]
#96 edges, length 2, found by minimum distances between vertices
p=[]
24.times{|i|24.times{|j|
p<<[i,j] if i<j && ((v[i][0]-v[j][0])**2+(v[i][1]-v[j][1])**2+(v[i][2]-v[j][2])**2+(v[i][3]-v[j][3])**2)**0.5<2.1
}}
#96 triangles
#If 2 edges share a common vertex and the other 2 vertices form an edge in the list, it is a valid triangle.
q=[]
96.times{|i|96.times{|j|
q<< [p[i][0],p[i][1],p[j][1]] if i<j && p[i][0]==p[j][0] && p.index([p[i][1],p[j][1]])
}}
#24 cells. Calculates the centre of the cell and the 6 vertices nearest it
r=(0..23).map{|i|a,b=(-1)**i,(-1)**(i/2)
c=[[a,b,0,0],[a,0,b,0],[a,0,0,b],[0,a,b,0],[0,a,0,b],[0,0,a,b]][i/4]
s=[]
24.times{|j|t=v[j]
s<<j if (c[0]-t[0])**2+(c[1]-t[1])**2+(c[2]-t[2])**2+(c[3]-t[3])**2<=2
}
s}
https://en.wikipedia.org/wiki/600-cell
http://mathworld.wolfram.com/600-Cell.html
https://en.wikipedia.org/wiki/120-cell
http://mathworld.wolfram.com/120-Cell.html
https://en.wikipedia.org/wiki/24-cell
http://mathworld.wolfram.com/24-Cell.html
Kullanım ve çıktı örneği
cell24 = polytope[[3,4,3]]
puts "vertices"
cell24[0].each{|i|p i}
puts "edges"
cell24[1].each{|i|p i}
puts "faces"
cell24[2].each{|i|p i}
puts "cells"
cell24[3].each{|i|p i}
vertices
[2, 0, 0, 0]
[0, 2, 0, 0]
[0, 0, 2, 0]
[0, 0, 0, 2]
[-2, 0, 0, 0]
[0, -2, 0, 0]
[0, 0, -2, 0]
[0, 0, 0, -2]
[1, 1, 1, 1]
[1, 1, 1, -1]
[1, 1, -1, 1]
[1, 1, -1, -1]
[1, -1, 1, 1]
[1, -1, 1, -1]
[1, -1, -1, 1]
[1, -1, -1, -1]
[-1, 1, 1, 1]
[-1, 1, 1, -1]
[-1, 1, -1, 1]
[-1, 1, -1, -1]
[-1, -1, 1, 1]
[-1, -1, 1, -1]
[-1, -1, -1, 1]
[-1, -1, -1, -1]
edges
[0, 8]
[0, 9]
[0, 10]
[0, 11]
[0, 12]
[0, 13]
[0, 14]
[0, 15]
[1, 8]
[1, 9]
[1, 10]
[1, 11]
[1, 16]
[1, 17]
[1, 18]
[1, 19]
[2, 8]
[2, 9]
[2, 12]
[2, 13]
[2, 16]
[2, 17]
[2, 20]
[2, 21]
[3, 8]
[3, 10]
[3, 12]
[3, 14]
[3, 16]
[3, 18]
[3, 20]
[3, 22]
[4, 16]
[4, 17]
[4, 18]
[4, 19]
[4, 20]
[4, 21]
[4, 22]
[4, 23]
[5, 12]
[5, 13]
[5, 14]
[5, 15]
[5, 20]
[5, 21]
[5, 22]
[5, 23]
[6, 10]
[6, 11]
[6, 14]
[6, 15]
[6, 18]
[6, 19]
[6, 22]
[6, 23]
[7, 9]
[7, 11]
[7, 13]
[7, 15]
[7, 17]
[7, 19]
[7, 21]
[7, 23]
[8, 9]
[8, 10]
[8, 12]
[8, 16]
[9, 11]
[9, 13]
[9, 17]
[10, 11]
[10, 14]
[10, 18]
[11, 15]
[11, 19]
[12, 13]
[12, 14]
[12, 20]
[13, 15]
[13, 21]
[14, 15]
[14, 22]
[15, 23]
[16, 17]
[16, 18]
[16, 20]
[17, 19]
[17, 21]
[18, 19]
[18, 22]
[19, 23]
[20, 21]
[20, 22]
[21, 23]
[22, 23]
faces
[0, 8, 9]
[0, 8, 10]
[0, 8, 12]
[0, 9, 11]
[0, 9, 13]
[0, 10, 11]
[0, 10, 14]
[0, 11, 15]
[0, 12, 13]
[0, 12, 14]
[0, 13, 15]
[0, 14, 15]
[1, 8, 9]
[1, 8, 10]
[1, 8, 16]
[1, 9, 11]
[1, 9, 17]
[1, 10, 11]
[1, 10, 18]
[1, 11, 19]
[1, 16, 17]
[1, 16, 18]
[1, 17, 19]
[1, 18, 19]
[2, 8, 9]
[2, 8, 12]
[2, 8, 16]
[2, 9, 13]
[2, 9, 17]
[2, 12, 13]
[2, 12, 20]
[2, 13, 21]
[2, 16, 17]
[2, 16, 20]
[2, 17, 21]
[2, 20, 21]
[3, 8, 10]
[3, 8, 12]
[3, 8, 16]
[3, 10, 14]
[3, 10, 18]
[3, 12, 14]
[3, 12, 20]
[3, 14, 22]
[3, 16, 18]
[3, 16, 20]
[3, 18, 22]
[3, 20, 22]
[4, 16, 17]
[4, 16, 18]
[4, 16, 20]
[4, 17, 19]
[4, 17, 21]
[4, 18, 19]
[4, 18, 22]
[4, 19, 23]
[4, 20, 21]
[4, 20, 22]
[4, 21, 23]
[4, 22, 23]
[5, 12, 13]
[5, 12, 14]
[5, 12, 20]
[5, 13, 15]
[5, 13, 21]
[5, 14, 15]
[5, 14, 22]
[5, 15, 23]
[5, 20, 21]
[5, 20, 22]
[5, 21, 23]
[5, 22, 23]
[6, 10, 11]
[6, 10, 14]
[6, 10, 18]
[6, 11, 15]
[6, 11, 19]
[6, 14, 15]
[6, 14, 22]
[6, 15, 23]
[6, 18, 19]
[6, 18, 22]
[6, 19, 23]
[6, 22, 23]
[7, 9, 11]
[7, 9, 13]
[7, 9, 17]
[7, 11, 15]
[7, 11, 19]
[7, 13, 15]
[7, 13, 21]
[7, 15, 23]
[7, 17, 19]
[7, 17, 21]
[7, 19, 23]
[7, 21, 23]
cells
[0, 1, 8, 9, 10, 11]
[1, 4, 16, 17, 18, 19]
[0, 5, 12, 13, 14, 15]
[4, 5, 20, 21, 22, 23]
[0, 2, 8, 9, 12, 13]
[2, 4, 16, 17, 20, 21]
[0, 6, 10, 11, 14, 15]
[4, 6, 18, 19, 22, 23]
[0, 3, 8, 10, 12, 14]
[3, 4, 16, 18, 20, 22]
[0, 7, 9, 11, 13, 15]
[4, 7, 17, 19, 21, 23]
[1, 2, 8, 9, 16, 17]
[2, 5, 12, 13, 20, 21]
[1, 6, 10, 11, 18, 19]
[5, 6, 14, 15, 22, 23]
[1, 3, 8, 10, 16, 18]
[3, 5, 12, 14, 20, 22]
[1, 7, 9, 11, 17, 19]
[5, 7, 13, 15, 21, 23]
[2, 3, 8, 12, 16, 20]
[3, 6, 10, 14, 18, 22]
[2, 7, 9, 13, 17, 21]
[6, 7, 11, 15, 19, 23]