
    
        
        
        
                
        
        
        
                
        
        
        
                
        
        
        
                
        
        
        
                
        
        
        
                
        
        
        
                
        
        
        
                
        
        
        
                
        
        
        
            
{"version":"https:\/\/jsonfeed.org\/version\/1","title":"mathspp.com feed","home_page_url":"https:\/\/mathspp.com\/blog\/tags\/mathematics","feed_url":"https:\/\/mathspp.com\/blog\/tags\/mathematics.json","description":"Stay up-to-date with the articles on mathematics and programming that get published to mathspp.com.","author":{"name":"Rodrigo Gir\u00e3o Serr\u00e3o"},"items":[{"title":"TIL #133 \u2013 Shoelace formula","date_published":"2025-09-25T12:16:00+02:00","id":"https:\/\/mathspp.com\/blog\/til\/shoelace-formula","url":"https:\/\/mathspp.com\/blog\/til\/shoelace-formula","content_html":"<p>Today I learned about the shoelace formula to compute the area of arbitrary simple polygons.<\/p>\n\n<p>If you have a polygon with no holes and that doesn't intersect itself you can use the shoelace formula to compute its area. If <span class=\"mathjax mathjax--inline\">\\(P_i = (x_i, y_i), i = 1, \\cdots, n\\)<\/span> are the vertices of the polygon, then the area is given by<\/p>\n<p class=\"mathjax mathjax--block\">\\[\nA = \\frac12 \\left| \\sum_{i = 1}^{n} x_iy_{i + 1} - y_i x_{i + 1} \\right|\\]<\/p>\n<p>In the formula above, <span class=\"mathjax mathjax--inline\">\\(P_{n + 1}\\)<\/span> is <span class=\"mathjax mathjax--inline\">\\(P_1\\)<\/span>.<\/p>\n<p>The formula is super practical and easy to compute, which I find amusing given that it works for any (simple) polygon!<\/p>","summary":"Today I learned about the shoelace formula to compute the area of arbitrary simple polygons.","date_modified":"2025-10-20T22:34:56+02:00","tags":["mathematics","geometry"],"image":"\/user\/pages\/02.blog\/04.til\/133.shoelace-formula\/thumbnail.webp"},{"title":"TIL #132 \u2013 Double factorial","date_published":"2025-09-25T11:47:00+02:00","id":"https:\/\/mathspp.com\/blog\/til\/double-factorial","url":"https:\/\/mathspp.com\/blog\/til\/double-factorial","content_html":"<p>Today I learned about the double factorial.<\/p>\n\n<p>The double factorial, <span class=\"mathjax mathjax--inline\">\\(n!!\\)<\/span>, is defined as the product of all positive integers less than or equal to <span class=\"mathjax mathjax--inline\">\\(n\\)<\/span> that have the same parity as <span class=\"mathjax mathjax--inline\">\\(n\\)<\/span>.<\/p>\n<p>Some examples:<\/p>\n<ul>\n<li><span class=\"mathjax mathjax--inline\">\\(5!! = 5 \\times 3 \\times 1\\)<\/span><\/li>\n<li><span class=\"mathjax mathjax--inline\">\\(8!! = 8 \\times 6 \\times 4 \\times 2\\)<\/span><\/li>\n<\/ul>\n<p>When reading about it in a book authored by a friend of mine, the identity <span class=\"mathjax mathjax--inline\">\\((2n)!! = 2^n n!\\)<\/span> was also presented, and I'll prove it now by induction.\nFor <span class=\"mathjax mathjax--inline\">\\(n = 1\\)<\/span>, we have <span class=\"mathjax mathjax--inline\">\\(2!! = 2 = 2^1 \\times 1!\\)<\/span>, which is true.\nNow, assuming the identity holds up to <span class=\"mathjax mathjax--inline\">\\(n\\)<\/span>, we show it holds for <span class=\"mathjax mathjax--inline\">\\(n + 1\\)<\/span>:<\/p>\n<p class=\"mathjax mathjax--block\">\\[\n\\begin{align}\n(2(n + 1))!! &amp;= (2(n + 1)) \\times (2n)!! \\\\\n&amp;= (2(n + 1)) \\times 2^n n! \\\\\n&amp;= (n + 1) \\times 2^{n + 1} n! \\\\\n&amp;= 2^{n + 1} (n + 1)!\n\\end{align}\\]<\/p>\n<p>Done!<\/p>","summary":"Today I learned about the double factorial.","date_modified":"2025-10-20T22:34:56+02:00","tags":["combinatorics","arithmetic","induction","mathematics"],"image":"\/user\/pages\/02.blog\/04.til\/132.double-factorial\/thumbnail.webp"},{"title":"TIL #126 \u2013 Hash of infinity","date_published":"2025-07-20T22:18:00+02:00","id":"https:\/\/mathspp.com\/blog\/til\/hash-of-infinity","url":"https:\/\/mathspp.com\/blog\/til\/hash-of-infinity","content_html":"<p>Today I learned about a Python Easter Egg hidden in the hash of two special float values.<\/p>\n\n<h2 id=\"hash-of-infinity\">Hash of infinity<a href=\"#hash-of-infinity\" class=\"toc-anchor after\" data-anchor-icon=\"#\" aria-label=\"Anchor\"><\/a><\/h2>\n<p>Today I learned that the values <code>float(\"inf\")<\/code> and <code>float(\"-inf\")<\/code> have two very special hashes:<\/p>\n<pre><code class=\"language-pycon\">&gt;&gt;&gt; hash(float(\"inf\"))\n314159\n&gt;&gt;&gt; hash(float(\"-inf\"))\n-314159<\/code><\/pre>\n<p>In case you can't tell, those are the first few digits of the mathematical constant <span class=\"mathjax mathjax--inline\">\\(\\pi\\)<\/span>:<\/p>\n<pre><code class=\"language-pycon\">&gt;&gt;&gt; import math\n&gt;&gt;&gt; math.pi\n3.141592653589793\n## ^^^^^<\/code><\/pre>\n<p>I learned about this during the <a href=\"https:\/\/ep2025.europython.eu\/session\/cpython-core-development-panel\" target=\"_blank\" rel=\"nofollow noopener noreferrer\" class=\"external-link no-image\">CPython panel<\/a> held at EuroPython 2025, after the hosts \u0141ukasz &amp; Pablo asked the panel if they know what <a href=\"\/blog\/til\/hash-of-1-is-2\">the hash of <code>-1<\/code> was<\/a>.<\/p>","summary":"Today I learned about a Python Easter  Egg hidden in the hash of two special float values.","date_modified":"2025-10-20T22:34:56+02:00","tags":["algorithms","mathematics","python","programming"],"image":"\/user\/pages\/02.blog\/04.til\/126.hash-of-infinity\/thumbnail.webp"},{"title":"Animating a tree fractal","date_published":"2025-01-12T19:10:00+01:00","id":"https:\/\/mathspp.com\/blog\/animating-a-tree-fractal","url":"https:\/\/mathspp.com\/blog\/animating-a-tree-fractal","content_html":"<p>This article walks through the code used to animate a tree fractal.<\/p>\n\n<p>I really enjoy fractals and for the longest time I've been meaning to draw the classical tree fractal that starts with the main trunk which then successively splits into two branches, that themselves can be seen as the full tree.<\/p>\n<p>Today I quickly put together the code to do this and then I animated the rotation of the tree to make sure it's easy to see the self-similarity of the tree.<\/p>\n<p>This is the animated GIF that I produced:<\/p>\n<p><img alt=\"Animated GIF of a tree fractal rotating and zooming in, so that the end position is the same as the starting position, displaying the self-similarity properties of the fractal.\" src=\"\/user\/pages\/02.blog\/animating-a-tree-fractal\/_tree.gif?decoding=auto&amp;fetchpriority=auto\"><\/p>\n<h2 id=\"drawing-the-tree\">Drawing the tree<a href=\"#drawing-the-tree\" class=\"toc-anchor after\" data-anchor-icon=\"#\" aria-label=\"Anchor\"><\/a><\/h2>\n<p>To draw the tree I wrote a recursive function (obviously!) that draws a trunk and then recursively draws the remainder of the tree.\nTo &ldquo;recursively draw the remainder of the tree&rdquo; I needed to compute the two trunks that stem from the trunk I just drew, so to do that I:<\/p>\n<ul><li>computed the direction of the trunk I just drew as a numpy vector;<\/li>\n<li>rotated this vector by 60 degrees (clockwise and counter-clockwise);<\/li>\n<li>scaled down this vector; and<\/li>\n<li>used it to compute the two new trunks.<\/li>\n<\/ul><p>The recursive function looks like this:<\/p>\n<pre><code class=\"language-py\">def tree(screen, start, to, depth=0):\n    if depth &gt;= 15:\n        return\n    sx, sy = start\n    tx, ty = to\n    pygame.draw.line(\n        screen,\n        BLACK,\n        (WIDTH \/\/ 2 + sx, HEIGHT \/\/ 2 - sy),\n        (WIDTH \/\/ 2 + tx, HEIGHT \/\/ 2 - ty),\n        1,\n    )\n    direction = np.array([[tx - sx], [ty - sy]])\n    for angle in [pi \/ 3, -pi \/ 3]:\n        rot = np.array(\n            [\n                [cos(angle), -sin(angle)],\n                [sin(angle), cos(angle)],\n            ]\n        )\n        new_direction = ((rot @ ((direction) \/ 1.7))).reshape((2,))\n        tree(screen, to, to + new_direction, depth + 1)<\/code><\/pre>\n<p>One important thing that I ended up doing, and that explains the weird calculations inside the call to <code>pygame.draw.line<\/code>, is that I decided to do all calculations as if the coordinate system were the standard one from maths class: the origin is at the centre of the pygame window and the values of the coordinate y increase by going up, not by going down.\nThen, I need to convert from this sytem to the pygame system right before drawing, which is why I add <code>(WIDTH \/\/ 2, HEIGHT \/\/ 2)<\/code> to the points we're drawing and then for the y coordinate I need to use the symmetric value (<code>-y<\/code> instead of <code>y<\/code>) to compensate for the fact that the y axis is flipped.<\/p>\n<p>The full script to draw the tree looks like this:<\/p>\n<pre><code class=\"language-py\">from math import sin, cos, pi\nimport sys\n\nimport numpy as np\nimport pygame\nimport pygame.locals\n\nWIDTH, HEIGHT = 600, 400\n\nWHITE = (255, 255, 255)\nBLACK = (0, 0, 0)\n\nscreen = pygame.display.set_mode((WIDTH, HEIGHT))\n\ndef tree(screen, start, to, depth=0):\n    ...\n\ndef main() -&gt; None:\n    screen.fill(WHITE)\n    tree(screen, np.array((0, -200)), np.array((0, 0)))\n    pygame.display.flip()\n    pygame.image.save(screen, \"tree.png\")\n\n    while True:\n        for event in pygame.event.get():\n            if event.type == pygame.locals.QUIT:\n                pygame.quit()\n                sys.exit(0)\n\nif __name__ == \"__main__\":\n    main()<\/code><\/pre>\n<h2 id=\"animating-the-tree\">Animating the tree<a href=\"#animating-the-tree\" class=\"toc-anchor after\" data-anchor-icon=\"#\" aria-label=\"Anchor\"><\/a><\/h2>\n<p>To make it easier to animate the tree I first started by splitting the function <code>tree<\/code> in two:<\/p>\n<ol><li>a...<\/li><\/ol>","summary":"This article walks through the code used to animate a tree fractal.","date_modified":"2025-07-23T16:49:02+02:00","tags":["fractals","mathematics","programming","pygame","python","recursion","visualisation"],"image":"\/user\/pages\/02.blog\/animating-a-tree-fractal\/thumbnail.webp"},{"title":"Reverse-engineering the \u201cChronospatial Computer\u201d","date_published":"2024-12-21T09:00:00+01:00","id":"https:\/\/mathspp.com\/blog\/reverse-engineering-the-chronospatial-computer","url":"https:\/\/mathspp.com\/blog\/reverse-engineering-the-chronospatial-computer","content_html":"<p>Reverse-engineering the program from &ldquo;Chronospatial Computer&rdquo;, day 17 of Advent of Code 2024.<\/p>\n\n<p>The &ldquo;Chronospatial Computer&rdquo; is from <a href=\"https:\/\/adventofcode.com\/2024\/day\/17\" target=\"_blank\" rel=\"nofollow noopener noreferrer\" class=\"external-link no-image\">Advent of Code 2024, day 17<\/a>, a problem that entertained me for a couple of hours.<\/p>\n<h2 id=\"parsing-the-input\">Parsing the input<a href=\"#parsing-the-input\" class=\"toc-anchor after\" data-anchor-icon=\"#\" aria-label=\"Anchor\"><\/a><\/h2>\n<p>My input file looked like this:<\/p>\n<pre><code class=\"language-txt\">Register A: 64012472\nRegister B: 0\nRegister C: 0\n\nProgram: 2,4,1,7,7,5,0,3,1,7,4,1,5,5,3,0<\/code><\/pre>\n<p>To read the input and parse it I used a context manager and a couple of calls to <code>readline<\/code>:<\/p>\n<pre><code class=\"language-py\">with open(\"input.txt\", \"r\") as f:\n    register_a = int(f.readline().split()[-1])\n    register_b = int(f.readline().split()[-1])\n    register_c = int(f.readline().split()[-1])\n    _ = f.readline()\n    program = [int(num) for num in f.readline().split()[-1].split(\",\")]\n\nprint(program, register_a, register_b, register_c)<\/code><\/pre>\n<h2 id=\"solving-part-1-with-functional-programming\">Solving part 1 with functional programming<a href=\"#solving-part-1-with-functional-programming\" class=\"toc-anchor after\" data-anchor-icon=\"#\" aria-label=\"Anchor\"><\/a><\/h2>\n<p>Part 1 required me to simulate a series of simple instructions that operate on three registers.\nWhen I read the problem statement, I decided I wanted to use some ideas from functional programming.\nSo, what I did was to separate each operator (there are 8) into three parts:<\/p>\n<ol><li>the part that performs some computation with the registers and\/or with the operand;<\/li>\n<li>the part that updates the state of the program, maybe by updating a register or by outputting a value; and<\/li>\n<li>the part that updates the pointer of the program, which controls the instruction that will run next.<\/li>\n<\/ol><p>By using <code>lambda<\/code> functions, <a href=\"\/blog\/pydonts\/dunder-methods\">dunder methods<\/a>, and <a href=\"\/blog\/functools-partial\">currying with <code>functools.partial<\/code><\/a>, each list below represents one of the three parts of each opcode.<\/p>\n<p>First, the computation part of each operation:<\/p>\n<pre><code class=\"language-py\">registers = [0, 1, 2, 3, register_A, register_B, register_C]\nA, B, C = 4, 5, 6  # Indices of the named registers in the list `registers`.\n\ncomputations = [\n    lambda o: registers[A] \/\/ pow(2, registers[o]),  # ADV\n    lambda o: registers[B] ^ o,                      # BXL\n    lambda o: registers[o] % 8,                      # BST\n    lambda o: ...,                                   # JNZ\n    lambda o: registers[B] ^ registers[C],           # BXC\n    lambda o: registers[o] % 8,                      # OUT\n    lambda o: registers[A] \/\/ pow(2, registers[o]),  # BDV\n    lambda o: registers[A] \/\/ pow(2, registers[o]),  # CDV\n]<\/code><\/pre>\n<p>In the lambda functions above, when we use <code>o<\/code> in isolation, we're using the operand as a literal operand, whereas the list <code>registers<\/code> maps an operand into its combo operand.\nBy using this list, we can map the numbers 0 through 3 to themselves and the indices 4, 5, and 6, to the registers A, B, and C, respectively, without having to use a conditional statement.<\/p>\n<p>The operation <code>JNZ<\/code> has a lambda function that does nothing because there is no proper computation for this operator.<\/p>\n<p>Then, I wrote a list with all the functions that update the state of the program:<\/p>\n<pre><code class=\"language-py\">from functools import partial\n\noutput = []\nstate_updates = [\n    partial(registers.__setitem__, A),\n    partial(registers.__setitem__, B),\n    partial(registers.__setitem__, B),\n    lambda v: ...,\n    partial(registers.__setitem__, B),\n    output.append,\n    partial(registers.__setitem__, B),\n    partial(registers.__setitem__, C),\n]<\/code><\/pre>\n<p>This uses the <a href=\"\/blog\/pydonts\/dunder-methods\">dunder method <code>__setitem__<\/code><\/a> and <a href=\"\/blog\/functools-partial\">the function <code>functools.partial<\/code><\/a> to create a function that accepts a single value and that writes that value to the correct register in the list <code>registers<\/code>.<\/p>\n<p>Finally, all operators move the program pointer by two positions except the operator <code>JNZ...<\/code><\/p>","summary":"Reverse-engineering the program from \u201cChronospatial Computer\u201d, day 17 of Advent of Code 2024.","date_modified":"2025-07-23T16:49:02+02:00","tags":["algorithms","mathematics","modular arithmetic","programming","python","recursion"],"image":"\/user\/pages\/02.blog\/reverse-engineering-the-chronospatial-computer\/thumbnail.webp"},{"title":"Solving \u201cBridge Repair\u201d in 4ms with Python","date_published":"2024-12-07T19:00:00+01:00","id":"https:\/\/mathspp.com\/blog\/solving-bridge-repair-in-4ms-with-python","url":"https:\/\/mathspp.com\/blog\/solving-bridge-repair-in-4ms-with-python","content_html":"<p>Solving &ldquo;Bridge Repair&rdquo;, from day 7 of Advent of Code 2024, in 4ms with Python with a simple deductive algorithm.<\/p>\n\n<p>Today I solved the problem from <a href=\"https:\/\/adventofcode.com\/2024\/day\/7\" target=\"_blank\" rel=\"nofollow noopener noreferrer\" class=\"external-link no-image\">Advent of Code 2024, day 7<\/a> in 4ms using Python.\nMy first solution used brute-force and ran in 15 seconds.\nIt was very easy to implement and I got the job done quite quickly.\nBut then I thought about using a smarter algorithm, and I got a solution that's over 4,000 times faster and that runs in under 4ms.\nI will describe both solutions in this article.<\/p>\n<p>(It should be obvious by now, but this article contains spoilers!)<\/p>\n<h2 id=\"problem-statement\">Problem statement<a href=\"#problem-statement\" class=\"toc-anchor after\" data-anchor-icon=\"#\" aria-label=\"Anchor\"><\/a><\/h2>\n<p>In short, given a target integer and a list of integers, can we use addition, multiplication, and concatenation, to manipulate the list of integers to equal the target integer?\nThere is the added restriction that the operations are always evaluated from left to right and the integers cannot be reordered.<\/p>\n<p>Here are some examples that are possible:<\/p>\n<pre><code>5: 2 3\n6: 2 3\n23: 2 3\n94: 2 4 9 5<\/code><\/pre>\n<p>To make <span class=\"mathjax mathjax--inline\">\\(5\\)<\/span> with <span class=\"mathjax mathjax--inline\">\\(2\\)<\/span> and <span class=\"mathjax mathjax--inline\">\\(3\\)<\/span> we can do <span class=\"mathjax mathjax--inline\">\\(5 = 2 + 3\\)<\/span>.\nTo make <span class=\"mathjax mathjax--inline\">\\(6\\)<\/span> with <span class=\"mathjax mathjax--inline\">\\(2\\)<\/span> and <span class=\"mathjax mathjax--inline\">\\(3\\)<\/span> we can multiply the two numbers and to make <span class=\"mathjax mathjax--inline\">\\(23\\)<\/span> with <span class=\"mathjax mathjax--inline\">\\(2\\)<\/span> and <span class=\"mathjax mathjax--inline\">\\(3\\)<\/span> we can concatenate the two digits.\nFinally, to make <span class=\"mathjax mathjax--inline\">\\(94\\)<\/span> with the integers <span class=\"mathjax mathjax--inline\">\\(2\\)<\/span>, <span class=\"mathjax mathjax--inline\">\\(4\\)<\/span>, <span class=\"mathjax mathjax--inline\">\\(9\\)<\/span>, and <span class=\"mathjax mathjax--inline\">\\(5\\)<\/span>, we start by multiplying, then we concatenate, and then we add.\nIf we use <span class=\"mathjax mathjax--inline\">\\(||\\)<\/span> to represent concatenation, then <span class=\"mathjax mathjax--inline\">\\(94 = ((2 \\times 4) || 9) + 5\\)<\/span>.<\/p>\n<h2 id=\"brute-force-solution-15-seconds\">Brute-force solution, 15 seconds<a href=\"#brute-force-solution-15-seconds\" class=\"toc-anchor after\" data-anchor-icon=\"#\" aria-label=\"Anchor\"><\/a><\/h2>\n<p>To determine if a certain list of numbers can be manipulated to match the target value, we can write a function that generates all distinct sequences of operators and then tries to use each sequence of operators in turn.<\/p>\n<p>Using <code>itertools.product<\/code>, we can generate all sequences of distinct operators quite easily:<\/p>\n<pre><code class=\"language-py\">from itertools import product\nfrom operator import add, mul\n\nvalid_operators = [\n    add,\n    mul,\n    lambda x, y: int(f\"{x}{y}\")\n]\n\ndef is_valid(target, operands):\n    operator_sequences = product(valid_operators, repeat=len(operands) - 1)\n    start, *head = operands\n    for operators in operator_sequences:\n        total = start\n        for operator, operand in zip(operators, head):\n            total = operator(total, operand)\n        if total == target:\n            return True\n    return False\n\nprint(is_valid(94, [2, 4, 9, 5]))<\/code><\/pre>\n<p>Advent of Code provides an <a href=\"\/blog\/solving-bridge-repair-in-4ms-with-python\/.\/input.txt\">input file with 850 tests<\/a> and this code takes slightly over 15 seconds to classify all 850 tests on my machine.\nNow, I will show you how you can speed this up by a factor of 2,000.<\/p>\n<h2 id=\"deducing-valid-operations-4-milliseconds\">Deducing valid operations, 4 milliseconds<a href=\"#deducing-valid-operations-4-milliseconds\" class=\"toc-anchor after\" data-anchor-icon=\"#\" aria-label=\"Anchor\"><\/a><\/h2>\n<p>The faster algorithm is conceptually very simple.\nDisappointingly simple.\nInstead of working from the front to the back, trying random operations and seeing if they work out in the end, we work from the back to the front.<\/p>\n<p>For example, consider the target <code>94<\/code> and the list of integers <code>[2, 4, 9, 5]<\/code>.\nIf this is a possible case, then the final operation must be an addition.\nWhy?<\/p>\n<p>The...<\/p>","summary":"Solving \u201cBridge Repair\u201d, from day 7 of Advent of Code 2024, in 4ms with Python with a simple deductive algorithm.","date_modified":"2025-07-23T16:49:02+02:00","tags":["algorithms","mathematics","programming","python","recursion"],"image":"\/user\/pages\/02.blog\/solving-bridge-repair-in-4ms-with-python\/thumbnail.webp"},{"title":"Problem #066 \u2013 regex crossword","date_published":"2024-08-27T12:00:00+02:00","id":"https:\/\/mathspp.com\/blog\/problems\/regex-crossword","url":"https:\/\/mathspp.com\/blog\/problems\/regex-crossword","content_html":"<p>Can you solve this crossword where all hints are regular expressions?<\/p>\n\n<h2 id=\"problem-statement\">Problem statement<a href=\"#problem-statement\" class=\"toc-anchor after\" data-anchor-icon=\"#\" aria-label=\"Anchor\"><\/a><\/h2>\n<figure class=\"image-caption\"><img title=\"The regex crossword puzzle grid.\" alt=\"Puzzle in the shape of an hexagonal tiled region where cells are supposed to be filled in with characters from the alphabet according to hints given as regular expressions.\" src=\"\/user\/pages\/02.blog\/03.problems\/p066-regex-crossword\/_puzzle.webp\"><figcaption class=\"\">The regex crossword puzzle grid.<\/figcaption><\/figure>\n<p>At <a href=\"https:\/\/ep2024.europython.eu\" target=\"_blank\" rel=\"nofollow noopener noreferrer\" class=\"external-link no-image\">EuroPython 2024<\/a> I watched a lightning talk about the art of puzzle solving.\nIn it, the speaker showed the regex crossword puzzle that you can see above, <a href=\"https:\/\/puzzles.mit.edu\/2013\/coinheist.com\/rubik\/a_regular_crossword\/\" target=\"_blank\" rel=\"nofollow noopener noreferrer\" class=\"external-link no-image\">that I took from this URL<\/a>.\nYou are supposed to fill the hexagonal grid with letters so that all of the regular expressions shown match.<\/p>\n<p>If you don't know regular expressions, the puzzle only uses a simple subset of the syntax:<\/p>\n<ul>\n<li>literal character matches;<\/li>\n<li>wildcard matches with <code>.<\/code>;<\/li>\n<li>alternatives with <code>|<\/code>;<\/li>\n<li>the quantifiers <code>?<\/code>, <code>+<\/code>, and <code>*<\/code>;<\/li>\n<li>character sets with <code>[...]<\/code> and negated character sets with <code>[^...]<\/code>; and<\/li>\n<li>groups with <code>()<\/code> and group references with <code>\\1<\/code>, <code>\\2<\/code>, etc.<\/li>\n<\/ul>\n<p>You can look this up and then you will be able to solve the challenge.\nYou can also use <a href=\"https:\/\/regex101.com\" target=\"_blank\" rel=\"nofollow noopener noreferrer\" class=\"external-link no-image\">the site regex101<\/a> to help you check what each regular expression means.<\/p>\n<div class=\"notices blue\">\n<p>Give it some thought!<\/p>\n<\/div>\n<h2 id=\"solution\">Solution<a href=\"#solution\" class=\"toc-anchor after\" data-anchor-icon=\"#\" aria-label=\"Anchor\"><\/a><\/h2>\n<p>In the spirit of the puzzle hunting community, I will not share my solved grid here.\nIf you need help, feel free to <a href=\"mailto:rodrigo@mathspp.com\" class=\"mailto\">email me<\/a> and we can talk it over.<\/p>\n<p>P.S. if I understood correctly, in the puzzle hunting community you're not supposed to just fill in the grid.\nIn some way, somehow, you are supposed to be able to extract an English word or phrase from that filled puzzle without any extra information, and then you check that you got it correctly by <a href=\"https:\/\/puzzles.mit.edu\/2013\/coinheist.com\/rubik\/a_regular_crossword\/\" target=\"_blank\" rel=\"nofollow noopener noreferrer\" class=\"external-link no-image\">\u201cchecking your answer spoiler-free\u201d in the website where I took the regex crossword from<\/a>\nI am still stuck in that step!<\/p>","summary":"Can you solve this crossword where all hints are regular expressions?","date_modified":"2025-07-23T16:49:02+02:00","tags":["mathematics","regex"],"image":"\/user\/pages\/02.blog\/03.problems\/p066-regex-crossword\/thumbnail.webp"},{"title":"Animating a rotating spiral","date_published":"2024-07-10T00:00:00+02:00","id":"https:\/\/mathspp.com\/blog\/animating-a-rotating-spiral","url":"https:\/\/mathspp.com\/blog\/animating-a-rotating-spiral","content_html":"<p>With a couple of loops and a bit of maths you can create a rotating spiral.<\/p>\n\n<video width=\"400\" height=\"400\" poster=\"\/blog\/animating-a-rotating-spiral\/_rotating.mp4.thumb.png\" controls><source src=\"\/blog\/animating-a-rotating-spiral\/_rotating.mp4\" type=\"video\/mp4\">\n  A video animation of a colourful rotating spiral that keeps expanding and contracting and changing colour.\n<\/source><\/video><p>Following up on the concepts covered in my previous article <a href=\"\/blog\/animations-from-first-principles-in-5-minutes\">&ldquo;Animations from first principles in 5 minutes&rdquo;<\/a> and <a href=\"\/blog\/more-animations-from-first-principles-in-5-minutes\">&ldquo;More animations from first principles in 5 minutes&rdquo;<\/a>, in this article we will create the animation you can see above.<\/p>\n<p>We start by modifying the parametrisation of the circle to create a spiral:<\/p>\n<pre><code class=\"language-py\">SIDE = 600\n\ndef spiral(percentage):\n    return (\n        SIDE \/\/ 2\n        * percentage\n        * cos(10 * pi * percentage),\n        SIDE \/\/ 2\n        * percentage\n        * sin(10 * pi * percentage),\n    )<\/code><\/pre>\n<p>The <code>10<\/code> inside <code>cos<\/code>\/<code>sin<\/code> dictate how many turns the spiral does, all you have to do is divide that number by <code>2<\/code>, so a <code>10<\/code> means we do <code>5<\/code> turns around the centre of the spiral.<\/p>\n<p>You can &ldquo;easily&rdquo; put the spiral on the screen:<\/p>\n<pre><code class=\"language-py\">from itertools import product\nfrom math import sin, cos, pi\n\nimport pygame\n\nSIDE = 600\nWHITE = (255, 255, 255)\nBLACK = (0, 0, 0)\n\nscreen = pygame.display.set_mode((SIDE, SIDE))\nscreen.fill(WHITE)\n\ndef draw_pixel(screen, x, y, colour):\n    x, y = round(x), round(y)\n    for dx, dy in product(range(-1, 2), repeat=2):\n        screen.set_at((x + dx, y + dy), colour)\n\ndef spiral(percentage):\n    return (\n        SIDE \/\/ 2 * percentage * cos(10 * pi * percentage),\n        SIDE \/\/ 2 * percentage * sin(10 * pi * percentage),\n    )\n\nSTEPS = 3000\nfor step in range(STEPS + 1):\n    percentage = step \/ STEPS\n    x, y = rotating_spiral(percentage, tick \/ 10)\n    draw_pixel(screen, x, y, BLACK)\npygame.display.flip()\ninput()<\/code><\/pre>\n<p>By modifying the function <code>spiral<\/code> to accept an argument that represents time and by creating an outer loop that emulates ticking of time, we can rotate this spiral:<\/p>\n<pre><code class=\"language-py\"># ...\n\ndef spiral(percentage, time):\n    return (\n        SIDE \/\/ 2 * percentage * cos(10 * pi * percentage + time),\n        SIDE \/\/ 2 * percentage * sin(10 * pi * percentage + time),\n    )\n\n# ...\n\nSTEPS = 3000\nfor tick in count():\n    screen.fill(WHITE)\n    for step in range(STEPS + 1):\n        percentage = step \/ STEPS\n        x, y = rotating_spiral(percentage, tick \/ 10)\n        draw_pixel(screen, x, y, BLACK)\n    pygame.display.flip()<\/code><\/pre>\n<p>To make the spiral expand and contract, we must make it so that the radius has to change as time ticks:<\/p>\n<pre><code class=\"language-py\">def rotating_spiral(percentage, time):\n    return (\n        SIDE \/\/ 2\n        + (1 + sin(time) \/ 10)  # &lt;-- new\n        * percentage * (SIDE \/\/ 3) * cos(10 * pi * percentage + time),\n        SIDE \/\/ 2\n        + (1 + sin(time) \/ 10)  # &lt;-- new\n        * percentage * (SIDE \/\/ 3) * sin(10 * pi * percentage + time),\n    )<\/code><\/pre>\n<p>Finally, to add colour, we create two functions that generate the background and foreground colours for each frame instead of using the constants <code>WHITE<\/code> \/ <code>BLACK<\/code>:<\/p>\n<pre><code class=\"language-py\"># ...\n\ndef bg(time):\n    return (\n        40 + int(abs(30 * sin(0.05 * time))),\n        40 + int(abs(30 * sin(0.05 * time))),\n        40 + int(abs(30 * sin(0.05 * time))),\n    )\n\ndef...<\/code><\/pre>","summary":"With a couple of loops and a bit of maths you can create a rotating spiral.","date_modified":"2025-07-23T16:49:02+02:00","tags":["geometry","mathematics","programming","pygame","python","visualisation"],"image":"\/user\/pages\/02.blog\/animating-a-rotating-spiral\/thumbnail.webp"},{"title":"Problem #065 \u2013 clock synchronisation","date_published":"2024-01-15T00:00:00+01:00","id":"https:\/\/mathspp.com\/blog\/problems\/clock-synchronisation","url":"https:\/\/mathspp.com\/blog\/problems\/clock-synchronisation","content_html":"<p>When will these two clocks synchronise again?<\/p>\n\n<h2 id=\"problem-statement\">Problem statement<a href=\"#problem-statement\" class=\"toc-anchor after\" data-anchor-icon=\"#\" aria-label=\"Anchor\"><\/a><\/h2>\n<p>You have two digital clocks.\nOne of them just displays the hours and minutes in the format HH:MM while the other is a stopwatch that displays minutes and seconds in the format MM:SS.\nThe stopwatch wraps around at 59:59, when it goes back to 00:00.<\/p>\n<p>On a certain day at 00:00, the stopwatch is turned on.\nWhen will the clock and the stopwatch have matching displays again?\nAnd how often does that happen?<\/p>\n<div class=\"notices blue\">\n<p>Give it some thought!<\/p>\n<\/div>\n<h2 id=\"solution\">Solution<a href=\"#solution\" class=\"toc-anchor after\" data-anchor-icon=\"#\" aria-label=\"Anchor\"><\/a><\/h2>\n<p>The two clocks will have matching displays again at 01:01:01, then again at 02:02:02, 03:03:03, 04:04:04, ..., 23:23:23, so this happens 24 times per day.<\/p>\n<p>To get to this conclusion, we start by realising that the stopwatch can actually be seen as a clock that shows the current time, but without the hours.\nThus, the minutes display of the regular clock will always match the minutes display of the stopwatch.<\/p>\n<p>To recap, the two clocks have displays in the format HH:MM and MM:SS and we already know that the MM sections always match.\nThis means that for the two displays to display the same thing, we must have HH = MM = SS, which happens at 00:00:00, 01:01:01, ..., up to 23:23:23.<\/p>\n<h3 id=\"bonus-question\">Bonus question<a href=\"#bonus-question\" class=\"toc-anchor after\" data-anchor-icon=\"#\" aria-label=\"Anchor\"><\/a><\/h3>\n<p>What if the stopwatch wraps around at 99:59 instead of 59:59?<\/p>","summary":"When will these two clocks synchronise again?","date_modified":"2025-07-23T16:49:02+02:00","tags":["mathematics"],"image":"\/user\/pages\/02.blog\/03.problems\/p065-clock-synchronisation\/thumbnail.webp"},{"title":"Base conversion in Python","date_published":"2024-01-07T10:00:00+01:00","id":"https:\/\/mathspp.com\/blog\/base-conversion-in-python","url":"https:\/\/mathspp.com\/blog\/base-conversion-in-python","content_html":"<p>This article shows how to do base conversions in Python with the built-in int, how to write integer literals in other bases, and how to do base conversions in general.<\/p>\n\n<link rel=\"stylesheet\" href=\"https:\/\/unpkg.com\/@antonz\/codapi@0.12.2\/dist\/snippet.css\"><script async src=\"https:\/\/unpkg.com\/@antonz\/codapi@0.12.2\/dist\/snippet.js\"><\/script><p>In this article I'll assume you know what a number base is and how there are multiple number bases.\nMy focus will be on showing you the tools that Python provides to work with multiple number bases, an in particular with the binary, octal, decimal, and hexadecimal, number bases.<\/p>\n<h2 id=\"bases-change-the-representation-not-the-number\">Bases change the representation, not the number<a href=\"#bases-change-the-representation-not-the-number\" class=\"toc-anchor after\" data-anchor-icon=\"#\" aria-label=\"Anchor\"><\/a><\/h2>\n<p>Before diving right into the tools that Python gives you to work with different number bases I want to stress that a number base doesn't change the underlying number we're talking about, only its <em>representation<\/em>.<\/p>\n<p>For example, many people around the world have three meals per day: breakfast, lunch, and dinner.\nIt doesn't matter whether I write &ldquo;three&rdquo; in English, &ldquo;tr&ecirc;s&rdquo; in Portuguese, &ldquo;3&rdquo; in the decimal number base, or &ldquo;11&rdquo; in the binary number base.\nWe're always talking about the same number of meals: breakfast, lunch, and dinner.<\/p>\n<p>This is very important!<\/p>\n<h2 id=\"built-in-bases-for-integer-literals\">Built-in bases for integer literals<a href=\"#built-in-bases-for-integer-literals\" class=\"toc-anchor after\" data-anchor-icon=\"#\" aria-label=\"Anchor\"><\/a><\/h2>\n<p>Python (and most programming languages) let you write integer literals in the decimal number base, and we typically don't even think about it.\nPython also lets you write integer literals in three other bases:<\/p>\n<ol><li>binary;<\/li>\n<li>octal; and<\/li>\n<li>hexadecimal.<\/li>\n<\/ol><p>To write an integer literal in any base other than the decimal base, you always start your integer literal with a <code>0<\/code> followed by the letter that identifies the base.\nThis is summarised in the table below:<\/p>\n<table><thead><tr><th style=\"text-align: left;\">Base<\/th>\n<th style=\"text-align: left;\">Prefix<\/th>\n<\/tr><\/thead><tbody><tr><td style=\"text-align: left;\">binary<\/td>\n<td style=\"text-align: left;\"><code>0b<\/code><\/td>\n<\/tr><tr><td style=\"text-align: left;\">octal<\/td>\n<td style=\"text-align: left;\"><code>0o<\/code><\/td>\n<\/tr><tr><td style=\"text-align: left;\">hexadecimal<\/td>\n<td style=\"text-align: left;\"><code>0x<\/code><\/td>\n<\/tr><\/tbody><\/table><p>Thus, all four assignments below create the same integer literal:<\/p>\n<pre><code class=\"language-py\">svty_three = 73\nsvty_three_bin = 0b1001001\nsvty_three_oct = 0o111\nsvty_three_hex = 0x49<\/code><\/pre>\n<codapi-snippet sandbox=\"python\" editor=\"none\" id=\"variable_assignment\"><\/codapi-snippet><p>Because <a href=\"#bases-change-the-representation-not-the-number\">the base changes the representation but not the number<\/a>, printing any of the four variables will print <code>73<\/code>:<\/p>\n<pre><code class=\"language-py\">print(svty_three)  # 73\nprint(svty_three_bin)  # 73\nprint(svty_three_oct)  # 73\nprint(svty_three_hex)  # 73<\/code><\/pre>\n<codapi-snippet sandbox=\"python\" editor=\"basic\" depends-on=\"variable_assignment\"><\/codapi-snippet><p>In any of these bases, you can <a href=\"\/blog\/pydonts\/usages-of-underscore\">use the underscore <code>_<\/code> to group digits to make the literals more readable<\/a>.\nFor example, in the decimal base you can use the underscore <code>_<\/code> as the thousands separator:<\/p>\n<pre><code class=\"language-py\">huge_number = 17_532_546_253_000_000<\/code><\/pre>\n<h2 id=\"built-in-functions-for-base-conversion\">Built-in functions for base conversion<a href=\"#built-in-functions-for-base-conversion\" class=\"toc-anchor after\" data-anchor-icon=\"#\" aria-label=\"Anchor\"><\/a><\/h2>\n<p>Python contains 3 built-ins that let you convert integers to <em>string<\/em> representations in the three other bases:<\/p>\n<table><thead><tr><th style=\"text-align: left;\">Base<\/th>\n<th style=\"text-align: left;\">Built-in<\/th>\n<\/tr><\/thead><tbody><tr><td style=\"text-align: left;\">binary<\/td>\n<td style=\"text-align: left;\"><code>bin<\/code><\/td>\n<\/tr><tr><td style=\"text-align: left;\">octal<\/td>\n<td style=\"text-align: left;\"><code>oct<\/code><\/td>\n<\/tr><tr><td style=\"text-align: left;\">hexadecimal<\/td>\n<td style=\"text-align: left;\"><code>hex<\/code><\/td>\n<\/tr><\/tbody><\/table><p>Here's example usages of all three:<\/p>\n<pre><code class=\"language-py\">print(bin(73))  # 0b1001001\nprint(oct(73))  # 0o111\nprint(hex(73))  # 0x49<\/code><\/pre>\n<codapi-snippet sandbox=\"python\" editor=\"basic\"><\/codapi-snippet><p>Notice that these converting functions include the base prefix in the converted representation!<\/p>\n<p>If you want to use these string representations to represent the number in its base, you can discard the prefix and then convert each digit.\nThe code below uses <a href=\"\/blog\/pydonts\/list-comprehensions-101\">a list comprehension<\/a> and the built-in <code>bin<\/code> to convert an integer to a list of its binary digits:<\/p>\n<pre><code class=\"language-py\">&gt;&gt;&gt; [int(digit) for digit in bin(73)[2:]]\n[1, 0, 0, 1, 0, 0, 1]<\/code><\/pre>\n<h2 id=\"string-formatting-in-binary-octal-and-hexadecimal\">String formatting in binary, octal, and hexadecimal<a href=\"#string-formatting-in-binary-octal-and-hexadecimal\" class=\"toc-anchor after\" data-anchor-icon=\"#\" aria-label=\"Anchor\"><\/a><\/h2>\n<p>The prefix letters for the integer literals can also be used as...<\/p>","summary":"This article shows how to do base conversions in Python with the built-in int, how to write integer literals in other bases, and how to do base conversions in general.","date_modified":"2025-07-23T16:49:02+02:00","tags":["binary","mathematics","modular arithmetic","programming","python"],"image":"\/user\/pages\/02.blog\/base-conversion-in-python\/thumbnail.webp"}]}
