Merge branch 'feature-120-cell-index'

experiments-120-cell
Mike Lynch 2023-08-26 16:03:08 +10:00
commit f3bd62d2c2
3 changed files with 293 additions and 19 deletions

View File

@ -5,13 +5,6 @@ Steps forward -
2. using this, generate a list of all 120 dodecahedra:
[ a b c d e f g h i j k l m n o p q r s t ] <- 20 vertices
Check that each vertex appears in four of these
Then - either manually start labelling them, or build an interface to help
with the manual labelling
1.
@ -30,7 +23,31 @@ the last five.
2. have tried manual labelling and it will drive me crazy before I finish
3. Automated approach based on what I've got so far:
- should be possible to colour a single dodecahedron from a single face and
one other vertex (to pick a chirality)
- write a function to do this - the compound-of-four-tetrahedra map can be
more or less hard coded: follow the pattern 1-2-3-4-5, 3-4-5-1-2, etc out
from the inner ring, and map the original face's permutation
From this:
- colour the first dodecahedron, picking a chirality
- the next vertices from each of this dodecahedron's vertices have colours
which come from the first dodeca
- these can be used to colour the next layer of dodecahedra
- and so on
Alternatively:
- do it by the discrete Hopf fibration, one fibre at a time

View File

@ -303,7 +303,7 @@ function label_faces_120cell(nodes, faces, cfaces, label) {
}
function manual_label_120cell(nodes, links) {
function basic_auto_label_120cell(nodes, links) {
const faces = auto_120cell_faces(links);
const dodecas = DODECAHEDRA.DODECAHEDRA;
@ -332,11 +332,118 @@ function manual_label_120cell(nodes, links) {
}
// manual compound-of-tetrahedra colouring
function manual_label_120cell(nodes, links) {
label_nodes(nodes, [1, 153, 29, 105], 1);
label_nodes(nodes, [317, 409, 265, 109], 2);
label_nodes(nodes, [221, 337, 25, 509], 3);
label_nodes(nodes, [217, 413, 457, 361], 4);
label_nodes(nodes, [313, 157, 461, 505], 5);
// second dodecahedron needs to have opposite chirality
label_nodes(nodes, [ 165, 33, 117 ], 1);
label_nodes(nodes, [ 161, 465, 517 ], 2);
label_nodes(nodes, [ 417, 469, 365 ], 3);
label_nodes(nodes, [ 341, 37, 513 ], 4);
label_nodes(nodes, [ 421, 269, 113 ], 5);
// third
label_nodes(nodes, [ 45, 101, 181 ], 1);
label_nodes(nodes, [ 241, 429, 53 ], 2);
label_nodes(nodes, [ 93, 229 ], 3);
label_nodes(nodes, [ 173, 437 ], 4);
label_nodes(nodes, [ 245, 325 ], 5);
// fourth (id = 3)
label_nodes(nodes, [ 89, 169, 49 ], 1);
label_nodes(nodes, [ 321 ], 2);
label_nodes(nodes, [ 425, 177 ], 3);
label_nodes(nodes, [ 97, 225 ], 4);
label_nodes(nodes, [ 41, 433], 5);
}
function meridian_label_120cell(nodes, links) {
const DODECAS = [
[
313, 1, 317, 221, 217, 417,
341, 421, 165, 161, 465, 469,
37, 269, 33, 113, 117, 517,
365, 513
],
[
513, 365, 517, 117, 113, 577,
15, 581, 565, 561, 397, 399,
85, 389, 81, 301, 303, 213,
293, 209
],
[
301, 209, 293, 213, 303,
211, 309, 294, 311, 215,
310, 210, 214, 312, 295,
212, 302, 304, 216, 296
],
[
304, 302, 212, 296, 216, 400,
398, 84, 392, 88, 16, 580,
564, 568, 584, 368, 516, 116,
120, 520
],
[
368, 516, 116, 120, 520, 272,
36, 468, 472, 40, 164, 420,
344, 424, 168, 220, 316, 4,
320, 224
],
[
316, 4, 320, 224, 220, 412,
340, 416, 160, 156, 460, 464,
32, 268, 28, 108, 112, 512,
364, 508
],
[
508, 364, 512, 112, 108, 572,
14, 576, 560, 556, 394, 396,
80, 388, 76, 298, 300, 208,
292, 204
],
[
300, 298, 204, 292, 208,
206, 202, 306, 291, 308,
290, 305, 203, 207, 307,
289, 201, 297, 299, 205
],
[
299, 297, 201, 289, 205, 395,
393, 73, 385, 77, 13, 569,
553, 557, 573, 361, 505, 105,
109, 509
],
[
361, 505, 105, 109, 509, 265,
25, 457, 461, 29, 153, 409,
337, 413, 157, 217, 313, 1,
317, 221
]
]
let col = 1;
for( const dd of DODECAS ) {
label_nodes(nodes, dd, 5);
col++;
if( col > 5 ) {
col = 1;
}
}
}
@ -344,7 +451,7 @@ export const cell120 = () => {
const nodes = make_120cell_vertices();
const links = auto_detect_edges(nodes, 4);
manual_label_120cell(nodes, links);
meridian_label_120cell(nodes, links);
return {
nodes: nodes,

View File

@ -361,6 +361,148 @@ function make_dodecahedron(faces, f1, f2) {
}
function faces_to_dodecahedron(faces, f1, f2) {
const dodecahedron = [ f1, f2 ];
// take f1 as the 'center', get the other four around it from f2
const fs = find_dodeca_mutuals(faces, f1, f2);
const f3 = fs[0];
const f6 = fs[1];
dodecahedron.push(f3);
const f4 = find_dodeca_next(faces, dodecahedron, f1, f3);
dodecahedron.push(f4);
const f5 = find_dodeca_next(faces, dodecahedron, f1, f4);
dodecahedron.push(f5);
dodecahedron.push(f6);
// get the next ring
const f7 = find_dodeca_next(faces, dodecahedron, f6, f2);
dodecahedron.push(f7);
const f8 = find_dodeca_next(faces, dodecahedron, f2, f3);
dodecahedron.push(f8);
const f9 = find_dodeca_next(faces, dodecahedron, f3, f4);
dodecahedron.push(f9);
const f10 = find_dodeca_next(faces, dodecahedron, f4, f5);
dodecahedron.push(f10);
const f11 = find_dodeca_next(faces, dodecahedron, f5, f6);
dodecahedron.push(f11);
// get the last
const f12 = find_dodeca_next(faces, dodecahedron, f7, f8);
dodecahedron.push(f12);
return dodecahedron;
}
// from a face and one neighbouring node, return a dodecahedron
function face_plus_to_dodecahedron(faces, f1, node) {
const neighbours = find_adjacent_faces(faces, f1);
const nodens = neighbours.filter((f) => f.nodes.includes(node));
return faces_to_dodecahedron(faces, f1, nodens[0]); // does it matter which?
}
// for three faces, return their common vertex (if they have one)
function find_dodeca_vertex(f1, f2, f3) {
const v12 = f1.nodes.filter((n) => f2.nodes.includes(n));
const v123 = v12.filter((n) => f3.nodes.includes(n));
if( v123.length === 1 ) {
return v123[0];
} else {
console.log(`warning: faces ${f1.id} ${f2.id} ${f3.id} don't share 1 vertex`);
return false;
}
}
const VERTEX_MAP = [
[ 0, 1, 5 ],
[ 0, 1, 2 ],
[ 0, 2, 3 ],
[ 0, 3, 4 ],
[ 0, 4, 5 ],
[ 1, 5, 6 ],
[ 1, 2, 7 ],
[ 2, 3, 8 ],
[ 3, 4, 9 ],
[ 4, 5, 10 ],
[ 1, 6, 7 ],
[ 2, 7, 8 ],
[ 3, 8, 9 ],
[ 4, 9, 10 ],
[ 5, 6, 10 ],
[ 6, 7, 11 ],
[ 7, 8, 11 ],
[ 8, 9, 11 ],
[ 9, 10, 11 ],
[ 6, 10, 11 ],
];
function dodecahedron_vertices(faces) {
const face_sets = VERTEX_MAP.map((vs) => vs.map((v) => faces[v]));
return face_sets.map((fs) => find_dodeca_vertex(...fs));
}
// p is the permutation of the first face
function dodecahedron_colours(vertices, p) {
const LEFT_PART = [
1, 2, 3, 4, 5, 3, 4, 5, 1, 2, 5, 1, 2, 3, 4, 2, 3, 4, 5, 1,
];
const RIGHT_PART = [
1, 2, 3, 4, 5, 4, 5, 1, 2, 3, 3, 4, 5, 1, 2, 1, 2, 3, 4, 5,
];
const part = LEFT_PART;
const colours = {};
for( let i = 0; i < 20; i++ ) {
const v = vertices[i];
const colour = p[part[i] - 1];
colours[v] = colour;
}
return colours;
}
// p is the permutation of the first face
function colour_one_dodecahedron(faces, face, node, p) {
const dd = face_plus_to_dodecahedron(faces, face, node);
const vertices = dodecahedron_vertices(dd);
return dodecahedron_colours(vertices, p);
}
// go along a meridian
function meridian(faces, startf, startn) {
const dds = [ face_plus_to_dodecahedron(faces, startf, startn) ];
while( dds.length < 10 ) {
const dd = dds[dds.length - 1];
const nextf = dd[11]; // opposite to startf
const neighbours = find_adjacent_faces(faces, nextf);
const nextnbors = neighbours.filter((f) => !dd.includes(f));
const nextdd = faces_to_dodecahedron(faces, nextf, nextnbors[0]);
dds.push(nextdd);
}
return dds;
}
// for a face, pick an edge, and then find the other two faces which
// share this edge. These can be used as the starting points for the
// first face's two dodecahedra
@ -392,13 +534,20 @@ function dd_fingerprint(dodecahedron) {
function make_120cell_cells(faces) {
const dodecas = [];
const seen = {};
let i = 1;
for( const face of faces ) {
const dds = face_to_dodecahedra(faces, face);
for( const dd of dds ) {
const fp = dd_fingerprint(dd);
if( ! (fp in seen) ) {
//console.log(`added dodeca ${fp}`);
dodecas.push(dd);
const d = {
id: i,
faces: dd,
nodes: dodecahedron_vertices(dd),
}
dodecas.push(d);
i += 1;
seen[fp] = 1;
}
}
@ -422,19 +571,20 @@ const cell120 = () => {
}
function dodeca_nodes(dd) {
const ns = new Set();
for( const face of dd.faces ) {
for( const node of face.nodes ) {
ns.add(node);
}
}
dd.nodes = Array.from(ns);
}
const nodes = make_120cell_vertices();
const links = auto_detect_edges(nodes, 4);
const faces = auto_120cell_faces(links);
const dodecas = make_120cell_cells(faces);
const ddfaces = dodecas.map((dd) => dd.map((f) => f.id));
console.log(JSON.stringify(ddfaces));
// for( const dodeca of dodecas ) {
// console.log(dodeca.map((f) => f.id)
// }
//const dodecas = make_120cell_cells(faces);