iterative orthogonal extrusion:
generative unit: 1-cube
n-cube = n-fold Cartesian product of 1-cube
vertex set: {0,1}^n
square (2-cube) is first case with visible combinatorial structure
binary digits give coordinates:
bit d = 0 -> -1
bit d = 1 -> +1
vertex(v) = (coord_0, coord_1, …, coord_{n-1})
all vertices:
vertices of a k-face:
face pattern templates:
example: 2-cube faces of a 4-cube (f=fixed, v=variable): ffvv, fvfv, fvvf, vffv, vfvf, vvff
example face (pattern vfvf, fixed bits v0v1): 0001, 0011, 1001, 1011
k-face counts by (vary, fix):
3-cube: edges (1,2), squares (2,1), cubes (3,0)
4-cube: edges (1,3), squares (2,2), cubes (3,1)
2-cube:
3-cube:
4-cube:
# map integer vertex index v ∈ [0, 2^n) to coordinate array in { -1, +1 }^n # input: v (integer), n (dimensions) # output: array of length n, each element = -1 or +1 bits_to_array = (v, n) -> # [±1, ±1, ±1, ...] [0...n].map (d) -> if (v >> d & 1) == 0 then -1 else 1
# generate all k-combinations of {0,...,n-1} as binary bitmasks # input: n (set size), k (subset size) # output: array of integers, each bitmask has exactly k bits set get_bit_combinations = (n, k) -> # [integer, ...] result = [] a = (1 << k) - 1 while a < (1 << n) result.push a b = a & -a c = a + b a = (((c ^ a) >> 2) / b) | c result
# partition a set of vertex indices into all k-faces of the n-cube # input: # vertices: array of integer vertex bitmasks (length = 2^n) # indices: array of vertex indices to consider # n: cube dimension # k: number of varying coordinates in each face # cell_length: number of vertices per k-face (= 2^k) # output: array of k-faces, each face = array of vertex indices group_n_cells = (vertices, indices, n, k, cell_length) -> # [[integer, ...], ...] fixed_combinations = get_bit_combinations n, k cell_indices = [] for fixed in fixed_combinations cell_vertices = {} for i in indices key = fixed & vertices[i] if cell_vertices[key] cell_vertices[key].push i else cell_vertices[key] = [i] new_cells = Object.values(cell_vertices).filter (a) -> cell_length == a.length cell_indices = cell_indices.concat new_cells cell_indices
# enumerate all cells of an n-cube, grouped by dimension # input: # vertices: array of integer vertex bitmasks # n: cube dimension # output: # nested arrays; level 0 = 1-faces (edges), ..., level n-1 = n-faces (the cube itself) # each cell represented as array of vertex indices get_cells = (vertices, n) -> # [[[integer, ...], ...], [[integer, ...], ...], ...] subcells = (indices, k) -> return indices unless k < n indices = group_n_cells vertices, indices, n, k, 2 ** (n - k) subcells a, k + 1 for a in indices subcells [0...vertices.length], 1
n = 4 bit_vertices = [0...2 ** n] # vertices as coordinate arrays in { -1, +1 }^n vertices = bit_vertices.map (v) -> bits_to_array v, n # all cells, grouped by dimension (edges, squares, cubes, hypercubes) cells = get_cells bit_vertices, n