{ "cells": [ { "cell_type": "markdown", "id": "856a821b-5d9e-41f9-99f1-cf655f621cc7", "metadata": {}, "source": [ "# Elite Academy\n", "\n", "\"Classic\n", "\n", "
\n", "\n", "Long Beach: adjacent the [Queen Mary](https://flic.kr/p/cGoQ29) (former [Spruce Goose](https://www.drivearchive.co.uk/xplanes/goose.htm) garage)\n", "\n", "Another take on linear algebra involves importing from what we call Martian Math. A goal is to connect both to science fiction and to the notion of something alien, as in unfamiliar. The coordinate system and vector apparatus shared below is anything but mainstream.\n", "\n", "\"Relative\n", "\n", "We call it Quadrays. The picture below is a screen shot, so clicking on the links only takes you to the archive for the picture.\n", "\n", "\"Quadray" ] }, { "cell_type": "code", "execution_count": 1, "id": "192c98ac-db21-49a1-af47-b8a904ad4cd0", "metadata": {}, "outputs": [], "source": [ "import qrays\n", "from qrays import Qvector as Martian\n", "from qrays import Vector" ] }, { "cell_type": "code", "execution_count": 2, "id": "65bd5b21-21f3-4c1a-9fc8-2a666a0aa2f7", "metadata": {}, "outputs": [], "source": [ "from itertools import permutations as perm" ] }, { "cell_type": "code", "execution_count": 3, "id": "78fa3ba1-f700-423d-b756-e8d5c574fcf8", "metadata": {}, "outputs": [ { "data": { "text/plain": [ "{(0, 0, 0, 1), (0, 0, 1, 0), (0, 1, 0, 0), (1, 0, 0, 0)}" ] }, "execution_count": 3, "metadata": {}, "output_type": "execute_result" } ], "source": [ "dir_4 = {spoke for spoke in perm((0,0,0,1))} # dupeless\n", "dir_4" ] }, { "cell_type": "markdown", "id": "890a00fb-7102-45a8-96a4-c05581869105", "metadata": {}, "source": [ "\"Quadray\n", "\n", "Four rays splay from the origin to carve space into four quadrants. Linear combinations of vectors in these four directions span all of space. \n", "\n", "These four elementary rays need not be unit length. Rather, the bounding tetrahedron has unit edges and unit volume.\n", "\n", "In a lowest terms representation of any point, at least one coordinate is always zero, the ray not directly bounding the quadrant wherein the point resides. The remaining three vectors add together positively to reach the point i.e. quadray coordinates in lowest terms are always non-negative." ] }, { "cell_type": "code", "execution_count": 4, "id": "d328d0e4-1997-4840-a82b-b559f1463eec", "metadata": {}, "outputs": [], "source": [ "a,b,c,d = [Martian(coords) for coords in dir_4]" ] }, { "cell_type": "code", "execution_count": 5, "id": "33e17c8e-29d6-43fd-8b9d-8364bdd1d34f", "metadata": {}, "outputs": [ { "data": { "text/plain": [ "ivm_vector(a=0, b=0, c=0, d=0)" ] }, "execution_count": 5, "metadata": {}, "output_type": "execute_result" } ], "source": [ "a + b + c + d" ] }, { "cell_type": "code", "execution_count": 6, "id": "df1a9b7f-9a28-4c6a-82c3-956369e1d10e", "metadata": {}, "outputs": [ { "data": { "text/plain": [ "0.6123724356957945" ] }, "execution_count": 6, "metadata": {}, "output_type": "execute_result" } ], "source": [ "a.length()" ] }, { "cell_type": "code", "execution_count": 7, "id": "0d714ab9-9286-4bcb-a907-d045e925f750", "metadata": {}, "outputs": [ { "data": { "text/plain": [ "1.0" ] }, "execution_count": 7, "metadata": {}, "output_type": "execute_result" } ], "source": [ "(a - b).length()" ] }, { "cell_type": "code", "execution_count": 8, "id": "ee3cad63-fadd-4239-96b7-abb68859727b", "metadata": {}, "outputs": [ { "data": { "text/latex": [ "$\\displaystyle 109.471220634491$" ], "text/plain": [ "109.471220634491" ] }, "execution_count": 8, "metadata": {}, "output_type": "execute_result" } ], "source": [ "a.angle(b)" ] }, { "cell_type": "markdown", "id": "d72c6456-9f50-4379-85f0-3f87b16c4b2a", "metadata": {}, "source": [ "## Converting Between Martian and XYZ Coordinates" ] }, { "cell_type": "code", "execution_count": 9, "id": "c8029c4a-57e7-4d90-acbb-ebf39ad85ec4", "metadata": {}, "outputs": [], "source": [ "import sympy as sp\n", "root2 = sp.sqrt(2)" ] }, { "cell_type": "code", "execution_count": 10, "id": "230de934-ffa7-485c-9840-05ed1fb1373f", "metadata": {}, "outputs": [], "source": [ "import qrays\n", "import importlib\n", "importlib.reload(qrays)\n", "from qrays import Vector, Qvector as Martian" ] }, { "cell_type": "code", "execution_count": 11, "id": "8c2d2029-acb7-4294-956c-f8d6252ef0ee", "metadata": {}, "outputs": [], "source": [ "def to_xyz(a, b, c, d):\n", " k = root2/4\n", " x = k * (a - b - c + d)\n", " y = k * (a - b + c - d)\n", " z = k * (a + b - c - d)\n", " return x,y,z" ] }, { "cell_type": "code", "execution_count": 12, "id": "fe31ddf5-6993-4523-ba95-c27248f15c4c", "metadata": {}, "outputs": [ { "data": { "text/plain": [ "(sqrt(2)/4, sqrt(2)/4, sqrt(2)/4)" ] }, "execution_count": 12, "metadata": {}, "output_type": "execute_result" } ], "source": [ "x,y,z = to_xyz(1,0,0,0) # convert from Martian\n", "(x,y,z)" ] }, { "cell_type": "code", "execution_count": 13, "id": "bac16c38-c6d1-4683-bad5-da803ac63a70", "metadata": {}, "outputs": [], "source": [ "def to_qray(x, y, z):\n", " \"\"\"return (a, b, c, d) quadray based on current (x, y, z)\"\"\"\n", " k = root2\n", " \n", " x_ge_0 = 1 if x >=0 else 0\n", " y_ge_0 = 1 if y >=0 else 0\n", " z_ge_0 = 1 if z >=0 else 0\n", " x_lt_0 = 1 if x < 0 else 0\n", " y_lt_0 = 1 if y < 0 else 0\n", " z_lt_0 = 1 if z < 0 else 0\n", " \n", " a = k * (x_ge_0 * x + y_ge_0 * y + z_ge_0 * z)\n", " b = k * (x_lt_0 * -x + y_lt_0 * -y + z_ge_0 * z)\n", " c = k * (x_lt_0 * -x + y_ge_0 * y + z_lt_0 * -z)\n", " d = k * (x_ge_0 * x + y_lt_0 * -y + z_lt_0 * -z)\n", " # put in canonical form\n", " m = min((a,b,c,d))\n", " a,b,c,d = a-m, b-m, c-m, d-m\n", " return (a, b, c, d)" ] }, { "cell_type": "code", "execution_count": 14, "id": "5e22e21e-1bd7-4b8f-a28a-c16b37f69158", "metadata": {}, "outputs": [ { "data": { "text/plain": [ "(1, 0, 0, 0)" ] }, "execution_count": 14, "metadata": {}, "output_type": "execute_result" } ], "source": [ "to_qray(x, y, z) # convert to Martian" ] }, { "cell_type": "code", "execution_count": 15, "id": "cc3aaaa2-6b96-434f-b503-e36554c97c0d", "metadata": {}, "outputs": [ { "data": { "text/plain": [ "xyz_vector(x=sqrt(2)/4, y=sqrt(2)/4, z=sqrt(2)/4)" ] }, "execution_count": 15, "metadata": {}, "output_type": "execute_result" } ], "source": [ "v = Vector((x,y,z))\n", "v" ] }, { "cell_type": "code", "execution_count": 16, "id": "660a1291-0591-49a4-841f-def657488271", "metadata": {}, "outputs": [ { "data": { "text/plain": [ "ivm_vector(a=1, b=0, c=0, d=0)" ] }, "execution_count": 16, "metadata": {}, "output_type": "execute_result" } ], "source": [ "q = v.quadray() # convert to Martian\n", "q" ] }, { "cell_type": "code", "execution_count": 17, "id": "a6b2b8ec-75da-4b04-bcf0-cf288893f887", "metadata": {}, "outputs": [ { "data": { "text/plain": [ "xyz_vector(x=0.25*sqrt(2), y=0.25*sqrt(2), z=0.25*sqrt(2))" ] }, "execution_count": 17, "metadata": {}, "output_type": "execute_result" } ], "source": [ "q.xyz" ] }, { "cell_type": "markdown", "id": "f58c3421-3863-45ac-9aef-eebfb4c95181", "metadata": {}, "source": [ "Two of one quadray, added to one of two others, with a fourth set to zero, equals one of the twelve directions from a ball center to a neighboring ball center within the IVM (isotropic vector matrix). The ball packing in question is known as the CCP (cubic close packing).\n", "\n" ] }, { "cell_type": "code", "execution_count": 18, "id": "a7fced32-903e-453a-a2d5-c6d291bfa24d", "metadata": {}, "outputs": [ { "data": { "text/plain": [ "{(0, 1, 1, 2),\n", " (0, 1, 2, 1),\n", " (0, 2, 1, 1),\n", " (1, 0, 1, 2),\n", " (1, 0, 2, 1),\n", " (1, 1, 0, 2),\n", " (1, 1, 2, 0),\n", " (1, 2, 0, 1),\n", " (1, 2, 1, 0),\n", " (2, 0, 1, 1),\n", " (2, 1, 0, 1),\n", " (2, 1, 1, 0)}" ] }, "execution_count": 18, "metadata": {}, "output_type": "execute_result" } ], "source": [ "dir_12 = {spoke for spoke in perm((0,1,1,2))} # dupeless\n", "dir_12" ] }, { "cell_type": "markdown", "id": "4c2229cb-d7fd-4a43-894c-8105b2d07f43", "metadata": {}, "source": [ "From Wikipedia:\n", "\n", "\"quadrays\"\n", "\n", "\"2F" ] }, { "cell_type": "code", "execution_count": 19, "id": "77cb17f4-9b43-4ec7-bed9-8fb737df2335", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "spokes.pov ready for rendering\n" ] } ], "source": [ "from pov import POV_Vector, pov_header\n", "beacon = [Martian((t)) for t in dir_12]\n", "xyz_beacon = [POV_Vector(v.xyz.x, v.xyz.y, v.xyz.z) for v in beacon]\n", "\n", "# POV-Ray\n", "edge_color = \"rgb <1, 0.4, 0>\"\n", "edge_radius= 0.03\n", "vert_color = \"rgb <0, 0, 1>\"\n", "vert_radius= 0.05\n", "\n", "with open(\"spokes.pov\", 'w') as output:\n", " print(pov_header, file=output) # print to the output file\n", " for v in xyz_beacon:\n", " v.draw_edge(edge_color, edge_radius, output)\n", " v.draw_vert(vert_color, vert_radius, output) \n", " \n", "print(\"spokes.pov ready for rendering\")" ] }, { "cell_type": "markdown", "id": "6bfc959d-1366-4cb5-ac7d-4f2941acb3ba", "metadata": {}, "source": [ "![spokes](spokes.png)" ] }, { "cell_type": "code", "execution_count": 20, "id": "03b0bb7d-5a34-4016-be64-301eb42a3f13", "metadata": {}, "outputs": [], "source": [ "o,p,q,r,s,t,u,v,w,x,y,z = [Martian((t)) for t in dir_12]" ] }, { "cell_type": "markdown", "id": "c19be080-493f-4d79-85b1-910e80eba897", "metadata": {}, "source": [ "## Multiplication\n", "\n", "* vector times vector = area\n", "* vector times vector times vector = volume\n", "\n", "In the case of the XYZ coordinate system, three vectors from the origin, in x, y and z directions, define a 90-90-90 degree corner. If the lengths of the three vectors are a, b, c then the volume of the resulting parallelopiped is their product. \n", "\n", "In the case of the IVM, consider any three vectors defining a 60-60-60 degree corner with lengths a, b and c. Their volume is the resulting tetrahedron, and is likewise their product.\n", "\n", "\"Martian" ] }, { "cell_type": "code", "execution_count": 21, "id": "6d0f5e43-ca57-464c-9169-1820273eb96e", "metadata": {}, "outputs": [], "source": [ "origin = Martian((0,0,0,0))" ] }, { "cell_type": "markdown", "id": "0f0541c3-2eea-4852-807d-b4e71f9c367f", "metadata": {}, "source": [ "The absolute value of the determinant of a matrix, times 1/4, gives the volume, in tetravolumes, of the tetrahedron determined by four quadrays (a, b, c, d), each with four coordinates (e.g. a0, a1, a2, a3).\n", "\n", "
\n", "$$\n", "V_{ivm} = (1/4) \n", "\\begin{vmatrix}\n", "a0&a1&a2&a3&1\\\\\n", "b0&b1&b2&b3&1\\\\\n", "c0&c1&c2&c3&1\\\\\n", "d0&d1&d2&d3&1\\\\\n", "1&1&1&1&0\\\\\n", "\\end{vmatrix}\n", "$$\n", "
" ] }, { "cell_type": "markdown", "id": "653087e8-5d6a-4f16-895c-0c2c9480d972", "metadata": {}, "source": [ "Lets find three vectors from our 12 above, that form a 60-60-60 corner. We may then scale each to a different length and compute the resulting volume. The quadray to the origin, (0,0,0,0), will be one of the four points." ] }, { "cell_type": "code", "execution_count": 22, "id": "6ce04095-f34b-47dd-94a6-30af98e16688", "metadata": {}, "outputs": [ { "data": { "text/latex": [ "$\\displaystyle 60.0$" ], "text/plain": [ "60.0000000000000" ] }, "execution_count": 22, "metadata": {}, "output_type": "execute_result" } ], "source": [ "o.angle(s)" ] }, { "cell_type": "code", "execution_count": 23, "id": "9bb223c3-497b-44e6-9271-bbedb5ae01ff", "metadata": {}, "outputs": [ { "data": { "text/latex": [ "$\\displaystyle 60.0$" ], "text/plain": [ "60.0000000000000" ] }, "execution_count": 23, "metadata": {}, "output_type": "execute_result" } ], "source": [ "s.angle(v)" ] }, { "cell_type": "code", "execution_count": 24, "id": "e29822b9-ad92-4a3b-80fd-4fb21ce85293", "metadata": {}, "outputs": [ { "data": { "text/latex": [ "$\\displaystyle 60.0$" ], "text/plain": [ "60.0000000000000" ] }, "execution_count": 24, "metadata": {}, "output_type": "execute_result" } ], "source": [ "o.angle(v)" ] }, { "cell_type": "code", "execution_count": 25, "id": "cd34d391-6d90-4cba-be9d-9bb0c2824f4c", "metadata": {}, "outputs": [], "source": [ "from sympy import Matrix" ] }, { "cell_type": "markdown", "id": "c8bafb14-683e-4442-84be-94a6aab4025e", "metadata": {}, "source": [ "[The Matrix object in sympy](https://docs.sympy.org/latest/tutorial/matrices.html)\n", "\n", "[Volume Talk](https://github.com/4dsolutions/School_of_Tomorrow/blob/master/VolumeTalk.ipynb)\n", "\n", "[Tetravolumes from Quadrays](https://github.com/4dsolutions/School_of_Tomorrow/blob/master/Qvolume.ipynb)" ] }, { "cell_type": "code", "execution_count": 26, "id": "2b87d179-b3e8-4b79-9b82-30e4a187d6de", "metadata": {}, "outputs": [], "source": [ "# try varying scale factors\n", "e0, e1, e2 = o*3, s*3, v*3 # per picture: 2, 2, 5" ] }, { "cell_type": "markdown", "id": "c52905c7-61e8-4d27-9864-abe465d07ec6", "metadata": {}, "source": [ "The four corners of a tetrahedron with a 60-60-60 degree corner at the origin, e0, e1, e2." ] }, { "cell_type": "code", "execution_count": 27, "id": "9db5d99f-e7d5-4199-92e6-94ef4e213bb0", "metadata": {}, "outputs": [ { "data": { "text/latex": [ "$\\displaystyle \\left[\\begin{matrix}0 & 0 & 0 & 0 & 1\\\\3 & 0 & 3 & 6 & 1\\\\3 & 0 & 6 & 3 & 1\\\\6 & 0 & 3 & 3 & 1\\\\1 & 1 & 1 & 1 & 0\\end{matrix}\\right]$" ], "text/plain": [ "Matrix([\n", "[0, 0, 0, 0, 1],\n", "[3, 0, 3, 6, 1],\n", "[3, 0, 6, 3, 1],\n", "[6, 0, 3, 3, 1],\n", "[1, 1, 1, 1, 0]])" ] }, "execution_count": 27, "metadata": {}, "output_type": "execute_result" } ], "source": [ "uvt = Matrix([[*origin.coords,1], # origin\n", " [*e0.coords, 1], # e0\n", " [*e1.coords, 1], # e1\n", " [*e2.coords, 1], # e2\n", " [1,1,1,1,0]])\n", "uvt" ] }, { "cell_type": "code", "execution_count": 28, "id": "ee44d4f1-ec90-41a2-9240-a8a8ae4572ba", "metadata": {}, "outputs": [ { "data": { "text/latex": [ "$\\displaystyle 27$" ], "text/plain": [ "27" ] }, "execution_count": 28, "metadata": {}, "output_type": "execute_result" } ], "source": [ "abs(uvt.det())/4" ] }, { "cell_type": "code", "execution_count": 29, "id": "6aa831cf-38c6-4ea4-b0f8-f2c1b9000969", "metadata": {}, "outputs": [ { "data": { "text/latex": [ "$\\displaystyle 1.0$" ], "text/plain": [ "1.00000000000000" ] }, "execution_count": 29, "metadata": {}, "output_type": "execute_result" } ], "source": [ "s.area(v)" ] }, { "cell_type": "markdown", "id": "52ad411d-925f-480c-8a06-8e183c08237f", "metadata": {}, "source": [ "\"6" ] }, { "cell_type": "markdown", "id": "18926605-ab2a-488a-a210-23c4a5b2ade9", "metadata": {}, "source": [ "## Volumes Table\n", "\n", "Now that we have the notion of \"tetravolumes\" firmly nailed down, we're able to create a new volumes table:\n", "\n", "\"Master" ] }, { "cell_type": "code", "execution_count": 30, "id": "9d5c02f0-a9db-4635-a83f-96a5f6c94d76", "metadata": {}, "outputs": [], "source": [ "# try varying scale factors\n", "e0, e1, e2 = o, s, v # 1, 1, 1" ] }, { "cell_type": "code", "execution_count": 31, "id": "edf69c5a-b31c-4a4a-94da-39d3ef8b7874", "metadata": {}, "outputs": [], "source": [ "def tetravol(v0, v1, v2):\n", " uvt = Matrix([[*origin.coords,1], # origin\n", " [*v0.coords, 1], # e0\n", " [*v1.coords, 1], # e1\n", " [*v2.coords, 1], # e2\n", " [1,1,1,1,0]])\n", " return abs(uvt.det())/4\n", "\n", "def frustrum(start, end):\n", " s0 = o*start\n", " s1 = s*start\n", " s2 = v*start\n", " e0 = o*end\n", " e1 = s*end\n", " e2 = v*end\n", " return tetravol(e0,e1,e2) - tetravol(s0, s1, s2)" ] }, { "cell_type": "code", "execution_count": 32, "id": "568a96bd-5334-4e19-a34e-96f68b714a63", "metadata": {}, "outputs": [ { "data": { "text/latex": [ "$\\displaystyle 1$" ], "text/plain": [ "1" ] }, "execution_count": 32, "metadata": {}, "output_type": "execute_result" } ], "source": [ "tip = tetravol(e0, e1, e2)\n", "tip" ] }, { "cell_type": "code", "execution_count": 33, "id": "ee4be7c3-8125-4b2d-868f-3a83fef741d7", "metadata": {}, "outputs": [ { "data": { "text/latex": [ "$\\displaystyle 56$" ], "text/plain": [ "56" ] }, "execution_count": 33, "metadata": {}, "output_type": "execute_result" } ], "source": [ "frust = frustrum(2, 4)\n", "frust" ] }, { "cell_type": "code", "execution_count": 34, "id": "b9fff6e5-8e61-4c8d-a5d5-a038d18b2f85", "metadata": {}, "outputs": [ { "data": { "text/latex": [ "$\\displaystyle 125$" ], "text/plain": [ "125" ] }, "execution_count": 34, "metadata": {}, "output_type": "execute_result" } ], "source": [ "frustrum(0, 1) + frustrum(1, 2) + frustrum(2, 3) + frustrum(3, 4) + frustrum(4, 5)" ] }, { "cell_type": "code", "execution_count": 35, "id": "41d5e25d-06ed-47b2-a0a7-eeafede6a358", "metadata": {}, "outputs": [], "source": [ "import pandas as pd\n", "import numpy as np" ] }, { "cell_type": "code", "execution_count": 36, "id": "174d8c6d-4642-4680-94a7-07d6066d7091", "metadata": {}, "outputs": [ { "data": { "text/plain": [ "array([0. , 0.05, 0.1 , 0.15, 0.2 , 0.25, 0.3 , 0.35, 0.4 , 0.45, 0.5 ,\n", " 0.55, 0.6 , 0.65, 0.7 , 0.75, 0.8 , 0.85, 0.9 , 0.95, 1. , 1.05,\n", " 1.1 , 1.15, 1.2 , 1.25, 1.3 , 1.35, 1.4 , 1.45, 1.5 , 1.55, 1.6 ,\n", " 1.65, 1.7 , 1.75, 1.8 , 1.85, 1.9 , 1.95, 2. , 2.05, 2.1 , 2.15,\n", " 2.2 , 2.25, 2.3 , 2.35, 2.4 , 2.45, 2.5 , 2.55, 2.6 , 2.65, 2.7 ,\n", " 2.75, 2.8 , 2.85, 2.9 , 2.95, 3. , 3.05, 3.1 , 3.15, 3.2 , 3.25,\n", " 3.3 , 3.35, 3.4 , 3.45, 3.5 , 3.55, 3.6 , 3.65, 3.7 , 3.75, 3.8 ,\n", " 3.85, 3.9 , 3.95, 4. , 4.05, 4.1 , 4.15, 4.2 , 4.25, 4.3 , 4.35,\n", " 4.4 , 4.45, 4.5 , 4.55, 4.6 , 4.65, 4.7 , 4.75, 4.8 , 4.85, 4.9 ,\n", " 4.95])" ] }, "execution_count": 36, "metadata": {}, "output_type": "execute_result" } ], "source": [ "notches = np.linspace(0, 5, 101)[:-1]\n", "notches" ] }, { "cell_type": "code", "execution_count": 37, "id": "b83c0305-bc02-4f15-b956-6a22ce538d6f", "metadata": {}, "outputs": [ { "data": { "text/plain": [ "0.05" ] }, "execution_count": 37, "metadata": {}, "output_type": "execute_result" } ], "source": [ "delta = notches[1]-notches[0]\n", "delta" ] }, { "cell_type": "code", "execution_count": 38, "id": "929f7a1f-f734-4185-ae5d-2cda2d742e45", "metadata": {}, "outputs": [ { "data": { "text/html": [ "
\n", "\n", "\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "
notchnext_notch
00.000.05
10.050.10
20.100.15
30.150.20
40.200.25
\n", "
" ], "text/plain": [ " notch next_notch\n", "0 0.00 0.05\n", "1 0.05 0.10\n", "2 0.10 0.15\n", "3 0.15 0.20\n", "4 0.20 0.25" ] }, "execution_count": 38, "metadata": {}, "output_type": "execute_result" } ], "source": [ "df = pd.DataFrame({\"notch\":notches, \n", " \"next_notch\":notches+delta})\n", "df.head() " ] }, { "cell_type": "code", "execution_count": 39, "id": "6f9e5fc4-b358-4f87-98de-0ae970949f46", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "\n", "RangeIndex: 100 entries, 0 to 99\n", "Data columns (total 2 columns):\n", " # Column Non-Null Count Dtype \n", "--- ------ -------------- ----- \n", " 0 notch 100 non-null float64\n", " 1 next_notch 100 non-null float64\n", "dtypes: float64(2)\n", "memory usage: 1.7 KB\n" ] } ], "source": [ "df.info()" ] }, { "cell_type": "code", "execution_count": 40, "id": "e56acbad-a1f6-4f34-b9d8-1aac039ee3c3", "metadata": {}, "outputs": [ { "data": { "text/html": [ "
\n", "\n", "\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "
notchnext_notchFrustrum
00.000.050.000125
10.050.100.000875
20.100.150.002375
30.150.200.004625
40.200.250.007625
............
954.754.803.420125
964.804.853.492125
974.854.903.564875
984.904.953.638375
994.955.003.712625
\n", "

100 rows × 3 columns

\n", "
" ], "text/plain": [ " notch next_notch Frustrum\n", "0 0.00 0.05 0.000125\n", "1 0.05 0.10 0.000875\n", "2 0.10 0.15 0.002375\n", "3 0.15 0.20 0.004625\n", "4 0.20 0.25 0.007625\n", ".. ... ... ...\n", "95 4.75 4.80 3.420125\n", "96 4.80 4.85 3.492125\n", "97 4.85 4.90 3.564875\n", "98 4.90 4.95 3.638375\n", "99 4.95 5.00 3.712625\n", "\n", "[100 rows x 3 columns]" ] }, "execution_count": 40, "metadata": {}, "output_type": "execute_result" } ], "source": [ "df[\"Frustrum\"] = [float(frustrum(df.notch[i], df.next_notch[i])) for i in df.index]\n", "df" ] }, { "cell_type": "code", "execution_count": 41, "id": "21d04cd6-cb1a-4f35-b5e6-00aedb5df96e", "metadata": {}, "outputs": [ { "data": { "text/plain": [ "0 0.000125\n", "1 0.001000\n", "2 0.003375\n", "3 0.008000\n", "4 0.015625\n", " ... \n", "95 110.592000\n", "96 114.084125\n", "97 117.649000\n", "98 121.287375\n", "99 125.000000\n", "Name: Frustrum, Length: 100, dtype: float64" ] }, "execution_count": 41, "metadata": {}, "output_type": "execute_result" } ], "source": [ "df.Frustrum.cumsum()" ] }, { "cell_type": "code", "execution_count": 42, "id": "3bf63932-4521-4600-aaa6-ce9146f46c10", "metadata": {}, "outputs": [], "source": [ "df[\"Cumulative\"] = df.Frustrum.cumsum()" ] }, { "cell_type": "code", "execution_count": 43, "id": "3bb34e11-98c3-4cfa-9357-bff159230d0d", "metadata": {}, "outputs": [ { "data": { "text/html": [ "
\n", "\n", "\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "
notchnext_notchFrustrumCumulative
00.000.050.0001250.000125
10.050.100.0008750.001000
20.100.150.0023750.003375
30.150.200.0046250.008000
40.200.250.0076250.015625
...............
954.754.803.420125110.592000
964.804.853.492125114.084125
974.854.903.564875117.649000
984.904.953.638375121.287375
994.955.003.712625125.000000
\n", "

100 rows × 4 columns

\n", "
" ], "text/plain": [ " notch next_notch Frustrum Cumulative\n", "0 0.00 0.05 0.000125 0.000125\n", "1 0.05 0.10 0.000875 0.001000\n", "2 0.10 0.15 0.002375 0.003375\n", "3 0.15 0.20 0.004625 0.008000\n", "4 0.20 0.25 0.007625 0.015625\n", ".. ... ... ... ...\n", "95 4.75 4.80 3.420125 110.592000\n", "96 4.80 4.85 3.492125 114.084125\n", "97 4.85 4.90 3.564875 117.649000\n", "98 4.90 4.95 3.638375 121.287375\n", "99 4.95 5.00 3.712625 125.000000\n", "\n", "[100 rows x 4 columns]" ] }, "execution_count": 43, "metadata": {}, "output_type": "execute_result" } ], "source": [ "df" ] }, { "cell_type": "code", "execution_count": 44, "id": "782d5080-6c56-4c48-a4ea-eca95c6f7f5a", "metadata": {}, "outputs": [], "source": [ "df[\"Difference\"] = df.Frustrum.diff()" ] }, { "cell_type": "code", "execution_count": 45, "id": "1317d6d8-b309-4ad8-afc3-614024209921", "metadata": {}, "outputs": [ { "data": { "text/html": [ "
\n", "\n", "\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "
notchnext_notchFrustrumCumulativeDifference
00.000.050.0001250.000125NaN
10.050.100.0008750.0010000.00075
20.100.150.0023750.0033750.00150
30.150.200.0046250.0080000.00225
40.200.250.0076250.0156250.00300
..................
954.754.803.420125110.5920000.07125
964.804.853.492125114.0841250.07200
974.854.903.564875117.6490000.07275
984.904.953.638375121.2873750.07350
994.955.003.712625125.0000000.07425
\n", "

100 rows × 5 columns

\n", "
" ], "text/plain": [ " notch next_notch Frustrum Cumulative Difference\n", "0 0.00 0.05 0.000125 0.000125 NaN\n", "1 0.05 0.10 0.000875 0.001000 0.00075\n", "2 0.10 0.15 0.002375 0.003375 0.00150\n", "3 0.15 0.20 0.004625 0.008000 0.00225\n", "4 0.20 0.25 0.007625 0.015625 0.00300\n", ".. ... ... ... ... ...\n", "95 4.75 4.80 3.420125 110.592000 0.07125\n", "96 4.80 4.85 3.492125 114.084125 0.07200\n", "97 4.85 4.90 3.564875 117.649000 0.07275\n", "98 4.90 4.95 3.638375 121.287375 0.07350\n", "99 4.95 5.00 3.712625 125.000000 0.07425\n", "\n", "[100 rows x 5 columns]" ] }, "execution_count": 45, "metadata": {}, "output_type": "execute_result" } ], "source": [ "df" ] }, { "cell_type": "code", "execution_count": 46, "id": "f0041864-ad10-4489-a5ea-e6651e00f88f", "metadata": {}, "outputs": [ { "data": { "text/plain": [ "0.0015" ] }, "execution_count": 46, "metadata": {}, "output_type": "execute_result" } ], "source": [ "0.002375 - 0.000875" ] }, { "cell_type": "code", "execution_count": 47, "id": "55411769-7315-4f22-8097-61eebf71db54", "metadata": {}, "outputs": [], "source": [ "df[\"DiffDiff\"] = df.Difference.diff()" ] }, { "cell_type": "code", "execution_count": 48, "id": "080e7601-bf38-411f-b865-addcb30156e4", "metadata": {}, "outputs": [ { "data": { "text/html": [ "
\n", "\n", "\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "
notchnext_notchFrustrumCumulativeDifferenceDiffDiff
00.000.050.0001250.000125NaNNaN
10.050.100.0008750.0010000.00075NaN
20.100.150.0023750.0033750.001500.00075
30.150.200.0046250.0080000.002250.00075
40.200.250.0076250.0156250.003000.00075
.....................
954.754.803.420125110.5920000.071250.00075
964.804.853.492125114.0841250.072000.00075
974.854.903.564875117.6490000.072750.00075
984.904.953.638375121.2873750.073500.00075
994.955.003.712625125.0000000.074250.00075
\n", "

100 rows × 6 columns

\n", "
" ], "text/plain": [ " notch next_notch Frustrum Cumulative Difference DiffDiff\n", "0 0.00 0.05 0.000125 0.000125 NaN NaN\n", "1 0.05 0.10 0.000875 0.001000 0.00075 NaN\n", "2 0.10 0.15 0.002375 0.003375 0.00150 0.00075\n", "3 0.15 0.20 0.004625 0.008000 0.00225 0.00075\n", "4 0.20 0.25 0.007625 0.015625 0.00300 0.00075\n", ".. ... ... ... ... ... ...\n", "95 4.75 4.80 3.420125 110.592000 0.07125 0.00075\n", "96 4.80 4.85 3.492125 114.084125 0.07200 0.00075\n", "97 4.85 4.90 3.564875 117.649000 0.07275 0.00075\n", "98 4.90 4.95 3.638375 121.287375 0.07350 0.00075\n", "99 4.95 5.00 3.712625 125.000000 0.07425 0.00075\n", "\n", "[100 rows x 6 columns]" ] }, "execution_count": 48, "metadata": {}, "output_type": "execute_result" } ], "source": [ "df" ] }, { "cell_type": "markdown", "id": "3d3f5a4e-8801-45ac-a9db-9e62d66d44bb", "metadata": {}, "source": [ "Increments of 0.5 instead of 0.05:\n", "\n", "\"Screen" ] }, { "cell_type": "code", "execution_count": 49, "id": "0065106b-aea1-4827-8ee0-513950d49272", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "\n", "RangeIndex: 100 entries, 0 to 99\n", "Data columns (total 6 columns):\n", " # Column Non-Null Count Dtype \n", "--- ------ -------------- ----- \n", " 0 notch 100 non-null float64\n", " 1 next_notch 100 non-null float64\n", " 2 Frustrum 100 non-null float64\n", " 3 Cumulative 100 non-null float64\n", " 4 Difference 99 non-null float64\n", " 5 DiffDiff 98 non-null float64\n", "dtypes: float64(6)\n", "memory usage: 4.8 KB\n" ] } ], "source": [ "df.info()" ] }, { "cell_type": "code", "execution_count": 50, "id": "db71d96a-2ec1-4285-bed7-6696009ed593", "metadata": {}, "outputs": [ { "data": { "image/png": "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\n", "text/plain": [ "
" ] }, "metadata": { "needs_background": "light" }, "output_type": "display_data" } ], "source": [ "df.plot(x=\"next_notch\", y=[\"Frustrum\", \"Difference\", \"DiffDiff\"]);" ] }, { "cell_type": "code", "execution_count": 51, "id": "6a9975e6-12ec-46f7-967a-7f641467dcc1", "metadata": {}, "outputs": [ { "data": { "image/png": "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\n", "text/plain": [ "
" ] }, "metadata": { "needs_background": "light" }, "output_type": "display_data" } ], "source": [ "df.plot(x=\"next_notch\", y=[\"Frustrum\", \"Difference\"]);" ] }, { "cell_type": "code", "execution_count": 52, "id": "ada2053b-1b1f-4876-8a92-0d6afe22f802", "metadata": {}, "outputs": [ { "data": { "text/latex": [ "$\\displaystyle 125$" ], "text/plain": [ "125" ] }, "execution_count": 52, "metadata": {}, "output_type": "execute_result" } ], "source": [ "frustrum(0, 1) + frustrum(1, 5)" ] }, { "cell_type": "code", "execution_count": 53, "id": "0f6366ad-8ac9-4b9b-aa05-c764ec00bbaa", "metadata": {}, "outputs": [ { "data": { "text/latex": [ "$\\displaystyle 124$" ], "text/plain": [ "124" ] }, "execution_count": 53, "metadata": {}, "output_type": "execute_result" } ], "source": [ "frustrum(1, 5)" ] }, { "cell_type": "markdown", "id": "216f44cc-c5db-47a0-97c9-6dd9b2f4edfb", "metadata": {}, "source": [ "## Cheese Tetrahedron\n", "\n", "In the explorations below, we're continuing to slice our tetrahedron parallel to any face." ] }, { "cell_type": "code", "execution_count": 54, "id": "57022db2-ef66-4d86-924c-9b80c3788803", "metadata": {}, "outputs": [], "source": [ "from sympy.utilities.lambdify import lambdify" ] }, { "cell_type": "code", "execution_count": 55, "id": "cad00a67-ed7e-4a14-8f04-00f9aab941c6", "metadata": {}, "outputs": [], "source": [ "pd.set_option(\"display.precision\", 10)" ] }, { "cell_type": "code", "execution_count": 56, "id": "e97e14ff-fc53-476f-8031-7e95547112c0", "metadata": {}, "outputs": [], "source": [ "X = sp.Symbol('X')" ] }, { "cell_type": "code", "execution_count": 57, "id": "b2af6c6d-4e87-4d22-9688-02b232abbfaf", "metadata": {}, "outputs": [ { "data": { "text/plain": [ "array([0. , 0.05, 0.1 , 0.15, 0.2 , 0.25, 0.3 , 0.35, 0.4 , 0.45, 0.5 ,\n", " 0.55, 0.6 , 0.65, 0.7 , 0.75, 0.8 , 0.85, 0.9 , 0.95, 1. , 1.05,\n", " 1.1 , 1.15, 1.2 , 1.25, 1.3 , 1.35, 1.4 , 1.45, 1.5 , 1.55, 1.6 ,\n", " 1.65, 1.7 , 1.75, 1.8 , 1.85, 1.9 , 1.95, 2. , 2.05, 2.1 , 2.15,\n", " 2.2 , 2.25, 2.3 , 2.35, 2.4 , 2.45, 2.5 , 2.55, 2.6 , 2.65, 2.7 ,\n", " 2.75, 2.8 , 2.85, 2.9 , 2.95, 3. , 3.05, 3.1 , 3.15, 3.2 , 3.25,\n", " 3.3 , 3.35, 3.4 , 3.45, 3.5 , 3.55, 3.6 , 3.65, 3.7 , 3.75, 3.8 ,\n", " 3.85, 3.9 , 3.95, 4. , 4.05, 4.1 , 4.15, 4.2 , 4.25, 4.3 , 4.35,\n", " 4.4 , 4.45, 4.5 , 4.55, 4.6 , 4.65, 4.7 , 4.75, 4.8 , 4.85, 4.9 ,\n", " 4.95, 5. ])" ] }, "execution_count": 57, "metadata": {}, "output_type": "execute_result" } ], "source": [ "notches = np.linspace(0, 5, 101)\n", "notches" ] }, { "cell_type": "code", "execution_count": 58, "id": "a4e55809-ceae-44ca-8bab-6e26aff230ea", "metadata": {}, "outputs": [], "source": [ "linear = 0.015 * X - 0.00075\n", "quadratic = 0.15*X**2 - 0.0075*X + 0.000125\n", "third_power = X**3" ] }, { "cell_type": "code", "execution_count": 59, "id": "18b96f53-7d3c-49b5-9cee-bc99bdfc13d0", "metadata": {}, "outputs": [ { "data": { "text/html": [ "
\n", "\n", "\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "
notch
00.00
10.05
20.10
30.15
40.20
......
964.80
974.85
984.90
994.95
1005.00
\n", "

101 rows × 1 columns

\n", "
" ], "text/plain": [ " notch\n", "0 0.00\n", "1 0.05\n", "2 0.10\n", "3 0.15\n", "4 0.20\n", ".. ...\n", "96 4.80\n", "97 4.85\n", "98 4.90\n", "99 4.95\n", "100 5.00\n", "\n", "[101 rows x 1 columns]" ] }, "execution_count": 59, "metadata": {}, "output_type": "execute_result" } ], "source": [ "df2 = pd.DataFrame({\"notch\":notches})\n", "df2" ] }, { "cell_type": "code", "execution_count": 60, "id": "ccadc64f-e597-427e-9190-2016a395d3a7", "metadata": {}, "outputs": [ { "data": { "text/html": [ "
\n", "\n", "\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "
notchFrustrum
00.000.000000
10.050.000125
20.100.000875
30.150.002375
40.200.004625
.........
964.803.420125
974.853.492125
984.903.564875
994.953.638375
1005.003.712625
\n", "

101 rows × 2 columns

\n", "
" ], "text/plain": [ " notch Frustrum\n", "0 0.00 0.000000\n", "1 0.05 0.000125\n", "2 0.10 0.000875\n", "3 0.15 0.002375\n", "4 0.20 0.004625\n", ".. ... ...\n", "96 4.80 3.420125\n", "97 4.85 3.492125\n", "98 4.90 3.564875\n", "99 4.95 3.638375\n", "100 5.00 3.712625\n", "\n", "[101 rows x 2 columns]" ] }, "execution_count": 60, "metadata": {}, "output_type": "execute_result" } ], "source": [ "df2[\"Frustrum\"] = [float(frustrum(df2.notch[i]-0.05, df2.notch[i])) for i in df2.index]\n", "df2.iloc[0,1]=0\n", "df2" ] }, { "cell_type": "code", "execution_count": 61, "id": "2f75d65f-ff8b-4e03-b7d9-50e4f6458c1f", "metadata": {}, "outputs": [], "source": [ "linear_f = lambdify(X, linear, 'numpy')" ] }, { "cell_type": "code", "execution_count": 62, "id": "bb80cd4d-35c2-43de-9a69-dbd2ea1f1567", "metadata": {}, "outputs": [], "source": [ "df2['linear'] = linear_f(df2.notch)" ] }, { "cell_type": "code", "execution_count": 63, "id": "27ec3d15-ae61-457e-8a8d-51dbe734a5bb", "metadata": {}, "outputs": [ { "data": { "text/html": [ "
\n", "\n", "\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "
notchFrustrumlinear
00.000.000000-0.00075
10.050.0001250.00000
20.100.0008750.00075
30.150.0023750.00150
40.200.0046250.00225
............
964.803.4201250.07125
974.853.4921250.07200
984.903.5648750.07275
994.953.6383750.07350
1005.003.7126250.07425
\n", "

101 rows × 3 columns

\n", "
" ], "text/plain": [ " notch Frustrum linear\n", "0 0.00 0.000000 -0.00075\n", "1 0.05 0.000125 0.00000\n", "2 0.10 0.000875 0.00075\n", "3 0.15 0.002375 0.00150\n", "4 0.20 0.004625 0.00225\n", ".. ... ... ...\n", "96 4.80 3.420125 0.07125\n", "97 4.85 3.492125 0.07200\n", "98 4.90 3.564875 0.07275\n", "99 4.95 3.638375 0.07350\n", "100 5.00 3.712625 0.07425\n", "\n", "[101 rows x 3 columns]" ] }, "execution_count": 63, "metadata": {}, "output_type": "execute_result" } ], "source": [ "df2" ] }, { "cell_type": "code", "execution_count": 64, "id": "36ab3271-4fba-43e4-8bd2-eeab43c80bfc", "metadata": {}, "outputs": [ { "data": { "text/html": [ "
\n", "\n", "\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "
notchFrustrumlinearDiffFrustrum
00.000.000000-0.00075NaN
10.050.0001250.000000.000125
20.100.0008750.000750.000750
30.150.0023750.001500.001500
40.200.0046250.002250.002250
...............
964.803.4201250.071250.071250
974.853.4921250.072000.072000
984.903.5648750.072750.072750
994.953.6383750.073500.073500
1005.003.7126250.074250.074250
\n", "

101 rows × 4 columns

\n", "
" ], "text/plain": [ " notch Frustrum linear DiffFrustrum\n", "0 0.00 0.000000 -0.00075 NaN\n", "1 0.05 0.000125 0.00000 0.000125\n", "2 0.10 0.000875 0.00075 0.000750\n", "3 0.15 0.002375 0.00150 0.001500\n", "4 0.20 0.004625 0.00225 0.002250\n", ".. ... ... ... ...\n", "96 4.80 3.420125 0.07125 0.071250\n", "97 4.85 3.492125 0.07200 0.072000\n", "98 4.90 3.564875 0.07275 0.072750\n", "99 4.95 3.638375 0.07350 0.073500\n", "100 5.00 3.712625 0.07425 0.074250\n", "\n", "[101 rows x 4 columns]" ] }, "execution_count": 64, "metadata": {}, "output_type": "execute_result" } ], "source": [ "df2['DiffFrustrum'] = df2.Frustrum.diff()\n", "df2" ] }, { "cell_type": "code", "execution_count": 65, "id": "4a5b7dba-a986-4c7f-9a58-2306eaefa0b1", "metadata": {}, "outputs": [], "source": [ "df2['Total_Volume'] = df2.Frustrum.cumsum()" ] }, { "cell_type": "code", "execution_count": 66, "id": "2866d49f-3ba6-494b-8fee-e672db65ee74", "metadata": {}, "outputs": [ { "data": { "text/html": [ "
\n", "\n", "\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "
notchFrustrumlinearDiffFrustrumTotal_Volume
00.000.000000-0.00075NaN0.000000
10.050.0001250.000000.0001250.000125
20.100.0008750.000750.0007500.001000
30.150.0023750.001500.0015000.003375
40.200.0046250.002250.0022500.008000
..................
964.803.4201250.071250.071250110.592000
974.853.4921250.072000.072000114.084125
984.903.5648750.072750.072750117.649000
994.953.6383750.073500.073500121.287375
1005.003.7126250.074250.074250125.000000
\n", "

101 rows × 5 columns

\n", "
" ], "text/plain": [ " notch Frustrum linear DiffFrustrum Total_Volume\n", "0 0.00 0.000000 -0.00075 NaN 0.000000\n", "1 0.05 0.000125 0.00000 0.000125 0.000125\n", "2 0.10 0.000875 0.00075 0.000750 0.001000\n", "3 0.15 0.002375 0.00150 0.001500 0.003375\n", "4 0.20 0.004625 0.00225 0.002250 0.008000\n", ".. ... ... ... ... ...\n", "96 4.80 3.420125 0.07125 0.071250 110.592000\n", "97 4.85 3.492125 0.07200 0.072000 114.084125\n", "98 4.90 3.564875 0.07275 0.072750 117.649000\n", "99 4.95 3.638375 0.07350 0.073500 121.287375\n", "100 5.00 3.712625 0.07425 0.074250 125.000000\n", "\n", "[101 rows x 5 columns]" ] }, "execution_count": 66, "metadata": {}, "output_type": "execute_result" } ], "source": [ "df2" ] }, { "cell_type": "markdown", "id": "18f70a6a-dca9-4fb8-9b70-3eb63e2788da", "metadata": {}, "source": [ "## Earthling Volume (Cube)\n", "\n", "\"S3\"\n", "\n", "Lets construct the unit XYZ cube with normal vectors, convert them to Quadrays, and feed them to our tetravolumes formula. \n", "\n", "To express the result in cubic volumes, we will need to convert out of tetravolumes using the Synergetics Constant S3 i.e. $\\sqrt{9/8}$.\n", "\n", "The relationship between XYZ and IVM that the Martians + Earthings have constructed (in the science fiction story behind Martian Math), assumes a CCP ball size in common, i.e. an IVM ball of radius R, diameter D. \n", "\n", "The unit XYZ cube has edges R, whereas the IVM tetrahedron has edges D. Nevertheless, the $R^{3}$ cube has volume greater than $D^{3}$ by a scale factor of S3.\n", "\n", "In the qrays module, the edges between any two elementary quadray tips is unity (the unity-2 of 2R). With respect to 2R, the XYZ cube has edges half that length, or R. So the X, Y and Z vectors of length R get entered with length 1/2 with respect to the IVM prime vector of length 1.\n", "\n", "\"Units" ] }, { "cell_type": "code", "execution_count": 67, "id": "29dd67c3-fd8c-4a2b-922e-fafda752373d", "metadata": {}, "outputs": [], "source": [ "ex = qrays.Vector((1/2,0,0)) \n", "ey = qrays.Vector((0,1/2,0)) \n", "ez = qrays.Vector((0,0,1/2))" ] }, { "cell_type": "code", "execution_count": 68, "id": "dcabe8ea-bd26-481c-b622-76a910bada10", "metadata": {}, "outputs": [ { "data": { "text/latex": [ "$\\displaystyle 90.0$" ], "text/plain": [ "90.0000000000000" ] }, "execution_count": 68, "metadata": {}, "output_type": "execute_result" } ], "source": [ "ex.angle(ey).evalf()" ] }, { "cell_type": "code", "execution_count": 69, "id": "587aa991-a847-42d8-b79f-bc42229ede5e", "metadata": {}, "outputs": [ { "data": { "text/latex": [ "$\\displaystyle 90.0$" ], "text/plain": [ "90.0000000000000" ] }, "execution_count": 69, "metadata": {}, "output_type": "execute_result" } ], "source": [ "ex.angle(ez).evalf()" ] }, { "cell_type": "code", "execution_count": 70, "id": "211459cf-55a8-4344-ba2b-0877009c290c", "metadata": {}, "outputs": [ { "data": { "text/latex": [ "$\\displaystyle 90.0$" ], "text/plain": [ "90.0000000000000" ] }, "execution_count": 70, "metadata": {}, "output_type": "execute_result" } ], "source": [ "ey.angle(ez).evalf()" ] }, { "cell_type": "code", "execution_count": 71, "id": "955bad34-38f5-463e-a117-53931ac9891c", "metadata": {}, "outputs": [], "source": [ "qx = ex.quadray()\n", "qy = ey.quadray()\n", "qz = ez.quadray()" ] }, { "cell_type": "code", "execution_count": 72, "id": "b633c6f6-17a5-41bb-9658-74a7cf4a6315", "metadata": {}, "outputs": [ { "data": { "text/latex": [ "$\\displaystyle 90.0$" ], "text/plain": [ "90.0000000000000" ] }, "execution_count": 72, "metadata": {}, "output_type": "execute_result" } ], "source": [ "qx.angle(qy).evalf()" ] }, { "cell_type": "code", "execution_count": 73, "id": "59ede58f-24e7-41e2-bae6-9778ac28aef6", "metadata": {}, "outputs": [ { "data": { "text/latex": [ "$\\displaystyle 1.06066017177982119257251270028$" ], "text/plain": [ "1.06066017177982119257251270028" ] }, "execution_count": 73, "metadata": {}, "output_type": "execute_result" } ], "source": [ "S3 = sp.sqrt(9/8)\n", "S3.evalf(30)" ] }, { "cell_type": "code", "execution_count": 74, "id": "30ed7c51-5305-4467-b1fa-31cde1cd7ff2", "metadata": {}, "outputs": [], "source": [ "def corner_vol(v0, v1, v2):\n", " uvt = Matrix([[*origin.coords,1], # origin\n", " [*v0.coords, 1], # v0\n", " [*v1.coords, 1], # v1\n", " [*v2.coords, 1], # v2\n", " [1,1,1,1,0]])\n", " return abs(uvt.det())/4\n", "\n", "def tetra_vol(v0, v1, v2, v3):\n", " uvt = Matrix([[*v0.coords,1], # v0\n", " [*v1.coords, 1], # v1\n", " [*v2.coords, 1], # v2\n", " [*v3.coords, 1], # v3\n", " [1,1,1,1,0]])\n", " return abs(uvt.det())/4 " ] }, { "cell_type": "markdown", "id": "5790b172-3b8f-4667-a61a-19b47c9c28dd", "metadata": {}, "source": [ "Lets test our volume function with the original basic Quadray tetrahedron of edges D and tetravolume 1." ] }, { "cell_type": "code", "execution_count": 82, "id": "a3751f6e-e5f5-4733-8148-c2d58b3ece86", "metadata": {}, "outputs": [], "source": [ "qa = Martian((1,0,0,0))\n", "qb = Martian((0,1,0,0))\n", "qc = Martian((0,0,1,0))\n", "qd = Martian((0,0,0,1))" ] }, { "cell_type": "code", "execution_count": 83, "id": "f16b8f6e-696d-4696-846c-2df97a29da82", "metadata": {}, "outputs": [ { "data": { "text/latex": [ "$\\displaystyle 1$" ], "text/plain": [ "1" ] }, "execution_count": 83, "metadata": {}, "output_type": "execute_result" } ], "source": [ "tetra_vol(qa, qb, qc, qd)" ] }, { "cell_type": "markdown", "id": "30e6154d-3fe9-4381-80ec-0c7b29f10851", "metadata": {}, "source": [ "Confirm or qx, qy, qz are the expected normal vectors of length R." ] }, { "cell_type": "code", "execution_count": 77, "id": "5f9d7910-cef0-4079-8768-1a32ff8ef47c", "metadata": {}, "outputs": [ { "data": { "text/plain": [ "xyz_vector(x=0.500000000000000, y=0, z=0)" ] }, "execution_count": 77, "metadata": {}, "output_type": "execute_result" } ], "source": [ "qx.xyz" ] }, { "cell_type": "code", "execution_count": 78, "id": "5f2ee39a-4b16-4485-a403-04a44dd11db5", "metadata": {}, "outputs": [ { "data": { "text/plain": [ "xyz_vector(x=0, y=0.500000000000000, z=0)" ] }, "execution_count": 78, "metadata": {}, "output_type": "execute_result" } ], "source": [ "qy.xyz" ] }, { "cell_type": "code", "execution_count": 79, "id": "d6fbce69-977c-41fd-a6c3-5a6bcda8039a", "metadata": {}, "outputs": [ { "data": { "text/plain": [ "xyz_vector(x=0, y=0, z=0.500000000000000)" ] }, "execution_count": 79, "metadata": {}, "output_type": "execute_result" } ], "source": [ "qz.xyz" ] }, { "cell_type": "markdown", "id": "611e0665-25ab-45e3-9a31-6e2fe48c8161", "metadata": {}, "source": [ "The 90-90-90 tip tetrahedron is one 1/4 of 2/3 of the total cube, i.e. 4 such tips apply to an internal tetrahedron of 1/3 the total cube's volume. I.E. 1/6th the total cube. \n", "\n", "So multiply the result we get, for the cube's tetrahedron tip (closing the lid on qx, qy, qz), by 6 to get the total cube volume." ] }, { "cell_type": "code", "execution_count": 80, "id": "8a4513d6-7056-47af-8a55-c6b60e950893", "metadata": {}, "outputs": [ { "data": { "text/latex": [ "$\\displaystyle 1.06066017177982$" ], "text/plain": [ "1.06066017177982" ] }, "execution_count": 80, "metadata": {}, "output_type": "execute_result" } ], "source": [ "(corner_vol(qx, qy, qz) * 6).evalf()" ] }, { "cell_type": "markdown", "id": "0f60b347-8267-460c-9eea-4e448888d59c", "metadata": {}, "source": [ "But we're still in tetravolumes. \n", "\n", "It takes fewer XYZ unit cubes (edges R) than IVM unit tetrahedrons (edges D) to fill the same volume, i.e. the XYZ unit cube is bigger by a scale factor of S3. \n", "\n", "So use 1/S3 when going from tetravolumes to cubic volumes i.e. it takes fewer of the latter so your constant is < 1." ] }, { "cell_type": "code", "execution_count": 81, "id": "f81c2451-288d-41f4-871e-a5ab2ae3bc55", "metadata": {}, "outputs": [ { "data": { "text/latex": [ "$\\displaystyle 1.0$" ], "text/plain": [ "1.00000000000000" ] }, "execution_count": 81, "metadata": {}, "output_type": "execute_result" } ], "source": [ "(corner_vol(qx, qy, qz) * 6 * 1/S3).evalf()" ] } ], "metadata": { "kernelspec": { "display_name": "Python 3 (ipykernel)", "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.9.15" } }, "nbformat": 4, "nbformat_minor": 5 }