Compare commits

..

No commits in common. "0e1d8df7b5a7c02a8061ea5b3caa4902fcf9a498" and "1e59b55f5e7a4257e4fb71a966d264efcac9294b" have entirely different histories.

5 changed files with 65 additions and 232 deletions

View File

@ -104,12 +104,16 @@ export const LAYERS120 = {
163,219,271,223,167] 163,219,271,223,167]
}; };
// just one for now
export const CELL120_CELL5 = { export const CELL120_CELL5 = {
"1": [ 258, 1, 510, 304, 431 ], "1": [ 1, 258, 304, 431, 510 ],
"2": [ 185, 93, 222, 295, 372 ], "2": [ 1, 260, 302, 427, 506 ],
} "3": [1, 264, 298, 435, 514],
"4": [1, 330, 334, 387, 391],
"5": [1, 491, 503, 574, 578],
"6": [1, 495, 499, 570, 582 ],
};
// Schoute's partition via https://arxiv.org/abs/1010.4353 // Schoute's partition via https://arxiv.org/abs/1010.4353

View File

@ -1,24 +1,10 @@
// TODO - try visualising the 5-cells from a vertex on the layered 120-cell
// and get an intuition for how they work with the dodecahedral structure
// Another new approach -
// pick a starting 5-cell
// look at the neighbours on the 120-cell of all of its 5 vertices
// try to find abother 5-cell with these neighbours
// if there's only one, add that to the list and keep going
// if there's more than one, are they disjoint with each other?
import * as POLYTOPES from './polytopes.js'; import * as POLYTOPES from './polytopes.js';
// exploring more inscriptions of the 120-cell // exploring more inscriptions of the 120-cell
function choice(a) {
const r = Math.floor(Math.random() * a.length);
return a[r];
}
export function nodes_links(links, nodeid) { export function nodes_links(links, nodeid) {
return links.filter((l) => l.source === nodeid || l.target === nodeid); return links.filter((l) => l.source === nodeid || l.target === nodeid);
} }
@ -114,6 +100,11 @@ export function chord_survey() {
} }
} }
// how to proceed: start with the 120-cell that has five 600-cells inscribed
// in it. Take the 120 nodes from one of those 600-cells, and construct a 5-cell
// from each such that all of the vertices are on different 600-cells.
// collect them and output by label because every 5-cell is on all 5 600-cells
function overlap(c1, c2) { function overlap(c1, c2) {
for( const l in c1 ) { for( const l in c1 ) {
@ -125,13 +116,13 @@ function overlap(c1, c2) {
} }
export function gather_5cells(cell120) { export function gather_5cells() {
const cell120 = POLYTOPES.cell120_inscribed();
const CHORD5 = round_dist(Math.sqrt(2.5)); const CHORD5 = round_dist(Math.sqrt(2.5));
const bins = []; const bins = [];
const all = [];
cell120.nodes.filter((n) => n.label === 1).map((n) => { cell120.nodes.filter((n) => n.label === 1).map((n) => {
const cells = [ ];
const g = distance_group(cell120, n, CHORD5); const g = distance_group(cell120, n, CHORD5);
const cells = [ ];
for( const pair of g ) { for( const pair of g ) {
let seen = false; let seen = false;
for( const cell of cells ) { for( const cell of cells ) {
@ -155,163 +146,26 @@ export function gather_5cells(cell120) {
cells.push(cell); cells.push(cell);
} }
} }
all.push(...cells); //console.log(`From ${n.id}`);
}); //console.log(cells);
return all;
}
function audit_5cells(cells) {
// this verifies that for each label (a 600-cell set), each of its
// vertices is in exactly 7 5-cells. It checks out.
['1','2','3','4','5'].map((l) => {
const sets = {};
for( const cell of cells ) { for( const cell of cells ) {
const lv = cell[l]; let binned = false;
if( !(lv in sets) ) { for( const bin of bins ) {
sets[lv] = []; const overlaps = bin.filter((b) => overlap(b, cell));
if( overlaps.length === 0 ) {
bin.push(cell);
binned = true;
break;
} }
sets[lv].push(cell);
} }
for( const lv in sets ) { if( !binned ) {
const ok = ( sets[lv].length === 7 ) ? 'ok' : 'miss'; console.log(`new bin for ${JSON.stringify(cell)}`);
console.log(`${l},${lv},${sets[lv].length},${ok}`); bins.push([ cell ]);
} }
}); }
//console.log(bins);
})
;
} }
function try_120_5_cells_fails(cell120, cells, l) { gather_5cells();
// iterate over every vertex in the 600-cell defined by label l,
// get all 7 5-cells including that vertex, and add them if they are
// disjoint with what we already have
// this always runs out of disjoint nodes early
const vertices = cell120.nodes.filter((n) => n.label === l);
const cellset = [];
for( const v of vertices ) {
console.log(`Vertex ${v.id}`);
const vcells = cells.filter((c) => c[l] === v.id);
const overlap_any = (cs, c) => {
for( const seen of cs ) {
if( overlap(seen, c) ) {
console.log("overlap");
console.log(c);
return true;
}
}
return false;
}
const disjoint = vcells.filter((c) => ! overlap_any(cellset, c));
console.log(`Found ${disjoint.length} disjoint cells`);
if( disjoint.length > 0 ) {
cellset.push(choice(disjoint));
}
}
console.log(`Found total of ${cellset.length} disjoint cells`);
//console.log(cellset);
}
function overlap_any(cs, c) {
for( const seen of cs ) {
if( overlap(seen, c) ) {
return true;
}
}
return false;
}
function explore_disjoint(cell120, all5, l) {
const a = all5[0];
const overlaps = all5.filter((c) => overlap(c, a));
console.log(a);
console.log(overlaps.length);
console.log(overlaps);
}
// select a five-cell from a starting vertex v
// find a neighbor of v vn on its 600 cell, find all of the 5-cells which include
// vn. Then see if we can find any from that set which are similiar neighbours to
// the other four vertices in the first 5-cell
// the idea is that the 600-cells are a guide to finding the right subset of
// 5-cells
function neighbours600(cell120, vid) {
const v = cell120.nodes.filter((node) => node.id === vid)[0];
const label = v.label;
const links = cell120.links.filter((l) => {
return l.label === v.label && (l.source === v.id || l.target == v.id );
});
const nodes = links.map((l) => {
if( l.source === v.id ) {
return l.target;
} else {
return l.source;
}
});
return nodes;
}
function cell120node(cell120, nid) {
return cell120.nodes.filter((n) => n.id === nid)[0];
}
function node_dist(cell120, aid, bid) {
const a = cell120node(cell120, aid);
const b = cell120node(cell120, bid);
return dist(a, b);
}
function follow_600(cell120, all5) {
const v = cell120.nodes[0];
console.log("Start vertex:");
console.log(v);
const v5s = all5.filter((c5) => c5[v.label] === v.id);
console.log(`Vertex ${v.id} belongs to these 5-cells:`);
console.log(v5s);
const n600s = neighbours600(cell120, v.id);
const n600id = n600s[0];
const n600 = cell120node(cell120, n600id);
console.log("One 600-cell neighbour:");
console.log(n600);
const DIST600 = round_dist(node_dist(cell120, v.id, n600id));
const nv5s = all5.filter((c5) => c5[v.label] === n600id);
console.log(`Vertex ${n600id} belongs to these 5-cells:`);
console.log(nv5s);
console.log("Distances for each pair of 5-cells from the two sets:");
for( const v5a of v5s ) {
for( const v5b of nv5s ) {
let match = true;
const d = {};
for( const label in v5a ) {
d[label] = round_dist(node_dist(cell120, v5a[label], v5b[label]));
if( d[label] != DIST600 ) {
match = false;
}
}
if( match ) {
console.log("--- pair ---");
console.log(v5a);
console.log(v5b);
}
}
}
}
const cell120 = POLYTOPES.cell120_inscribed();
const all5 = gather_5cells(cell120);
follow_600(cell120, all5);

48
gui.js
View File

@ -28,10 +28,9 @@ const DEFAULTS = {
class FourDGUI { class FourDGUI {
constructor(funcs) { constructor(shapes, changeShape, setColor, setBackground, setNodeOpacity,setLinkOpacity, setVisibility, showDocs) {
this.shapes = funcs.shapes;
this.gui = new GUI(); this.gui = new GUI();
const SHAPE_NAMES = this.shapes.map((s) => s.name); const SHAPE_NAMES = shapes.map((s) => s.name);
this.parseLinkParams(); this.parseLinkParams();
const guiObj = this; const guiObj = this;
@ -56,52 +55,41 @@ class FourDGUI {
captions: true, captions: true,
dtheta: this.link['dtheta'], dtheta: this.link['dtheta'],
dpsi: this.link['dpsi'], dpsi: this.link['dpsi'],
"copy link": function () { guiObj.copyUrl() }, "copy link": function () { guiObj.copyUrl() }
}; };
if( funcs.extras ) {
for( const label in funcs.extras ) {
console.log(label);
console.log(funcs.extras[label]);
this.params[label] = funcs.extras[label];
}
}
let options_ctrl; let options_ctrl;
this.gui.add(this.params, 'shape', SHAPE_NAMES).onChange((shape) => { this.gui.add(this.params, 'shape', SHAPE_NAMES).onChange((shape) => {
const options = this.getShapeOptions(shape); const options = this.getShapeOptions(shapes, shape);
options_ctrl = options_ctrl.options(options).onChange((option) => { options_ctrl = options_ctrl.options(options).onChange((option) => {
funcs.setVisibility(option) setVisibility(option)
}); });
options_ctrl.setValue(options[0]) options_ctrl.setValue(options[0])
funcs.changeShape(shape) changeShape(shape)
}); });
const options = this.getShapeOptions(this.params['shape']); const options = this.getShapeOptions(shapes, this.params['shape']);
options_ctrl = this.gui.add(this.params, 'option').options(options).onChange((option) => { options_ctrl = this.gui.add(this.params, 'option').options(options).onChange((option) => {
funcs.setVisibility(option) setVisibility(option)
}); });
this.gui.add(this.params, 'hyperplane', 0.5, 1 / 0.8); this.gui.add(this.params, 'hyperplane', 0.5, 1 / 0.8);
this.gui.add(this.params, 'zoom', 0.1, 2.0); this.gui.add(this.params, 'zoom', 0.1, 2.0);
this.gui.add(this.params, 'nodesize', 0, 1.5); this.gui.add(this.params, 'nodesize', 0, 1.5);
this.gui.add(this.params, 'nodeopacity', 0, 1).onChange(funcs.setNodeOpacity); this.gui.add(this.params, 'nodeopacity', 0, 1).onChange(setNodeOpacity);
this.gui.add(this.params, 'linksize', 0, 2); this.gui.add(this.params, 'linksize', 0, 2);
console.log(funcs.setLinkOpacity); console.log(setLinkOpacity);
this.gui.add(this.params, 'linkopacity', 0, 1).onChange((v) => funcs.setLinkOpacity(v, true)); this.gui.add(this.params, 'linkopacity', 0, 1).onChange((v) => setLinkOpacity(v, true));
this.gui.add(this.params, 'link2opacity', 0, 1).onChange((v) => funcs.setLinkOpacity(v, false)); this.gui.add(this.params, 'link2opacity', 0, 1).onChange((v) => setLinkOpacity(v, false));
this.gui.addColor(this.params, 'color').onChange(funcs.setColor); this.gui.addColor(this.params, 'color').onChange(setColor);
this.gui.addColor(this.params, 'background').onChange(funcs.setBackground); this.gui.addColor(this.params, 'background').onChange(setBackground);
this.gui.add(this.params, 'xRotate', [ 'YW', 'YZ', 'ZW' ]); this.gui.add(this.params, 'xRotate', [ 'YW', 'YZ', 'ZW' ]);
this.gui.add(this.params, 'yRotate', [ 'XZ', 'XY', 'XW' ]); this.gui.add(this.params, 'yRotate', [ 'XZ', 'XY', 'XW' ]);
this.gui.add(this.params, 'captions').onChange(this.showDocs); this.gui.add(this.params, 'captions').onChange(showDocs);
this.gui.add(this.params, 'damping'); this.gui.add(this.params, 'damping');
this.gui.add(this.params, 'copy link'); this.gui.add(this.params, 'copy link');
if( funcs.extras ) {
for( const label in funcs.extras ) {
this.gui.add(this.params, label);
}
}
} }
getShapeOptions(shape) { getShapeOptions(shapes, shape) {
const spec = this.shapes.filter((s) => s.name === shape); const spec = shapes.filter((s) => s.name === shape);
if( spec && spec[0].options ) { if( spec && spec[0].options ) {
return spec[0].options.map((o) => o.name); return spec[0].options.map((o) => o.name);
} else { } else {

22
main.js
View File

@ -200,20 +200,14 @@ function setVisibility(option_name) {
gui = new FourDGUI( gui = new FourDGUI(
{ STRUCTURES,
shapes: STRUCTURES, changeShape,
changeShape: changeShape, setColors,
setColors: setColors, setBackground,
setBackground: setBackground, setNodeOpacity,
setNodeOpacity: setNodeOpacity, setLinkOpacity,
setLinkOpacity: setLinkOpacity, setVisibility,
setVisibility: setVisibility, showDocs
showDocs: showDocs,
extras: {
"Show an alert": function() { alert("hi there") },
"Show a different one": function() { alert('yowza')},
},
}
); );
// these are here to pick up colour settings from the URL params // these are here to pick up colour settings from the URL params

View File

@ -463,27 +463,19 @@ export const cell120_inscribed = () => {
export const cell120_inscribed_cell5 = () => { export const cell120_inscribed_cell5 = () => {
const nodes = make_120cell_vertices(); const nodes = make_120cell_vertices();
//const links = auto_detect_edges(nodes, 4); const links = auto_detect_edges(nodes, 4);
for( const cstr in CELLINDEX.INDEX120 ) { for( const cstr in CELLINDEX.INDEX120 ) {
label_nodes(nodes, CELLINDEX.INDEX120[cstr], Number(cstr)); label_nodes(nodes, CELLINDEX.INDEX120[cstr], Number(cstr));
} }
//links.map((l) => l.label = 0); links.map((l) => l.label = 0);
const links = [];
for( const p of [ 1, 2 ]) {
const nodes600 = nodes.filter((n) => n.label === p);
const links600 = auto_detect_edges(nodes600, 12);
links600.map((l) => l.label = p);
links.push(...links600);
}
for( const c5 in CELLINDEX.CELL120_CELL5 ) { for( const c5 in CELLINDEX.CELL120_CELL5 ) {
const nodes5 = nodes.filter((n) => CELLINDEX.CELL120_CELL5[c5].includes(n.id)); const nodes5 = nodes.filter((n) => CELLINDEX.CELL120_CELL5[c5].includes(n.id));
console.log(`node5 = ${nodes5}`);
const links5 = auto_detect_edges(nodes5, 4); const links5 = auto_detect_edges(nodes5, 4);
links5.map((l) => l.label = 0); links5.map((l) => l.label = c5);
links.push(...links5); links.push(...links5);
} }
@ -492,7 +484,8 @@ export const cell120_inscribed_cell5 = () => {
nodes: nodes, nodes: nodes,
links: links, links: links,
options: [ options: [
{ name: "5-cells", links: [ 0, 1, 2, 3, 4, 5, 6 ] }, { name: "none", links: [ 0 ]},
{ name: "one inscribed 5-cell", links: [ 0, 1 ] },
], ],
description: `The 120-cell with one of its 5-cells.`, description: `The 120-cell with one of its 5-cells.`,
} }