{ "cells": [ { "cell_type": "markdown", "id": "2a3641ed", "metadata": {}, "source": [ "* [Home](Home.ipynb)\n", "\n", "\n", "# Random Walks in the Matrix\n", "\n", "\"Rhombic\n", "\n", "Imagine standing at the center of a sphere, with 12 equally-sized spheres all around you, at the corners of a cuboctahedron. Each time you step into a random neighboring sphere, you're in the same circumstance, of having a choice of twelve nextdoor neighbors.\n", "\n", "Have you seen [random walks](http://4dsolutions.net/ocn/numeracy3.html) on chess or checker boards? Just take the checker pattern and extend it indefinitely around an arbitrary square marked with a lamp post. \n", "\n", "Our little man has maybe had too much to drink and is moving randomly from one square to the next, but only across an edge, not through a diagonal. On a square grid, he has four neighbors to select from. On an hexagonal grid, he would have six.\n", "\n", "Back to our space-filling grid, our cells are rhombic dodecahedron shaped (twelve diamond faces). We're free to hop at random, leaving a trace over time, of what our pathway has been. This concept of a pathway applies regardless of which grid we're imagining.\n", "\n", "What we're going to find is that four random walkers, setting out from the same origin (lamp post) will define the four CCP sphere corners of a random tetrahedron. That tetrahedron will have a whole number volume relative to the unit tetrahedron of four CCP balls and volume one.\n", "\n", "### Quadrays\n", "\n", "To make our pathway through the CCP (the name of this sphere packing pattern) easy to compute and keep track of, we're going to want to label all the spheres with vectorial coordinates.\n", "\n", "We will find it convenient to do so using Quadrays, an interface bolted on XYZ and easy to reason about independently of XYZ. In this game of vectors, the origin sphere will be labeled (0,0,0,0) and the twelve around it will be the unique permutations of (2,1,1,0). \n", "\n", "Each time our random walker takes a step, he has one of twelve vectors to choose from. Adding that vector to his current position takes him to a next position and so on, onward along a pathway.\n", "\n", "\n", "\"Quadray\n", "\n", "Linear combinations of the four basis rays (lets use that shoptalk) map to any point in space, as expressed by 4-tuples. \n", "\n", "At least one of the four rays, the one not bordering a specified point's quadrant, will not contribute to wayfinding. In canonical form, at least one element of the 4-tuple will be zero, the others non-negative.\n", "\n", "Qvectors are additive and scalable, have length and direction, according to the usual rules of vector algebra. \n", "\n", "Two way conversion from to XYZ is assurred, given Qvectors come with the one canonical representation per point, just as XYZ does. \n", "\n", "Quadrays may be seen as \"syntactic sugar\" atop XYZ, an API. Or vice versa." ] }, { "cell_type": "code", "execution_count": 1, "id": "83480225", "metadata": {}, "outputs": [], "source": [ "from qrays import Qvector\n", "from math import sqrt" ] }, { "cell_type": "markdown", "id": "ea08f246", "metadata": {}, "source": [ "Is it bizarre to the point of macabre to have our basis rays not also be of unit length? \n", "\n", "The tetrahedron cage is more important: it's edges should be 1 exactly (or 2 if measured in sphere radii). \n", "\n", "Our context is the IVM (= CCP = FCC), a closest packed spheres pattern well known to mathematicians, but by other names.\n", "\n", "\"Sphere" ] }, { "cell_type": "code", "execution_count": 2, "id": "b58696ca", "metadata": {}, "outputs": [ { "data": { "text/plain": [ "0.6123724356957945" ] }, "execution_count": 2, "metadata": {}, "output_type": "execute_result" } ], "source": [ "a = Qvector((1,0,0,0))\n", "a.length()" ] }, { "cell_type": "code", "execution_count": 3, "id": "cb67a6d8", "metadata": {}, "outputs": [ { "data": { "text/plain": [ "0.6123724356957945" ] }, "execution_count": 3, "metadata": {}, "output_type": "execute_result" } ], "source": [ "b = Qvector((0,1,0,0))\n", "b.length()" ] }, { "cell_type": "markdown", "id": "864e56a6", "metadata": {}, "source": [ "To subtract is to add the additive inverse of, which is the Qvector rotated to point oppositely. (1,0,0,0), negated, is (0,1,1,1). \n", "\n", "The result of a subtraction is another Qvector, and its length will be the length separating the \"arrow tips\" of the two subtracted." ] }, { "cell_type": "code", "execution_count": 4, "id": "138b9acf", "metadata": {}, "outputs": [ { "data": { "text/plain": [ "1.0" ] }, "execution_count": 4, "metadata": {}, "output_type": "execute_result" } ], "source": [ "(a-b).length() # the edge of our base tetrahedron" ] }, { "cell_type": "markdown", "id": "c29384fd", "metadata": {}, "source": [ "### IVM Vectors\n", "\n", "Two of any quadray, plus one each of two others, plus zero, will always point to one of the twelve directions surrounding any sphere in the IVM (CCP).\n", "\n", "In other words, every unique permutation of {2, 1, 1, 0} will be a vector from the origin to one of the corners of a cuboctahedron, a ball center one sphere diameter distant.\n", "\n", "Our random walks will randomly choose one of these twelve directions at each turn to play. Lets call these \"moves\" (as in chess moves)." ] }, { "cell_type": "code", "execution_count": 5, "id": "ddcf2f0a", "metadata": {}, "outputs": [ { "data": { "text/plain": [ "[ivm_vector(a=0, b=1, c=1, d=2),\n", " ivm_vector(a=1, b=0, c=1, d=2),\n", " ivm_vector(a=2, b=0, c=1, d=1),\n", " ivm_vector(a=0, b=2, c=1, d=1),\n", " ivm_vector(a=0, b=1, c=2, d=1),\n", " ivm_vector(a=1, b=2, c=1, d=0),\n", " ivm_vector(a=1, b=1, c=2, d=0),\n", " ivm_vector(a=2, b=1, c=1, d=0),\n", " ivm_vector(a=1, b=0, c=2, d=1),\n", " ivm_vector(a=1, b=2, c=0, d=1),\n", " ivm_vector(a=2, b=1, c=0, d=1),\n", " ivm_vector(a=1, b=1, c=0, d=2)]" ] }, "execution_count": 5, "metadata": {}, "output_type": "execute_result" } ], "source": [ "from itertools import permutations\n", "from random import choice \n", "\n", "moves = [Qvector(p) for p in set(permutations((2,1,1,0)))]\n", "moves" ] }, { "cell_type": "code", "execution_count": 6, "id": "ae643ff9", "metadata": {}, "outputs": [], "source": [ "def random_walk(start, steps):\n", " end = start\n", " for _ in range(steps):\n", " end += choice(moves)\n", " return end \n", "\n", "vA = random_walk(Qvector((0,0,0,0)), 1000)\n", "vB = random_walk(Qvector((0,0,0,0)), 1000)\n", "vC = random_walk(Qvector((0,0,0,0)), 1000)\n", "vD = random_walk(Qvector((0,0,0,0)), 1000) " ] }, { "cell_type": "code", "execution_count": 7, "id": "9d690466", "metadata": {}, "outputs": [], "source": [ "import tetravolume as tv" ] }, { "cell_type": "code", "execution_count": 8, "id": "1199eb7e", "metadata": {}, "outputs": [], "source": [ "c = Qvector((0,0,1,0))\n", "d = Qvector((0,0,0,1))\n", "\n", "ab = (a-b).length()\n", "ac = (a-c).length()\n", "ad = (a-d).length()\n", "bc = (b-c).length()\n", "cd = (c-d).length()\n", "bd = (b-d).length()" ] }, { "cell_type": "code", "execution_count": 9, "id": "cfe37247", "metadata": {}, "outputs": [], "source": [ "t = tv.Tetrahedron(ab,ac,ad,bc,cd,ad)" ] }, { "cell_type": "code", "execution_count": 10, "id": "bbc69221", "metadata": {}, "outputs": [ { "data": { "text/plain": [ "1.0" ] }, "execution_count": 10, "metadata": {}, "output_type": "execute_result" } ], "source": [ "t.ivm_volume()" ] }, { "cell_type": "code", "execution_count": 11, "id": "4203ca0d", "metadata": {}, "outputs": [ { "data": { "text/plain": [ "0.9428090415820635" ] }, "execution_count": 11, "metadata": {}, "output_type": "execute_result" } ], "source": [ "t.xyz_volume()" ] }, { "cell_type": "markdown", "id": "7a501335", "metadata": {}, "source": [ "\"Computer" ] }, { "cell_type": "code", "execution_count": 12, "id": "dad3eef3", "metadata": {}, "outputs": [ { "data": { "text/plain": [ "(xyz_vector(x=mpfr('0.35355339059327373'), y=mpfr('0.35355339059327373'), z=mpfr('0.35355339059327373')),\n", " xyz_vector(x=mpfr('-0.35355339059327373'), y=mpfr('-0.35355339059327373'), z=mpfr('0.35355339059327373')),\n", " xyz_vector(x=mpfr('-0.35355339059327373'), y=mpfr('0.35355339059327373'), z=mpfr('-0.35355339059327373')),\n", " xyz_vector(x=mpfr('0.35355339059327373'), y=mpfr('-0.35355339059327373'), z=mpfr('-0.35355339059327373')))" ] }, "execution_count": 12, "metadata": {}, "output_type": "execute_result" } ], "source": [ "(a.xyz,\n", "b.xyz,\n", "c.xyz,\n", "d.xyz)" ] }, { "cell_type": "markdown", "id": "5bed8861", "metadata": {}, "source": [ "Now lets get the volume using our random IVM corners." ] }, { "cell_type": "code", "execution_count": 13, "id": "1a310ce7", "metadata": {}, "outputs": [], "source": [ "ab = (vA-vB).length()\n", "ac = (vA-vC).length()\n", "ad = (vA-vD).length()\n", "bc = (vB-vC).length()\n", "cd = (vC-vD).length()\n", "bd = (vB-vD).length()" ] }, { "cell_type": "code", "execution_count": 14, "id": "66998470", "metadata": {}, "outputs": [ { "data": { "text/plain": [ "6958.999999999965" ] }, "execution_count": 14, "metadata": {}, "output_type": "execute_result" } ], "source": [ "t = tv.Tetrahedron(ab,ac,ad,bc,cd,bd)\n", "t.ivm_volume()" ] }, { "cell_type": "markdown", "id": "bcbccab4", "metadata": {}, "source": [ "Just keep re-running the cell below to appreciate how we only get whole number tetravolumes, for all of these random tetrahedrons. Within floating point rounding error." ] }, { "cell_type": "code", "execution_count": 15, "id": "8e925671", "metadata": {}, "outputs": [ { "data": { "text/plain": [ "3424.0" ] }, "execution_count": 15, "metadata": {}, "output_type": "execute_result" } ], "source": [ "vA = random_walk(Qvector((0,0,0,0)), 1000)\n", "vB = random_walk(Qvector((0,0,0,0)), 1000)\n", "vC = random_walk(Qvector((0,0,0,0)), 1000)\n", "vD = random_walk(Qvector((0,0,0,0)), 1000) \n", "ab = (vA-vB).length()\n", "ac = (vA-vC).length()\n", "ad = (vA-vD).length()\n", "bc = (vB-vC).length()\n", "cd = (vC-vD).length()\n", "bd = (vB-vD).length()\n", "t = tv.Tetrahedron(ab,ac,ad,bc,cd,bd)\n", "round(t.ivm_volume(), 8)" ] }, { "cell_type": "code", "execution_count": 16, "id": "541089e8", "metadata": {}, "outputs": [ { "data": { "text/plain": [ "mpfr('16772.0',200)" ] }, "execution_count": 16, "metadata": {}, "output_type": "execute_result" } ], "source": [ "import gmpy2\n", "from gmpy2 import mpfr\n", "gmpy2.get_context().precision=200\n", "z0 = mpfr('0')\n", "vA = random_walk(Qvector((z0,z0,z0,z0)), 1000)\n", "vB = random_walk(Qvector((z0,z0,z0,z0)), 1000)\n", "vC = random_walk(Qvector((z0,z0,z0,z0)), 1000)\n", "vD = random_walk(Qvector((z0,z0,z0,z0)), 1000) \n", "ab = (vA-vB).length()\n", "ac = (vA-vC).length()\n", "ad = (vA-vD).length()\n", "bc = (vB-vC).length()\n", "cd = (vC-vD).length()\n", "bd = (vB-vD).length()\n", "t = tv.Tetrahedron(ab,ac,ad,bc,cd,bd)\n", "t.ivm_volume()" ] }, { "cell_type": "markdown", "id": "ad66de21", "metadata": {}, "source": [ "### Volume of the A Module\n", "\n", "The cells below confirm that our base tetrahedron of unit volume, fractionates into 24 subvolumes with angles and edges at our finger tips, thanks to the ```qrays``` module" ] }, { "cell_type": "markdown", "id": "4277a641", "metadata": {}, "source": [ "\"24\n", "\n", "" ] }, { "cell_type": "code", "execution_count": 17, "id": "dfd2be80", "metadata": {}, "outputs": [], "source": [ "amod_E = Qvector((0,0,0,0))\n", "amod_C = b\n", "amod_D = (b + c)/2\n", "amod_F = (b + c + d)/3\n", "\n", "# apex E to base F, C, D\n", "amod_EF = amod_F\n", "amod_CE = b\n", "amod_DE = amod_D\n", "\n", "# around the base, C, D, E\n", "amod_CF = amod_C - amod_F\n", "amod_CD = amod_C - amod_D\n", "amod_DF = amod_D - amod_F" ] }, { "cell_type": "code", "execution_count": 18, "id": "5221cd50", "metadata": {}, "outputs": [ { "data": { "text/plain": [ "0.2041241452319315" ] }, "execution_count": 18, "metadata": {}, "output_type": "execute_result" } ], "source": [ "amod_EF.length() # apex to face center" ] }, { "cell_type": "code", "execution_count": 19, "id": "c65442d9", "metadata": {}, "outputs": [ { "data": { "text/plain": [ "0.6123724356957945" ] }, "execution_count": 19, "metadata": {}, "output_type": "execute_result" } ], "source": [ "amod_CE.length() # apex to corner" ] }, { "cell_type": "code", "execution_count": 20, "id": "3533cd1e", "metadata": {}, "outputs": [ { "data": { "text/plain": [ "0.3535533905932738" ] }, "execution_count": 20, "metadata": {}, "output_type": "execute_result" } ], "source": [ "amod_DE.length() # apex to mid-edge" ] }, { "cell_type": "code", "execution_count": 21, "id": "6fc0a373", "metadata": {}, "outputs": [ { "data": { "text/plain": [ "0.5773502691896258" ] }, "execution_count": 21, "metadata": {}, "output_type": "execute_result" } ], "source": [ "amod_CF.length() # face center to corner" ] }, { "cell_type": "code", "execution_count": 22, "id": "3b6d4d6a", "metadata": {}, "outputs": [ { "data": { "text/plain": [ "0.5" ] }, "execution_count": 22, "metadata": {}, "output_type": "execute_result" } ], "source": [ "amod_CD.length() # corner to mid-edge" ] }, { "cell_type": "code", "execution_count": 23, "id": "89752032", "metadata": {}, "outputs": [ { "data": { "text/plain": [ "0.2886751345948129" ] }, "execution_count": 23, "metadata": {}, "output_type": "execute_result" } ], "source": [ "amod_DF.length() # mid-edge to face center" ] }, { "cell_type": "code", "execution_count": 24, "id": "ad15cf98", "metadata": {}, "outputs": [ { "data": { "text/plain": [ "0.04166666666666655" ] }, "execution_count": 24, "metadata": {}, "output_type": "execute_result" } ], "source": [ "lengths = map(lambda v: v.length(), \n", " (amod_EF, amod_CE, amod_DE, amod_CF, amod_CD, amod_DF))\n", "t = tv.Tetrahedron(*lengths)\n", "t.ivm_volume()" ] }, { "cell_type": "markdown", "id": "d36c4a54", "metadata": {}, "source": [ "## And now, in higher precision..." ] }, { "cell_type": "code", "execution_count": 25, "id": "61af27d3", "metadata": { "tags": [] }, "outputs": [], "source": [ "one = mpfr('1')\n", "a = Qvector((one, z0, z0, z0))\n", "b = Qvector((z0, one, z0, z0))\n", "c = Qvector((z0, z0, one, z0))\n", "d = Qvector((z0, z0, z0, one))" ] }, { "cell_type": "code", "execution_count": 26, "id": "f0c1fe1b", "metadata": {}, "outputs": [ { "data": { "text/plain": [ "mpfr('1.0',200)" ] }, "execution_count": 26, "metadata": {}, "output_type": "execute_result" } ], "source": [ "(a-b).length()" ] }, { "cell_type": "code", "execution_count": 27, "id": "b41db896", "metadata": {}, "outputs": [], "source": [ "amod_E = Qvector((z0,z0,z0,z0))\n", "amod_C = b\n", "amod_D = (b + c)/mpfr('2')\n", "amod_F = (b + c + d)/mpfr('3')\n", "\n", "# apex E to base F, C, D\n", "amod_EF = amod_F\n", "amod_CE = b\n", "amod_DE = amod_D\n", "\n", "# around the base, C, D, E\n", "amod_CF = amod_C - amod_F\n", "amod_CD = amod_C - amod_D\n", "amod_DF = amod_D - amod_F\n", "\n", "lengths = list(map(lambda v: v.length(), \n", " (amod_EF, amod_CE, amod_DE, amod_CF, amod_CD, amod_DF)))" ] }, { "cell_type": "code", "execution_count": 28, "id": "13259235", "metadata": {}, "outputs": [ { "data": { "text/plain": [ "mpfr('0.20412414523193150818310700622549094933049562338805584403605771',200)" ] }, "execution_count": 28, "metadata": {}, "output_type": "execute_result" } ], "source": [ "lengths[0] # checking length" ] }, { "cell_type": "code", "execution_count": 29, "id": "1bfeca89", "metadata": {}, "outputs": [ { "data": { "text/plain": [ "mpfr('0.20412414523193150818310700622549094933049562338805584403605771',200)" ] }, "execution_count": 29, "metadata": {}, "output_type": "execute_result" } ], "source": [ "gmpy2.sqrt(mpfr('6'))/12 # length of EF in Fig. 913.01 of Synergetics" ] }, { "cell_type": "code", "execution_count": 30, "id": "a17e165f", "metadata": {}, "outputs": [ { "data": { "text/plain": [ "mpfr('0.041666666666666666666666666666666666666666666666666666666666835',200)" ] }, "execution_count": 30, "metadata": {}, "output_type": "execute_result" } ], "source": [ "t = tv.Tetrahedron(*lengths)\n", "t.ivm_volume()" ] }, { "cell_type": "markdown", "id": "9db0e384", "metadata": {}, "source": [ "\n", "\"quadray_papers\"\n" ] }, { "cell_type": "markdown", "id": "f2d0cb36", "metadata": {}, "source": [ "* [Wikipedia Entry](https://en.wikipedia.org/wiki/Quadray_coordinates)\n", "* [Early Development](http://grunch.net/synergetics/quadrays.html)\n", "* [Recent Use](https://nbviewer.jupyter.org/github/4dsolutions/School_of_Tomorrow/blob/master/Flextegrity_Lattice.ipynb)\n", "* [Clues for Teachers](https://mybizmo.blogspot.com/2021/07/canonical-lesson-plan.html)" ] } ], "metadata": { "kernelspec": { "display_name": "Python 3", "language": "python", "name": "python3" }, "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.7.9" } }, "nbformat": 4, "nbformat_minor": 5 }