diff --git a/posts/pentagons/1/goldberg/common.py b/posts/pentagons/1/goldberg/display.py similarity index 67% rename from posts/pentagons/1/goldberg/common.py rename to posts/pentagons/1/goldberg/display.py index 1245de3..afb55cd 100644 --- a/posts/pentagons/1/goldberg/common.py +++ b/posts/pentagons/1/goldberg/display.py @@ -1,14 +1,12 @@ import itertools -from dataclasses import dataclass, field from typing import Iterable, Literal import re -import sympy - -from goldberg.operators import GoldbergOperator, Polyhedron +from goldberg.operators import Polyhedron GoldbergClass = Literal["I", "II", "III"] + def group_dict(xs: Iterable, key=None): """ Group the items of `xs` into a dict using `sorted` and `itertools.groupby`. @@ -17,7 +15,7 @@ def group_dict(xs: Iterable, key=None): return {i: list(j) for i, j in itertools.groupby(sorted(xs, key=key), key=key)} -def hexagons_to_polyhedron(hexagon_count: int): # | sympy.Expr): +def hexagons_to_polyhedron(hexagon_count: int): """General Goldberg solution""" return Polyhedron( face_count=hexagon_count + 12, @@ -26,26 +24,8 @@ def hexagons_to_polyhedron(hexagon_count: int): # | sympy.Expr): ) -@dataclass -class GoldbergData: - parameter: tuple[int, int] - conway: str - - parameter_link: str | None = None - conway_recipe: str | None = None - - extra: list = field(default_factory=list) - - def link_polyhedronisme(text: str, recipe: str) -> str: - return f"[{text}](https://levskaya.github.io/polyhedronisme/?recipe={recipe}){{target=\"_blank\"}}" - - -@dataclass -class GCOperator: - name: GoldbergOperator - matrix: sympy.Matrix - parameter: int | sympy.Symbol + return f'[{text}](https://levskaya.github.io/polyhedronisme/?recipe={recipe}){{target="_blank"}}' def parameter_to_class(parameter: tuple[int, int]) -> GoldbergClass: @@ -57,11 +37,17 @@ def parameter_to_class(parameter: tuple[int, int]) -> GoldbergClass: def display_conway(conway_notation: str, seed: str | None = None): + """ + Display a Conway notation string in LaTeX. + Indexed operators (u, t, and k) have their indices placed in subscripts. + + If `seed` is given, the notation is applied to it. + If the notation contains equals signs, these are interpreted as separate recipes to apply. + """ # If a seed is given, split at the equals and apply to both sides if seed is not None: conway_notation = " = ".join( - operation + seed - for operation in conway_notation.split(" = ") + operation + seed for operation in conway_notation.split(" = ") ) # Latexify and subscript the numbers in u, t, and k diff --git a/posts/pentagons/1/goldberg/dodecahedral.py b/posts/pentagons/1/goldberg/dodecahedral.py index dd1bb02..5471e41 100644 --- a/posts/pentagons/1/goldberg/dodecahedral.py +++ b/posts/pentagons/1/goldberg/dodecahedral.py @@ -21,7 +21,9 @@ dodecahedral_goldberg_recipes: dict[tuple[int, int], str] = { # Assert all the above recipes are correct verify_recipes( { - param: " = ".join([op + "D" for op in goldberg_parameters_to_operations[param].split(" = ")]) + param: " = ".join( + [op + "D" for op in goldberg_parameters_to_operations[param].split(" = ")] + ) for param in dodecahedral_goldberg_recipes.keys() }, dodecahedral_goldberg_recipes, diff --git a/posts/pentagons/1/goldberg/operators.py b/posts/pentagons/1/goldberg/operators.py index f093532..decebb3 100644 --- a/posts/pentagons/1/goldberg/operators.py +++ b/posts/pentagons/1/goldberg/operators.py @@ -106,7 +106,7 @@ def generalize_recipe(recipe: str | list[str], depth: int = 3) -> set[str]: "u(\\D)", "u2\\1", re.sub("([KC]\\d*)", "", rec), - ) + ), ).replace("dd", "") for rec in recipe ] @@ -204,7 +204,9 @@ goldberg_operators: dict[GoldbergOperator, sympy.Matrix] = { ), } goldberg_operators["tk"] = goldberg_operators["dk"] @ goldberg_operators["dk"] -goldberg_operators["g_T"] = from_same_eigenspace(goldberg_operators["dk"], [t_param % 3, 1, t_param]) +goldberg_operators["g_T"] = from_same_eigenspace( + goldberg_operators["dk"], [t_param % 3, 1, t_param] +) def apply_goldberg_operator( @@ -215,18 +217,22 @@ def apply_goldberg_operator( # Naive combinatorial method if isinstance(operator, tuple): return Polyhedron( - *(goldberg_operators["g_T"] @ poly.as_matrix()).subs(t_param, loeschian_norm(*operator)) + *(goldberg_operators["g_T"] @ poly.as_matrix()).subs( + t_param, loeschian_norm(*operator) + ) ) # Try lookup parameter if (parameter := goldberg_operators_to_parameters.get(operator)) is not None: return Polyhedron( - *(goldberg_operators["g_T"] @ poly.as_matrix()).subs(t_param, loeschian_norm(*parameter)) - ) - elif (matrix := goldberg_operators.get(operator)) is not None: # pyright: ignore[reportArgumentType] - return Polyhedron( - *(matrix @ poly.as_matrix()) + *(goldberg_operators["g_T"] @ poly.as_matrix()).subs( + t_param, loeschian_norm(*parameter) + ) ) + elif ( + matrix := goldberg_operators.get(operator) # pyright: ignore[reportArgumentType] + ) is not None: + return Polyhedron(*(matrix @ poly.as_matrix())) # Partition the recipe into operators for which we have the matrix partitioned = [] @@ -237,7 +243,7 @@ def apply_goldberg_operator( for op in goldberg_operators.keys(): if recipe.find(op) == 0: partitioned.append(op) - recipe = recipe[len(op):] + recipe = recipe[len(op) :] break else: bad_recipe = True @@ -249,8 +255,6 @@ def apply_goldberg_operator( if partitioned: # Technically you could just pointwise multiply the eigenvalues matrix = reduce(matmul, (goldberg_operators[i] for i in partitioned)) - return Polyhedron( - *(matrix @ poly.as_matrix()) - ) + return Polyhedron(*(matrix @ poly.as_matrix())) raise ValueError("Could not partition operators!") diff --git a/posts/pentagons/1/goldberg/tetrahedral.py b/posts/pentagons/1/goldberg/tetrahedral.py index 5fa3dda..cd0596a 100644 --- a/posts/pentagons/1/goldberg/tetrahedral.py +++ b/posts/pentagons/1/goldberg/tetrahedral.py @@ -171,6 +171,7 @@ def _apply_double( operation: GoldbergOperator, ) -> dict[tuple[int, int], TetrahedralAntitruncation]: """Build data for a double-Goldberg tetrahedral solution""" + regularized_operation = "K300" + operation if operation == "w" else operation return { entry: TetrahedralAntitruncation( conway=" = ".join( @@ -179,8 +180,8 @@ def _apply_double( conway_recipe=( "*" if antitruncation.conway_recipe.find("*") == 0 - else operation + antitruncation.conway_recipe - ), # TODO: might need to commute whirl with the last regularization operator + else regularized_operation + antitruncation.conway_recipe + ), intercluster_paths=double_goldberg_paths[operation][ antitruncation.intercluster_paths[0] ], diff --git a/posts/pentagons/1/goldberg/triangles.py b/posts/pentagons/1/goldberg/triangles.py index 31f40ca..6974de0 100644 --- a/posts/pentagons/1/goldberg/triangles.py +++ b/posts/pentagons/1/goldberg/triangles.py @@ -315,9 +315,11 @@ def recenter_axes(a: int, b: int): xspan = maxx - minx yspan = maxy - miny - extent_x = a + 2*b + (a - b) * root3.real # rightward extent due to blue triangle + extent_x = a + 2 * b + (a - b) * root3.real # rightward extent due to blue triangle if a > b and min(a, b) != 0: - extent_x += -(a-b) + (1 + a-b) * root3.real # leftward extent due to green parallelogram + extent_x += ( + -(a - b) + (1 + a - b) * root3.real + ) # leftward extent due to green parallelogram extent_y = (2 * max(a, b) + min(a, b)) * root3.imag diff --git a/posts/pentagons/1/index.qmd b/posts/pentagons/1/index.qmd index 1025e55..6e81b73 100644 --- a/posts/pentagons/1/index.qmd +++ b/posts/pentagons/1/index.qmd @@ -30,7 +30,12 @@ import sympy from tabulate import tabulate import goldberg.triangles as goldberg_triangles -from goldberg.common import link_polyhedronisme, parameter_to_class, display_conway, remove_repeats +from goldberg.display import ( + display_conway, + link_polyhedronisme, + parameter_to_class, + remove_repeats, +) from goldberg.operators import ( Polyhedron, goldberg_parameters_to_operations, @@ -527,7 +532,7 @@ Though this list can be found #| classes: plain @dataclass -class DodecahedralGoldbergSolution: +class DodecahedralSolution: klass: str parameter: str hexagon_count: str @@ -543,9 +548,9 @@ special_names: dict[tuple[int, int], str] = { (1, 1): "https://en.wikipedia.org/wiki/Truncated_icosahedron", } -rows: list[DodecahedralGoldbergSolution] = [ +rows: list[DodecahedralSolution] = [ # General solution - DodecahedralGoldbergSolution( + DodecahedralSolution( klass="", parameter="(a, b)", hexagon_count=f"${sympy.latex(polyhedron.face_count - 12)}$", @@ -562,7 +567,7 @@ rows: list[DodecahedralGoldbergSolution] = [ ] + sorted( [ # Particular solutions - DodecahedralGoldbergSolution( + DodecahedralSolution( klass=parameter_to_class(parameter), parameter=f"[{parameter}]({special_name})" if special_name is not None else str(parameter), hexagon_count=str(polyhedron.face_count - 12), @@ -589,7 +594,7 @@ rows: list[DodecahedralGoldbergSolution] = [ key = lambda x: x.klass ) -headers = DodecahedralGoldbergSolution( +headers = DodecahedralSolution( klass="Class", parameter="Parameter", hexagon_count="$F_6$", diff --git a/posts/pentagons/2/index.qmd b/posts/pentagons/2/index.qmd index 8be6eaa..b79b327 100644 --- a/posts/pentagons/2/index.qmd +++ b/posts/pentagons/2/index.qmd @@ -32,12 +32,12 @@ from IPython.display import Markdown import matplotlib.pyplot as plt from tabulate import tabulate -from goldberg.common import ( - hexagons_to_polyhedron, +from goldberg.display import ( + display_conway, group_dict, + hexagons_to_polyhedron, link_polyhedronisme, parameter_to_class, - display_conway, remove_repeats, ) from goldberg.operators import ( diff --git a/posts/pentagons/3/index.qmd b/posts/pentagons/3/index.qmd index c259d1f..cb31d7a 100644 --- a/posts/pentagons/3/index.qmd +++ b/posts/pentagons/3/index.qmd @@ -35,9 +35,9 @@ from IPython.display import Markdown import sympy from tabulate import tabulate -from goldberg.common import ( - hexagons_to_polyhedron, +from goldberg.display import ( group_dict, + hexagons_to_polyhedron, link_polyhedronisme, ) from goldberg.operators import (