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], 1n = 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