def test_coordinate_pentatope(self): a = Vector4(0,0,0,0) b = Vector4(1,0,0,0) c = Vector4(0,1,0,0) d = Vector4(0,0,1,0) e = Vector4(0,0,0,1) self.assertAlmostEqual(pentatope4_hypervolume(a,b,c,d,e), 1/24.0)
def cell_24_tesselation(rotation_matrix=Matrix4([[1, 0, 0, 0], [0, 1, 0, 0], [0, 0, 1, 0], [0, 0, 0, 1]]), bounding_box=[[-5, 5]] * 4, frames_per_unit=30, rotation_rate=360, elevation_rate=20.0, epsilon=0.6, folder_name='demos/c24_tess1'): b = Tiling3ImageMaker() c24 = cell24_tiling_seperate(bounding_box) b.tiling3_axis_limit = bounding_box c24 = [ t4.deform(rotation_matrix) for t4 in c24 if len( restrict43( t4.deform(rotation_matrix).translate( Vector4(0, 0, 0.000001, 0.0001))).volumes) > 0 and len([ e for e in restrict43( t4.deform(rotation_matrix).translate( Vector4(0, 0, 0.000001, 0.0001))).edges if list(e)[0].distance(list(e)[1]) > epsilon ]) > 0 ] for i in range(len(c24)): for j in range(frames_per_unit): b.elevation = elevation_rate * sin( (float(j) / frames_per_unit + i)) b.azimuth = j * rotation_rate / (frames_per_unit - 1) + i * rotation_rate poster_figure = plt.figure(figsize=[9, 9]) b.store_image([ restrict43(t4.translate(Vector4(0, 0, 0.000001, 0.0001))) for t4 in c24[:(i + 1)] ], folder=folder_name, save_name=str(j + i * frames_per_unit))
def cell24_tiling_separate(box): periods = [Vector4(4, 0, 0, 0), Vector4(2, -2, 0, 0), Vector4(0, 2, -2, 0), Vector4(0, 0, 2, -2)] return list(periodic_copies(cell24(), box, periods=periods))
def cell24_tiling(box): periods = [Vector4(4, 0, 0, 0), Vector4(2, -2, 0, 0), Vector4(0, 2, -2, 0), Vector4(0, 0, 2, -2)] return simple_periodic_tiling4(cell24(), box, periods=periods)
def pentatope(): root5 = 5**0.5 dictionary_of_vertices = { Vector4(1, 1, 1, -1/root5): 0, Vector4(1, -1, -1, -1/root5): 1, Vector4(-1, 1, -1, -1/root5): 2, Vector4(-1, -1, 1, -1/root5): 3, Vector4(0, 0, 0, root5 - 1/root5): 4 } return tiling4_convex_hull(dictionary_of_vertices)
def periodic_copies(tiling4, bounding_box, periods=[Vector4(1,0,0,0), Vector4(0,1,0,0), Vector4(0,0,1,0), Vector4(0,0,0,1)]): gen = LatticeSearcher(len(periods)) for n in gen: t1 = tiling4.translate(sum((u*c for (u,c) in zip(periods, n)), Vector4(0,0,0,0))) if t1.in_box(bounding_box): yield t1 else: gen.reject()
def __call__(self, other): "Matrix acting on a vector" [a, b, c, d] = [ sum(self[(i, j)] * other[j] for j in [1, 2, 3, 4]) for i in [1, 2, 3, 4] ] return Vector4(a, b, c, d)
def cell600_cell120(): poster_figure = plt.figure(figsize=[40, 4]) polytopes = [cell600(), cell120()] subplot_count = 0 b = Tiling3ImageMaker() b.elevation = 31 b.azimuth = -147 b.edges_alpha = 0.15 b.number_of_rows = 2 b.number_of_columns = 16 for (j, polytope) in enumerate(polytopes): minz = polytope.minz() maxz = polytope.maxz() b.tiling3_axis_limit = [[-1.2, 1.2]] * 3 if j == 1: b.elevation = -3 b.azimuth = -143 b.tiling3_axis_limit = [[-1.7, 1.7]] * 3 a = range(16) rate = float(abs(maxz - minz)) / (len(a)) for i in a: b.image([ restrict43( polytope.translate( Vector4(0, 0, 0.00001, -0.001 + minz + i * rate))) ]) b.position_code = (i + 1) + subplot_count * (len(a)) subplot_count += 1 plt.savefig(os.path.join(target_dir, "cell600_cell120")) plt.close()
def cell120(): ''' The 120 Cell. ''' tau2 = tau * tau taui = -tau.conj() tau2i = taui * taui def vertices(): for p in all_permutations_plus_minus([2, 2, 0, 0]): yield p for p in all_permutations_plus_minus([1, 1, 1, root5]): yield p for p in all_permutations_plus_minus([tau, tau, tau, tau2i]): yield p for p in all_permutations_plus_minus([taui, taui, taui, tau2]): yield p for p in even_permutations_plus_minus([0, tau2i, 1, tau2]): yield p for p in even_permutations_plus_minus([0, taui, tau, root5]): yield p for p in even_permutations_plus_minus([taui, 1, tau, 2]): yield p vs = (Vector4(w, x, y, z) for (w, x, y, z) in remove_duplicates(vertices())) return tiling4_convex_hull(dict(zip(vs, range(600))), statusreport=True, max_volumes_per_vertex=4)
def cell16(): dictionary_of_vertices = { Vector4(1, 0, 0, 0): 0, Vector4(0, 1, 0, 0): 1, Vector4(0, 0, 1, 0): 2, Vector4(0, 0, 0, 1): 3, Vector4(-1, 0, 0, 0): 4, Vector4(0, -1, 0, 0): 5, Vector4(0, 0, -1, 0): 6, Vector4(0, 0, 0, -1): 7 } return tiling4_convex_hull(dictionary_of_vertices)
def setUp(self): self.p1 = pentatope() self.p2 = pentatope().translate(Vector4(4,5,6,7)) self.c1 = hypercube() self.c2 = hypercube().scale(2.5) n = lambda x: None self.p1a = self.p1.map(n, n, n, n, n) self.p2a = self.p2.map(n, n, n, n, n) self.c1a = self.c1.map(n, n, n, n, n) self.c2a = self.c2.map(n, n, n, n, n)
def cubic_tiling4(bounding_box): v = {(): Vector4(0,0,0,0)} # Origin e = {(1,2): [((), (0,0,0,0)), ((), (1,0,0,0))], (1,4): [((), (0,0,0,0)), ((), (0,1,0,0))], (1,9): [((), (0,0,0,0)), ((), (0,0,1,0))], (1,5): [((), (0,0,0,0)), ((), (0,0,0,1))]} f = { (1,2,3,4): [((1,2), (0,0,0,0)), ((1,2), (0,1,0,0)), ((1,4), (0,0,0,0)), ((1,4), (1,0,0,0))], (1,2,9,10): [((1,2), (0,0,0,0)), ((1,2), (0,0,1,0)), ((1,9), (0,0,0,0)), ((1,9), (1,0,0,0))], (1,2,5,6): [((1,2), (0,0,0,0)), ((1,2), (0,0,0,1)), ((1,5), (0,0,0,0)), ((1,5), (1,0,0,0))], (1,4,9,12): [((1,4), (0,0,0,0)), ((1,4), (0,0,1,0)), ((1,9), (0,0,0,0)), ((1,9), (0,1,0,0))], (1,4,5,8): [((1,4), (0,0,0,0)), ((1,4), (0,0,0,1)), ((1,5), (0,0,0,0)), ((1,5), (0,1,0,0))], (1,5,9,13): [((1,5), (0,0,0,0)), ((1,5), (0,0,1,0)), ((1,9), (0,0,0,0)), ((1,9), (0,0,0,1))]} g = { (1,2,3,4,5,6,7,8): [((1,2,5,6), (0,0,0,0)), ((1,2,5,6), (0,1,0,0)), ((1,4,5,8), (0,0,0,0)),((1,4,5,8), (1,0,0,0)), ((1,2,3,4), (0,0,0,0)),((1,2,3,4), (0,0,0,1))], (1,2,5,6,9,10,13,14): [((1,2,5,6), (0,0,0,0)), ((1,2,5,6), (0,0,1,0)), ((1,5,9,13), (0,0,0,0)),((1,5,9,13), (1,0,0,0)), ((1,2,9,10), (0,0,0,0)),((1,2,9,10), (0,0,0,1))], (1,4,5,8,9,12,13,16): [((1,5,9,13), (0,0,0,0)), ((1,5,9,13), (0,1,0,0)), ((1,4,9,12), (0,0,0,0)),((1,4,9,12), (0,0,0,1)), ((1,4,5,8), (0,0,0,0)),((1,4,5,8), (0,0,1,0))], (1,2,3,4,9,10,11,12): [((1,2,3,4), (0,0,0,0)), ((1,2,3,4), (0,0,1,0)), ((1,2,9,10), (0,0,0,0)),((1,2,9,10), (0,1,0,0)), ((1,4,9,12), (0,0,0,0)),((1,4,9,12), (1,0,0,0))]} h = {(1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16): [ ((1,4,5,8,9,12,13,16),(0,0,0,0)),((1,4,5,8,9,12,13,16),(1,0,0,0)), ((1,2,5,6,9,10,13,14),(0,0,0,0)),((1,2,5,6,9,10,13,14),(0,1,0,0)), ((1,2,3,4,5,6,7,8),(0,0,0,0)),((1,2,3,4,5,6,7,8),(0,0,1,0)), ((1,2,3,4,9,10,11,12),(0,0,0,0)),((1,2,3,4,9,10,11,12),(0,0,0,1))]} return periodic_tiling4(v,e,f,g,h,bounding_box)
def tetra4_volume(v0, v1, v2, v3): a = v1 - v0 b = v2 - v0 c = v3 - v0 return Vector4( a.x * b.y * c.z - a.x * b.z * c.y + a.z * b.x * c.y - a.z * b.y * c.x + a.y * b.z * c.x - a.y * b.x * c.z, a.w * b.y * c.z - a.w * b.z * c.y + a.z * b.w * c.y - a.z * b.y * c.w + a.y * b.z * c.w - a.y * b.w * c.z, a.x * b.w * c.z - a.x * b.z * c.w + a.z * b.x * c.w - a.z * b.w * c.x + a.w * b.z * c.x - a.w * b.x * c.z, a.x * b.y * c.w - a.x * b.w * c.y + a.w * b.x * c.y - a.w * b.y * c.x + a.y * b.w * c.x - a.y * b.x * c.w).norm() / 6.0
def rotation_matrix_producer_4(normal=Vector4(1, 1, 1, 1)): u = normal / normal.norm() v0 = random_norm1_4() v1 = v0 - u * (u.dot(v0)) v = v1 / (v1.norm()) w0 = random_norm1_4() w1 = w0 - u * (u.dot(w0)) - v * (v.dot(w0)) w = w1 / (w1.norm()) x0 = random_norm1_4() x1 = x0 - w * (w.dot(x0)) - u * (u.dot(x0)) - v * (v.dot(x0)) x = x1 / x1.norm() m = Matrix4([x, v, w, u]) if m.determinant() < 0: m = Matrix4([x, v, -w, u]) return m
def cell24(): ''' The 24 Cell. ''' def vertices(): for p in all_permutations_plus_minus([2, 0, 0, 0]): yield p for p in all_permutations_plus_minus([1, 1, 1, 1]): yield p vs = (Vector4(w, x, y, z) for (w, x, y, z) in remove_duplicates(vertices())) return tiling4_convex_hull(dict(zip(vs, range(24))), statusreport=True, max_volumes_per_vertex=6)
def cell600(): ''' The 600 Cell. ''' def vertices(): for p in all_permutations_plus_minus([1, 1, 1, 1]): yield p for p in all_permutations_plus_minus([0, 0, 0, 2]): yield p for p in even_permutations_plus_minus([tau, 1, tau.conj(), 0]): yield p vs = (Vector4(w, x, y, z) for (w, x, y, z) in remove_duplicates(vertices())) return tiling4_convex_hull(dict(zip(vs, range(120))), statusreport=True)
def make_rotate_wx(name, polytope, frames=500, axis_limit=[[-1.2, 1.2]] * 3, elevation=40, azimuth=30): b = Tiling3ImageMaker() b.tiling3_axis_limit = axis_limit b.elevation = elevation b.azimuth = azimuth rate = (2 * pi) / (frames - 1) polytopes = ([ restrict43( polytope.deform(rotate_wx(i * rate)).translate( Vector4(0, 0, 0.000001, 0.000001))) ] for i in range(frames)) b.animation(polytopes, 'demos/' + name, number=frames)
def tiling4_dual(tiling4): ''' This function is designed for producing the duals of convex polytopes. ''' dual_vertices = [] for volume in tiling4.volumes: distinct_verticies = set() for face in volume : for edge in face: for vertex in edge: distinct_verticies.add(vertex) sum_vertex = Vector4(0,0,0,0) for vertex in distinct_verticies : sum_vertex += vertex centroid = sum_vertex/len(distinct_verticies) dual_vertices.append(centroid) return tiling4_convex_hull(dict(zip(dual_vertices,range(len(dual_vertices)))))
def make_translate_z_4d(name, polytope, frames=500, axis_limit=[[-1.2, 1.2]] * 3, elevation=40, azimuth=30): b = Tiling3ImageMaker() minz = polytope.minz() maxz = polytope.maxz() b.tiling3_axis_limit = axis_limit b.elevation = elevation b.azimuth = azimuth rate = abs(maxz - minz) / frames polytopes = ([ restrict43( polytope.translate(Vector4(0, 0, 0.00001, -0.001 + minz + i * rate))) ] for i in range(frames)) b.animation(polytopes, 'demos/' + name, number=frames)
def hypercube_crosssections(): n = 15 poster_figure = plt.figure(figsize=[30, 4]) polytopes = [ hypercube(), hypercube().deform( rotate_wx(pi / 3) * rotate_wz(5 * pi / 4) * rotate_yz(3 * pi / 5)) ] subplot_count = 0 b = Tiling3ImageMaker() b.elevation = 20 b.azimuth = 20 b.edges_alpha = 0.15 b.number_of_rows = 2 b.number_of_columns = n for (j, polytope) in enumerate(polytopes): minz = polytope.minz() maxz = polytope.maxz() b.tiling3_axis_limit = [[-1.2, 1.2]] * 3 rate = float(abs(maxz - minz)) / n for i in range(n): b.image([ restrict43( polytope.translate( Vector4(0, 0, 0.00001, -0.001 + minz + i * rate))) ]) b.position_code = (i + 1) + subplot_count * n subplot_count += 1 b.elevation = 16 b.azimuth = -117 plt.savefig(os.path.join(target_dir, "hypercube_crosssections")) plt.close()
def periodic_tiling4(fundamental_vertices, fundamental_edges, fundamental_faces, fundamental_volumes, fundamental_hypervolumes, bounding_box, periods = [Vector4(1,0,0,0), Vector4(0,1,0,0), Vector4(0,0,1,0), Vector4(0,0,0,1)]): """ Build a periodic tiling. The fundamental geometric features are given as dicts. For fundamental_vertices, the keys are labels, and the values are vectors. For the rest, the keys are labels, and the values are lists of pairs whose first element is the label of something of dimension one less, and whose second element is a tuple of coefficients of the period vectors. The extent of the structure is found by adding and subtracting the elements of periods from the given vertices, while still remaining inside the box. In the resulting tiling, the labels are pairs: one is a label, and the other is a tuple of coefficients of the period vectors. """ ((minw,maxw),(minx, maxx), (miny, maxy), (minz, maxz)) = bounding_box n = len(periods) # 4 for a space-filling tiling, but let's not assume vertices = {} for (label, v0) in fundamental_vertices.items(): if (minw > v0.w or maxw < v0.w or minx > v0.x or maxx < v0.x or miny > v0.y or maxy < v0.y or minz > v0.z or maxz < v0.z): raise ValueError("The bounding box should contain the fundamental domain") gen = LatticeSearcher(n) for coeffs in gen: v = sum((u*c for (c,u) in zip(coeffs, periods)), v0) if minw <= v.w <= maxw and minx <= v.x <= maxx and miny <= v.y <= maxy and minz <= v.z <= maxz: vertices[(label,coeffs)] = v else: gen.reject() def tsum(t1,t2): return tuple(x+y for (x,y) in zip(t1,t2)) edges = {} for (label, vs) in fundamental_edges.items(): gen = LatticeSearcher(n) for coeffs in gen: s = [(a,tsum(coeffs,offset)) for (a,offset) in vs] if all(v in vertices for v in s): edges[(label,coeffs)] = frozenset(vertices[v] for v in s) else: gen.reject() faces = {} for (label, es) in fundamental_faces.items(): gen = LatticeSearcher(n) for coeffs in gen: s = [(a,tsum(coeffs,offset)) for (a,offset) in es] if all(e in edges for e in s): faces[(label,coeffs)] = frozenset(edges[e] for e in s) else: gen.reject() volumes = {} for (label, fs) in fundamental_volumes.items(): gen = LatticeSearcher(n) for coeffs in gen: s = [(a,tsum(coeffs,offset)) for (a,offset) in fs] if all(f in faces for f in s): volumes[(label,coeffs)] = frozenset(faces[f] for f in s) else: gen.reject() hypervolumes = {} for (label, gs) in fundamental_hypervolumes.items(): gen = LatticeSearcher(n) for coeffs in gen: s = [(a,tsum(coeffs,offset)) for (a,offset) in gs] if all(g in volumes for g in s): hypervolumes[(label,coeffs)] = frozenset(volumes[g] for g in s) else: gen.reject() v = dict((x,l) for (l,x) in vertices.items()) e = dict((x,l) for (l,x) in edges.items()) f = dict((x,l) for (l,x) in faces.items()) g = dict((x,l) for (l,x) in volumes.items()) h = dict((x,l) for (l,x) in hypervolumes.items()) return Tiling4(v,e,f,g,h)
def hypercube(box=((-1,1),(-1,1),(-1,1),(-1,1))): (ws,xs,ys,zs) = box vertices = [Vector4(w,x,y,z) for w in ws for x in xs for y in ys for z in zs] return tiling4_convex_hull(dict(zip(vertices,range(16))))
def cell24(): m010_1 =\ Matrix4([[0.056328, -0.675362, -0.290862,0.675362], [-0.624211, -0.184595, 0.736349,0.184595], [0.779222, -0.099053, 0.610893,0.099053], [0.000000, -0.707107, 0.000000,-0.707107]]) m010_1 m011_1 =\ Matrix4([[-0.071790, -0.165030, 0.773165,0.608135], [0.978870, -0.165143, 0.103850,-0.061292], [-0.191468, -0.782406, 0.241036,-0.541371], [0.000000, 0.577350, 0.577350,-0.577350]]) poster_figure = plt.figure(figsize=[12, 9]) b = Tiling3ImageMaker() b.number_of_rows = 3 b.number_of_columns = 4 for i in range(12): b.position_code = i + 1 if i == 0: b.tiling3_axis_limit = [[-1.5, 1.5]] * 3 b.azimuth = 82 b.elevation = 27 a = cell24_tiling([[-3, 3], [-3, 3], [-3, 3], [-3, 3]]) if i == 1: b.tiling3_axis_limit = [[-1, 3]] * 3 b.azimuth = 4 b.elevation = 19 a = cell24_tiling([[-5, 3], [-3, 5], [-3, 3], [-3, 3]]).translate(Vector4(-2, 0, 0, 0)) if i == 2: b.tiling3_axis_limit = [[-1, 3]] * 3 b.azimuth = 29 b.elevation = 7 a = cell24_tiling([[-5, 3], [-5, 3], [-3, 5], [-5, 5]]).translate(Vector4(-2, 0, 0, 0)) if i == 3: b.tiling3_axis_limit = [[-2, 4]] * 3 b.azimuth = 22 b.elevation = -1 a = cell24_tiling([[-5, 5], [-5, 5], [-5, 5], [-5, 5]]).translate(Vector4(-2, 0, 0, 0)) b.image([restrict43((a.translate(Vector4(0, 0, 0.00001, 0.00001))))]) if i == 4: b.tiling3_axis_limit = [[-1.5, 1.5]] * 3 b.azimuth = -30 b.elevation = 38 a = cell24_tiling([[-3, 3], [-3, 3], [-3, 3], [-3, 3]]).deform(m010_1) if i == 5: b.tiling3_axis_limit = [[-1, 3]] * 3 b.azimuth = -35 b.elevation = -138 a = cell24_tiling([[-5, 3], [-5, 3], [-3, 5], [-5, 3]]).translate(Vector4(0, 0, 0, 0)).deform(m010_1) if i == 6: b.tiling3_axis_limit = [[-2.2, 2.5]] * 3 b.azimuth = 71 b.elevation = -153 a = cell24_tiling([[-5, 3], [-5, 3], [-3, 5], [-5, 5]]).translate(Vector4(0, 0, 0, 0)).deform(m010_1) if i == 7: b.tiling3_axis_limit = [[-4, 4]] * 3 b.azimuth = 69 b.elevation = 36 a = cell24_tiling([[-5, 5], [-5, 5], [-5, 5], [-5, 5]]).translate(Vector4(0, 0, 0, 0)).deform(m010_1) b.image([restrict43(a.translate(Vector4(0, 0, 0.00001, 0.00001)))]) if i == 8: b.tiling3_axis_limit = [[-1.5, 1.5]] * 3 b.azimuth = -47 b.elevation = 172 a = cell24_tiling([[-3, 3], [-3, 3], [-3, 3], [-3, 3]]).deform(m011_1) if i == 9: b.tiling3_axis_limit = [[-2, 2]] * 3 b.azimuth = 43 b.elevation = -55 a = cell24_tiling([[-5, 3], [-3, 5], [-3, 3], [-3, 3]]).translate(Vector4(2, 0, 0, 0)).deform(m011_1) if i == 10: b.tiling3_axis_limit = [[-2.2, 2.5]] * 3 b.azimuth = -58 b.elevation = 46 a = cell24_tiling([[-5, 3], [-5, 3], [-3, 5], [-5, 5]]).translate(Vector4(0, 0, 0, 0)).deform(m011_1) if i == 11: b.tiling3_axis_limit = [[-4, 4]] * 3 b.azimuth = 69 b.elevation = 33 a = cell24_tiling([[-5, 5], [-5, 5], [-5, 5], [-5, 5]]).translate(Vector4(0, 0, 0, 0)).deform(m011_1) b.image([restrict43(a.translate(Vector4(0, 0, 0.00001, 0.00001)))]) plt.savefig(os.path.join(target_dir, "cell24")) plt.close()
def simple_periodic_tiling4(tiling4, bounding_box, periods=[Vector4(1,0,0,0), Vector4(0,1,0,0), Vector4(0,0,1,0), Vector4(0,0,0,1)]): return simple_union(periodic_copies(tiling4, bounding_box, periods))
def v00(v1,v2): return Vector4(v1.x, v1.y, v2.x, v2.y)