Rubi
Latar Belakang
Ada tiga keluarga polytope reguler yang memanjang ke dimensi tak terbatas:
simpleks, di mana tetrahedron adalah anggota (saya akan sering menyebut mereka di sini sebagai hypertetrahedra, meskipun istilah simpleks lebih tepat.) Simbol schlafi mereka adalah dari bentuk {3,3,...,3,3}
kubus-n, dimana kubus adalah anggota. Simbol schlafi mereka berbentuk{4,3,...,3,3}
orthoplexes, di mana octahedron adalah anggota (saya akan sering menyebut mereka di sini sebagai hyperoctahedra) Simbol schlafi mereka adalah dari bentuk {3,3,...,3,4}
Ada satu keluarga tak terbatas lebih lanjut dari polytopes reguler, simbol {m}
, bahwa dari poligon 2 dimensi, yang mungkin memiliki sejumlah sisi m.
Selain itu, hanya ada lima kasus khusus lainnya dari polytope reguler: icosahedron 3-dimensi {3,5}
dan dodecahedron {5,3}
; analog 4 dimensi mereka 600 sel {3,3,5}
dan 120 sel {5,3,3}
; dan satu polytope 4 dimensi lainnya, sel-24 {3,4,3}
(yang analog terdekatnya dalam 3 dimensi adalah cuboctahedron dan dual-nya dodecahedron rhombic.)
Fungsi utama
Di bawah ini adalah polytope
fungsi utama yang mengartikan simbol schlafi. Itu mengharapkan array angka, dan mengembalikan array yang berisi sekelompok array sebagai berikut:
Array semua simpul, masing-masing dinyatakan sebagai array n-elemen dari koordinat (di mana n adalah jumlah dimensi)
Array semua tepi, masing-masing dinyatakan sebagai 2-elemen dari indeks titik
Array semua wajah, masing-masing dinyatakan sebagai m-elemen dari indeks titik (di mana m adalah jumlah simpul per wajah)
dan sebagainya sesuai untuk jumlah dimensi.
Ini menghitung 2d polytopes itu sendiri, memanggil fungsi untuk 3 dimensi tak terbatas keluarga, dan menggunakan tabel pencarian untuk lima kasus khusus. Diharapkan untuk menemukan fungsi dan tabel yang dideklarasikan di atasnya.
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
}
Fungsi untuk keluarga tetrahedron, kubus dan segi delapan
https://en.wikipedia.org/wiki/Simplex
https://en.wikipedia.org/wiki/5-cell (simpleks 4d)
http://mathworld.wolfram.com/Simplex.html
Penjelasan keluarga Tetrahedron - koordinat
simpleks n-dimensional / hypertetrahedron memiliki n +1 poin. Sangat mudah untuk memberikan simpul simpleks n-dimensional dalam n + 1 dimensi.
Dengan demikian (1,0,0),(0,1,0),(0,0,1)
menggambarkan segitiga 2d tertanam dalam 3 dimensi dan (1,0,0,0),(0,1,0,0),(0,0,1,0),(0,0,0,1)
menggambarkan tetrahedron 3d tertanam dalam 4 dimensi. Ini mudah diverifikasi dengan mengonfirmasi bahwa semua jarak antar simpul adalah sqrt (2).
Berbagai algoritma rumit diberikan di internet untuk menemukan simpul untuk simpleks n-dimensional dalam ruang n-dimensional. Saya menemukan yang sangat sederhana di komentar Will Jagy pada jawaban ini /mathpro//a/38725 . Titik terakhir terletak pada garis p=q=...=x=y=z
pada jarak sqrt (2) dari yang lain. Dengan demikian segitiga di atas dapat dikonversi menjadi tetrahedron dengan menambahkan titik di salah satu (-1/3,-1/3,-1/3)
atau (1,1,1)
. 2 nilai yang mungkin dari koordinat untuk titik terakhir diberikan oleh (1-(1+n)**0.5)/n
dan(1+(1+n)**0.5)/n
Karena pertanyaannya mengatakan ukuran n-tope tidak masalah, saya lebih suka mengalikan n dengan menggunakan dan menggunakan koordinat (n,0,0..0)
hingga (0..0,0,n)
dengan titik akhir di (t,t,..,t,t)
mana t = 1-(1+n)**0.5
untuk kesederhanaan.
Karena pusat dari tetrahedron ini bukan pada titik asal, koreksi terhadap semua koordinat harus dilakukan oleh garis s.map!{|j|j-((1-(1+n)**0.5)+n)/(1+n)}
yang menemukan seberapa jauh pusat itu dari titik asal dan mengurangkannya. Saya telah menyimpan ini sebagai operasi terpisah. Namun saya telah menggunakan di s[i]+=n
mana s[i]=n
akan lakukan, untuk menyinggung fakta bahwa ketika array diinisialisasi oleh s=[0]*n
kita bisa menempatkan offset yang benar di sini sebagai gantinya dan melakukan koreksi keterpusatan di awal daripada di akhir.
Penjelasan keluarga Tetrahedron - topologi grafik
Grafik simpleks adalah grafik lengkap: setiap titik terhubung tepat satu kali ke setiap titik lainnya. Jika kita memiliki n simpleks, kita dapat menghapus simpul mana pun untuk memberikan simpleks n-1, hingga ke titik di mana kita memiliki segitiga atau bahkan tepi.
Oleh karena itu kami memiliki total 2 ** (n +1) item untuk katalog, masing-masing diwakili oleh nomor biner. Ini berkisar dari semua 0
s untuk ketiadaan, melalui satu 1
untuk simpul dan dua 1
s untuk tepi, hingga semua 1
s untuk polytope lengkap.
Kami menyiapkan array array kosong untuk menyimpan elemen dari setiap ukuran. Kemudian kita loop dari nol ke (2 ** n +1) untuk menghasilkan masing-masing himpunan bagian dari simpul, dan menyimpannya dalam array sesuai dengan ukuran masing-masing subset.
Kami tidak tertarik pada apa pun yang lebih kecil dari ujung (titik atau nol) atau dalam polytope lengkap (karena kubus lengkap tidak diberikan dalam contoh dalam pertanyaan), jadi kami kembali tg[2..n]
untuk menghapus elemen yang tidak diinginkan ini. Sebelum kembali, kami memasang [tv] yang berisi koordinat titik ke awal.
kode
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]}
penjelasan keluarga kubus dan segi delapan - koordinat
N-cube memiliki 2**n
simpul, masing-masing diwakili oleh array ns 1
dan -1
s (semua kemungkinan dibolehkan.) Kita beralih melalui indeks 0
ke 2**n-1
daftar semua simpul, dan membangun sebuah array untuk setiap simpul dengan mengulangi bit-bit dari indeks dan menambahkan -1
atau 1
ke array (bit paling signifikan ke bit paling signifikan.) Dengan demikian Binary 1101
menjadi titik 4d [1,-1,1,1]
.
N-octahedron atau n-orthoplex memiliki 2n
simpul, dengan semua koordinat nol kecuali satu, yang menjadi 1
atau -1
. Urutan simpul dalam array yang dihasilkan adalah [[1,0,0..],[-1,0,0..],[0,1,0..],[0,-1,0..],[0,0,1..],[0,0,-1..]...]
. Perhatikan bahwa karena octahedron adalah dual dari kubus, simpul dari octahedron ditentukan oleh pusat-pusat wajah kubus yang mengelilinginya.
penjelasan keluarga kubus dan segi delapan - topologi grafik
Beberapa inspirasi diambil dari sisi Hypercube dan fakta bahwa hyperoctahedron adalah ganda dari hypercube.
Untuk n-cube, ada 3**n
item untuk katalog. Misalnya, 3 kubus memiliki 3**3
= 27 elemen. Ini dapat dilihat dengan mempelajari kubus rubik, yang memiliki 1 pusat, 6 wajah, 12 tepi dan 8 simpul untuk total 27. Kami beralih melalui -1,0 dan -1 di semua dimensi yang mendefinisikan n-kubus sidelength 2x2x2 .. dan kembalikan semua simpul yang TIDAK berada di sisi berlawanan dari kubus. Jadi titik pusat kubus mengembalikan semua 2 ** n simpul, dan memindahkan satu unit dari pusat sepanjang sumbu apa pun mengurangi jumlah simpul hingga setengahnya.
Seperti halnya keluarga tetrahedron, kita mulai dengan menghasilkan array array kosong dan mengisinya sesuai dengan jumlah simpul per elemen. Perhatikan bahwa karena jumlah simpul bervariasi sebagai 2 ** n ketika kita naik melalui tepi, wajah, kubus, dll, kita menggunakan log2(s.size)+1
bukan hanya s.size
. Sekali lagi, kita harus menghapus hypercube itu sendiri dan semua elemen dengan kurang dari 2 simpul sebelum kembali dari fungsi.
Keluarga octahedron / orthoplex adalah dual dari keluarga kubus, oleh karena itu lagi ada 3**n
item untuk katalog. Di sini kita mengulangi -1,0,1
untuk semua dimensi dan jika koordinat nol nol sama dengan koordinat titik yang sesuai, titik ditambahkan ke daftar yang sesuai dengan titik itu. Jadi suatu tepi berhubungan dengan suatu titik dengan dua koordinat bukan nol, segitiga ke satu titik dengan 3 koordinat bukan nol dan satu tetrahedron ke suatu titik dengan 4 kontak bukan nol (dalam ruang 4d.)
Array verteks yang dihasilkan untuk setiap titik disimpan dalam array besar seperti untuk kasus lain, dan kami harus menghapus elemen dengan kurang dari 2 simpul sebelum kembali. Tetapi dalam hal ini kita tidak harus menghapus induk lengkap n-tope karena algoritma tidak merekamnya.
Implementasi kode untuk kubus dirancang agar semirip mungkin. Meskipun ini memiliki keanggunan tertentu, ada kemungkinan bahwa algoritma yang lebih efisien berdasarkan prinsip yang sama dapat dirancang.
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
Kode untuk menghasilkan tabel untuk kasus khusus 3d
Orientasi dengan orientasi icosahedron / dodecahedron dengan sumbu simetri berlipat lima sejajar dengan dimensi terakhir digunakan, karena dibuat untuk pelabelan bagian yang paling konsisten. Penomoran simpul dan wajah untuk icosahedron sesuai diagram dalam komentar kode, dan dibalik untuk dodecahedron.
Menurut https://en.wikipedia.org/wiki/Regular_icosahedron garis lintang 10 simpul non-polar dari icosahedron adalah +/- arctan (1/2) Koordinat dari 10 simpul pertama dari icosahedron dihitung dari ini, pada dua lingkaran jari-jari 2 pada jarak +/- 2 dari bidang xy. Ini membuat radius keseluruhan circumsphere sqrt (5) sehingga 2 simpul terakhir berada pada (0,0, + / - sqrt (2)).
Koordinat simpul dodecahedron dihitung dengan menjumlahkan koordinat dari tiga simpul icosahedron yang mengelilinginya.
=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]]
Kode untuk menghasilkan tabel untuk kasus khusus 4d
Ini sedikit peretasan. Kode ini membutuhkan beberapa detik untuk dijalankan. Akan lebih baik untuk menyimpan output dalam file dan memuatnya sesuai kebutuhan.
Daftar 120 titik koordinat untuk 600sel adalah dari http://mathworld.wolfram.com/600-Cell.html . 24 titik koordinat yang tidak memiliki rasio emas membentuk simpul dari sel 24. Wikipedia memiliki skema yang sama tetapi memiliki kesalahan dalam skala relatif dari 24 koordinat ini dan 96 lainnya.
#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
Contoh penggunaan dan output
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]