{ "cells": [ { "cell_type": "markdown", "id": "0789894a-f7c9-4c58-89e2-6dd43ed5f431", "metadata": {}, "source": [ "#### M4W Series\n", "\n", "* [Table of Contents](M4WTOC.ipynb)\n", "* \"Open\n", "* [![nbviewer](https://raw.githubusercontent.com/jupyter/design/master/logos/Badges/nbviewer_badge.svg)](https://nbviewer.org/github/4dsolutions/m4w/blob/main/Sequences.ipynb)" ] }, { "cell_type": "markdown", "id": "8043de89-4f7b-4e5c-b14a-72f041a55e9f", "metadata": {}, "source": [ "# Sequences of Figurate and Polyhedral Numbers\n", "\n", "Cross references: \n", "\n", "* [*The Book of Numbers*](https://www.goodreads.com/book/show/682027.The_Book_of_Numbers) by Conway and Guy\n", "* [Numeracy 101](http://4dsolutions.net/ocn/numeracy0.html) more curriculum writing\n", "* [M4W Workshop](https://controlroom.blogspot.com/2023/08/m4w-workshop.html) blog post\n", "* [edu-sig](https://www.python.org/community/sigs/current/edu-sig/) for archived discussions\n", "* [math4wisdom](https://www.freelists.org/archive/math4wisdom/) for archived discussions\n", "\n", "## Pascal's Triangle\n", "\n", "Pascal's Triangle is a \"grand central station\" type topic, where many trains of thought converge. It's at the heart of the Binomial Theorem, usually celebrated as Isaac Newton's discovery. We find earlier Chinese versions. In data science, Pascal's Triangle is presented in conjunction with the Bell Curve, attributed to Gauss, with successive rows giving a discrete histogram approximation to the final curve." ] }, { "cell_type": "markdown", "id": "bbcb3e2b-cd82-463c-a7ff-a9c1995a42b3", "metadata": {}, "source": [ "The Python generator function uses the keyword `yield` in place of `return` such that the flow of execution may be surrendered but then resumed right where it left off." ] }, { "cell_type": "code", "execution_count": 1, "id": "3fef5507-c1d5-437a-96b2-ca685e4b0832", "metadata": {}, "outputs": [], "source": [ "def pascal():\n", " row = [1]\n", " while True:\n", " yield row\n", " rshift = [0] + row # push a 0 to the front (left) [0 1 2 1]\n", " lshift = row + [0] # append 0 to the end (right) [1 2 1 0]\n", " row = [(a+b) for a,b in zip(rshift, lshift)] # add the rows verically: [1 3 3 1]" ] }, { "cell_type": "code", "execution_count": 2, "id": "408a1087-8ca8-4cb4-9f10-c172a78db1f2", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "[1]\n", "[1, 1]\n", "[1, 2, 1]\n", "[1, 3, 3, 1]\n", "[1, 4, 6, 4, 1]\n", "[1, 5, 10, 10, 5, 1]\n", "[1, 6, 15, 20, 15, 6, 1]\n", "[1, 7, 21, 35, 35, 21, 7, 1]\n", "[1, 8, 28, 56, 70, 56, 28, 8, 1]\n", "[1, 9, 36, 84, 126, 126, 84, 36, 9, 1]\n" ] } ], "source": [ "g = pascal()\n", "for _ in range(10):\n", " print(next(g))" ] }, { "cell_type": "markdown", "id": "889f0366-9d30-4bdd-b660-902d0777f907", "metadata": {}, "source": [ "## Triangular Numbers\n", "#### (column 2)\n", "\n", "[OEIS A000217](https://oeis.org/A000217)\n", "\n", "The sum of two consecutive triangular numbers is a square number. See [*Getting Serious About Series*](http://4dsolutions.net/ocn/numeracy0.html) for a visual proof." ] }, { "cell_type": "code", "execution_count": 3, "id": "dc393b85-c91d-4cb1-a952-aecd0876a744", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "1\n", "3\n", "6\n", "10\n", "15\n", "21\n", "28\n", "36\n" ] } ], "source": [ "g = pascal()\n", "col = 3\n", "for i in range(10):\n", " if i < col-1: \n", " next(g) # skip rows\n", " continue\n", " print(next(g)[col-1]) # column from here" ] }, { "cell_type": "markdown", "id": "9c636e5a-2a7d-4ab4-8744-987f2f28af1e", "metadata": {}, "source": [ "## Tetrahedral Numbers\n", "#### (column 3)\n", "\n", "[OEIS A000292](https://oeis.org/A000292)\n", "\n", "A tetrahedral packing of balls is likewise the cubic close packing (CCP), likewise [the face-centerd cubic](https://github.com/4dsolutions/elite_school/blob/master/Py4HS_sphere_packing_classroom.ipynb) (FCC), which, as a scaffolding of ball-center connecting edges is likewise the octet-truss used in architecture.\n", "\n", "\"Octet\n", "\n", "
\n", "\n", "\"Bell's" ] }, { "cell_type": "code", "execution_count": 4, "id": "389c3a16-e2da-4b13-b721-a268669d4ceb", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "1\n", "4\n", "10\n", "20\n", "35\n", "56\n", "84\n", "120\n", "165\n", "220\n", "286\n", "364\n" ] } ], "source": [ "g = pascal()\n", "col = 4\n", "for i in range(15):\n", " if i < col-1: \n", " next(g) # skip rows\n", " continue\n", " print(next(g)[col-1]) # column from here" ] }, { "cell_type": "markdown", "id": "576a785f-4d64-4a3f-bb41-a5b7073842a7", "metadata": {}, "source": [ "We may look up this sequence in the Online Encyclopedia of Integer Sequences, and find it listed as [A000292](https://oeis.org/A000292). A closed form formula is provided: n*(n+1)*(n+2)/6. Lets test it:" ] }, { "cell_type": "code", "execution_count": 5, "id": "d740577e-5879-4823-8f58-5478a023ee46", "metadata": {}, "outputs": [ { "data": { "text/plain": [ "[1, 4, 10, 20, 35, 56, 84, 120, 165, 220, 286]" ] }, "execution_count": 5, "metadata": {}, "output_type": "execute_result" } ], "source": [ "def A000292(n: int) -> int:\n", " return n*(n+1)*(n+2)//6\n", "\n", "[A000292(n) for n in range(1, 12)]" ] }, { "cell_type": "code", "execution_count": 6, "id": "a66416e6-126e-4aaa-b564-259962d3c242", "metadata": {}, "outputs": [ { "data": { "text/plain": [ "2024" ] }, "execution_count": 6, "metadata": {}, "output_type": "execute_result" } ], "source": [ "A000292(22) # 22 balls along an edge" ] }, { "cell_type": "markdown", "id": "cfe76ae5-18a2-45e5-8107-17de8d01e86c", "metadata": {}, "source": [ "A number of folks have pointed out that the year 2024 is a tetrahedral number.\n", "\n", "\"Screen" ] }, { "cell_type": "markdown", "id": "b3c08d6d-8ffd-4766-a495-6e022652db0f", "metadata": {}, "source": [ "## Deriving the Formula for Tetrahedral Numbers\n", "\n", "How might we get the expression for tetrahedral numbers, starting from raw data, the tabulations. One way is to solve a system of 4 linear equations, starting from the hypothetical expression we seek, in the form:\n", "\n", "$$\n", "A n^{3} + B n^{2} + C n + D\n", "$$\n", "\n", "where n = 1, 2, 3, 4... and we get back 1, 4, 10, 20 etc.\n", "\n", "Using these values for n, we get the following linear equations, with A, B, C, D still unknown to us:\n", "\n", "$A + B + C + D = 1$\n", "\n", "$8A + 4B + 2C + D = 4$\n", "\n", "$27A + 9B + 3C + D = 10$\n", "\n", "$64A + 16B + 4C + D = 20$\n", "\n", "This is a job for linear algebra, using matrices.\n" ] }, { "cell_type": "code", "execution_count": 7, "id": "48b22e10-1ec7-46f2-86bf-0b54f927e931", "metadata": {}, "outputs": [], "source": [ "from sympy.matrices import Matrix" ] }, { "cell_type": "markdown", "id": "74da44e4-73a8-4939-a3fd-f8f6845c39cc", "metadata": {}, "source": [ "$$\n", "A^{-1} A X = A^{-1} \n", "\\begin{bmatrix}\n", "1 \\\\\n", "4 \\\\\n", "10 \\\\\n", "20 \\\\\n", "\\end{bmatrix}\n", "$$\n", "which, since $A^{-1} A$ is the identity matrix, simplifies to:\n", "$$\n", "X = A^{-1} \n", "\\begin{bmatrix}\n", "1 \\\\\n", "4 \\\\\n", "10 \\\\\n", "20 \\\\\n", "\\end{bmatrix}\n", "$$\n", "where column matrix X will contain the coefficients we seek i.e. A, B, C, D.\n" ] }, { "cell_type": "code", "execution_count": 8, "id": "b2bcf726-e710-4cab-8e0a-799c212700d5", "metadata": {}, "outputs": [ { "data": { "text/latex": [ "$\\displaystyle \\left[\\begin{matrix}1 & 1 & 1 & 1\\\\8 & 4 & 2 & 1\\\\27 & 9 & 3 & 1\\\\64 & 16 & 4 & 1\\end{matrix}\\right]$" ], "text/plain": [ "Matrix([\n", "[ 1, 1, 1, 1],\n", "[ 8, 4, 2, 1],\n", "[27, 9, 3, 1],\n", "[64, 16, 4, 1]])" ] }, "execution_count": 8, "metadata": {}, "output_type": "execute_result" } ], "source": [ "A = Matrix([[1, 1, 1, 1],[8, 4, 2, 1], [27, 9, 3, 1], [64, 16, 4, 1]])\n", "A" ] }, { "cell_type": "code", "execution_count": 9, "id": "6730e847-0503-41ad-9d34-56e55cb6615b", "metadata": {}, "outputs": [ { "data": { "text/latex": [ "$\\displaystyle \\left[\\begin{matrix}- \\frac{1}{6} & \\frac{1}{2} & - \\frac{1}{2} & \\frac{1}{6}\\\\\\frac{3}{2} & -4 & \\frac{7}{2} & -1\\\\- \\frac{13}{3} & \\frac{19}{2} & -7 & \\frac{11}{6}\\\\4 & -6 & 4 & -1\\end{matrix}\\right]$" ], "text/plain": [ "Matrix([\n", "[ -1/6, 1/2, -1/2, 1/6],\n", "[ 3/2, -4, 7/2, -1],\n", "[-13/3, 19/2, -7, 11/6],\n", "[ 4, -6, 4, -1]])" ] }, "execution_count": 9, "metadata": {}, "output_type": "execute_result" } ], "source": [ "Ainv = A.inv()\n", "Ainv" ] }, { "cell_type": "code", "execution_count": 10, "id": "d7490870-7fb3-473a-8976-26627c81528a", "metadata": {}, "outputs": [ { "data": { "text/latex": [ "$\\displaystyle \\left[\\begin{matrix}1 & 0 & 0 & 0\\\\0 & 1 & 0 & 0\\\\0 & 0 & 1 & 0\\\\0 & 0 & 0 & 1\\end{matrix}\\right]$" ], "text/plain": [ "Matrix([\n", "[1, 0, 0, 0],\n", "[0, 1, 0, 0],\n", "[0, 0, 1, 0],\n", "[0, 0, 0, 1]])" ] }, "execution_count": 10, "metadata": {}, "output_type": "execute_result" } ], "source": [ "A * Ainv" ] }, { "cell_type": "markdown", "id": "c9bca97e-9fb4-4f0b-8d21-bfd4bc068a17", "metadata": {}, "source": [ "The coefficients we seek." ] }, { "cell_type": "code", "execution_count": 11, "id": "c901ab01-9f04-4529-872a-ba942491c14c", "metadata": {}, "outputs": [ { "data": { "text/latex": [ "$\\displaystyle \\left[\\begin{matrix}\\frac{1}{6}\\\\\\frac{1}{2}\\\\\\frac{1}{3}\\\\0\\end{matrix}\\right]$" ], "text/plain": [ "Matrix([\n", "[1/6],\n", "[1/2],\n", "[1/3],\n", "[ 0]])" ] }, "execution_count": 11, "metadata": {}, "output_type": "execute_result" } ], "source": [ "X = Ainv * Matrix([[1],[4], [10], [20]])\n", "X" ] }, { "cell_type": "code", "execution_count": 12, "id": "ce359b03-48b6-4178-a8af-59ebaacf30e4", "metadata": {}, "outputs": [], "source": [ "from sympy import Expr, Symbol, Rational, Integer" ] }, { "cell_type": "code", "execution_count": 13, "id": "d710c216-06d2-4071-8657-c60adf7c5fef", "metadata": {}, "outputs": [ { "data": { "text/latex": [ "$\\displaystyle \\frac{n^{3}}{6} + \\frac{n^{2}}{2} + \\frac{n}{3}$" ], "text/plain": [ "n**3/6 + n**2/2 + n/3" ] }, "execution_count": 13, "metadata": {}, "output_type": "execute_result" } ], "source": [ "n = Symbol('n')\n", "tetnumb = Rational(1,6)*n**3 + Rational(1,2)*n**2 + Rational(1,3)*n\n", "tetnumb" ] }, { "cell_type": "code", "execution_count": 14, "id": "d39e511c-b38f-41c3-96d9-e0c373458f3e", "metadata": {}, "outputs": [ { "data": { "text/latex": [ "$\\displaystyle \\frac{n \\left(n^{2} + 3 n + 2\\right)}{6}$" ], "text/plain": [ "n*(n**2 + 3*n + 2)/6" ] }, "execution_count": 14, "metadata": {}, "output_type": "execute_result" } ], "source": [ "tetnumb.simplify()" ] }, { "cell_type": "code", "execution_count": 15, "id": "e610d52c-23cb-4d02-bdc5-02e9c43dc293", "metadata": {}, "outputs": [ { "data": { "text/latex": [ "$\\displaystyle \\frac{n \\left(n + 1\\right) \\left(n + 2\\right)}{6}$" ], "text/plain": [ "n*(n + 1)*(n + 2)/6" ] }, "execution_count": 15, "metadata": {}, "output_type": "execute_result" } ], "source": [ "tetnumb.factor()" ] }, { "cell_type": "code", "execution_count": 16, "id": "1b72e096-4e5c-422f-b2a4-0a735de46f9f", "metadata": {}, "outputs": [], "source": [ "def A000292(n: int) -> int:\n", " return n*(n+1)*(n+2)//6" ] }, { "cell_type": "markdown", "id": "0abd9021-d465-46a1-9195-0543aba23ec1", "metadata": {}, "source": [ "Checking were n = 22..." ] }, { "cell_type": "code", "execution_count": 17, "id": "646b18ac-e4b6-4e8a-bc99-757d1611dd7f", "metadata": {}, "outputs": [ { "data": { "text/latex": [ "$\\displaystyle \\left[\\begin{matrix}2024\\end{matrix}\\right]$" ], "text/plain": [ "Matrix([[2024]])" ] }, "execution_count": 17, "metadata": {}, "output_type": "execute_result" } ], "source": [ "X.T * Matrix([[22**3],[22**2], [22], [0]]) # 22nd Tetrahedral Number" ] }, { "cell_type": "markdown", "id": "57f90ae3-ad19-413b-97c8-9a0fa62d239b", "metadata": {}, "source": [ "## Hollow Tetrahedrons\n", "\n", "[OEIS A005893](https://oeis.org/A005893)\n", "\n", "Lets consider only the number of balls in the most outward shell of a tetrahedron, meaning we will not count any balls not on the surface.\n", "\n", "Multiplying successive triangular numbers by four, for each facet, is too many balls, as edge balls (excluding the tips) will be counted twice and the four tips will be counted thrice. \n", "\n", "So we need to subtract any edge balls once and tips twice (2 x 4 = 8). The first edge balls appear when we have 3 balls on each edge including the two tip balls. When starting out with n=1, we simply return 1.\n", "\n", "A shorter way to get triangular numbers is using n * (n + 1) / 2 where n = 1, 2, 3..." ] }, { "cell_type": "code", "execution_count": 18, "id": "6aa2d801-b349-47cf-a330-f6060258de1d", "metadata": {}, "outputs": [ { "data": { "text/plain": [ "[1, 3, 6, 10, 15, 21, 28, 36, 45, 55]" ] }, "execution_count": 18, "metadata": {}, "output_type": "execute_result" } ], "source": [ "def trinum(n: int):\n", " return n*(n+1)//2\n", "\n", "[trinum(n) for n in range(1, 11)]" ] }, { "cell_type": "code", "execution_count": 19, "id": "a80eca5f-6667-4f3e-b632-cbe61fc72146", "metadata": {}, "outputs": [], "source": [ "def tetra(n: int):\n", " if n == 1:\n", " return 1\n", " edge_balls = 0 if (n-2)<=0 else n-2\n", " tip_balls = 4\n", " return 4 * trinum(n) - edge_balls * 6 - tip_balls * 2" ] }, { "cell_type": "code", "execution_count": 20, "id": "96e8d7e3-40c1-4299-b003-341a26a5566d", "metadata": {}, "outputs": [ { "data": { "text/plain": [ "[1,\n", " 4,\n", " 10,\n", " 20,\n", " 34,\n", " 52,\n", " 74,\n", " 100,\n", " 130,\n", " 164,\n", " 202,\n", " 244,\n", " 290,\n", " 340,\n", " 394,\n", " 452,\n", " 514,\n", " 580,\n", " 650,\n", " 724]" ] }, "execution_count": 20, "metadata": {}, "output_type": "execute_result" } ], "source": [ "[tetra(n) for n in range(1, 21)]" ] }, { "cell_type": "markdown", "id": "603ddc2e-e315-4cc9-9d4e-d2a791e4c71f", "metadata": {}, "source": [ "OEIS has this sequence listed as [A005893](https://oeis.org/A005893)." ] }, { "cell_type": "markdown", "id": "65aeecf7-a006-4d4a-85d7-bc211289ede6", "metadata": {}, "source": [ "## A Grand Central Station..." ] }, { "cell_type": "markdown", "id": "3bd0e3ff-9894-4aed-9d46-c1a29670dd6c", "metadata": {}, "source": [ "#### Combinatorics" ] }, { "cell_type": "code", "execution_count": 21, "id": "a59969ff-4383-473b-a9c8-5129cbd20d66", "metadata": {}, "outputs": [], "source": [ "from math import factorial\n", "\n", "def combos(r, n):\n", " \"\"\"\n", " This expression may be used to populate pascal's triangle\n", " r = number chosen... (think columns)\n", " n = from how many total (think rows)\n", " \"\"\"\n", " return factorial(n)//(factorial(r) * factorial(n-r))" ] }, { "cell_type": "code", "execution_count": 22, "id": "35372806-68a9-4597-bded-3d5f47241783", "metadata": {}, "outputs": [ { "data": { "text/plain": [ "84" ] }, "execution_count": 22, "metadata": {}, "output_type": "execute_result" } ], "source": [ "combos(3, 9) # how many ways might I choose 3 distinct things from a bag of 9 unique objects" ] }, { "cell_type": "code", "execution_count": 23, "id": "c1931598-5068-41b8-9371-0f5920988d17", "metadata": {}, "outputs": [ { "data": { "text/plain": [ "[1, 9, 36, 84, 126, 126, 84, 36, 9, 1]" ] }, "execution_count": 23, "metadata": {}, "output_type": "execute_result" } ], "source": [ "[combos(i, 9) for i in range(10)]" ] }, { "cell_type": "code", "execution_count": 24, "id": "c439d00e-4905-460c-a2e0-fb37e87f94c2", "metadata": {}, "outputs": [ { "data": { "text/plain": [ "[1, 7, 21, 35, 35, 21, 7, 1]" ] }, "execution_count": 24, "metadata": {}, "output_type": "execute_result" } ], "source": [ "[combos(i, 7) for i in range(8)] # one way to pick 7, 7 ways to pick 1, 21 ways to pick 2..." ] }, { "cell_type": "code", "execution_count": 25, "id": "1b68e4e1-95a0-43bb-adc4-4f529e7d72cc", "metadata": {}, "outputs": [], "source": [ "from itertools import combinations" ] }, { "cell_type": "code", "execution_count": 26, "id": "fbced62a-2846-450e-bf12-911d21e53e53", "metadata": {}, "outputs": [ { "data": { "text/plain": [ "\u001b[0;31mInit signature:\u001b[0m \u001b[0mcombinations\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0miterable\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mr\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", "\u001b[0;31mDocstring:\u001b[0m \n", "Return successive r-length combinations of elements in the iterable.\n", "\n", "combinations(range(4), 3) --> (0,1,2), (0,1,3), (0,2,3), (1,2,3)\n", "\u001b[0;31mType:\u001b[0m type\n", "\u001b[0;31mSubclasses:\u001b[0m " ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "? combinations" ] }, { "cell_type": "code", "execution_count": 27, "id": "dfb6c292-8cd8-4265-8105-ff34f2fd6fe6", "metadata": {}, "outputs": [ { "data": { "text/plain": [ "35" ] }, "execution_count": 27, "metadata": {}, "output_type": "execute_result" } ], "source": [ "len(list(combinations(range(7), 3))) # 35 ways to pick 3 from 7" ] }, { "cell_type": "code", "execution_count": 28, "id": "3b800a15-1453-4ef8-9681-bda21612e962", "metadata": {}, "outputs": [ { "data": { "text/plain": [ "84" ] }, "execution_count": 28, "metadata": {}, "output_type": "execute_result" } ], "source": [ "len(list(combinations(range(9), 3))) # 84 ways to pick 3 from 9" ] }, { "cell_type": "markdown", "id": "f9ae3046-32f9-4022-b0a6-2b98481cfb22", "metadata": {}, "source": [ "#### Number Theory\n", "\n", "If and only if the number n in column 1 (e.g. the 9 in row 9) divides all the other numbers in the same row (but for the ones), without remainder, then n is prime.\n", "\n", "See [Curated Videos](Curated_Videos.ipynb) for more information." ] }, { "cell_type": "code", "execution_count": 29, "id": "02e9cf54-643f-40c8-8fd3-9a7eaf332c14", "metadata": {}, "outputs": [ { "data": { "text/plain": [ "[1,\n", " 23,\n", " 253,\n", " 1771,\n", " 8855,\n", " 33649,\n", " 100947,\n", " 245157,\n", " 490314,\n", " 817190,\n", " 1144066,\n", " 1352078,\n", " 1352078,\n", " 1144066,\n", " 817190,\n", " 490314,\n", " 245157,\n", " 100947,\n", " 33649,\n", " 8855,\n", " 1771,\n", " 253,\n", " 23,\n", " 1]" ] }, "execution_count": 29, "metadata": {}, "output_type": "execute_result" } ], "source": [ "row24 = [combos(i, 23) for i in range(24)] \n", "row24" ] }, { "cell_type": "code", "execution_count": 30, "id": "89fff51f-22ea-4353-a320-d79c883afe8b", "metadata": {}, "outputs": [], "source": [ "# showing no remainder when row elements other than 1 get divided by 23\n", "from operator import mod" ] }, { "cell_type": "code", "execution_count": 31, "id": "52b06638-d9d1-4e35-8cde-da39845df833", "metadata": {}, "outputs": [ { "data": { "text/plain": [ "0" ] }, "execution_count": 31, "metadata": {}, "output_type": "execute_result" } ], "source": [ "mod(25, 5)" ] }, { "cell_type": "code", "execution_count": 32, "id": "8f9b23bd-5629-4cb2-9faa-f073104015a1", "metadata": {}, "outputs": [ { "data": { "text/plain": [ "1" ] }, "execution_count": 32, "metadata": {}, "output_type": "execute_result" } ], "source": [ "mod(26, 5)" ] }, { "cell_type": "code", "execution_count": 33, "id": "6bc1cdce-7518-4d05-bf6a-a75c9300444c", "metadata": {}, "outputs": [ { "data": { "text/plain": [ "[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]" ] }, "execution_count": 33, "metadata": {}, "output_type": "execute_result" } ], "source": [ "[mod(elem, 23) for elem in row24[1:-1]]" ] }, { "cell_type": "markdown", "id": "152e865c-5c3e-44bc-8d2f-3f7309afe92e", "metadata": {}, "source": [ "#### Data Science\n", "\n", "Since we're also in the process of introducing more of the Python ecosystem, replacing the role of the graphing calculator with alternative plotting tools.\n", "\n", "[pandas.Dataframe.plot](https://pandas.pydata.org/pandas-docs/stable/reference/api/pandas.DataFrame.plot.html)" ] }, { "cell_type": "code", "execution_count": 34, "id": "5551858f-2d05-4e30-b7ac-8a5fdfcdd782", "metadata": {}, "outputs": [], "source": [ "import pandas as pd" ] }, { "cell_type": "code", "execution_count": 35, "id": "892365f1-3f2a-4ada-ac11-97c57560d7f9", "metadata": {}, "outputs": [ { "data": { "image/png": "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", "text/plain": [ "
" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "pd.DataFrame(row24).plot();" ] }, { "cell_type": "markdown", "id": "d501d2af-433a-4898-b4a2-3a7d77921db4", "metadata": {}, "source": [ "#### Hypertext Markup Language Protocol\n", "\n", "Using the 3rd party requests library to query the Online Encyclopedia of Integer Sequences (OEIS)" ] }, { "cell_type": "code", "execution_count": 36, "id": "262fc8aa-6985-4517-8f98-247e0b801447", "metadata": {}, "outputs": [], "source": [ "import requests" ] }, { "cell_type": "code", "execution_count": 37, "id": "35d8901b-bd9c-413a-bd94-898d3a5977d1", "metadata": {}, "outputs": [], "source": [ "response = requests.get(\"https://oeis.org/A000217\")" ] }, { "cell_type": "code", "execution_count": 38, "id": "98ab753a-0550-40c9-a43a-9ebea7435053", "metadata": {}, "outputs": [ { "data": { "text/plain": [ "" ] }, "execution_count": 38, "metadata": {}, "output_type": "execute_result" } ], "source": [ "response" ] }, { "cell_type": "code", "execution_count": 39, "id": "2fd92a67-f767-4c2e-bbe1-3d067c20f891", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "\n", "\n", "\n" ] } ], "source": [ "print(\"\\n\".join(response.text.split(\"\\n\")[:3]))" ] }, { "cell_type": "code", "execution_count": 40, "id": "35bc6333-f061-4cc2-bd59-bd06905b3ea0", "metadata": {}, "outputs": [], "source": [ "response = requests.get(\"https://oeis.org/search?fmt=text&q=1,12,42,92,162\")" ] }, { "cell_type": "code", "execution_count": 41, "id": "818e86d3-7f8f-4404-beac-433f4477a0ea", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "# Greetings from The On-Line Encyclopedia of Integer Sequences! http://oeis.org/\n", "\n", "Search: seq:1,12,42,92,162\n", "Showing 1-1 of 1\n", "\n", "%I A005901 M4834 #109 Dec 12 2023 11:11:49\n", "%S A005901 1,12,42,92,162,252,362,492,642,812,1002,1212,1442,1692,1962,2252,\n", "%T A005901 2562,2892,3242,3612,4002,4412,4842,5292,5762,6252,6762,7292,7842,\n", "%U A005901 8412,9002,9612,10242,10892,11562,12252,12962,13692,14442,15212,16002\n", "%N A005901 Number of points on surface of cuboctahedron (or icosahedron): a(0) = 1; for n > 0, a(n) = 10n^2 + 2. Also coordination sequence for f.c.c. or A_3 or D_3 lattice.\n" ] } ], "source": [ "print(\"\\n\".join(response.text.split(\"\\n\")[:10]))" ] }, { "cell_type": "code", "execution_count": 42, "id": "1de1b6e0-4b69-4de6-acd8-7251dbe496d7", "metadata": {}, "outputs": [ { "data": { "text/plain": [ "True" ] }, "execution_count": 42, "metadata": {}, "output_type": "execute_result" } ], "source": [ "\"Urner\" in response.text # vanity search" ] }, { "cell_type": "markdown", "id": "314c058b-6cd5-4bfa-944f-7a16b9f86636", "metadata": {}, "source": [ "## Cuboctahedral Numbers\n", "\n", "![](http://www.4dsolutions.net/ocn/graphics/cubanim.gif)\n", "\n", "Consider the ball packing that starts with a nuclear sphere and then acculumates successive layers of balls in the form of a growing cuboctahedron. The sequence goes: 1, 13, 55, 147... as we add 12, 42, 92... (successive layers).\n", "\n", "\n", "$$\n", "A n^{3} + B n^{2} + C n + D\n", "$$\n", "\n", "where n = 1, 2, 3, 4... and we get back 1, 13, 55, 147 etc.\n", "\n", "Using these values for n, we get the following linear equations, with A, B, C, D still unknown to us:\n", "\n", "$A + B + C + D = 1$\n", "\n", "$8A + 4B + 2C + D = 13$\n", "\n", "$27A + 9B + 3C + D = 55$\n", "\n", "$64A + 16B + 4C + D = 147$\n" ] }, { "cell_type": "code", "execution_count": 43, "id": "b6dea72e-c779-4ed2-8e6e-fdb2f91bb6c8", "metadata": {}, "outputs": [ { "data": { "text/latex": [ "$\\displaystyle \\left[\\begin{matrix}\\frac{10}{3}\\\\-5\\\\\\frac{11}{3}\\\\-1\\end{matrix}\\right]$" ], "text/plain": [ "Matrix([\n", "[10/3],\n", "[ -5],\n", "[11/3],\n", "[ -1]])" ] }, "execution_count": 43, "metadata": {}, "output_type": "execute_result" } ], "source": [ "X = Ainv * Matrix([[1],[13], [55], [147]])\n", "X" ] }, { "cell_type": "markdown", "id": "b812d722-1f8a-4c24-8384-1c39d32b3d9c", "metadata": {}, "source": [ "Let's test it as a function:" ] }, { "cell_type": "code", "execution_count": 44, "id": "207c2d95-0e3b-44fe-a5fa-a11252eebe44", "metadata": {}, "outputs": [ { "data": { "text/plain": [ "[1, 13, 55, 147, 309, 561, 923, 1415, 2057, 2869, 3871]" ] }, "execution_count": 44, "metadata": {}, "output_type": "execute_result" } ], "source": [ "def A005902(n):\n", " \"\"\"\n", " https://oeis.org/A005902\n", " \"\"\"\n", " return Rational(10, 3) * n**3 - 5 * n**2 + Rational(11, 3) * n - 1 \n", "\n", "[A005902(x) for x in range(1, 12)]" ] }, { "cell_type": "code", "execution_count": 45, "id": "2be1e66a-c230-41b5-94a5-dab3e69d4ddd", "metadata": {}, "outputs": [ { "data": { "text/latex": [ "$\\displaystyle \\frac{10 n^{3}}{3} - 5 n^{2} + \\frac{11 n}{3} - 1$" ], "text/plain": [ "10*n**3/3 - 5*n**2 + 11*n/3 - 1" ] }, "execution_count": 45, "metadata": {}, "output_type": "execute_result" } ], "source": [ "icosanumb = Rational(10, 3) * n**3 - 5 * n**2 + Rational(11, 3) * n - 1 \n", "icosanumb" ] }, { "cell_type": "code", "execution_count": 46, "id": "891dbf47-82d9-4205-aebf-0df302617039", "metadata": {}, "outputs": [ { "data": { "text/plain": [ "[1, 13, 55, 147, 309, 561, 923, 1415, 2057, 2869, 3871]" ] }, "execution_count": 46, "metadata": {}, "output_type": "execute_result" } ], "source": [ "[Integer(icosanumb.evalf(subs={'n':i})) for i in range(1, 12)]" ] }, { "cell_type": "code", "execution_count": 47, "id": "9fa242e2-3de8-4de4-af80-011006f68d11", "metadata": {}, "outputs": [ { "data": { "text/latex": [ "$\\displaystyle \\frac{\\left(2 n - 1\\right) \\left(5 n^{2} - 5 n + 3\\right)}{3}$" ], "text/plain": [ "(2*n - 1)*(5*n**2 - 5*n + 3)/3" ] }, "execution_count": 47, "metadata": {}, "output_type": "execute_result" } ], "source": [ "icosanumb.factor()" ] }, { "cell_type": "markdown", "id": "c778ea5c-4e0f-43f3-a37f-f2b6b498bc6a", "metadata": {}, "source": [ "OEIS gives: \n", "\n", "$$\n", "a(n) = (2 n+1)(5 n^{2} + 5 n + 3)/3\n", "$$\n", "\n", "which assumes n = 0, 1, 2, 3... versus n = 1, 2, 3..." ] }, { "cell_type": "code", "execution_count": 52, "id": "af4343a0-b2c5-4d0f-b9da-15d7d5d61a4c", "metadata": {}, "outputs": [ { "data": { "text/plain": [ "[1, 13, 55, 147, 309, 561, 923, 1415, 2057, 2869, 3871, 5083]" ] }, "execution_count": 52, "metadata": {}, "output_type": "execute_result" } ], "source": [ "def A005902_v2(n):\n", " \"\"\"\n", " https://oeis.org/A005902\n", " \"\"\"\n", " return ((2*n + 1) * (5*n**2 + 5*n + 3))//3\n", "\n", "[A005902_v2(x) for x in range(12)] # start from i = 0" ] } ], "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.11.3" } }, "nbformat": 4, "nbformat_minor": 5 }