diff --git a/ChairTiling_huda.ipynb b/ChairTiling_huda.ipynb new file mode 100644 index 0000000..29bb062 --- /dev/null +++ b/ChairTiling_huda.ipynb @@ -0,0 +1,253 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": 2, + "id": "adcacb25-63bf-4773-a97a-7c2429f851a2", + "metadata": { + "collapsed": false + }, + "outputs": [ + ], + "source": [ + "#imports go here\n", + "\n", + "from sage.plot.polygon import Polygon\n", + "from sage.plot.colors import rainbow" + ] + }, + { + "cell_type": "code", + "execution_count": 9, + "id": "b55d5ee7-0fb5-42d3-bb1a-015b75954dee", + "metadata": { + "collapsed": false + }, + "outputs": [ + ], + "source": [ + "\"\"\"\n", + "There are two problems we want to solve:\n", + "1) How large of a supertile must we compute to find all of the 1-collared prototiles?\n", + "2) How can we generate all of the 1-collared prototiles from a large enough subsection of the tiling?\n", + "\n", + "Also, we want to be able to do this for other types of tilings, not just those that use vertical/horizontal\n", + "lines to construct the prototiles. For instance, https://tilings.math.uni-bielefeld.de/substitution/binary/\n", + "uses rhombuses with internal angles either in {pi/5, 3pi/5} or {2pi/5, 4pi/5}\n", + "\n", + "For now, the focus will be on representing tilings as a collection of objects rather than as a graphics\n", + "object, as this will save computing power and the resulting collections can just be graphed after being\n", + "generated. Once we can generate large supertile objects, we can start to write functions that generate\n", + "the possible collars of a set of prototiles.\n", + "\"\"\"\n", + "\n", + "class ChairTile:\n", + " \n", + " # We define a supertile by:\n", + " # level, i.e. n where the supertile is L_n\n", + " # orientation as a multiple of pi describing rotation around its center\n", + " # origin, describing where to place this tile when moving up a level. The origin is the point that stays fixed\n", + " # when moving up a level.\n", + " def __init__(self, level: int, orientation: RR, origin: vector):\n", + " self.points = []\n", + " self.level = level\n", + " self.orientation = orientation\n", + " self.origin = origin\n", + "\n", + " if (level < 0):\n", + " raise Exception(\"Level must be a non-negative integer.\")\n", + " \n", + " if (level == 0):\n", + " self.points = [vector((0 + origin[0], 0 + origin[1])), \n", + " vector((2 + origin[0], 0 + origin[1])), \n", + " vector((2 + origin[0], 1 + origin[1])), \n", + " vector((1 + origin[0], 1 + origin[1])), \n", + " vector((1 + origin[0], 2 + origin[1])), \n", + " vector((0 + origin[0], 2 + origin[1]))]\n", + " self.rotate_tile(self.origin, self.orientation)\n", + "\n", + " else:\n", + " # If this is a supertile, we consider it to be the collection of all the prototiles that make it up\n", + " self.subtiles = []\n", + " R = rotation_matrix(self.orientation)\n", + " \n", + " st_1 = ChairTile(level - 1, self.orientation, origin)\n", + " st_2 = ChairTile(level - 1, self.orientation, origin + R*vector((2**(level - 1), 2**(level - 1))))\n", + " st_3 = ChairTile(level - 1, self.orientation + pi/2, origin + R*vector ((2** (level + 1), 0)))\n", + " st_4 = ChairTile(level - 1, self.orientation + 3*pi/2, origin + R*vector((0, 2** (level + 1))))\n", + "\n", + " self.subtiles.append(st_1)\n", + " self.subtiles.append(st_2)\n", + " self.subtiles.append(st_3)\n", + " self.subtiles.append(st_4)\n", + "\n", + " \n", + "\n", + " # Rotates a tile around center by theta degrees, clockwise\n", + " def rotate_tile(self, center, theta):\n", + " if (theta == 0):\n", + " return\n", + " R = rotation_matrix(theta)\n", + " pts = [R*vector((self.points[i][0]-center[0],self.points[i][1]-center[1])) for i in range(len(self.points))]\n", + " self.points = [(pts[i][0]+center[0],pts[i][1]+center[1]) for i in range(len(self.points))]\n", + " \n", + " def iterate_subtiles(self):\n", + " if self.level >> 0:\n", + " for s in self.subtiles:\n", + " \n", + " \n", + " # Graphs all tiles in supertile recursively\n", + " def graph(self):\n", + " P = Graphics()\n", + " if self.level >> 0:\n", + " for s in self.subtiles:\n", + " P += s.graph()\n", + " else:\n", + " P += polygon(self.points, fill=False)\n", + " \n", + " return P\n", + " \n", + " # Given a supertile, finds the relevant verticies on the inner edges\n", + " # these vertices will be used to find the tiles on the growing edge of the supertile\n", + " # i.e. the tiles for which we can find a 1-collar!\n", + " # uh this only works for orientation = 0 supertiles, whoops\n", + " def find_corner_points(self):\n", + " self.corner_points = []\n", + " \n", + " # There is the vertical edge, and the horizontal edge.\n", + " # We will order the points from the topmost on the vertical\n", + " # edge, all the way around to the rightmost on the horizontal edge\n", + " \n", + " # Number of vertices on each edge, minus\n", + " # the two annoying innermost corner points\n", + " num = 2**(self.level-1)\n", + " \n", + " # Starts at top point of the vertical edge\n", + " x, y = (2**(self.level), 2**(self.level+1))\n", + " \n", + " # Iterate through vertical edge\n", + " for n in range(0, num):\n", + " self.corner_points.append((self.origin[0] + x, self.origin[1] + y - 2*n))\n", + " \n", + " # Add on the two annoying innermost corner vertices!\n", + " self.corner_points.append((self.origin[0] + 2**(self.level), self.origin[1] + 2**(self.level) + 1))\n", + " self.corner_points.append((self.origin[0] + 2**(self.level) + 1, self.origin[1] + 2**(self.level)))\n", + " \n", + " # Now, we are on the horizonal edge!\n", + " x, y = (2**(self.level) + 2, 2**(self.level))\n", + " \n", + " # Iterate through vertices on horizontal edge\n", + " for m in range(0, num):\n", + " self.corner_points.append((self.origin[0] + x + 2*n, self.origin[1] + y))\n", + " \n", + " # Done!\n", + " return\n", + " \n", + "# quickly get rotation matrix for an angle, just for convenience\n", + "def rotation_matrix(theta):\n", + " R = matrix(2,2,[cos(theta),-sin(theta),sin(theta),cos(theta)])\n", + " return R\n", + "\n", + "\n", + "# Not sure if I should include the next two functions in the class or not...\n", + "\n", + "# Ok so the plan here is that I iterate through every point in self.corner_points\n", + "# and I search all tiles in the supertile and the supertile + (2**level, 2**level)\n", + "# and see which ones have said point. Then, I search my narrowed down list for the tiles\n", + "# that ALSO have the next point in my self.corner_points list. This way, I find the tiles that\n", + "# share an edge with the corner edge. This is the most efficient way I came up with, not sure if\n", + "# there is a better way.\n", + "def find_tiles(supertile: ChairTile):\n", + " return\n", + "\n", + "\n", + "# For each tile, we can run this function to find it's 1-collar\n", + "def find_collar(supertile: ChairTile, tile: ChairTile)\n", + " return\n", + " \n", + " " + ] + }, + { + "cell_type": "code", + "execution_count": 0, + "id": "54c938", + "metadata": { + "collapsed": false + }, + "outputs": [ + ], + "source": [ + ] + }, + { + "cell_type": "code", + "execution_count": 16, + "id": "91291bac-65f2-485a-994f-4d9fbd3a0d95", + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "data": { + "image/png": "iVBORw0KGgoAAAANSUhEUgAAAdkAAAHWCAYAAAA7EfPXAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjguMCwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy81sbWrAAAACXBIWXMAAA9hAAAPYQGoP6dpAAA04klEQVR4nO3df2xc5Z3v8Y9Lk7kBbLNZiO1AiJwl5pqf2ly44FCRQEVEwmah2UW0oFWgUsUWgxalFSigCCNvE4pURCVbXml37YKyCIT4UVZ1gXQhztJJ2sTAJU29kCrmx3ZxIxDMhAC2cZ/7x3SGhDjkPM/M9/jx+P2SRsb2Oc+P+c74mxOcz6lxzjkBAICK+8pULwAAgGpFkwUAwAhNFgAAIzRZAACM0GQBADBCkwUAwAhNFgAAIzRZAACMRNdknXPK5/MiIwMAMN1F12QPHDig+vp6HThwYKqXAgBAWaJrsgAAVAuaLAAARmiyAAAYockCAGCEJgsAgJGvTvUCAEyh3l7p/fel2bOlf/iHqV4NUHVqYrtpez6fV319vXK5nOrq6io69ttvS++9V9EhjzA6KmUyzDHV4zNHMq3Xnq05+36rP55Yq68cyNtMAsxg0VzJdnd3q7u7WxMTEybjv/221NoqffyxyfDAtPQbSWdL+ugj6cO3pdNPn+oVAdVlxlzJvvyy9H/+j7R5c6HZWujvlzZskDo7pVWrmGOqxmeO5IpXsnnV6neDeS1ZUvk5gJksmivZtLS2yuwHydBQ4WNzM3NM5fjM4eF/GYwJoITfLgYAwAhNFgAAIzRZAACM0GQBADBCkwUAwAhNFgAAIzRZAACM0GQBADAy48IofG3fLu3bl+zYX/7y8I9JLFoktbX5r8uHzx6k6thHyB4k+31USy0AJBNNk7XOLg6xfbu0dKn/eT09hUdS2azdD8XQPUjVsQ/fPUh2+6iWWgBILpom297ervb29lJ2cQyKVxzf/a50ySXJzhkbK9w1LIlf/rLwg3PfPrsfiCF7kKpjHz57kOz3US21AJBcNE02ZpdcIt1wg83YvldZoSz3ILEPH9WwBwDJ8ItPAAAYockCAGCEJgsAgBGaLAAARmiyAAAYockCAGCEJgsAgBGaLAAARmiyAAAYmXGJT/390tBQsmN9w+Ul+xB733PSDMq3XJN1LQ6dw2ofMdbiqpx0kt/QAHy4SHR1dbnW1lbX0tLiJLlcLlfR8bNZ56SwR2+v/RwxPrLZZPvu7U1vTdSisrX4jc5yTnI51SaeA0By0VzJWt8gIJMpfOzslJqbk51TDFtPGs4eEgA/Pi7NmpXs2EPXFFNQfnHspGsK2UMatZDCwvjTqLdVLU69U9LvC/9dfI8AqJxommxaVq2SlixJfnxI2HoaAfAxhsz7rClkD9QiucRr2qhSkwVQefziEwAARmiyAAAYockCAGCEJgsAgBGaLAAARryabE9Pj8477zzV1dWprq5ObW1t+vnPf176vnNOHR0dmj9/vubMmaPly5drz549FV80AADTgVeTPe2003Tfffdp165d2rVrly6//HJdffXVpUZ6//3364EHHlBXV5d27typxsZGXXHFFTpw4IDJ4gEAiJlXk129erVWrVqllpYWtbS06Ac/+IFOPPFE7dixQ845Pfjgg7r77ru1Zs0anXPOOXrooYf08ccf65FHHrFaPwAA0QoOo5iYmNDjjz+ugwcPqq2tTcPDwxoZGdGKFStKx2QyGS1btkzZbFY333zzpOOMjo5qdHS09Hk+nw9dkhnfbFof1vm6Ulj2rc8cIfsOZb0m6+zpaqoFgGPzbrK7d+9WW1ubPv30U5144ol66qmndNZZZymbzUqSGhoaDju+oaFBb7311lHH27Rpk+69917fZaRi0aLCx54ev9Sd8fFkx23fLi1d6r+ukDVls8l/uI+Nhc1RfL4shNaiuJckQuthWYviaymmWgBIzrvJnnnmmXr11Vf14Ycf6oknntDatWs1MDBQ+n5NTc1hxzvnjvjaodavX69169aVPs/n81qwYIHvsky0tRV+IPpc2fT0JM+mTTNfN2n2reSffyuFX6ElFVoLn8zmkHpY16L4WoqpFgCS826ys2fP1hlnnCFJuuCCC7Rz5079+Mc/1p133ilJGhkZUVNTU+n4/fv3H3F1e6hMJqNMxMnkbW1+P7BizdcNYb0uX2nUQrLdd4xrAmCn7H8n65zT6Oiompub1djYqC1btpS+NzY2poGBAS0N/TtRAACmMa8r2bvuuksrV67UggULdODAAT366KPaunWrnn32WdXU1Oj222/Xxo0btXjxYi1evFgbN27U8ccfr+uvv95q/QAARMuryf7hD3/Q3/3d3+ndd99VfX29zjvvPD377LO64oorJEl33HGHPvnkE91y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EZosAABGoolVjNX27dK+fcmODQmMX7RIamvzX5cPnz1I1bGP0PB+632E1sKX73ljY8mjGNNaUzW8pqphD1J17CONPUyqMgFU5evq6nKtra2upaUlmljFbLZwjvUjm02+Jt84sbT24LOPkEi0athHOXvo65u+z1Nvb3y1SPO54v0dzz58alGpWMVormStbxAQovinKp8AeN8rgp6ewjxWf8IK2YNUHfvw2YNkv4+QPRTXNGtWsuPb2qRs1v9q2fdGBz5XBcUahOx7Or+mqmEPUnXsI409HE00TTZml1wi3XCDzdg9PTbjfpHlHiT24cN3D75ramvz/0HS02P/3FrvOxTv72Orhn2ktYcv4hefAAAwQpMFAMAITRYAACM0WQAAjHg32W3btmn16tWaP3++ampq9PTTTx/2/RtvvFE1NTWHPS6++OJKrRcAgGnDu8kePHhQ559/vrq6uo56zJVXXql333239Ojv7y9rkQAATEfe/4Rn5cqVWrly5Zcek8lk1NjYGLwoAACqgcn/k926davmzZunlpYWfec739H+/fstpgEAIGoVD6NYuXKlrr32Wi1cuFDDw8PasGGDLr/8cg0ODiqTyRxx/OjoqEZHR0uf5/P5Si/pMP390tBQsmNDMlqt8zd9z0kzq9RyTda1OHQOq32EZv76njs+njwh6tCxfeZII+vY59w03kuS7fsiZE3V8L4IPce6FsPDfmMfVTmZjJLcU0899aXH/M///I+bNWuWe+KJJyb9/j333OMkHfGodHZxOdmYvb32c8T4SCObdibWIukeYt+H1esp7deU1T54X1RHLXxet5Mxj1VsamrSwoULtXfv3km/v379eq1bt670eT6f14IFCyq+juJFdGen1Nyc7Jxi3mXSP7GH5G+GXHX45sxaZ5X6ZtOG7CGNWkhheai++/aphW8WcTnPrWX9fK860nhNSbb5t+VkNlu9pmJ8XxT5/CxMoxbDw9KGDZ/3jlDmTfb999/XO++8o6ampkm/n8lkJv1rZCurVklLliQ/PiTvMo0c0RizSn3WFLKHaqhFyB58s4hDn1vr+oWIbU1pvAbTeE3F9r4IncOXz5pefrnQZMvl3WQ/+ugj/e53vyt9Pjw8rFdffVVz587V3Llz1dHRob/5m79RU1OT3nzzTd111106+eST9Y1vfKP81QIAMI14N9ldu3bpsssu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T//0T1Owwsr74p6dc27t2rXu6quvnpL1pGn//v1OkhsYGHDOzYx6O3fkvp2bOTX/sz/7M/cv//IvVV1rrmSnib1792r+/Plqbm7WN7/5Te3bt2+ql5S64eFhjYyMaMWKFaWvZTIZLVu2TNlsdgpXZm/r1q2aN2+eWlpa9J3vfEf79++f6iVVXC6XkyTNnTtX0syp9xf3XVTNNZ+YmNCjjz6qgwcPqq2traprTZOdBi666CI9/PDDeu655/TP//zPGhkZ0dKlS/X+++9P9dJSNTIyIklqaGg47OsNDQ2l71WjlStX6t/+7d/0wgsv6Ec/+pF27typyy+/XKOjo1O9tIpxzmndunX62te+pnPOOUfSzKj3ZPuWqrfmu3fv1oknnqhMJqO///u/11NPPaWzzjqrqmtdNXfhqWYrV64s/fe5556rtrY2/cVf/IUeeughrVu3bgpXNjW+eFsp59yX3mpqurvuuutK/33OOefoggsu0MKFC/Wzn/1Ma9asmcKVVc6tt96q1157TS+99NIR36vmeh9t39Va8zPPPFOvvvqqPvzwQz3xxBNau3atBgYGSt+vxlpzJTsNnXDCCTr33HO1d+/eqV5Kqoq/Uf3FP9nu37//iD8BV7OmpiYtXLiwaup/22236ZlnntGLL76o0047rfT1aq/30fY9mWqp+ezZs3XGGWfoggsu0KZNm3T++efrxz/+cVXXmiY7DY2OjmpoaEhNTU1TvZRUNTc3q7GxUVu2bCl9bWxsTAMDA1q6dOkUrixd77//vt55551pX3/nnG699VY9+eSTeuGFF9Tc3HzY96u13sfa92SqpeZf5JzT6Oho1dZaEr9dPB1873vfc1u3bnX79u1zO3bscH/1V3/lamtr3ZtvvjnVS6u4AwcOuFdeecW98sorTpJ74IEH3CuvvOLeeust55xz9913n6uvr3dPPvmk2717t/vWt77lmpqaXD6fn+KVh/uyPR84cMB973vfc9ls1g0PD7sXX3zRtbW1uVNPPXVa79k557773e+6+vp6t3XrVvfuu++WHh9//HHpmGqs97H2Xa01X79+vdu2bZsbHh52r732mrvrrrvcV77yFff8888756qz1s45R5OdBq677jrX1NTkZs2a5ebPn+/WrFnj9uzZM9XLMvHiiy86SUc81q5d65wr/LOOe+65xzU2NrpMJuMuvfRSt3v37qlddJm+bM8ff/yxW7FihTvllFPcrFmz3Omnn+7Wrl3r3n777aledtkm27Mk19fXVzqmGut9rH1Xa82//e1vu4ULF7rZs2e7U045xX39618vNVjnqrPWzjnHre4AADDC/5MFAMAITRYAACM0WQAAjNBkAQAwQpMFAMAITRYAACM0WQAAjNBkAQAwQpMFAMAITRYAACM0WQAAjNBkAQAw8v8BDVgwLnegTeoAAAAASUVORK5CYII=", + "text/plain": [ + "Graphics object consisting of 257 graphics primitives" + ] + }, + "execution_count": 16, + "metadata": { + }, + "output_type": "execute_result" + } + ], + "source": [ + "p = ChairTile(4, 0, vector((1,1)))\n", + "p.find_corner_points()\n", + "cp = line(p.corner_points, thickness = 2, rgbcolor = (1, 0, 0))\n", + "P = p.graph() + cp\n", + "show(P)\n" + ] + } + ], + "metadata": { + "kernelspec": { + "argv": [ + "sage-10.4", + "--python", + "-m", + "sage.repl.ipython_kernel", + "--matplotlib=inline", + "-f", + "{connection_file}" + ], + "display_name": "SageMath 10.4", + "env": { + }, + "language": "sagemath", + "metadata": { + "cocalc": { + "description": "Open-source mathematical software system", + "priority": 10, + "url": "https://www.sagemath.org/" + } + }, + "name": "sage-10.4", + "resource_dir": "/ext/jupyter/kernels/sage-10.4" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.12.4" + } + }, + "nbformat": 4, + "nbformat_minor": 4 +} \ No newline at end of file