Epiplexis

Ambiguous slug:

gng
[
  {
    "id": "9877232c-d6e3-46c1-a140-3be13685ae82",
    "content": "",
    "description": "",
    "duration": null,
    "meta": {},
    "ownerId": "41786b7c-b873-4373-8ede-477bf85070a1",
    "publicationDate": "2024-06-15 23:40:16.340316 UTC",
    "slug": "",
    "title": "Triangle inequality",
    "type": "article"
  },
  {
    "id": "22a7b232-f4d0-492f-8249-5f2f7bf0d9f7",
    "content": "\\[ f(t) = \\cos t + i\\sin t \\]\n\n\\[\\begin{align*}\n  \\frac d{dt}\\cos t &= -\\sin t\\\\[.5em]\n  \\frac d{dt}\\sin t &=  \\cos t\n\\end{align*}\\]\n\n\\[ f'(t) = ci f(t) \\]\nfor some constant $c>0$. In fact, we have $c=1$ since blah. Thus, $f(t)$ satisfies the **initial value problem**\n\\[\\begin{aligned}\n  f'(t) &= i f(t)\\\\\n   f(0) &= 1. \\]\n\\end{aligned}\\]\n\nWe know that the unique solution to the equation\n\\[\\begin{aligned}\n  f'(t) &= k f(t)\\\\\n   f(0) &= a. \\]\n\\end{aligned}\\]\nis\n\\[ f(t) = ae^{kt} \\]\n\n\\[ e^{it} = \\cos t + i \\sin t \\]\n\nThis is known as **Euler's formula**.\n\n### A note on definitions\nDepending on your definition of $e^x$, the above equation may or may not be meaningful. There's no problem with the right-hand side: we already know what $\\cos(t)$ and $\\sin(t)$ mean for $t\\in\\R$.\n\\[ \\exp(z) = \\sum_{n=0}^\\infty \\frac{z^n}{n!} \\]\n\nIt might be better to write\n\\[ \\exp(it) = \\cos t + i\\sin t \\]\n\n## The kernel\n\n\\[ e^{\\Twopi i} = 1 \\]\n\nMore specifically,\n\n\\[ e^{i\\theta_1} = e^{i\\theta_2} \\iff \\theta_1 - \\theta_2 \\in \\Twopi\\Z \\]\n\n(rant about abelian groups?)\n\n## Trigonometric identities\n\\[\\begin{align*}\n  \\cos(\\alpha+\\beta) + i\\sin(\\alpha+\\beta)\n    &= e^{i(\\alpha+\\beta)}\\\\\n    &= e^{i\\alpha} e^{i\\beta}\\\\\n    &= (\\cos\\alpha+i\\sin\\alpha)(\\cos\\beta+i\\sin\\beta)\\\\\n    &= (\\cos\\alpha\\cos\\beta - \\sin\\alpha\\sin\\beta)+i(\\sin\\alpha\\cos\\beta+\\cos\\alpha\\sin\\beta)\n\\end{align*}\\]\n\nSetting real and imaginary parts equal to each other, we get\n\n\\[\\begin{align*}\n  \\cos(\\alpha+\\beta) &= \\cos\\alpha\\cos\\beta - \\sin\\alpha\\sin\\beta\\\\\n  \\sin(\\alpha+\\beta) &= \\sin\\alpha\\cos\\beta + \\cos\\alpha\\sin\\beta\n\\end{align*}\\]\n\n<iframe src=\"https://www.desmos.com/calculator/vtoks21fah\"></iframe>",
    "description": "",
    "duration": null,
    "meta": {},
    "ownerId": "41786b7c-b873-4373-8ede-477bf85070a1",
    "publicationDate": "2024-06-15 23:40:16.340316 UTC",
    "slug": "euler",
    "title": "Euler's formula",
    "type": "article"
  },
  {
    "id": "e3772289-b7b0-4b9c-997f-0c1e448525da",
    "content": "",
    "description": "",
    "duration": null,
    "meta": {},
    "ownerId": "41786b7c-b873-4373-8ede-477bf85070a1",
    "publicationDate": "2024-06-15 23:40:16.340316 UTC",
    "slug": "trinequality",
    "title": "Triangle inequality",
    "type": "article"
  },
  {
    "id": "3a48eda2-c609-415b-abde-76be30a97ba3",
    "content": "Define oh no\n\nis it broken",
    "description": "",
    "duration": null,
    "meta": {},
    "ownerId": "41786b7c-b873-4373-8ede-477bf85070a1",
    "publicationDate": "2024-06-15 23:40:16.340316 UTC",
    "slug": "tan",
    "title": "tan and atan2",
    "type": "article"
  },
  {
    "id": "c486f03e-b8c0-44bd-b461-f6da8656e14c",
    "content": "",
    "description": "",
    "duration": null,
    "meta": {},
    "ownerId": "41786b7c-b873-4373-8ede-477bf85070a1",
    "publicationDate": "2024-06-15 23:40:16.340316 UTC",
    "slug": "complex",
    "title": "Complex numbers",
    "type": "article"
  },
  {
    "id": "04686363-c824-4cc8-a90c-8342bac06dd5",
    "content": "",
    "description": "",
    "duration": null,
    "meta": {},
    "ownerId": "41786b7c-b873-4373-8ede-477bf85070a1",
    "publicationDate": "2024-06-15 23:40:16.340316 UTC",
    "slug": "mandelbrot",
    "title": "Mandelbrot set",
    "type": "article"
  },
  {
    "id": "bced6fd2-30fd-4fa1-8db4-1b89d8bac593",
    "content": "",
    "description": "",
    "duration": null,
    "meta": {},
    "ownerId": "41786b7c-b873-4373-8ede-477bf85070a1",
    "publicationDate": "2024-06-15 23:40:16.340316 UTC",
    "slug": "reflections",
    "title": "Reflections",
    "type": "article"
  },
  {
    "id": "04e1b41e-8fdd-4fd3-a7b5-49433e5b6b02",
    "content": "In this post and [the next](./maps) we'll introduce the idea of *functions* or *maps* between spaces. This is where things start to get more interesting and dynamic. The sequel will dive into the theoretical ideas around functions; in this post, we'll focus more concretely on how to *graph* or *plot* them.\n\n## 2d graphing\n\nIf $f\\colon\\R\\to\\R$ is a function, its :dfn[graph] is the set\n\n\\[ \\{(x, f(x)) \\mid x \\in \\R \\} \\subset \\R^2. \\]\n\nThat is, we plot the input on the horizontal axis and the output on the vertical axis.\n\nA parametric plot involves _two_ functions $g,h\\colon\\R\\to\\R;$ in this case, we visualize these using the set\n\n\\[ \\{(g(t), h(t)) \\mid t\\in \\R\\} \\subset \\R^2. \\]\n\nNote that the graph of a function is a special case of parametric plotting via\n\n\\[ g(t) = t, \\quad h(t) = f(t). \\]\n\nHowever, on a general parametric plot, it's not possible to read off the input value $t$ which produced a given output value $(x,y).$\n\n### Desmos\n\n[Desmos](https://www.desmos.com/calculator) is the best 2d graphing calculator on the internet. Here's an example of explicit and parametric plotting in Desmos:\n\n<iframe class=\"w-full\" src=\"https://www.desmos.com/calculator/gshejpaijs\" height=\"500\"></iframe>\n\nIt's also possible to use Desmos programmatically. They provide an API that will embed the calculator directly into your webpage (not an iframe!)\n\n- [Desmos API docs](https://www.desmos.com/api/v1.7/docs/index.html#self-hosting)\n\n- in a TypeScript project, you can install [`@types/desmos`](https://www.npmjs.com/package/@types/desmos)\n\n- [`desmos-react`](https://github.com/ysulyma/desmos-react) provides a React wrapper around the Desmos APIs\n\nHere's an example of using `desmos-react` to embeds Desmos in a video:\n\n<iframe class=\"w-full\" src=\"https://liqvidjs.org/r/ex-desmos/\" allowfullscreen=\"\" style=\"aspect-ratio: 16 / 10;\"></iframe>\n\n[Source](https://github.com/ysulyma/ex-desmos)\n\n### SVG and Canvas\n\nSince this is a series about programming, we want to be able to plot things programmatically, without relying on GUI tools. There are two options for doing so: [SVG](https://developer.mozilla.org/en-US/docs/Web/SVG/Tutorial) and [`<canvas>`](https://developer.mozilla.org/en-US/docs/Web/API/Canvas_API). However, plotting functions directly using the APIs (rather than a library) is a bit manual, so I'll show how to do it after we cover linear interpolation (a few posts from now).\n\nAlso, for experimenting, using a GUI tool like Desmos is usually faster.\n\n## 3d graphing\n\nThere are two kinds of plotting we can do in 3d: curves and surfaces. Curves involve _three_ functions of _one_ variable:\n\n\\[\\begin{align*}\n  x &= f(t)\\\\\n  y &= g(t)\\\\\n  z &= h(t)\n\\end{align*}\\]\n\nSurfaces involve _three_ functions of _two_ variables:\n\n\\[\\begin{align*}\n  x &= f(u, v)\\\\\n  y &= g(u, v)\\\\\n  z &= h(u, v)\n\\end{align*}\\]\n\nIn 2d, a special kind of parametric curve was the graph of a single function. Similarly, if we have a _single_ function of _two_ variables $f(x, y),$ then we can visualize it using the parametric surface\n\n\\[\\begin{align*}\n  x &= u\\\\\n  y &= v\\\\\n  z &= f(u, v)\n\\end{align*}\\]\n\n### THREE.js\n\nIn this series, we'll use [THREE.js](https://threejs.org/docs/) for all our 3d examples. I'll also (usually) use it in conjunction with [React Three Fiber](https://docs.pmnd.rs/react-three-fiber/), which provides a nice declarative way to use THREE inside React.\n\nWe use [`TubeGeometry`](https://threejs.org/docs/#api/en/geometries/TubeGeometry) to plot curves, and [`ParametricGeometry`](https://threejs.org/docs/?q=parametric#examples/en/geometries/ParametricGeometry) to plot surfaces. Here's a demonstration of using THREE.js to plot the parametric curve\n\n\\[\n  \\vcenter{\n    \\begin{align*}\n      x &= 5\\cos(4\\pi t)\\\\\n      y &= 5\\sin(4\\pi t)\\\\\n      z &= -3 + 6t\n    \\end{align*}\n  }\\qquad 0 \\le t \\le 1\n\\]\n\nand the graph of the function\n\n\\[\n  z = \\cos(x)\\sin(y),\\qquad -2\\pi \\le x,\\, y\\le 2\\pi\n\\]\n\n::embed[{epiplexis-content}/gng/01-coordinates/03-plotting/three-plotting]{aspect-ratio=2.5 inline source appDir}\n\n(I'll explain in the next chapter how I came up with these formulas.)\n\n### WebGL / WebGPU\n\nTHREE.js is a friendly API over [WebGL](https://developer.mozilla.org/en-US/docs/Web/API/WebGL_API). There's also a fancy new thing called [WebGPU](https://developer.mozilla.org/en-US/docs/Web/API/WebGPU_API). It's probably worth getting familiar with using these technologies directly. If I ever get around to doing so, I'll talk about it in this series.\n\n### Grapher\n\nIf you're on OS X, it comes with a great piece of software called Grapher. It can do 2d and 3d graphing, as well as animations; it was hugely important for me when I was learning math growing up. Here's a tutorial video I recorded on how to use it:\n\n<iframe class=\"w-full\" src=\"https://www.youtube.com/embed/2zFUeiynYqc\" style=\"aspect-ratio: 16 / 10\" allowfullscreen></iframe>\n",
    "description": "",
    "duration": null,
    "meta": {
      "math": {
        "macros": ""
      }
    },
    "ownerId": "41786b7c-b873-4373-8ede-477bf85070a1",
    "publicationDate": "2024-06-15 23:40:16.340316 UTC",
    "slug": "plotting",
    "title": "Plotting",
    "type": "article"
  },
  {
    "id": "938e7233-5626-4ba3-9f29-4f322119d471",
    "content": "So far we've talked about representing data using ($n$-tuples of) numbers. In this post I want to take a closer look at how we do this, and distinguish between two different ways of describing spaces.\n\n## Example: the unit circle\n\nLet's start with the example of the unit circle (which we are calling $S^1$). This is defined to be the set of points in the plane which are at distance 1 from the origin $(0, 0).$ Using the Pythagorean theorem (to be discussed in [the next chapter](/gng/trig/pythagoras)), this translates to\n\n\\[ \\{(x, y)\\In\\R^2 \\mid \\red{x^2 + y^2 = 1}\\}. \\]\n\n\n<iframe class=\"w-full\" src=\"https://www.desmos.com/calculator/k9frdjmhuc\" height=\"450\"></iframe>\n\nFor example, $(1,0),\\,(0, -1)$, and $\\left(\\frac{\\sqrt2}2,\\frac{\\sqrt2}2\\right)$ are in the unit circle since\n\n\\[\\begin{align*}\n  1^2 + 0^2 &= 1\\\\\n  0^2 + (-1)^2 &= 1\\\\\n  \\left(\\tfrac{\\sqrt2}2\\right)^2 + \\left(\\tfrac{\\sqrt2}2\\right)^2\n    &= \\tfrac12 + \\tfrac12\\\\\n    &= 1\n\\end{align*}\\]\nand $(0.3, 0.7)$ is not since\n\\[\\begin{align*}\n  0.3^2 + 0.7^2 &= 0.09 + 0.49\\\\\n  &= 0.58\\\\\n  &\\ne 1.\n\\end{align*}\\]\n\nSo this description of the unit circle makes it easy to _check_ whether a given point $(x, y)$ is in $S^1$ or not. But it's not easy to _come up_ with examples of points on the circle. Let's start by picking a value for $x$, e.g. $x=0.3$. We can rearrange the equation for the circle as follows:\n\n\\[\\begin{align*}\n  x^2 + y^2 &= 1\\\\\n  y^2 &= 1 - x^2\\\\\n  y &= \\pm\\sqrt{1 - x^2}\n\\end{align*}\\]\n\nIn our case $x=0.3$, the possibilities for $y$ are $\\pm0.7$. In general, once we fix a value of $x$, we get either one or two options for $y$ (one option if $1-x^2=0$, i.e. when $x=\\pm1$.\n\nHowever, not every value of $x$ is possible, since we can't take the square root of a negative number. Let's solve for the constraint on $x:$\n\n\\[\\begin{align*}\n  1 - x^2 &\\ge 0\\\\\n  1 &\\ge x^2\\\\\n  1 &\\ge |x|\n\\end{align*}\\]\nwhich is equivalent to\n\\[ -1 \\le x \\le 1 .\\]\n\nIn other words, $x\\In[-1, 1].$\n\nWe now have two maps\n\n\\[ \\fplus ,\\, \\fminus \\colon [-1, 1] \\to S^1 \\subset \\R^2 \\]\n\ngiven by\n\n\\[\\begin{align*}\n  \\fplus(x) &\\blue{{}= \\left(x, \\phantom-\\sqrt{1 - x^2}\\right)}\\\\\n  \\fminus(x) &\\purple{{}= \\left(x, -\\sqrt{1 - x^2}\\right)}\n\\end{align*}\\]\n\nWith this description, it's easy to _produce_ examples of points on the unit circle: we just plug in any value of $x$ between $-1$ and $1.$ On the other hand, it's difficult to _check_ whether a given point, say $(0.71, 0.73),$ is on the unit circle: we'd need to reverse the above derivation.\n\n<iframe class=\"w-full\" src=\"https://www.desmos.com/calculator/eu5pxeb3yb\" height=\"500\"></iframe>\n\n## Implicit, parametric, and explicit descriptions\n\nLet's generalize what we saw in the above example. \n\n:::definition\nLet $X$ be a subspace of $\\R^n;$ in the example above, $n=2$ and $X=S^1.$\n\n- an :dfn[implicit] description of $X$ is a system of equations and inequalities whose solutions are exactly $X.$  \n\n  In the above example, this was $\\red{x^2 + y^2 = 1}.$\n\n- a :dfn[local parametrization] of $X$ is a subset $U\\subset\\R^d$ along with a map $f\\colon U\\to X.$  \n\n  In the above example, $d=1,$ $U=[-1, 1],$ and both $\\fplus$ and $\\fminus$ are local parametrizations.\n\n  The _local_ is there because a local parametrization may not see all of $X,$ e.g. $\\fplus$ only sees the top half of the circle, and $\\fminus$ only sees the bottom half.\n\n- a :dfn[parametric] description of $X$ is a collection of local parametrizations of $X$ which are \"_jointly_ surjective\" in the sense that every $x\\In X$ is in the image of _at least one_ local parametrization.\n\n  In the example above, $(0, -1)$ is not in the image of $\\fplus,$ but it is in the image of $\\fminus.$\n\n- an :dfn[explicit] description is when we can isolate one variable as a (single-valued) function of the others, such as  \n  \\[ z = -y + x \\]   \n  This is both a parametric equation _and_ an implicit equation: viewing $x$ and $y$ as parameters, we can plug in any value for them and then find the necessary value of $z;$ and we can easily check whether any given $(x,y,z)$ satisfies the equation.\n:::\n\n  Being able to find an explicit description of a space is rare, since it implies that if you fix all but one coordinate, there is at most one possibility for the last coordinate. This is not true for the circle, since e.g. there are two possibilities for $(0, \\mathord ?),$ namely $(0,1)$ and $(0,-1).$ However, it's always possible to find explicit descriptions _locally_:\n  \\[ y = \\sqrt{1-x^2} \\]\n  is an explicit description of the _top half_ of the circle, even though an explicit description can't exist for the _entire_ circle.\n\nWe can think about \"solving equations\" very generally as trying to convert between implicit and parametric descriptions of a space.\n\n<table>\n  <thead>\n    <tr>\n      <th></th>\n      <th>Check membership</th>\n      <th>Produce examples</th>\n    </tr>\n  </thead>\n  <tbody>\n    <tr>\n      <th>Parametric</th>\n      <td class=\"text-red-600\">✗</td>\n      <td class=\"text-green-600\">✓</td>\n    </tr>\n    <tr>\n      <th>Implicit</th>\n      <td class=\"text-green-600\">✓</td>\n      <td class=\"text-red-600\">✗</td>\n    </tr>\n    <tr>\n      <th>Explicit</th>\n      <td class=\"text-green-600\">✓</td>\n      <td class=\"text-green-600\">✓</td>\n    </tr>\n  </tbody>\n</table>\n\n:::remark\n  A given space will admit many different parametrizations, and we often need to convert between two different parametrizations. The more common way of parametrizing the unit circle, which we will discuss in the next chapter, is by **angles**. For _nearly_ all purposes, this is a more convenient parametrization than the one we found above.\n:::\n\n:::remark\n  There are typically some other assumptions that we impose on parametrizations.\n\n  - $f$ is supposed to be \"injective away from the boundary of $U$\". I don't want to give a precise definition of this; in the case of $U=[-1, 1],$ it means we'd allow $f(-1)=f(1),$ but we'd require that $f$ be [injective](./maps#terminology) when restricted to $(-1, 1).$\n  - $U$ is supposed to be \"full-dimensional\", i.e. \"$d$-dimensional\". Again, I don't want to make this precise here, but for example a finite set of points $\\{0,0.5,1\\}$ would not be an allowed subset of $\\R^1$.\n  \n  The first condition puts an upper bound on the value of $d\\colon$ for example, there are no injective maps $\\R^2 \\to S^1$ (this is maybe intuitively true, but very hard to prove). The maximum value of $d$ is called the :dfn[dimension] of $X.$ For example, the unit circle is considered 1-dimensional (even though it lives in 2-dimensional space).\n:::\n\n## Coordinates\n\nLet me give a slightly different perspective on implicit descriptions which is more symmetric with parametric descriptions.\n\nLet's think an object in motion, e.g. a cow hurtling through the air, and freeze at a particular moment in time. Let $S$ be the space of all possible situations like this. Given such a situation $s\\In S,$ there are various quantities we can measure:\n\n- the kinetic energy $E(s)$ of the object;\n- the mass $m(s)$ of the object;\n- the speed $v(s)$ of the object.\n\nIf we pick units of measurement, (say joules for energy, kilograms for mass, and meters per second for speed), then we can view these as three maps\n\\[ E,m,v\\colon S \\to \\R. \\]\n[Recall](./maps#maps-into-a-product) that three maps $S\\to\\R$ can equivalently be viewed as a _single_ map\n\\[ (E,m,v)\\colon S\\to\\R^3. \\]\nNot every point $(x,y,z)\\In\\R^3$ can be hit by this map: physics tells us that these quantities must satisfy the constraint\n\\[ E = \\frac12 mv^2 \\]\nso we will only hit points in\n\\[ \\{ (x,y,z) \\In \\R^3 \\mid x = \\tfrac12 yz^2 \\}. \\]\n\n:::definition\n  A :dfn[coordinate] on a space $S$ is a map $S\\to\\R.$\n  \n  A :dfn[coordinate system] is a collection of coordinates $x_1,\\dotsc,x_n\\colon S\\to \\R$ such that the induced map\n  \\[ (x_1,\\dotsc,x_n)\\colon S\\to \\R^n \\]\n  is injective.\n:::\n\nIn many cases, it is difficult to find a \"global\" coordinate system, but we may be able to find a _local_ coordinate system\n\\[ (x_1, \\dotsc, x_n) \\colon U \\to \\R^n \\]\nwhere $U\\subset S$ is a subset of $S$ (similar to local parametrizations, above).\n\nThe upshot of this discussion is that we can view parametrizations of $X$ as maps $\\R^n\\to X,$ and coordinate systems on $X$ as maps $X\\to\\R^n.$ This also applies to local parametrizations/coordinate systems if we allow a subspace $U\\subset X$ in place of the entire $X.$\n\n## Marching squares / cubes\n\nWe won't be able to solve every system of equations algebraically---in fact, it's extremely rare that we can. So how can we visualize spaces that are given to us implicitly?\n\nWe take advantage of the fact that it's easy to _test_ whether a given point belongs to an implicitly defined subspace. Let's take the example\n\\[ 2y(y^{2}-3x^{2})(1-z^{2})+(x^{2}+y^{2})^{2}-(9z^{2}-1)(1-z^{2})=0 \\]\n(I just took this example from Wikipedia). If we plug in the point $(0.5,0.9,0.9),$ the left-hand side works out to $\\approx-0.051.$ That means this point is _not_ in $S$. But $-0.051$ is _close_ to $0$, so there's probably a point _near_ $(0.5,0.9,0.9)$ which _is_ in $S.$\n\nTherefore, we can try to graph an implicit equation as follows. We'll restrict our attention to some box, like the cube $[-1,1]^3$; maybe we know ahead of time that our space is contained in this box, or maybe it's not and we'll only be graphing part of it. We can subdivide this box, take a bunch of sample points from it, and plug them into our equation. Our sample points will almost certainly not satisfy the equation, but we can use how close/far they are from satisfying the equation to get a good idea of what our shape must look like.\n\nThe :dfn[marching squares] / :dfn[marching cubes] algorithms are sophisticated implementations of this basic idea. They let us graph implicitly defined shapes _without_ finding a parametrization, and are used internally by tools like [Desmos and Grapher](./plotting). We need to cover a bit more math in order to fully understand how these algorithms work, but I can give you source code right now:\n\n::embed[{epiplexis-content}/gng/01-coordinates/05-params-coords/implicit]{appDir aspect-ratio=1.5 inline source}\n",
    "description": "",
    "duration": null,
    "meta": {
      "math": {
        "macros": "\\newcommand{\\fplus}{\\blue{f_+}}\n\\newcommand{\\fminus}{\\purple{f_-}}"
      }
    },
    "ownerId": "41786b7c-b873-4373-8ede-477bf85070a1",
    "publicationDate": "2024-06-15 23:40:16.340316 UTC",
    "slug": "params-coords",
    "title": "Parameters & Coordinates",
    "type": "article"
  },
  {
    "id": "6a4ab0e5-92e6-4921-9520-d00e20c2cb3d",
    "content": "<iframe allow=\"fullscreen\" class=\"w-full\" src=\"https://epiplexis.xyz/a/8xw/lesson/\" style=\"aspect-ratio: 8/5;\"></iframe>\n\nTODO input article",
    "description": "",
    "duration": null,
    "meta": {
      "math": {
        "macros": ""
      }
    },
    "ownerId": "41786b7c-b873-4373-8ede-477bf85070a1",
    "publicationDate": "2024-06-15 23:40:16.340316 UTC",
    "slug": "rotations",
    "title": "Rotations",
    "type": "article"
  },
  {
    "id": "9d312ac2-d367-49c2-be34-c931e1db8806",
    "content": "Previously, we learned to calculate the length of vectors in $\\VecR n$, and thus the distance between *points* in $\\AffR n$. It's often useful to express a vector in terms of its __length__ and its _direction_.\n\nLet's start by defining direction.\n\n:::definition\nA vector $u\\In\\VecR n$ is said to be a :dfn[unit vector] if $\\Norm u=1$. A unit vector is also called a :dfn[direction].\n:::\n\nIf $v\\In\\VecR n$ is any _nonzero_ vector, its _direction_ is\n\n\\[ \\Dir v \\Defeq \\frac v{\\Norm v} \\]\n\nThis is also called the :dfn[normalization] of $v$. By definition, we have\n\n\\[ v = \\Norm v \\Dir v, \\]\n\nwhich expresses $v$ as its direction times its length. The $0$ vector has no direction.\n\n:::example\n  \\[ v = \\begin{bmatrix*}[r]-1\\\\2\\\\2\\\\0\\end{bmatrix*} \\]\n  :::solution\n  The length of $v$ is\n  \\[\\begin{aligned}\n  \\Norm v &= \\sqrt{(-1)^2 + 2^2 + 2^2 + 0^2}\\\\\n  &= \\sqrt9\\\\\n  &= 3\n  \\end{aligned}\\]\n  Thus\n  \\[ \\Dir v = \\begin{bmatrix*}[r]-1/3\\\\2/3\\\\2/3\\\\0\\end{bmatrix*} \\]\n:::\n\n## Spheres\n\nWe can now give a formal definition of one of the most important spaces in geometry: the $n$-sphere. This is defined to be the set of unit vectors in $\\VecR{n+1}$:\n\n\\[\\begin{aligned}\n  \\S n\n    &\\Defeq \\{v\\In\\VecR{n+1} \\mid \\Norm v = 1\\}\\\\\n    &= \\left\\{\\ivec{x_0,\\dotsc,x_n}\\In\\VecR{n+1} \\mid \\sqrt{\\sum_{i=0}^n x_i^2} = 1\\right\\}\n\\end{aligned}\\]\n\nSince $1^2 = 1$, this is equivalent to\n\n\\[ \\S n = \\left\\{\\ivec{x_0,\\dotsc,x_n} \\In \\VecR{n+1} \\mid \\sum_{i=0}^n x_i^2 = 1\\right\\}\\]\n\nNote the shift in indexing: $\\S1\\subset\\VecR 2$ is the usual unit circle in 2d, while $\\S2\\subset\\VecR3$ is the usual unit sphere in 3d.\n\nIt's worth looking at the edge case\n\\[\\begin{aligned}\n  \\S 0 &= \\{v\\In\\VecR1 \\mid \\Norm v = 1\\}\\\\\n      &= \\{\\pm1\\} \\subset \\R\n\\end{aligned}\\]\n\nThat is, the $0$-sphere consists of exactly two points! While this may seem strange, it fits nicely into a pattern about spheres in general:\n\n- every \"slice\" or \"cross-section\" of $\\S2$ is a $1$-sphere, except for the \"north and south poles\" $\\ivec{0,0,\\pm1}$.\n\n  <iframe class=\"w-full mx-auto\" src=\"https://www.desmos.com/3d/24d3d54b26?embed\" height=\"500\"></iframe>\n\n- every \"slice\" or \"cross-section\" of $\\S1$ is a $0$-sphere, except for the \"north and south poles\" $\\ivec{0,\\pm1}$;\n\n  <iframe class=\"w-full mx-auto\" src=\"https://www.desmos.com/calculator/baghu7bqdv?embed\" height=\"500\"></iframe>\n\nLet's prove this in general! This is a nice example of how we can use mathematical formalism to prove statements in $n$ dimensions based on our intuition in $\\le 3$ dimensions.\n\n:::proposition\n  Consider the cross section\n  \\[ S^n_t \\Defeq \\{\\ivec{x_0,\\dotsc,x_n}\\In S^n \\mid x_n = t \\} \\]\n  Then $S^n_t$ consists of a single point when $t=\\pm1$, and is isomorphic to $S^{n-1}$ when $|t|<1$.\n  \n  :::proof\n  \n  By definition,\n  \\[ S^n_t = \\{\\ivec{x_0,\\dotsc,x_{n-1},t} \\In \\VecR{n+1} \\mid \\sum_{i=0}^{n-1} x_i^2 + t^2 = 1\\} \\]\n  Let $v=\\ivec{x_0,\\dotsc,x_{n-1}} \\In \\VecR n$. We can rearrange the above condition to\n  \\[\\begin{aligned}\n    \\sum_{i=0}^{n-1} x_i^2 &= 1-t^2\\\\\n    \\sqrt{\\sum_{i=0}^{n-1} x_i^2} &= \\sqrt{1-t^2}\\\\\n    \\Norm v &= \\sqrt{1-t^2}\n  \\end{aligned}\\]\n  When $t=\\pm1$, this becomes $\\Norm v=0$, which implies $v=0$. This means that $S^n_t$ consists of the single point\n  \\[ \\ivec{0,\\dotsc,0,t}. \\]\n  When $|t|<1$, we have that $S^n_t$ is isomorphic to the sphere of radius $\\sqrt{1-t^2}$ in $\\VecR n$.\n:::\n\n## Parametrization\n\nWe can use the defining equation of $\\S n$ to find a parametrization of it. Let's start with the case of $\\S1$. Its defining equation is\n\n\\[ x^2 + y^2 = 1 \\]\n\nLet's rearrange this to solve for $y$ in terms of $x$:\n\n\\[\\begin{aligned}\n  x^2 + y^2 &= 1\\\\\n  y^2 &= 1 - x^2\\\\\n  y^2 &= \\pm\\sqrt{1 - x^2}\n\\end{aligned}\\]\n\nSo we can take $x=t$ as our parameter variable. We also need to find the domain of $t$ (equivalently $x$). Remember that we can only take square roots of non-negative numbers. So we need to have\n\n\\[\\begin{aligned}\n  0 &\\le 1-x^2\\\\\n  x^2 &\\le 1\\\\\n  |x| &\\le 1\n\\end{aligned}\\]\nor equivalently\n\\[ -1 \\le x \\le 1. \\]\n\nLet's try this in Desmos:\n<iframe class=\"w-full mx-auto mt-2 mb-4\" src=\"https://www.desmos.com/calculator/km7gkuq0ra?embed\" height=\"500\"></iframe>\n\n<iframe class=\"w-full mx-auto my-2\" src=\"https://www.desmos.com/3d/687d619b00?embed\" height=\"500\"></iframe>\n",
    "description": "",
    "duration": null,
    "meta": {
      "math": {
        "macros": ""
      }
    },
    "ownerId": "41786b7c-b873-4373-8ede-477bf85070a1",
    "publicationDate": "2024-06-15 23:40:16.340316 UTC",
    "slug": "unit-vectors",
    "title": "Unit vectors",
    "type": "article"
  },
  {
    "id": "e644f2c2-617f-4bd0-87b2-98e16a467c6d",
    "content": "## Distance\n\n::unit[pythagoras]\n\n::unit[unit-vectors]\n\n::unit[arclength]\n\n## Trig functions\n::unit[cos-sin]\n\n::unit[rotations]\n\n::unit[2x2-matrices]",
    "description": "",
    "duration": null,
    "meta": {
      "math": {
        "macros": ""
      }
    },
    "ownerId": "41786b7c-b873-4373-8ede-477bf85070a1",
    "publicationDate": "2024-06-15 23:40:16.340316 UTC",
    "slug": "trig",
    "title": "Trigonometry",
    "type": "collection"
  },
  {
    "id": "3ff98f24-6b94-4fef-9cf4-1ce3be1993ba",
    "content": "The Pythagorean theorem allowed us to calculate the length of straight line segments. In this post, we'll see how to extend this to calculate the length of _curved_ paths.\n\nLet's consider this curved path:\n\n::embed[{epiplexis-content}/gng/02-trigonometry/03-arclength/curve]{class=my-4 inline width=80%}\n\nWe can sample points along this curve and connect them by line segments:\n\n::embed[{epiplexis-content}/gng/02-trigonometry/03-arclength/approx]{class=my-4 inline source}\n\nThe result is a \"piecewise linear\" curve, shown in red. Since each piece of this is a line segment, we can calculate its length by applying the Pythagorean theorem to each segment and summing the results.\n\nAs we increase the density of the sample points, the piecewise linear curve becomes a better and better approximation of the original curve, and is length becomes a better and better approximation of the length of the original curve.\n\nWe can do the same thing in three dimensions:\n\n::embed[{epiplexis-content}/gng/02-trigonometry/03-arclength/3d]{aspect-ratio=2 class=my-4 inline source}\n\nThere are several delicate questions raised by this procedure.\n\n- Are we calculating the \"true\" answer, or just approximations to it?\n\n- If we sample points differently, will we get a different answer?\n\n- If we use a different [parametrization](/gng/cg/params-coords) of the same curve, does the answer change?\n\nThe first point gets at the heart of what \"real numbers\" actually are. Think about how we use numbers in practice: we might only care about the value within $0.01$. If the values produced by the algorithm are guaranteed to stay within that error tolerance once the number of steps is big enough, we can use any of the values beyond that point as our answer.\n\nA thorough answer to these questions involves **limits**, which we'll discuss in Chapter 5.\n\n<!-- define this in earlier unit I guess -->\n\n## Arclength parametrization\n\nRecall that a _curve_ $C$ in $\\AffR n$ is the image of _some_ map\n\n\\[ f\\colon \\CIntvl ab \\to \\AffR n \\]\n\nA choice of such an $f$ is called a _parametrization_ of the curve $C$. For example, we can pre-compose $f$ with an easing function to get many other parametrizations.\n\nA curve has lots and lots of different parametrizations; which one is best depends on the situation at hand and the nature of the curve. However, every curve has a _canonical_ parametrization, called the :dfn[arclength] parametrization, and this is usually the best option. The definition is as follows:\n\n:::definition\n  Let $C$ be an oriented curve from $P$ to $Q$ in $\\AffR n$. Suppose the arclength of $C$ is $s$. The :dfn[arclength parametrization] of $C$ is the function\n  \\[ f\\colon \\CIntvl 0s \\to \\AffR n \\]\n  such that the image of $f$ is $C$, and the arclength of the restriction $\\Restrict{f}{[0;t]}$ is $t$.\n:::\n\n:::example\n  Find the arclength parametrization of the line segment from $\\ipt{1,1}$ to $\\ipt{2,3}$ in $\\AffR 2$.\n  \n  :::solution\n  Let's start by finding the arclength. Since this is a straight line segment, the length is\n  \\[\\begin{align*}\n    \\|\\ipt{2,3} - \\ipt{1,1}\\|\n      &= \\|\\ivec{1, 2}\\|\\\\\n      &= \\sqrt{1^2 + 2^2}\\\\\n      &= \\sqrt5\n  \\end{align*}\\]\n  So the arclength parametrization is going to be parametrized on $\\CIntvl 0{\\sqrt5}$. Let's start with the parametrization given by linear interpolation,\n  \\[\\begin{align*}\n    f(t)\n      &= \\ipt{1, 1} + t(1, 2) & t&\\in\\CIntvl01\\\\\n      &= \\ipt{1+t,1+2t}\n  \\end{align*}\\]\n  To reparametrize this to $\\CIntvl0{\\sqrt5}$, we pre-compose with the map\n  \\[\\begin{align*}\n    g\\colon\\CIntvl0{\\sqrt5} &\\xrightarrow\\sim \\CIntvl01\\\\\n    g(t) &= \\frac t{\\sqrt5}\n  \\end{align*}\\]\n  The final arclength parametrization is therefore\n  \\[\\begin{align*}\n    s(t)\n      &= \\ipt{1, 1} + \\frac t{\\sqrt5}\\ivec{1,2} &t&\\in\\CIntvl0{\\sqrt5}\\\\\n      &= \\ipt{1+\\frac t{\\sqrt5}, 1+\\frac{2t}{\\sqrt5}}\n  \\end{align*}\\]\n:::\n\nLater, we will learn to find the arclength parametrization of more complicated curves; however, it is usually not possible to find an exact formula. It is doable by computer, however. As the above example shows, even in cases when we can find an exact formula for the arclength parametrization, it is often ugly (when written out in full).\n\n## APIs\n\n- [`getTotalLength()`](https://developer.mozilla.org/en-US/docs/Web/API/SVGGeometryElement/getTotalLength)\n- [`getPointAtLength()`](https://developer.mozilla.org/en-US/docs/Web/API/SVGGeometryElement/getPointAtLength)\n\n## Exercises\n\n1. In [Parameters and coordinates](/gng/cg/params-coords#example-the-unit-circle), we found a parametrization of the unit circle given by\n\n\\[\n  f_+(x) = \\ivec{x,\\sqrt{1 - x^2}},\\qquad\n  f_-(x) = \\ivec{x,-\\sqrt{1 - x^2}}\n\\]\n\nUsing this parametrization, write code to calculate (approximate) the arclength of the unit circle.\n\n```js\n// !interactive\n/** Parametrization of the top half of the unit circle. */\nconst unitSemiCircle = (t) => [t, Math.sqrt(1 - t ** 2)];\n\n/**\n * Compute the arclength of a parametrized curve.\n * @param f Parametrization of the curve\n * @param a Starting point\n * @param b Ending point\n * @param samples Number of samples\n */\nfunction arclength(f, a, b, samples) {\n  let sum = 0;\n  const mesh = (b - a) / samples;\n  for (let i = 0; i < samples; ++i) {\n    const ti = a + i * mesh;\n    const tNext = ti + mesh;\n    const [x, y] = f(ti);\n    const [xNext, yNext] = f(tNext);\n    sum += Math.hypot(xNext - x, yNext - y);\n  }\n  return sum;\n}\n\n// since it is a bit messy to combine the parametrizations of the top\n// and bottom halves of the unit circle into a single parametrization,\n// we will calculate the arclength of just the top half and multiply\n// that by 2\nconsole.log(2 * arclength(unitSemiCircle, -1, 1, 10_000));\n```\n",
    "description": "",
    "duration": null,
    "meta": {
      "math": {
        "macros": ""
      }
    },
    "ownerId": "41786b7c-b873-4373-8ede-477bf85070a1",
    "publicationDate": "2024-06-15 23:40:16.340316 UTC",
    "slug": "arclength",
    "title": "Arclength",
    "type": "article"
  },
  {
    "id": "54d3cfd7-e370-43ba-a0c4-201922ec154b",
    "content": "::unit[spaces]\n\n::unit[products]\n\n::unit[plotting]\n\n::unit[maps]\n\n::unit[params-coords]\n\n::unit[points-vectors]\n\n::unit[dragging]",
    "description": "",
    "duration": null,
    "meta": {
      "math": {
        "macros": ""
      }
    },
    "ownerId": "41786b7c-b873-4373-8ede-477bf85070a1",
    "publicationDate": "2024-06-15 23:40:16.340316 UTC",
    "slug": "cg",
    "title": "Coordinate geometry",
    "type": "collection"
  },
  {
    "id": "4b5cebea-f831-4e18-92ab-b57bea11e359",
    "content": "<!-- #tab notes -->\n\n:::yell\n  $\\cos$ and $\\sin$ are what you use when you want to draw a circle, or animate something moving in a circle.\n:::\n\nIn the post on [unit vectors](./unit-vectors), we defined the unit $n$-sphere and found a parametrization of it. In the [previous post](./arclength), we encountered the **arclength parametrization**, which for most purposes is more convenient than other parametrizations. In this post, we discuss the arclength parametrization of the unit circle $\\cl{S}{S^1}$, which is given by the $\\cos$ and $\\sin$ functions. This will be useful for drawing things along a circle or animating something that's rotating.\n\n## Radians\n\nWe need to start by naming the length of the unit circle.\n\n:::definition\n  We write $\\Twopi$ (pronounced either \"circle\", \"var-pi\", or \"two-pi\") for the arclength, or :dfn[circumference], of the unit circle\n  \\[ \\cl{S}{S^1} \\Defeq \\{(x, y) \\in \\VecR2 \\mid x^2 + y^2 = 1 \\}. \\]\n  In the [exercises](./arclength#exercises) of the previous unit, you calculated that $\\Twopi\\approx6.28\\dotsc$\n:::\n\nBy scaling, it follows that the circumference of a circle of radius $r$ is given by $\\Twopi r$. For example, the circumference of a circle of radius $4$ is $4\\Twopi\\approx25.13\\dots$. Equivalently, we could define $\\Twopi$ as the ratio of _any_ circle's circumference to its radius.\n\n:::remark\n  You may be more used to the constant $\\pi=\\Twopi/2\\approx3.14\\dots$, which is the ratio of a circle's circumference to its **diameter** (twice the radius). It turns out the ancient Greeks made a mistake in defining $\\pi$: while diameter is relevant in real-life situations, mathematically it's much more convenient to index circles by their radius rather than their diameter.\n  \n  This is not something to get too worked up about, however: although $\\Twopi$ is an important number, numbers are not that important in mathematics.\n  \n  Many sources use the letter $\\tau$ instead of $\\varpi$. This is patently absurd: on top of having completely the wrong vibes to be a circle constant, $\\tau$ is a B-tier Greek letter while $\\Twopi$ is an S-tier constant.\n:::\n\n## cos and sin\n\n:::definition\n  We define the functions $\\cos$ and $\\sin$ such that\n  \\[ \\ivec{\\cos\\theta,\\, \\sin\\theta}, \\qquad \\theta\\in \\ClsdIntvl0{\\twopi} \\]\n  is the arclength parametrization of the unit circle $\\cl{S}{S^1}$, starting at the point $\\ivec{1,0}$ and traveling counterclockwise. Equivalently, $\\ivec{\\cos\\theta,\\sin\\theta}$ is the $\\ivec{x,y}$-coordinates of the point at angle $\\theta$ from the origin.\n:::\n\nHere's a graph to experiment with that.\n\n<iframe class=\"w-full my-4\" height=\"500\" src=\"https://www.desmos.com/calculator/9v62whmuxi\"></iframe>\n\nThis completely defines $\\cos$ and $\\sin$, but doesn't tell us how to compute them. However, in just a few posts we'll derive an algorithm to compute these.\n\nYou may be used to a definition of $\\cos$ and $\\sin$ in terms of ratios of right-angle triangles; I'll review that interpretation [below](#triangle-interpretation). That interpretation is often useful, but it doesn't work for angles larger than $90^\\circ$.\n\n## Animation\n\nLet's say more about animation. So far, $\\cos$ and $\\sin$ tell us how to parametrize the unit circle, i.e. the circle of radius $1$ centered at the origin $\\O=(0,0)$. What about other circles?\n\nLet's do this in steps. First, let\n\\[ \\cl S{S^1}(r) = \\{v\\in\\VecR2 \\mathrel: \\|v\\| = r \\} \\]\nbe the circle of radius $r$ centered at the origin. We have\n\\[\\begin{align*}\n  \\cl S{S^1}(r)\n    &\\phantom:= r \\cl S{S^1}\\\\\n    &\\Defeq \\{rv \\mid v\\in \\cl S{S^1}\\}\n\\end{align*}\\]\nso can parametrize this by\n\\[ r\\ivec{\\cos t,\\sin t} = \\ivec{r\\cos t,r\\sin t}, \\qquad t\\in\\CIntvl0\\twopi. \\]\n\nNext, let's consider circles centered at other points. For a point $P\\in\\AffR2$ and a radius $r>0$, let\n\\[ \\cl S{S^1}(P,r) \\Defeq \\{Q \\in \\AffR2 \\colon \\|P-Q\\| = r \\} \\]\nbe the circle of radius $r$ centered at $P$. Note that $\\cl S{S^1}(r)$ lives in the _vector_ space $\\VecR2$, while $\\cl S{S^1}(P,r)$ lives in the _affine_ space $\\AffR2$; recall that \"the origin\" is a feature of _vector_ space. We can get $\\cl S{S^1}(P, r)$ by **translating** $\\cl S{S^1}(r)$ to the point $P$: in other words,\n\\[\\begin{align*}\n  \\cl S{S^1}(P, r)\n    &\\phantom:= P + \\cl S{S^1}(r)\\\\\n    &\\Defeq \\{P + v \\mid v \\in \\cl S{S^1}(r) \\}\n\\end{align*}\\]\nTherefore, a parametrization of $\\cl S{S^1}(P, r)$ is given by\n\\[ P+r\\ivec{\\cos t,\\sin t} = \\ipt{\\cl{p}{p_1}+r\\cos t,\\cl{p}{p_2}+r\\sin t}, \\qquad t\\in\\CIntvl0\\twopi, \\]\nwhere $P=\\ipt{\\cl{p}{p_1},\\cl{p}{p_2}}$.\n\nThat does everything we need if we want to draw a circle (or a part of a circle). Often though, we want to **animate** something moving in a circle. This means we need to further take into account its **speed** (or **angular velocity**) and its **starting position**.\n\nBy default, $(\\cos t,\\sin t)$ starts at $(1,0)$ and goes around the circle one every $\\Twopi$ units of time, going counterclockwise. To have it start at a different angle $\\cl{θ}{\\theta_0}$, we just add that on to $t$:\n\n\\[ \\ivec{\\cos(\\cl{θ}{\\theta_0} + t), \\sin(\\cl{θ}{\\theta_0} + t)} \\]\n\nTo change the speed, we multiply $t$ by a constant. For example, if $t$ is measured in seconds and we want to go around the circle once every two seconds, we'd use\n\n\\[ \\ivec{\\cos\\left(\\cl{θ}{\\theta_0}+\\frac{\\Twopi t}2\\right), \\sin\\left(\\cl{θ}{\\theta_0}+\\frac{\\Twopi t}2\\right)} \\]\n\nsince going around the circle once every two seconds is the same as going halfway around the circle every second. We can also scale by a negative number to go clockwise instead of counter-clockwise.\n\nTo summarize:\n\n:::proposition\n  The parametrization of a particle travelling:\n  - on a circle of radius $r$\n  - centered at the point $P=\\ipt{\\cl{p}{p_1},\\cl{p}{p_2}}$\n  - starting from angle $\\cl{θ}{\\theta_0}$\n  - making $k$ (counter-clockwise) rotations per unit of time $t$\n  \n  is given by\n  \\[\n    P + r\\ivec{\\cos(\\cl{θ}{\\theta_0}+\\Twopi kt), \\sin(\\cl{θ}{\\theta_0}+{\\Twopi}kt)}\n  \\]\n  which is the same as\n  \\[\n    \\ipt{\\cl{p}{p_1}+r\\cos(\\cl{θ}{\\theta_0}+\\Twopi kt), \\cl{p}{p_2}+r\\sin(\\cl{θ}{\\theta_0}+\\Twopi kt)}.\n  \\]\n:::\n\nHere's some code to try that out:\n\n```tsx\n// !interactive\nimport { useEffect, useRef } from \"react\";\n\n/** Point in 2-dimensional (affine) space */\ntype Pt2 = [number, number];\n\ntype Circle = {\n  /** Measured in [0, 100] x [0, 100] and mapped onto the actual screen later */\n  center: Pt2;\n  radius: number;\n};\n\nconst SECONDS = 1000,\n  MINUTES = 60 * SECONDS;\n\nconst CIRCLE = 2 * Math.PI;\n\n// scene setup\nexport default function Graph() {\n  const items: MovingProps[] = [\n    {\n      children: \"👻\",\n      circle: {\n        center: [50, 50],\n        radius: 25,\n      },\n      rpm: 45,\n    },\n    {\n      children: \"😈\",\n      circle: {\n        center: [25, 25],\n        radius: 20,\n      },\n      // negative to go clockwise\n      rpm: -30,\n    },\n    {\n      children: \"😍\",\n      circle: {\n        center: [75, 40],\n        radius: 10,\n      },\n      rpm: 15,\n    },\n    {\n      children: \"😡\",\n      circle: {\n        center: [30, 60],\n        radius: 20,\n      },\n      rpm: -60,\n    },\n    {\n      children: \"😡\",\n      circle: {\n        center: [70, 60],\n        radius: 20,\n      },\n      // so it will collide with the other one\n      initialAngle: CIRCLE / 2,\n      rpm: 60,\n    },\n  ];\n\n  return (\n    <main>\n      {items.map((props) => (\n        <Moving key={JSON.stringify(props)} {...props} />\n      ))}\n    </main>\n  );\n}\n\n// moving divs\ninterface MovingProps {\n  children: React.ReactNode;\n  circle: Circle;\n\n  /**\n   * Initial angle.\n   * @default 0\n   */\n  initialAngle?: number;\n  \n  /** Revolutions per minute. */\n  rpm: number;\n}\n\nfunction Moving({ children, circle, initialAngle = 0, rpm }: MovingProp) {\n  const ref = useRef<HTMLDivElement>(null);\n\n  useEffect(() => {\n    const start = performance.now();\n\n    let cancelId: number;\n\n    // update handler\n    const update = (t: number) => {\n      if (!ref.current) return;\n\n      const angle = initialAngle + ((CIRCLE * (t - start)) / MINUTES) * rpm;\n      const [x, y] = toScreenCoords(getCoords(circle, angle));\n\n      // we want to position the center rather than the top-left corner\n      const rect = ref.current.getBoundingClientRect();\n      ref.current.style.transform = `translate(\n        ${x - rect.width / 2}px,\n        ${y - rect.height / 2}px\n      )`;\n\n      cancelId = requestAnimationFrame(update);\n    };\n\n    // start animation loop\n    cancelId = requestAnimationFrame(update);\n\n    // cancel animation loop on unmount\n    return () => cancelAnimationFrame(cancelId);\n  }, []);\n\n  return (\n    <div className=\"w-min text-3xl absolute\" ref={ref}>\n      {children}\n    </div>\n  );\n}\n\n/** Get the coordinates of a point on a circle. */\nfunction getCoords(circle: Circle, angle: number): Pt2 {\n  const {\n    center: [cx, cy],\n    radius: r,\n  } = circle;\n\n  // we subtract in the second coordinate because screen y-axis\n  // goes down while math y-axis goes up\n  return [cx + r * Math.cos(angle), cy - r * Math.sin(angle)];\n}\n\n/** Map [0, 100] x [0, 100] onto the actual screen dimensions */\nfunction toScreenCoords([x, y]: Pt2) {\n  return [(window.innerWidth * x) / 100, (window.innerHeight * y) / 100];\n}\n```\n\n## Triangle interpretation\n\nYou may be more used to a definition of $\\cos$ and $\\sin$ in terms of ratios of angles of right-angle triangles.\n\n<div className=\"flex items-center w-2/3 mx-auto\">\n  <svg class=\"mx-auto flex-1\" viewBox=\"0 0 250 100\">\n    <path\n      class=\"stroke-black dark:stroke-white fill-none\"\n      d=\"M 5 80 l 195 -75 v 75 z\"\n    />\n    <g class=\"dark:fill-white\">\n      <text\n        x=\"40\" y=\"80\" dx=\"3\" dy=\"-3\"\n        fill=\"mediumpurple\"\n        font-family=\"KaTeX_Math\"\n        font-size=\"12\"\n      >θ</text>\n      <text\n        text-anchor=\"start\"\n        font-family=\"KaTeX_Main\"\n        transform=\"translate(208, 6) rotate(90)\"\n      >opposite</text>\n      <text\n        x=\"100\" y=\"95\" dy=\"1\"\n        dominant-baseline=\"text-top\" text-anchor=\"middle\"\n        font-family=\"KaTeX_Main\"\n      >adjacent</text>\n      <text\n        font-family=\"KaTeX_Main\"\n        dominant-baseline=\"text-bottom\" text-anchor=\"middle\"\n        transform=\"translate(100, 38) rotate(${Math.atan2(-75, 195) * 180 / Math.PI})\">hypotenuse</text>\n    </g>\n  </svg>\n  <katex class=\"mx-auto text-xl\" display>\n    \\begin{aligned}\n      \\cos\\theta &= \\frac{\\text{adjacent}}{\\text{hypotenuse}}\\\\\n      \\sin\\theta &= \\frac{\\text{opposite}}{\\text{hypotenuse}}\n    \\end{aligned}\n    </katex>\n</div>\n\nThis perspective is often useful, but it doesn't work for angles larger than $90^\\circ$.\n\nHow does this relate to coordinates of points on the unit circle? First, note that for any point on a circle, we can form a right-angle triangle whose hypotenuse is the line segment from the center of the circle to that point (see below). In the case of the unit circle, \n\n\n<iframe class=\"w-full my-4\" height=\"500\" src=\"https://www.desmos.com/calculator/kzhc0ynx0k\"></iframe>\n\n## Special angles\n\nAlthough we don't yet have a general algorithm for computing $\\cos$ and $\\sin$, we can read off the values of the coordinates of East $(0)$, North $(90^\\circ=\\frac\\Twopi4)$, West $(180^\\circ=\\frac\\Twopi2)$, and South $(270^\\circ=\\frac{3\\Twopi}4$).\n\\[\\begin{align*}\n  \\ivec{\\cos0,\\,\\sin0} &= \\ivec{1,0} &\n  \\ivec{\\cos\\frac\\Twopi2,\\,\\sin\\frac\\Twopi2} &= \\ivec{-1,\\, 0}\\\\[.5em]\n  \\ivec{\\cos\\frac\\Twopi4,\\,\\sin\\frac\\Twopi4} &= \\ivec{0,\\, 1} &\n  \\ivec{\\cos\\frac{3\\Twopi}4,\\,\\sin\\frac{3\\Twopi}4} &= \\ivec{0,\\, -1}\n\\end{align*}\\]\n\nWith a bit more work, we can calculate the coordinates of the point at $45^\\circ$, using the triangle interpretation above.\n\n<svg class=\"mx-auto\" width=\"200\" viewBox=\"0 0 110 110\">\n  <g class=\"fill-none stroke-black dark:stroke-white\">\n    <path d=\"M 5 95 l 90 -90 v 90 z\" />\n    <path d=\"M 85 95 v -10 h 10\" />\n  </g>\n  <g class=\"dark:fill-white\">\n    <text\n      x=\"20\" y=\"90\" dx=\"3\" dy=\"-3\"\n      font-family=\"KaTeX_Math\"\n      font-size=\"11\"\n    >45°</text>\n    <text\n      x=\"50\" y=\"100\" dy=\"5\"\n      font-family=\"KaTeX_Math\"\n      font-size=\"11\"\n      dominant-baseline=\"text-top\"\n      text-anchor=\"middle\"\n    >x</text>\n    <text\n      x=\"100\" y=\"50\"\n      font-family=\"KaTeX_Math\"\n      font-size=\"11\"\n      dominant-baseline=\"middle\"\n      text-anchor=\"start\"\n    >x</text>\n    <text\n      x=\"50\" y=\"50\" dx=\"-10\" dy=\"-10\"\n      font-family=\"KaTeX_Math\"\n      font-size=\"12\"\n      dominant-baseline=\"middle\"\n      text-anchor=\"middle\"\n    >1</text>\n  </g>\n</svg>\n\nSince the angles of a triangle add up to $180^\\circ=\\Twopi/2$, the remaining angle is also $45^\\circ=\\Twopi/8$. This implies that the two side lengths $\\cos45^\\circ$ and $\\sin45^\\circ$ are equal; let's call that $x$. By the Pythagorean theorem,\n\\[\\begin{align*}\n  \\cos(45^\\circ)^2 + \\sin(45^\\circ)^2 &= 1\\\\\n  2x^2 &= 1\\\\\n  x^2 &= \\frac12\\\\\n  x &= \\sqrt{\\frac12}\\\\\n    &= \\frac1{\\sqrt2}\\\\\n    &= \\frac{\\sqrt2}2\n\\end{align*}\\]\nTherefore, we have\n\\[ \\cos45^\\circ = \\sin45^\\circ = \\frac{\\sqrt2}2. \\]\n\n<!-- #tab videos -->\n\nThese are some old videos on $\\cos$ and $\\sin$.\n\n<iframe allow=\"fullscreen\" class=\"w-full my-4\" src=\"https://epiplexis.xyz/a/9vg/lesson/?t=3:12\" style=\"aspect-ratio: 8/5;\"></iframe>\n\n<iframe allow=\"fullscreen\" class=\"w-full my-4\" src=\"https://epiplexis.xyz/a/9vb/lesson/\" style=\"aspect-ratio: 8/5;\"></iframe>\n\n<!-- #tab exercises -->\n\n1. Find $\\cos$ and $\\sin$ of $30^\\circ$ and $60^\\circ$.\n\n2. Consider the following diagram:  \n   ::embed[{epiplexis-content}/gng/02-trigonometry/04-cos-sin/exc-minus]{aspect-ratio=2.5 source inline}  \n   By calculating the length of the green line segment in two different ways, establish the identity\n   $$\n   \\begin{equation}\\htmlId{eq-sin-pyth}{}\n   2\\sin\\left(\\frac{\\alpha - \\beta}2\\right) =\n   \\pm\\sqrt{\n     (\\cos\\alpha - \\cos\\beta)^2 + (\\sin\\alpha - \\sin\\beta)^2\n   }\n   \\end{equation}\n   $$\n   :::popup{trigger=Solution}  \n   The horizontal distance between the two points is $(\\cos\\alpha-\\cos\\beta)$, while the vertical distance is $(\\sin\\alpha-\\sin\\beta)$. Applying the Pythagorean theorem, we see that the length of the green segment is\n   $$\n   (\\cos\\alpha-\\cos\\beta)^2 + (\\sin\\alpha-\\sin\\beta)^2.\n   $$\n   ::embed[{epiplexis-content}/gng/02-trigonometry/04-cos-sin/exc-minus?rightAngle]{aspect-ratio=2.5 inline}\n   On the other hand, we can get a right angle triangle by drawing a line from the center of the circle to the midpoint of the green line: \n   ::embed[{epiplexis-content}/gng/02-trigonometry/04-cos-sin/exc-minus?bisect]{aspect-ratio=2.5 inline}\n   Now the angle between the red line and the dashed green line is $\\frac{\\alpha-\\beta}2$, and so the side opposite to it has length $\\sin\\left(\\frac{\\alpha-\\beta}2\\right)$. But this side is exactly half of the length of the green line, so the green line has length\n   $$\n   2\\sin\\left(\\frac{\\alpha-\\beta}2\\right).\n   $$\n   Putting these together, we have \n   $$\n   2\\sin\\left(\\frac{\\alpha-\\beta}2\\right) = (\\cos\\alpha-\\cos\\beta)^2 + (\\sin\\alpha-\\sin\\beta)^2\n   $$\n   :::  \n3. Consider a regular $n$-gon inscribed in a circle of radius 1:  \n   ::embed[{epiplexis-content}/gng/02-trigonometry/04-cos-sin/exc-polygon]{aspect-ratio=2 source inline}  \n   1. Show that its perimeter is given by $2n\\sin\\frac\\Twopi{2n}$.  \n      \n      :::popup{trigger=Hint}\n      Use the angle-bisection trick from the previous exercise.\n      :::\n   2. Show that its area is given by $\\frac n2\\sin\\frac\\Twopi n$.\n\n4. Once we've established [$(1)$](#eq-sin-pyth), we can derive all the usual trigonometric identities using algebraic manipulations, with no further geometric insight required. \n   1. Use [$(1)$](#eq-sin-pyth) to derive the \"half-angle formulas\"\n      $$\n      \\begin{align}\n        \\htmlId{eq-cos-half}{}\\cos(\\theta/2) &= \\pm\\sqrt{\\frac{1+\\cos\\theta}2}\\\\[1em]\n        \\htmlId{eq-sin-half}{}\\sin(\\theta/2) &= \\pm\\sqrt{\\frac{1-\\cos\\theta}2}\n      \\end{align}\n      $$\n   2. Use [$(2)$](#eq-cos-half) and [$(3)$](#eq-sin-half) to derive the \"double-angle formulas\"\n      $$\n      \\begin{align*}\n        \\cos(2\\theta)\n          &= \\cos^2(\\theta)-\\sin^2(\\theta)\\\\\n          &= 2\\cos^2(\\theta) - 1\\\\\n          &= 1 - 2\\sin^2(\\theta)\\\\\n        \\sin(2\\theta) &= 2\\cos(\\theta)\\sin(\\theta)\n      \\end{align*}\n      $$\n   3. Derive the \"angle-difference\" formulas\n      $$\n      \\begin{align*}\n        \\cos(\\alpha-\\beta) &= \\cos(\\alpha)\\cos(\\beta) + \\sin(\\alpha)\\sin(\\beta)\\\\\n        \\sin(\\alpha-\\beta) &= \\sin(\\alpha)\\cos(\\beta) - \\cos(\\alpha)\\sin(\\beta)\n      \\end{align*}\n      $$\n      and the \"angle-sum\" formulas\n      $$\n      \\begin{align*}\n        \\cos(\\alpha+\\beta) &= \\cos(\\alpha)\\cos(\\beta) - \\sin(\\alpha)\\sin(\\beta)\\\\\n        \\sin(\\alpha+\\beta) &= \\sin(\\alpha)\\cos(\\beta) + \\cos(\\alpha)\\sin(\\beta)\n      \\end{align*}\n      $$\n      These are sometimes stated in combined form\n      $$\n      \\begin{align*}\n        \\cos(\\alpha\\pm\\beta) &= \\cos(\\alpha)\\cos(\\beta) \\mp \\sin(\\alpha)\\sin(\\beta)\\\\\n        \\sin(\\alpha\\pm\\beta) &= \\sin(\\alpha)\\cos(\\beta) \\pm \\cos(\\alpha)\\sin\\beta)\n      \\end{align*}\n      $$\n      This is not the best way to derive these formulas, but it works; the point is mainly that you can get them from each other using pure algebra. We'll see a more enlightening explanation of and in a future lesson, and then the rest will follow by algebra in a similar way (in the opposite order as you derived them here).\n",
    "description": "",
    "duration": null,
    "meta": {
      "math": {
        "macros": "\\newcommand{\\Twopi}{\\htmlClass{text-teal-600 dark:text-teal-500}{\\varpi}}\n"
      }
    },
    "ownerId": "41786b7c-b873-4373-8ede-477bf85070a1",
    "publicationDate": "2024-06-15 23:40:16.340316 UTC",
    "slug": "cos-sin",
    "title": "cos and sin",
    "type": "article"
  },
  {
    "id": "3a11bff6-c7cc-44c7-80cd-65d16f0a1642",
    "content": "## Introduction\n\n:::definition\nLet $X$ and $Y$ be sets. A :dfn[function] $f: X \\to Y$ is a rule which assigns to each element of $x$ an element $f(x)$ of $Y$.\n\nWhen $X$ and $Y$ are spaces, a :dfn[map] $f: X \\to Y$ is a function from $X$ to $Y$ which \"preserves the (geometric) structure of $X$\".\n:::\n\nSince I haven't said what \"space\" means, this is kind of meaningless. Once we encounter precise definitions of various types of spaces, they'll be accompanied by precise notions of \"map\". Still, I'm going to use the word \"map\" more than \"function\" because it's shorter and more evocative. Also, sets are one kind of space (with no additional structure), and in that case map does mean any function.\n\n## Terminology\n\n:::definition\nIn the above definition:\n\n- $X$ is called the :dfn[domain] of $f$\n- $Y$ is called the :dfn[codomain] of $f$\n- the :dfn[image] of $f$ is the set of all values taken by $f$,\n  \\[ \\im(f) \\Defeq \\{ f(x) \\mid x \\in Y \\} \\]\n- if $x \\in X$, we call the value $f(x)$ the _image of $x$ under $f$_. We also call $x$ a :dfn[preimage] of $y \\in Y$ if $f(x) = y$.\n:::\n\nThe difference between codomain and range can be hard to appreciate at first. The domain and codomain are part of the \"type\" of $f$, wheras the image might be something difficult to determine.\n\n:::example\nConsider the function\n  \\[\\begin{align*}\n    f\\colon & \\R\\to\\R\\\\\n    f(x) &= x^2\n  \\end{align*}\\]\n  The image of $2$ under $f$ is $f(2)=2^2=4$, so $2$ is a preimage of $4.$ Another preimage of $4$ is $-2.$ The image of $f$ is the set $\\R_{\\ge0}=[0,\\infty)$ of non-negative real numbers.\n:::\n\nIn terms of vibes, the notation $f: X \\to Y$ is approximately equivalent to\n\n```ts\nf: (x: X) => Y;\n```\n\nA more accurate (though still imperfect) translation would be\n\n```ts\nf: Map<X, Y>;\n```\n\nThis is because in math, two functions $f$ and $g$ are considered _equal_ if\n\n- they have the same domain and codomain\n- they map each input to the same output: $f(x) = g(x)$ for all $x \\in X$\n\nThe second point is an important difference between functions in math and functions in programming (which are really _algorithms_). For mathematical functions, there's no such thing as a \"function body\" or \"runtime\".\n\n:::warning\n  Many precalculus/calculus classes ask questions like: \"What is the domain of the function\n  \n  \\[ f(x) = \\frac1{x-1}? \\]\n  \n  This question doesn't make sense: the domain of the function is _part of the data of the function_. What it's really asking is \"what is the largest subspace of $\\R$ on which this expression makes sense?\" (The answer being $\\R - \\{1\\}$, since we can't divide by $0$.)\n:::\n\nSome more terminology.\n\n:::definition\n  A function is:\n- :dfn[injective] if it never sends two different inputs to the same output. This can be phrased as  \n  \\[ x \\ne y \\implies f(x) \\ne f(y) \\]  \n  or equivalently as  \n  \\[ f(x) = f(y) \\implies x = y. \\]  \n  The first form is maybe easier to think about, but the second is easier to work with.\n- :dfn[surjective] if every element of $Y$ is the image of some $x\\in X$.\n- :dfn[bijective] if it is both injective and surjective.\n:::\n\n:::example\n  Let $\\R_{\\ge0} = [0, \\infty)$ be the space of non-negative real numbers. Consider the functions:\n  \n  - $f\\colon \\R\\to\\R,\\quad f(x) = x^2$  \n    This is not injective since $f(2)=f(-2)=4$.\n    It is not surjective since there is no $x$ such that $f(x)=-1$.\n  - $g\\colon \\R\\to\\R_{\\ge0},\\quad g(x) = x^2$  \n    This is surjective but not injective.\n  - $h\\colon \\R_{\\ge0}\\to\\R,\\quad h(x) = x^2$  \n    This is injective but not surjective.\n  - $k\\colon \\R_{\\ge0}\\to\\R_{\\ge0},\\quad k(x) = x^2$  \n    This is bijective.\n:::\n\n## Exponential interpretation\n\nWhen we introduced products of spaces, we saw that that concept was related to multiplication of numbers. Functions are also related to a numeric concept: exponentiation.\n\nFor example, say we have two balls which can be painted any of three colors, red, green, blue. We can represent the possibilities as functions from $\\{B_1, B_2\\}$ to $\\{\\red r,\\green g,\\blue b\\}$, e.g.\n\\[\n  \\vcenter{\\LARGE{\\red\\bullet}{\\blue\\bullet}}\n  \\quad\\text{corresponds to}\\quad\n  f(B_1) = \\red r, \\quad f(B_2) = \\blue b.\n\\]\nThere are $9=3^2$ possibilities in total:\n\n\\[\n  \\Big\\{\n    f\\colon\n    \\{B_1,B_2\\}\n    \\to\n    \\{\\red r ,\\green g, \\blue b\\}\n  \\Big\\}\n  =\n  \\LARGE\n  \\left\\{\\begin{matrix}\n    \\red\\bullet\\red\\bullet & \\green\\bullet\\red\\bullet & \\blue\\bullet\\red\\bullet\\\\\n    \\red\\bullet\\green\\bullet & \\green\\bullet\\green\\bullet & \\blue\\bullet\\green\\bullet\\\\\n    \\red\\bullet\\blue\\bullet & \\green\\bullet\\blue\\bullet & \\blue\\bullet\\blue\\bullet\n  \\end{matrix}\\right\\}\n\\]\n\nIn general, if $X$ and $Y$ are finite sets with $|X|$ and $|Y|$ elements respectively, then the number of functions from $X$ to $Y$ is $|Y|^{|X|}$: there are $|Y|$ options where to send each $x \\in X$, and we can choose those values independently of one another.\n\nThis suggests defining $Y^X$ as the set of functions from $X$ to $Y$, so that\n\\[ |Y^X| = |Y|^{|X|}. \\]\nThis is called the **function set** or **mapping space** from $X$ to $Y$. Although this can be hard to think about, it's very powerful to go from thinking about\n\n- individual elements of $X$ and $Y$, to\n- individual functions $f: X \\to Y$, to\n- considering _all_ functions $X \\to Y$ as a single object.\n\nAnother notation for the mapping space (more common in CS than in math) is $X \\to Y$, in which case the notation $f: X \\to Y$ is literally a type declaration. In any case, the mapping space from $X$ to $Y$ is approximately equivalent to the type `(x: X) => Y` or `Map<X, Y>`.\n\nI'll try to avoid using the concept of mapping space except when we have precise definitions of \"space\" and \"map\", since\n\n- the precise definition of \"map\" will affect what the actual elements of $Y^X$ are. For example,\n  \\[\\begin{align*}\n    f&\\colon \\R \\to \\R\\\\\n    f(x) &= x+1\n  \\end{align*}\\]\n  is considered an _affine_ map but not a _linear_ map.\n- depending on the precise meaning of \"space\", it may be easy, difficult, or impossible to turn the _set_ of maps $X \\to Y$ into a \"space\".\n\n## Maps and products\n\nLet's see how this interacts with the other way we've seen of combining spaces, namely products.\n\n### Repeated multiplication\n\nWhen $x$ is a natural number ($0,1,2,...)$ and $y$ is any number, the exponential $y^x$ is defined as repreated multiplication:\n\n\\[ y^x = \\underbrace{yy\\dotsm y}_{x\\text{ times}} \\]\n\nSomething similar is true for function spaces. Recall that three-dimensional space $\\R^3$ can be understood as the threefold product of $\\R$ with itself,\n\n\\[ \\R^3 = \\R \\times \\R \\times \\R. \\]\n\nWe can also view $\\R^3$ as the function space $\\R^{\\{0,1,2\\}}$. In code, this is saying that the types\n\n```ts\n[number, number, number];\n```\n\nand\n\n```ts\n{\n  0: number;\n  1: number;\n  2: number;\n}\n```\n\nare \"equivalent\".\n\nDepending on your application, you might prefer to have types like\n\n```ts\n{\n  x: number;\n  y: number;\n  z: number;\n}\n```\n\nor\n\n```ts\n{\n  height: number;\n  width: number;\n}\n```\n\nThese can be encoded as the mapping spaces $\\R^{\\{\\r x,\\r y,\\r z\\}}$ and $\\R^{\\{\\r{height},\\r{width}\\}}$.\n\n### Maps into a product\n\nLet $X$, $Y$, and $Z$ be spaces. We can form the product $Y \\times Z$, and then ask what maps $f\\colon X \\to Y \\times Z$ look like.\n\nBy definition, $f$ needs to send each element $x$ of $X$ to an element of $Y \\times Z$. An element of $Y \\times Z$ is a pair $(y, z)$ with $y\\in Y$ and $z\\in Z$. So can define maps $g: X \\to Y$ and $h: X \\to Z$ as the first and second components of $f$:\n\n\\[ f(x) = (g(x), h(x)) \\]\n\nIn other words, _a function from $X$ to $Y \\times Z$ is equivalent to two separate functions $X \\to Y$ and $X \\to Z$_. In terms of mapping spaces, we can express this as\n\n\\[ (Y \\times Z)^X \\qeq Y^X \\times Z^X. \\]\n\n(I'll say more about $\\qeq$ in a future post.) This parallels the identity for numbers\n\n\\[ (yz)^x = y^x z^x. \\]\n\nHere's what this equivalence looks like in code:\n\n```ts\n/** Projection onto first factor */\nconst pr1 = <X, Y>([x, y]: [X, Y]): X => x;\n\n/** Projection onto second factor */\nconst pr2 = <X, Y>([x, y]: [X, Y]): Y => y;\n\n/** Convert a function into a product to a pair of functions **/\nconst split = <X, Y, Z>(f: (x: X) => [Y, Z]): [(x: X) => Y, (x: X) => Z] => [\n  (x) => pr1(f(x)),\n  (x) => pr2(f(x)),\n];\n\n/** Convert a pair of functions to a function into a product */\nconst combine =\n  <X, Y, Z>(g: (x: X) => Y, h: (x: X) => Z): ((x: X) => [Y, Z]) =>\n  (x) =>\n    [g(x), h(x)];\n```\n\n## Maps out of a product\n\nWhat about maps _out of_ a product? That is, for spaces $X$, $Y$, $Z$, let's think about what maps $X \\times Y \\to Z$ look like.\n\nThese correspond to \"functions of two variables\": for example, the function\n\n\\[ f(x, y) = x^2 + y^2 \\]\n\nis a map $\\R^2 \\to \\R$.\n\nThere is another way of encoding a function of two variables: for a fixed value of $x$, we can get a function $f_x: Y \\to Z$ by defining\n\n\\[ f_x(y) = f(x, y) \\]\n\nFor instance, if $f(x, y) = x^2 + y^2$ as above, then $f_2(y) = 4+y^2$. This is saying that a function of two variables can also be expressed as a function from $X$ to _the set of functions from $Y$ to $Z$_. Symbolically, this is\n\n\\[ Z^{X\\times Y} \\qeq (Z^Y)^X \\]\n\nor\n\n\\[ (X \\times Y) \\to Z \\qeq X \\to (Y \\to Z) \\]\n\nThis \"lifts\" the numeric identity\n\n\\[ z^{xy} = (z^y)^x. \\]\n\nIn programming, this equivalence is called \"currying\".\n\n```ts\n/** Convert a function of two variables into a function returning a function. */\nconst curry =\n  <X, Y, Z>(f: ([x, y]: [X, Y]) => Z): ((x: X) => (y: Y) => Z) =>\n  (x) =>\n  (y) =>\n    f([x, y]);\n\n/** Convert a function returning a function to a function of two variables. */\nconst uncurry =\n  <X, Y, Z>(f: (x: X) => (y: Y) => Z): (([x, y]: [X, Y]) => Z) =>\n  ([x, y]) =>\n    f(x)(y);\n```\n\n## Coproducts\n\nThere's one more exponential identity remaining,\n\n\\[ z^{x + y} = z^x z^y \\]\n\nTo get an analogue of this for mapping spaces, we need the concept of the _coproduct_ $X \\amalg Y$. I don't want to really get into this concept right now, but it corresponds to the union type `X | Y`. The relevant identity is\n\n\\[ Z^{X\\amalg Y} \\qeq Z^X \\times Z^Y \\]\n\nOr if you prefer, this is saying that the types `Map<X | Y, Z>` and `[Map<X, Z>, Map<Y, Z>]` are \"equivalent\".\n\n:::exercise\n  Convince yourself of the above, and implement the conversion in code.\n:::\n",
    "description": "",
    "duration": null,
    "meta": {
      "math": {
        "macros": "\\newcommand{\\r}{\\mathrm}\n\\newcommand{\\qeq}{\\cong}\n"
      }
    },
    "ownerId": "41786b7c-b873-4373-8ede-477bf85070a1",
    "publicationDate": "2024-06-15 23:40:16.340316 UTC",
    "slug": "maps",
    "title": "Maps",
    "type": "article"
  },
  {
    "id": "7e063b2d-2406-4557-a8ff-7e8a5a02b731",
    "content": "This will be a series on *geometry* (broadly speaking), applied to and demonstrated through *web graphics*. The code samples will be in TypeScript/React/THREE.js/react-three-fiber, but the concepts are completely general and applicable to many other areas (machine learning, modelling, optimization, …)\n\n## Geometry \nFor starters, what do I mean by *geometry*? Well, 2d and 3d geometry are particularly relevant to us because we live in 3d space. 2d shapes appear on screens and flat surfaces, while the objects around us have 3d shapes.\n\nBut geometry also comes from more abstract sources. Consider the following situations:\n\n- in physics, the kinetic energy $E$ of an object is related to its mass $m$ and its speed $v$ by the formula\n\n  \\[ E = \\frac12mv^2; \\]\n\n- again in physics: say an object starts from rest, and has constant acceleration $a$ (e.g. $a=9.8\\text{ m/s}^2$ for gravity). The distance $s$ it travels after time $t$ is given by\n\n  \\[ s = \\frac12at^2; \\]\n\n- in geometry: we consider the set of points $(x,y,z)$ in 3d space which satisfy the condition\n\n  \\[ z = \\frac12xy^2. \\]\n  \n  Here's what that looks like:\n  <iframe class=\"w-full mx-auto my-2\" src=\"https://www.desmos.com/3d/2875b3713c\" height=\"600\"></iframe>\n\n\nThese are all different physical situations. But mathematically, they're all equivalent: all that matters is the relations between the numbers, not what the numbers represent.\n:::yell\nUnderstanding the geometry of the above shape is equivalent to understanding any (and all) of the more concrete situations.\n:::\nFor instance, an object of mass $4\\text{ kg}$ and velocity $3\\text{ m/s}$ corresponds to the point $(4,3,18)$.\n\nComplex problems may involve more than three dimensions; search algorithms routinely calculate in thousands or millions of dimensions. It's harder to visualize these problems. But we can use our physical intuition from 2d and 3d space to develop formulas that make sense in any number of dimensions. For example, in just a few posts we'll see how to talk about *lines* in any-dimensional space.\n\nEven \"spatial\" geometry in 2d and 3d space naturally leads us to consider higher dimensions. As a simple example, a point in 6-dimensional space is equivalent to two points in 3d space, or three points in 2d space:\n\n\\[\n  \\begin{bmatrix*}[r]\n    1\\\\-3\\\\2\\\\4.1\\\\0\\\\1\n  \\end{bmatrix*}\n  \\leftrightarrow\n  \\begin{bmatrix*}[r]\n    1&4.1\\\\-3&0\\\\2&1\n  \\end{bmatrix*}\n  \\leftrightarrow\n  \\begin{bmatrix*}[r]\n     1 & 2 & 0\\\\\n    -3 & 4.1 & 1\\\\\n  \\end{bmatrix*}\n\\]\n\n## Spaces\n\nThis brings us to our first definition.\n\n:::definition\n  A **space** is any concept that can be described using numbers.\n:::\n\n### Subsets of $\\mathbf R^n$\n\nThe above \"definition\" is extremely vague. Let me be more precise:  \n\n:::definition\n  $\\R^n$ (\"arr-enn\") is the set of $n$-tuples of real numbers:  \n  \\[ \\R^n = \\{(x_1,\\dotsc,x_n)\\mid x_i\\in \\R\\text{ for } i = 1,\\dotsc,n\\} \\]\n:::\n\n($\\in$ means \"in\" or \"is an element of\"). For example, $(0,0)$ is a point in $\\R^2,$ and $(3,0,1)$ is a point in $\\R^3.$ I might also write these vertically, e.g.\n  \n\\[ \\vec00 \\quad\\text{or}\\quad \\vecc301. \\]\n\n$\\R^n$ is one of the most important examples of a space. Any subset of $\\R^n$ is a space, and you could well take that as the precise definition. For example, the blue shape above is a subset (I could also say subspace) of $\\R^3$.\n\nActually, the term *space* doesn't have a precise definition in math (neither does *number*). There are a lot of technical concepts that have *space* in their name, which do have precise definitions, depending on what aspect of geometry we're focusing on or what tools we're using:\n  - *affine/vector spaces* are used when studying *translation* and *scaling*;\n  - *metric spaces* are for studying the concept of *distance*;\n  - *inner product spaces* incorporate all of the above and also *angles*;\n  - …\n  \n(We'll learn about these in due time.) But \"space\" on its own is just a vibe.\n\n### Coordinates\nNotice the word *can* in the definition. There are many different ways to represent any given situation, and rarely is there a single best one. For example, $10\\text{ cm}$, $3.94\\text{ in}$, and $0.33\\text{ ft}$ are three different numbers corresponding to the same concept.\n\nSo, there's a space of physical distances. This space \"is\" the same as $\\R$, but it is \"equivalent to $\\R$ in many ways\". Moreover, notice that \"equations\" like\n\n\\[ \n\\begin{align*}\n  \\line{2em} + \\line{1em} &= \\line{3em}\\\\\n  3\\times\\line{1.5em} &= \\line{4.5em}\n\\end{align*}\n\\]\n\nare meaningful, without even needing to assign numbers to the lengths. (Although this may be useful in *verifying* that the equations are true.)\n\nIn this series, I'll try to take a *coordinate-free* approach where we focus on the *intrinsic* properties of things. How we describe those spaces numerically will then be a separate step. In particular, a big chunk of geometry is just converting between different coordinate systems.\n\nWhen we do calculations, they're always going to be with $n$-tuples of numbers, and you can write your programs thinking this way. The benefit of the more abstract perspective is similar to the benefit of having types in your code.\n\n### Intrinsic / Extrinsic\n*Space* in the mathematical sense means basically the same thing as *shape*. In everyday language, we tend to think of *space* as an ambient medium which is populated by *shapes*. It's very powerful to get rid of that distinction as every shape as a space in its own right, and then one space can *embed* in another in many different ways.\n\nFor instance, the following depicts two circles drawn on a torus in 3d space. We can think of the circles as living in 3d space, occupying some of the same space as the torus. But we can also *forget* about ambient 3d space and just think about the torus as the ambient space. Furthermore, we can think of both these circles as different embeddings of one \"platonic\" circle into the torus.\n\n::embed[{epiplexis-content}/gng/01-coordinates/01-spaces/torus]{aspect-ratio=2.5 inline source} \n\n## Important Examples\n\nFinally, let me introduce notation for some important examples.\n\n- as we have already seen, $\\R^n$ is \"$n$-dimensional space\". For many purposes we are especially interested in the cases $\\R^2$ and $\\R^3$.\n\n- Frequently, we want to put bounds on the numbers we use. An :dfn[interval] consists of all numbers between two numbers $a$ and $b;$ the numbers $a$ and $b$ are called the :dfn[endpoints] of the interval. There are different versions depending on whether we want to include the endpoints or not:\n  \\[\\begin{align*}\n    [a, b] \\Defeq \\{ x \\in \\R \\mid a\\le x\\le b \\}\\\\\n    (a, b) \\Defeq \\{ x \\in \\R \\mid a < x < b \\}\n  \\end{align*}\\]\n  We call $[a, b]$ a :dfn[closed interval] and $(a,b)$ an :dfn[open interval]. There are also variants where we want to include one endpoint but not the other:\n  \\[\\begin{align*}\n    [a, b) \\Defeq \\{ x \\in \\R \\mid a\\le x < b \\}\\\\\n    (a, b] \\Defeq \\{ x \\in \\R \\mid a < x\\le b \\}\n  \\end{align*}\\]\n  These are sometimes called :dfn[half-open intervals] but there aren't individual names for them. For example, when describing angles in degrees, we're interested in the interval $[0,360).$\n\n- In particular, the :dfn[unit interval]\n  \\[ \\I \\Defeq [0, 1] \\]\n  consists of all numbers between 0 and 1, inclusive of both. This space comes up a lot when dealing with paths and animation (= paths in time).\n\n- we write $\\Sone$ for a :dfn[circle]. This means the *edge* of a circle, not the points inside; a filled circle is called a :dfn[disk] and denoted by $\\Dtwo$. Below, I've drawn a *circle* on the left and a *disk* on the right:\n\n<iframe class=\"w-full\" src=\"https://www.desmos.com/calculator/m4kxsba4su?embed\" height=\"500\"></iframe>\n\n  The notation $S^1$ means a one-dimensional *sphere*. Even though it lives in _two_-dimensional space, the circle is itself considered _one_-dimensional since you can only move backwards/forwards along it. The disk, on the other hand, is considered two-dimensional.\n\n  The notations extend to higher dimensions: $\\Stwo$ refers to a (hollow) :dfn[sphere] in $\\R^3$, while $D^3$ refers to a filled-in :dfn[ball]. Once we learn how to make sense of \"distance\" in higher dimensions, we'll be able to define $\\S n$ and $D^n$ for all $n$.\n",
    "description": "",
    "duration": null,
    "meta": {
      "math": {
        "macros": "\\newcommand{\\vec}[2]{\\begin{bmatrix}#1\\\\#2\\end{bmatrix}}\n\\newcommand{\\vecc}[3]{\\begin{bmatrix}#1\\\\#2\\\\#3\\end{bmatrix}}\n\\newcommand{\\line}[1]{\n  \\mathord{\n    \\raisebox{.2em}{\n      $\\rule{#1}{2px}$\n    }\n  }\n}\n\n\\newcommand{\\Sone}{S^1}\n\\newcommand{\\Stwo}{S^2}\n\\newcommand{\\Dtwo}{D^2}"
      }
    },
    "ownerId": "41786b7c-b873-4373-8ede-477bf85070a1",
    "publicationDate": "2024-06-15 23:40:16.340316 UTC",
    "slug": "spaces",
    "title": "Spaces",
    "type": "article"
  },
  {
    "id": "a5f12e03-5616-499d-a349-5d82fcd00550",
    "content": "In the [last post](/gng/cg/spaces) we encountered the notion of _spaces_, which are a way of thinking about situations numerically and geometrically. We saw a few examples of spaces:\n\n- $\\R^n$ is the set of all $n$-tuples of real numbers, which we think of as $n$-dimensional space\n\n- $\\ClsdIntvl ab$ is the interval of numbers between $a$ and $b$ (inclusive on both sides).\n\n- in particular, $\\I\\Defeq\\ClsdIntvl01$ consists of all $x$ with $0\\le x\\le 1$\n\n- $S^1$ is the unit circle in $\\VecR 2$\n\nIn this post, we'll discuss a way to combine two (or more) spaces $X$ and $Y$ into a new space $X\\times Y$, called the :dfn[product] of $X$ and $Y$. There are two reasons to do this:\n\n- it gives us more interesting examples of spaces;\n\n- conversely, we understand complicated spaces by expressing them in terms of simpler \"building block\" spaces. Most questions about $X\\times Y$ can be answered by answering the same question for the spaces $X$ and $Y$, and combining the answers somehow.\n\n:::definition\n  Let $X$ and $Y$ be spaces. The **product** $X\\times Y$ consists of all pairs of elements from $X$ and $Y$:\n  \\[ X \\times Y \\Defeq \\{(x,y) \\mid x\\in X,\\, y\\in Y \\}. \\]\n:::\n\nThe space $X\\times Y$ is analogous to the tuple type `[X, Y]`.\n\n### Examples\n\n:::example\nSuppose a user's screen is $w$ pixels wide by $h$ pixels tall. The screen can be modelled by the space\n  \\[ \\ClsdIntvl 0w\\times \\ClsdIntvl0h. \\]\n  The usual convention is that $(0,0)$ corresponds to the top left corner, but this is arbitrary. The order of the coordinates is also arbitrary: $\\ClsdIntvl 0h\\times\\ClsdIntvl 0w$ would work just as well.\n:::\n\n:::example\nThe set of playing cards can be viewed as\n  \\[\n    \\{ \\spadesuit, \\heartsuit, \\clubsuit, \\diamondsuit \\}\n    \\times\n    \\{\\mathrm A,2,3,4,5,6,7,8,9,10,\\mathrm J,\\mathrm Q,\\mathrm K\\}\n  \\]\n:::\n\n:::example\n$\\VecR2=\\R\\times\\R,\\ \\VecR3=\\R\\times\\R\\times\\R$, and so on. (See below about products of more than two spaces.)\n:::\n\n:::example\n  - a cube is $I\\times I\\times I$,\n  \n  - $I\\times S^1$ is a (hollow) cylinder,\n\n  - $S^1\\times S^1$ is a (hollow) torus:\n\n  ::embed[{epiplexis-content}/gng/01-coordinates/02-products/examples]{aspect-ratio=2 source appDir}\n:::\n\n:::example\nThe $n$-dimensional unit cube is\n  \\[ I^n = \\underbrace{I\\times\\dotsb\\times I}_{n\\text{ times}} \\]\n  This is harder to visualize in the same way as the cube above. But we can visualize it as $n$ slider controls.\n:::\n\n## Multiplication\n\nLet's explain why this operation is called multiplication. If $X$ is a finite set, we write $|X|$ for the number of elements of $X$, also called the :dfn[cardinality] or :dfn[size] of $X.$ For example, $|\\{a,b,c\\}|=3.$\n\nWhen $X$ and $Y$ are finite sets, the size of $X\\times Y$ is the product of the sizes of $X$ and $Y:$\n\n\\[ |X\\times Y| = |X||Y|. \\]\n\nFor instance, say we have three possible colors and four shapes. The number of possible colored shapes is $3\\times4=12:$\n\n\\[\n  \\Large\n  \\{\\red{\\mathrm{red}},\\, \\green{\\mathrm{green}},\\, \\blue{\\mathrm{blue}}\\}\n  \\times\n  \\{\\blacktriangle,\\, \\blacksquare,\\, \\bigstar,\\, \\bullet\\}\n  =\n  \\left\\{\\begin{matrix}\n  \\red\\blacktriangle&\\red\\blacksquare&\\red\\bigstar&\\red\\bullet\\\\\n  \\green\\blacktriangle&\\green\\blacksquare&\\green\\bigstar&\\green\\bullet\\\\\n  \\blue\\blacktriangle&\\blue\\blacksquare&\\blue\\bigstar&\\blue\\bullet\n  \\end{matrix}\\right\\}\n\\]\n\n## Associativity\n\nOne of the most important properties of ordinary multiplication (of numbers) is _associativity_: this is the property\n\\[ (ab)c = a(bc). \\]\nwhich means that the expression $abc$ is unambiguous. For example, we could evaluate $2\\cdot3\\cdot4$ as\n\\[\\begin{align*}\n  (2\\cdot3)\\cdot4 &= 6\\cdot4 = 24\\\\\n  2\\cdot(3\\cdot4) &= 2\\cdot12 = 24\n\\end{align*}\\]\nand both give the same result.\n\nSomething similar is true for the product of spaces, but we have to be more careful. We can give a direct definition of $X\\times Y\\times Z$ a space of 3-tuples\n\\[ X\\times Y\\times Z \\Defeq \\{(x,y,z) \\mid x\\in X,\\, y\\in Y,\\, z\\in Z\\}, \\]\nor we can build it out of products of two spaces at a time:\n\\[\\begin{align*}\n  (X\\times Y)\\times Z &= \\{((x, y), z) \\mid x\\in X,\\, y\\in Y,\\, z\\in Z\\}\\\\[.5em]\n  X\\times (Y\\times Z) &= \\{(x, (y, z)) \\mid x\\in X,\\, y\\in Y,\\, z\\in Z\\}\n\\end{align*}\\]\n\nThese three options aren't \"literally\" equal. As an analogy, in TypeScript, `[X, Y, Z]`, `[[X, Y], Z]`, and `[X, [Y, Z]]` are all different types. But there is an obvious way to go between them:\n\\[ (x,y,z) \\longleftrightarrow ((x,y),z) \\longleftrightarrow (x,(y,z)). \\]\nIn math, we generally leave these conversions implicit, so we will write\n\\[ (X\\times Y)\\times Z = X\\times Y\\times Z = X\\times(Y\\times Z). \\]\n\nI'll say a bit more about this expanded view of equality a few posts from now.\n\nIn my area of math (homotopy theory), there's often a lot of work that needs to be done to keep track of all these implicit conversions. One of the difficulties is that when converting between $(X\\times X)\\times X$ and $X\\times(X\\times X)$, you don't want to accidentally use the \"wrong\" conversion\n\\[ ((x,y),z) \\longleftrightarrow (z,(y,x)) \\]\n(which wouldn't typecheck for $(X\\times Y)\\times Z$ versus $X\\times(Y\\times Z)$)\n",
    "description": "",
    "duration": null,
    "meta": {
      "math": {
        "macros": ""
      }
    },
    "ownerId": "41786b7c-b873-4373-8ede-477bf85070a1",
    "publicationDate": "2024-06-15 23:40:16.340316 UTC",
    "slug": "products",
    "title": "Products",
    "type": "article"
  },
  {
    "id": "8dd0419d-b2d7-4685-9cdb-575eed7a983c",
    "content": "<iframe class=\"w-full h-[1000px]\" src=\"https://epiplexis.xyz/a/fxh/2d/\"></iframe>\n\nTODO migrate article",
    "description": "",
    "duration": null,
    "meta": {
      "math": {
        "macros": ""
      }
    },
    "ownerId": "41786b7c-b873-4373-8ede-477bf85070a1",
    "publicationDate": "2024-06-15 23:40:16.340316 UTC",
    "slug": "2x2-matrices",
    "title": "$2\\times2$ matrices",
    "type": "article"
  },
  {
    "id": "ccbd70d8-9b8d-470c-95d9-77335d78e0a7",
    "content": "## Episode 1: The $q$-Legendre principle\n\n::unit[intro]\n\n::unit[bases]",
    "description": "",
    "duration": null,
    "meta": {
      "math": {
        "macros": ""
      }
    },
    "ownerId": "41786b7c-b873-4373-8ede-477bf85070a1",
    "publicationDate": "2024-06-15 23:40:16.340316 UTC",
    "slug": "what-study",
    "title": "What do I study?",
    "type": "collection"
  },
  {
    "id": "6a3c0838-f88e-4fdc-ace7-4ecbdf951a0c",
    "content": "Consider a right-angle triangle with side lengths as indicated:\n\n::embed[{epiplexis-content}/gng/02-trigonometry/01-pythagoras/setup]{class=my-4 inline width=50%}\n\nThe lengths $a$ and $b$ are called the _side lengths_, and $c$ is called the (length of the) _hypotenuse_. The Pythagorean theorem says that these are related by the equation\n\\[ a^2 + b^2 = c^2. \\]\n\nThis can be visualized in terms of the areas formed by squares drawn on the sides of the triangle:\n::embed[{epiplexis-content}/gng/02-trigonometry/01-pythagoras/statement]{class=my-4 inline width=75%}\n\n:::example\n  Find the length of the hypotenuse of a triangle with side lengths 3 and 4.\n  :::solution\n  The hypotenuse has length $\\sqrt{3^2 + 4^2} = \\sqrt{9 + 16} = \\sqrt{25} = 5$.\n:::\n\n:::example\n  If a right-angle triangle has a hypotenuse of length 6, and one side of length 3, find the remaining side length.\n  :::solution\n  Taking $a=3$, $c=6$, we have\n  \\[\\begin{aligned}\n    3^2 + b^2 &= 6^2\\\\\n    b^2 &= 36 - 9\\\\\n        &= 27\\\\\n    b &= \\sqrt{27}\\\\\n      &= 3\\sqrt 3.\n  \\end{aligned}\\]\n:::\n\n## Proof\n\nLet's see why the Pythagoream theorem is true. We'll draw two squares, both having side length $a+b$, and divide them in different ways:\n\n::embed[{epiplexis-content}/gng/02-trigonometry/01-pythagoras/proof]{inline}\n\nThe left square says that\n\\[ (\\red a + \\blue b)^2 = \\red{a^2} + \\violet{2ab} + \\blue{b^2} \\]\nThe right square says that\n\\[ (\\red a + \\blue b)^2 = \\green{c^2} + \\violet{2ab} \\]\n\nSetting these equal to each other, we get\n\\[\\begin{aligned}\n  \\red{a^2} + \\violet{2ab} + \\blue{b^2} &= \\green{c^2} + \\violet{2ab}\\\\\n  \\red{a^2} + \\xcancel{\\violet{2ab}} + \\blue{b^2} &= \\green{c^2} + \\xcancel{\\violet{2ab}}\\\\\n  \\red{a^2} + \\blue{b^2} &= \\green{c^2}.\n\\end{aligned}\\]\n\n## Three dimensions\n\nIf $v=\\ivec{x,y}$ is a vector in $\\VecR2$, the Pythagorean theorem implies that the _length_ of $v$ is\n\\[ \\sqrt{x^2+y^2}. \\]\nSimilarly, if $A=\\ipt{x_1,y_1}$ and $B=\\ipt{x_2,y_2}$ are points in $\\AffR 2$, the Pythagorean theorem tells us that the _distance_ between these is\n\\[\n  \\sqrt{(x_1-x_2)^2 + (y_1-y_2)^2}\n\\]\n\nHow can we extend this to higher dimensions? That is, if $A=\\ipt{x_1,y_1,z_2}$ and $B=\\ipt{x_2,y_2,z_2}$ are points in $\\AffR3$, what is $\\Dist AB$? Writing $A-B=v=\\ivec{x,y,z}$, this is the same as asking for the length of $v$.\n\nA naive guess is that the length of $v=\\ivec{x,y,z}$ might be\n\\[ \\sqrt[3]{x^3+y^3+z^3}. \\]\nBut this can't be true, since the length of $\\ivec{x,y,0}$ should be the same as the length of $\\ivec{x,y}$. That is, the appearance of the number $2$ in the Pythagorean theorem isn't related to the problem being in two dimensions.\n\nInstead, we can introduce the point \\[ C=\\ipt{x_2,y_2,z_1},\\] which has $1$ component in common with $A$ and $2$ components in common with $B$. The points $A$, $B$, and $C$ lie in a common plane, and we can apply the \"2d\" Pythagorean theorem within this plane to get $\\Dist AB$ in terms of $\\Dist AC$ and $\\dist BC$. The vertical distance $\\dist BC$ is just $|z_2-z_1|$, and we can compute $\\Dist AC$ by the \"2d\" Pythagorean theorem. This is illustrated in the animation below.\n\n::embed[{epiplexis-content}/gng/02-trigonometry/01-pythagoras/3d]{aspect-ratio=1.6 class=my-2 source}\n\n## Distance\n\n:::definition\n  The **length** of a vector $v=\\ivec{v_1,\\dotsc,v_n}\\in\\VecR n$ is defined to be\n  \\[\n    \\Norm v \\Defeq \\sqrt{v_1^2 + \\dotsc + v_n^2}.\n  \\]\n  This is also sometimes called the **norm** of $v$.\n:::\n\n:::definition\n  If $p,q\\in\\AffR n$ are two points in _affine_ space, then the distance between them is\n  \\[\\begin{align*}\n    \\Dist pq\n      &\\Defeq \\Norm{p-q}\\\\\n      &= \\sqrt{(p_1-q_1)^2 + \\dotsb + (p_n-q_n)^2}\n  \\end{align*}\\]\n:::\n\n:::remark\n  If $v=\\ivec{x}\\in\\VecR1$, then $\\Norm v=\\sqrt{x^2}=|x|$ is the absolute value of $x$. This explains the double-bars notation for length, and you may sometimes see $|v|$ instead of $\\|v\\|$.\n:::\n\n:::example\n  Find the length of the vector $v=\\ivec{-1,2,3,-4}\\in\\VecR 4$.\n  :::solution\n    \\[\\begin{aligned}\n      \\Norm v\n        &= \\sqrt{(-1)^2 + 2^2 + 3^2 + (-4^2)}\\\\\n        &= \\sqrt{1 + 4 + 9 + 16}\\\\\n        &= \\sqrt{30}.\n    \\end{aligned}\\]\n:::\n\n:::example\n  Find the distance between the points $p=\\ipt{1,4,2,5}$ and $q=\\ipt{-1, 3, 0, 1}$.\n  \n  :::solution\n    By definition, $\\Dist pq = \\Norm{p-q}$. We have\n    \\[\\begin{aligned}\n      p-q\\\\\n        &= \\begin{pmatrix}1\\\\4\\\\2\\\\5\\end{pmatrix} - \\begin{pmatrix}-1\\\\3\\\\0\\\\1\\end{pmatrix}\\\\\n        &= \\begin{bmatrix}2\\\\1\\\\2\\\\4\\end{bmatrix}\n    \\end{aligned}\\]\n    We thus get\n    \\[\\begin{aligned}\n      \\Dist pq\n        &= \\sqrt{2^2+1^2+2^2+4^2}\\\\\n        &= \\sqrt{4+1+4+16}\\\\\n        &= \\sqrt{25}\\\\\n        &= 5\n  \\end{aligned}\\]\n:::\n\n## APIs\n\nIn Javascript, we can compute the lengths of vectors using [`Math.hypot()`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/hypot).\n\n```js\n// !interactive\n// finding the length of a vector in R^4\nconsole.log(\"Finding the length of a vector in R^4\");\nconsole.log(Math.hypot(-1, 2, 3, -4));\n\n// finding the distance between two points in A^4\nconsole.log(\"Finding the distance between points in A^4\");\nvar p = [1, 4, 2, 5];\nvar q = [-1, 3, 0, 1];\nconsole.log(Math.hypot(...p.map((pi, i) => pi - q[i])));\n```\n\n\nIn THREE.js, we have the following APIs for calculating distances and lengths:\n- [`Vector3.prototype.distanceTo()`](https://threejs.org/docs/?q=vector3#api/en/math/Vector3.distanceTo)\n- [`Vector3.prototype.distanceToSquared()`](https://threejs.org/docs/?q=vector3#api/en/math/Vector3.distanceToSquared)\n- [`Vector3.prototype.length()`](https://threejs.org/docs/?q=vector3#api/en/math/Vector3.length)\n- [`Vector3.prototype.lengthSq()`](https://threejs.org/docs/?q=vector3#api/en/math/Vector3.lengthSq)\n\nFor the \"squared\" methods, note that when $x,y\\ge 0$ we have $x\\ge y$ if and only iff $x^2 \\ge y^2$.\n\n## Exercises\n\n1. Make an app to draw circles like below. (Don't look at the source until you've tried it yourself.)   \n   ::embed[{epiplexis-content}/gng/02-trigonometry/01-pythagoras/drawing]{aspect-ratio=2 class=mt-2 source}\n\n2. Extend the above app to disallow drawing circles which overlap.\n",
    "description": "",
    "duration": null,
    "meta": {
      "math": {
        "macros": ""
      }
    },
    "ownerId": "41786b7c-b873-4373-8ede-477bf85070a1",
    "publicationDate": "2024-06-15 23:40:16.340316 UTC",
    "slug": "pythagoras",
    "title": "Pythagorean theorem",
    "type": "article"
  },
  {
    "id": "ef4b41a0-e507-456c-840d-e420ffddd37a",
    "content": "<iframe class=\"mx-auto aspect-video w-3/4\" width=\"75%\" src=\"https://www.youtube.com/embed/rjmQ5tT1aso?si=Trs18laFx3V7_Gq3\" title=\"YouTube video player\" frameborder=\"0\" allow=\"accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share\" referrerpolicy=\"strict-origin-when-cross-origin\" allowfullscreen></iframe>\n\n## Week of Monday, June 5, 2023\nThis week I've been stuck trying to prove something that I left til the last stages of writing my paper, because I thought it would be very quick to prove, and it's turning out to be extremely difficult.\n\nRoughly speaking, I have these two axes, and I have this operation that pulls you towards the $x$-axis. If you're already on the $x$-axis, it does nothing. And I need to show that, although this operation pulls you _toward_ the $x$-axis, it can't pull you _in_ if you're not already there.\n\n<figure class=\"mx-auto my-4 text-center w-1/2\">\n  <me-embed inline aspect-ratio=\"1\" width=\"100%\" src=\"{epiplexis-content}/logs/crystalline/diagram\"></me-embed>\n  <figcaption class=\"mt-2 text-sm\">Adapted from Figure 11.1 of the <cite><a href=\"https://people.mpim-bonn.mpg.de/scholze/Berkeley.pdf#page=102\">Berkeley lectures on p-adic geometry</a></cite>\n</figure>\n\n<p class=\"opacity-20 text-xs\" style=\"opacity:0.2;\">(Math ppl: I want to show that a prism <katex>(A,I)</katex> is crystalline if and only if <katex>(A,\\phi(I)A)</katex> is crystalline)</p>\n\nThe reason I'm doing this is that there's these mathematical objects called **prisms** that were invented in 2019, and have been pretty revolutionary. Many problems that were considered untouchable for decades have been solved just in the past few years, largely coming out of this circle of ideas. I'm developing a different perspective on prisms, which is somehow based on the rotational symmetries of the circle.\n\nIn order to justify my perspective, I have to explain how to see various aspects of the theory of prisms in my language—actually, not just show that it's possible, but that it's _natural_ to do so. In the diagram above, I have a natural candidate for prisms which \"lie on the $x$-axis\" (called **crystalline** prisms), but it turns out to actually correspond to things whose _twist_ ends up on the $x$-axis. So I have to show that this is actually the same as already being on the $x$-axis.\n\nFor comparison, there _wasn't_ any existing concept in the \"symmetry world\" to correspond to prisms on the $y$-axis (called **transversal** prisms). But I invented (or discovered) something to correspond to these, and these turned out to be something extremely fundamental that no one had noticed before, and which _massively_ simplify a lot of things in \"symmetry world\".\n\n## Wednesday, June 7, 2023\n\nAnyway, I've been trying and failing to prove this for several days. I messaged Ben on Discord to explain my problem and ask if he had any ideas. Ben suggested I first try to prove this for transversal ($y$-axis) prisms, then extend from that case.\n\nThis is a standard technique: often you can use the transversal guys to control all the others. But it doesn't work in this case, basically because the only thing which is on both the $x$-axis and the $y$-axis is $(0,0)$, and that's boring. So I told Ben \"no, that will never work\", he said \"oh yeah, whoops, sorry that was silly\", and I said \"no worries, I totally tried the same thing before realizing it was nonsense\".\n\nNow, there's a prime number involved in all of this, and I _have_ managed to make this work for the prime number $2$. There's a bunch of stuff in this field that works for any prime number _except_ $2$, so maybe I could use that to deal with the remaining primes? But that stuff goes over my head, so I spent a few hours trying to understand it better.\n\n<p class=\"opacity-20 text-xs\">(Math ppl: I'm referring to obtaining prismatic cohomology from <katex>q</katex>-de Rham cohomology, e.g. Proposition 4.8.8 of <cite><a href=\"https://arxiv.org/pdf/2201.06120.pdf#page=109\">Absolute prismatic cohomology</a></cite>)</p>\n\n## Thursday, June 8, 2023\n\nThe thing I'm trying to prove is **_obviously false_**. Like, one of the most basic examples of a prism is a counterexample. Jesus I'm dumb.\n\n<p class=\"opacity-20 text-xs\">(Math ppl: I'm referring to the Hodge-Tate point of <katex>\\mathrm{WCart}</katex>, coming from <katex>V(1)</katex>, which is a counterexample since <katex>FV=p</katex>.)</p>\n\nNow, if the answer to \"what do crystalline prisms correspond to?\" isn't what I expected, then that question becomes much more interesting. It's interesting, but it's a lot more work, and I just want this \\*\\*\\*\\*ing paper to be done.\n\nWait—actually maybe this _isn't_ a counterexample. In this subject, there are **static** things and **animated** things. This counterexample is one of the standard examples of an _animated_ prism, but the question I'm working on is really only about _static_ things. So I did some googling, and yes, this counterexample will _never_ be static. So we're back in business!\n\n## Friday, June 9, 2023\n\n<p class=\"text-center font-bold text-2xl\">SUCCESS!!!</p>\n\nI proved what I wanted. It was a little bit subtle: it seemed like you should be able to do the proof in either of two ways, but actually one way was slightly better, and that was exactly what I needed.\n\nI excitedly messaged Noah on Discord, and said \"you do this and this and this, and after sufficiently many shenanigans, you get what you want.\" And Noah said, \"hmm, I'm not seeing the shenanigans\", and I told him, \"it's a bit sneaky, I'll write something up tonight\".\n\nBut it was time to celebrate, so I biked over to the Brooklyn Society for Ethical Culture for board game night. My team won at Secret Hitler (go Fascists!), and then at midnight we went to Union Hall for karaoke. I got home around 3:30am, so I didn't get back to Noah.\n\n## Saturday, June 10, 2023\n\nWoke up sometime after noon, started writing up the proof to send to Noah. That thing where it seemed like the proof should work in either of two ways, but actually it only worked in one? Yeah it actually just doesn't work. I'd gotten my head so tangled up in this problem that I ended up making a circular argument.\n\nThere's no happy ending to this story. I put out [the paper](https://arxiv.org/abs/2309.03181) in September, and I just left this as a conjecture.\n",
    "description": "",
    "duration": null,
    "meta": {
      "math": {
        "macros": ""
      }
    },
    "ownerId": "41786b7c-b873-4373-8ede-477bf85070a1",
    "publicationDate": "2024-06-15 23:40:16.340316 UTC",
    "slug": "crystalline",
    "title": "Crystalline prisms",
    "type": "article"
  },
  {
    "id": "fddcc78f-af38-4cb2-8fcf-e6a53825faa3",
    "content": "",
    "description": "",
    "duration": null,
    "meta": {},
    "ownerId": "41786b7c-b873-4373-8ede-477bf85070a1",
    "publicationDate": "2024-09-15 00:18:15.572 UTC",
    "slug": "",
    "title": "Popup demo",
    "type": "recording"
  },
  {
    "id": "1d6c0831-ae3d-47fa-a971-53aec8232fb2",
    "content": "",
    "description": "",
    "duration": null,
    "meta": {},
    "ownerId": "41786b7c-b873-4373-8ede-477bf85070a1",
    "publicationDate": "2024-10-15 08:18:46.365 UTC",
    "slug": "",
    "title": "Popup demo w/ video",
    "type": "recording"
  },
  {
    "id": "e7513c4e-b266-47aa-9b62-7102402ddfc9",
    "content": "",
    "description": "",
    "duration": null,
    "meta": {},
    "ownerId": "41786b7c-b873-4373-8ede-477bf85070a1",
    "publicationDate": "2024-06-15 23:40:16.340 UTC",
    "slug": "",
    "title": "broken",
    "type": "recording"
  },
  {
    "id": "7867ba76-ea6f-4d28-831b-f1ca7e6b6f8b",
    "content": "",
    "description": "",
    "duration": 365366,
    "meta": {
      "tracks": [
        {
          "kind": "captions",
          "srclang": "en"
        }
      ],
      "thumbs": "single",
      "origins": [
        "https://canvasconnect.its.virginia.edu"
      ]
    },
    "ownerId": "41786b7c-b873-4373-8ede-477bf85070a1",
    "publicationDate": "2025-01-17 23:37:36.338 UTC",
    "slug": "",
    "title": "SIR Python",
    "type": "recording"
  },
  {
    "id": "5781afb2-2877-4a4c-bc8b-ddbb8b0f3cbc",
    "content": "",
    "description": "",
    "duration": 41816,
    "meta": {},
    "ownerId": "4a4d8990-1de7-481e-be21-17d46c119e88",
    "publicationDate": "2025-02-07 20:29:41.288683 UTC",
    "slug": "",
    "title": "",
    "type": "recording"
  },
  {
    "id": "772469c8-3e46-4382-becf-d640e04bb4e9",
    "content": "So far we've been setting up a lot of abstract language to talk about geometry. Let's do something more concrete: how do we animate a character moving from point $\\a$ to point $\\b$?\n\n<!-- insert demo -->\n\nIn the language we set up in the last post, $\\a$ and $\\b$ are points in **affine** space. Their difference $\\b-\\a$ is a **vector**. If we add $\\b-\\a$ to $\\a$, we get $\\b$.\n\n\\[ \\b = \\a + (\\b-\\a) \\]\n\nSince $\\b-\\a$ is a vector, we can **scale** it. For example,\n\n\\[ \\a + \\tfrac12(\\b-\\a) \\]\n\nis the point $50\\%$ of the way between $\\a$ and $\\b$; similarly, $\\a+0.3(\\b-\\a)$ is $30\\%$ along the way from $\\a$ to $\\b$.\n\n:::definition\n  If $\\a$ and $\\b$ are points in an affine space, we write\n  \\[ \\lerp_\\t(\\a, \\b) \\Defeq \\a + \\t(\\b-\\a). \\]\n  This stands for :dfn[linear interpolation]. If we have to put a complicated expression for $\\t$, we might also use the notation $\\lerp(\\a,\\b;\\t)$.\n:::\n\nWe often restrict $\\t$ to $\\CIntvl 01$, although you could let it be bigger to \"overshoot\".\n\nIn terms of the abstract language we introduced [before](./params-coords), this is a **parametrization** of the line segment from $\\a$ to $\\b$.\n\nNote that this linear motion doesn't look very natural. A real object moving would accelerate when starting and decelerate towards the end. We'll address that in the next post.\n\nThere's two ways to remember the above formula. One is: start at $\\a$ and add some multiple of $\\b-\\a$ to move towards $\\b$. Another way is: let's rewrite this as\n\\[ \\a + \\t(\\b - \\a) = (1-\\t)\\a + \\t\\b \\]\nThen when $\\t=0$, this becomes\n\\[ (1-0)\\a + 0\\b = \\a \\]\nand when $\\t=1$, it becomes\n\\[ (1-1)\\a + 1\\b = 0\\a + 1\\b = \\b. \\]\n\nBut wait! We saw in [the last post](./affine) that it doesn't make sense to add or scale **points**, only vectors. However,\n\\[ \\a + \\t(\\b - \\a) \\]\n**does** make sense, so it turns out that\n\\[ (1-\\t)\\a + \\t\\b \\]\nmakes sense, even though $(1-\\t)\\a$ and $\\t\\b$ don't! In general, we can make sense of\n\\[ x\\a + y\\b \\]\nif and only if $x+y=1$. Basically, we can take **weighted averages** of points.\n\n## Code\n\nIn THREE.js, we have the methods [`Vector3.lerp()`](https://threejs.org/docs/?q=lerp#api/en/math/Vector3.lerp) and [`Vector3.lerpVectors()`](https://threejs.org/docs/?q=lerp#api/en/math/Vector3.lerpVectors) for lerping vectors.",
    "description": "",
    "duration": null,
    "meta": {
      "math": {
        "macros": "\\newcommand{\\a}{\\red a}\n\\newcommand{\\b}{\\blue b}\n\\newcommand{\\t}{{\\color{gold} t}}"
      }
    },
    "ownerId": "41786b7c-b873-4373-8ede-477bf85070a1",
    "publicationDate": "2024-06-15 23:40:16.340316 UTC",
    "slug": "lerp",
    "title": "Linear interpolation",
    "type": "article"
  },
  {
    "id": "ef51960f-fcc3-4dae-8241-537a5ac6135e",
    "content": "<!-- #tab notes -->\nIn the [previous post](./params-coords), we took a closer look at how we represent problems numerically. In this post, we'll intoduce some additional \"type safety\" into this prcess by distinguishing between two _types_ of quantities: **points** and **vectors**. You might also call these **absolute** and **relative** quantities, or **affine** and **vector** quantities. In the next post, we'll use this perspective to [build a draggable popup](./dragging).\n\n## Introduction\n\nLet's start with the example of **temperature**. Suppose the temperatures in a given week are as follows:\n\n<table>\n  <thead>\n    <tr>\n      <th></th>\n      <th>M</th>\n      <th>T</th>\n      <th>W</th>\n      <th>R</th>\n      <th>F</th>\n    </tr>\n  </thead>\n  <tbody>\n    <tr>\n      <th scope=\"row\">\n        <katex>{}^\\circ\\text{C}</katex>\n      </th>\n      <td>\n        <katex>0</katex>\n      </td>\n      <td>\n        <katex>5</katex>\n      </td>\n      <td>\n        <katex>10</katex>\n      </td>\n      <td>\n        <katex>20</katex>\n      </td>\n      <td>\n        <katex>15</katex>\n      </td>\n    </tr>\n    <tr>\n      <th scope=\"row\">\n        <katex>{}^\\circ\\text{F}</katex>\n      </th>\n      <td>\n        <katex>32</katex>\n      </td>\n      <td>\n        <katex>41</katex>\n      </td>\n      <td>\n        <katex>50</katex>\n      </td>\n      <td>\n        <katex>68</katex>\n      </td>\n      <td>\n        <katex>59</katex>\n      </td>\n    </tr>\n  </tbody>\n</table>\n\nLooking at the Celsius row, we might be tempted to say something like \"it was twice as hot on Wednesday as it was on Tuesday\", having the equation\n\\[ 2\\cdot 5 = 10 \\]\nin mind. But if we write the same equation in Fahrenheit, we'd get\n\\[ \\color{red} 2\\cdot 41 = 50  \\]\nwhich is wrong!\n\nOn the other hand, we could say \"it *got* twice as hot from Monday to Wednesday as it did from Monday to Tuesday\". In the Celsius case, we'd be thinking of the equation\n\\[ 2 \\cdot (5 - 0) = 10 - 0; \\]\nin the Fahrenheit case, we'd have the equation\n\\[ 2\\cdot(41 - 32) = 50 - 32, \\]\nand this equation is true.\n\nWhat's going on? \n\n## Operations\n\nThere are two distinct things we can mean by \"temperature\": an **absolute** temperature (how hot an object is, or the temperature outside), or a **relative** temperature, representing the **difference** between two absolute temperatures. The formulas for converting between these are different: for _relative_ temperatures, we just multiply or divide by $\\frac59$, whereas for _absolute_ temperatures we also have to offset by $32$.\n\nHere are some more examples of absolute vs relative quantities:\n\n- an _absolute_ time is a **datetime** like \"3:23pm April 19 1943\"; a _relative_ time is a **duration**, like \"4 minutes and 33 seconds\".\n\n- an _absolute_ position is a specific point in space, like the top of the Eiffel tower. A _relative_ position is something like \"2km north and 500m east\".\n\nWe will call relative quantities :dfn[vectors], and absolute quantities :dfn[points]. The \"allowed\" (or \"meaningful\") operations between these are\n\n- $\\ptxt{point} - \\ptxt{\\red point} = \\vtxt{\\green vector}$\n\n- $\\ptxt{point} + \\vtxt{vector} = \\ptxt{point}$\n\n- $\\vtxt{vector} + \\vtxt{vector} = \\vtxt{vector}$\n\n- $\\text{\\blue{number}} \\cdot \\vtxt{vector} = \\vtxt{vector}$\n\nHere are some demos of that in 2d and 3d space:\n\n::embed[{epiplexis-content}/gng/01-coordinates/06-points-vectors/operations]{appDir inline source width=150%}\n\nWhen you're working with numbers (i.e. once you've picked a [coordinate system](./params-coords)), you can't really tell the difference between points and vectors: you can add and multiply points willy-nilly. You'll run into problems, though, when you try to _change_ coordinate systems: if you do an \"illegal\" operation, you'll get different answers in different coordinate systems.\n\nLet's make a definition.\n\n:::definition\n  We write $\\AffR n$ for :dfn[$n$-dimensional affine space], consisting of $n$-tuples of real numbers:\n  \\[ \\AffR n \\Defeq \\{\\ipt{x_1,\\dotsc,x_n} \\mid x_i \\in \\R \\}. \\]\n  This is the same _set_ as $\\VecR n$; the only difference is what we're allowed to do with them. When we write $\\ipt{x_1,\\dotsc,x_n}$ instead of $\\ivec{x_1,\\dotsc,x_n}$, we're emphasizing that this represents an _absolute_ quantity rather than a relative one. In particular, we're not allowed to add elements of $\\AffR n$ together, nor multiply them by numbers.\n\n  When writing them vertically, I'll write\n  \\[ \\begin{bmatrix}x\\\\y\\\\z\\end{bmatrix}\\text{ for vectors,} \\qquad \\begin{pmatrix}x\\\\y\\\\z\\end{pmatrix} \\text{ for points}. \\]\n  This is admittedly not very consistent/logical.\n:::\n\n:::warning\n  My notation for distinguishing between points and vectors is not standard. Also, I will probably get lax about the difference from time to time. The important thing is to distinguish the two concepts in your mind.\n\n  Also: this use of \"point\" is specific to the context of linear algebra. Pretty much every object in math can get called a \"point\".\n:::\n\nLet's try to give a slightly more precise definition (although I don't want to be fully rigorous in the main series).\n\nIf vectors represent differences between points, we might think to define points first, and then vectors. But look back at the operations we can do: all the operations involving points also involve vectors, but adding and scaling of vectors doesn't involve points. So we can talk about vectors without mentioning points, but not vice versa.\n\nSecond, if the distinguishing property of vectors is that they can be added together with other vectors, and scaled by numbers to produce other vectors, then it doesn't make sense to talk about individual vectors in isolation.\n\n:::definition\n  A :dfn[vector space] is a set $V$ whose elements can be added together to produce other elements of $V$, and which can be multiplied by real numbers. More precisely, the data of a vector space is the set $V$ _along with_:\n  - a \"zero vector\" $0_V\\in V$;\n  - an \"addition\" operation $V\\times V\\xrightarrow+ V$\n  - a \"scalar multiplication\" operation $\\R\\times V\\xrightarrow\\cdot V$\n:::\n\nThese operations are required to satisfy several [axioms](https://en.wikipedia.org/wiki/Vector_space#Definition_and_basic_properties), such as $v+0_V=v$ and $u+v=v+u$.\n\n:::example\n  Let $V$ be the set of continuous functions $f\\colon R\\to\\R$. The \"zero vector\" is the constant function\n  \\[ 0_V(x) = 0. \\]\n  Addition and scalar multiplication are defined by\n  \\[ (f+g)(x) \\Defeq f(x) + g(x) \\qquad (cf)(x) \\Defeq cf(x) \\]\n  for $f,g\\In V$ and $c\\In\\R$.\n\n  For example, if $f(x)=\\cos(x)-2x^2$, and $g(x)=x^2+2^x$, then $f+2g\\in V$ is the function\n  \\[ (f+2g)(x) = \\cos(x)+2^{x+1}. \\]\n:::\n\nIt might be startling to think of _functions_ as vectors—but this perspective turns out to be very useful, for example when solving systems of differential equations. One of the benefits of the abstract perspective is that it allows us to extend the tools of linear algebra to situations we wouldn't have originally thought of.\n\nIn most situations there will be an obvious choice for the \"zero vector\", \"addition\", and \"scalar multiplication\". However, it should be stressed that these are **additional data** that needs to be specified along with the set $V$.\n\n:::example\n  Here's a funny example of a vector space. I'll use $\\oplus$ and $\\odot$ for the addition and scalar multiplication operations, so you don't get them confused with the usual operations.\n  - the underlying set of our vector space is $V=\\R_{>0}$, the set of positive real numbers\n  - the \"zero vector\" is $0_V=1$\n  - the \"addition\" operation is given by multiplication, $x\\oplus y\\Defeq xy$\n  - the \"scalar multiplication\" operation is given by exponentiation, $c\\odot x=x^c$\n\n  Can you see how this unusual vector space is actually the usual vector space $(\\R,0,+,\\cdot)$ \"in disguise\"?\n:::\n\n:::definition\n  Let $V$ be a vector space. An :dfn[affine space over $V$] is a set $A$ along with operations\n  \\[\\begin{align*}\n    A \\times A & \\xrightarrow- V\\\\\n    A \\times V &\\xrightarrow+ A\n  \\end{align*}\\]\n  These operations are required to satisfy [axioms](https://en.wikipedia.org/wiki/Affine_space#Definition) like\n  \\[\\begin{align*}\n    a + 0_V &= a\\\\\n    (a-b) + v &= a-(b+v)\n  \\end{align*}\\]\n  for $a,b\\In A$ and $v\\In V$. Beware that in the second equation, there are two different $+$ operations! The $+$ on the left-hand side is adding two elements of $V$ together, while the one on the right-hand side is adding an element of $A$ with an element of $V$.\n:::\n\n:::example\n  Vector and affine spaces come up naturally when solving linear equations (which is my main motivation for introducing the distinction). Let\n  \\[\\begin{align*}\n    V &= \\{\\ivec{x,y} \\mid y=3x\\}\\\\\n    A &= \\{\\ipt{x,y} \\mid y=3x+1\\}\n  \\end{align*}\\]\n  <iframe class=\"w-full mx-auto my-2\" src=\"https://www.desmos.com/calculator/s23v22wcxp\" height=\"400\"></iframe>\n  \n  Let's first check that $V$ is a vector space under the usual coordinate-wise addition and scaling. We need to show that if $\\ivec{x,y},\\ivec{\\cl x{x'},\\cl y{y'}}\\In V$, and $r\\In\\R$, then\n  \\[\\begin{align*}\n    \\ivec{x+\\cl x{x'},y+\\cl y{y'}} &\\In V\\\\\n    \\ivec{rx, {r}y} &\\In V\n  \\end{align*}\\]\n  By definition of $V$, we have $y=3x$ and $\\cl y{y'}=3\\cl x{x'}$. So\n  \\[\\begin{align*}\n    y + \\cl y{y'}\n      &= 3x + 3\\cl x{x'}\\\\\n      &= 3(x + \\cl x{x'})\n  \\end{align*}\\]\n  which shows that $\\ivec{x+\\cl x{x'},y+\\cl y{y'}}\\In V$. Similarly,\n  \\[\\begin{align*}\n    {r}y\n      &= r(3x)\\\\\n      &= 3(rx)\n  \\end{align*}\\]\n  which shows that $\\ivec{rx,{r}y}\\In V$.\n\n  Next, let's show that $A$ is **NOT** a vector space (using the usual addition formula). Let's take the two points $P=\\ipt{0,1}$ and $Q=\\ipt{1,4}$, both of which are in $A$. Then\n  \\[ P+Q=\\ipt{1,5}\\notin A \\quad\\text{since}\\quad 3\\cdot1+1=4\\ne 5 \\]\n  However, $A$ is an affine space over $V$. First we'll show that when we add elements of $A$ with elements of $V$, the result is still in $A$. For this, let $\\ipt{a,b}\\In A$ and let $\\ivec{x,y}\\In V$. This means that $b=3a+1$ and $y=3x$. Thus,\n \\[\\begin{align*}\n   b + y\n     &= (3a+1) + (3x)\\\\\n     &= 3(a+x)+1\n \\end{align*}\\]\n which shows that $\\ipt{a+x,b+y}\\In A$. Next, let $\\ipt{a,b},\\ipt{\\cl a{a'},\\cl b{b'}}\\In A$. Then\n \\[\\begin{align*}\n   b - b'\n     &= (3a+1) - (3\\cl a{a'}+1)\\\\\n     &= 3a - 3\\cl a{a'}\\\\\n     &= 3(a-\\cl a{a'})\n \\end{align*}\\]\n which shows that $\\ivec{a-\\cl a{a'},b-\\cl b{b'}}\\In V$.\n:::\n\n## Code\n\n### Graphics\nEvery graphics library will have methods for dealing with vectors. For example, in THREE.js the relevant class is [`THREE.Vector3`](https://threejs.org/docs/#api/en/math/Vector3).\n\nFew (if any) graphics libraries explicitly make the distinction between points and vectors. Still, remembering the distinction is helpful for understanding how to convert between different coordinate systems.\n\nIn computer graphics, the ambient \"affine space\" is called :dfn[world space]. The vector space centered at a particular object is called :dfn[object space]. (See [below](#dictionary) for what I mean by \"centered at\".)\n\n### DOM\n\nAnother example of points vs vectors comes from my favorite DOM method, [`getBoundingClientRect()`](https://developer.mozilla.org/en-US/docs/Web/API/Element/getBoundingClientRect). The return type of this is a [`DOMRect`](https://developer.mozilla.org/en-US/docs/Web/API/DOMRect), which (ignoring `readonly`) is\n\n```ts\ninterface DOMRect {\n    height: number;\n    width: number;\n    x: number;\n    y: number;\n  \n    readonly bottom: number;\n    readonly left: number;\n    readonly right: number;\n    readonly top: number;\n}\n```\n\nTo distinguish between points and vectors, we could type this more precisely as\n\n```ts\ninterface DOMRect {\n    height: Vector1;\n    width: Vector1;\n    x: Point1;\n    y: Point1;\n  \n    readonly bottom: Point1;\n    readonly left: Point1;\n    readonly right: Point1;\n    readonly top: Point1;\n}\n```\nHere a `Vector1` and a `Point1` are both just `number`s, but we're not allowed to add two `Point1`s together.\n\n### TypeScript\n\nThe above discussion of axioms and operations might have been a little abstract or confusing. The following code is an approximate TypeScript equivalent of what I was saying above. In particular, note that the operations `add()`, `scale()`, `sub()` have to be **specified/implemented**. \n\n```ts\n// helpers\n// https://stackoverflow.com/a/43674389\n\ninterface Type<T> {\n  // eslint-disable-next-line @typescript-eslint/no-explicit-any\n  new (...args: any[]): T;\n}\n\nfunction staticImplements<T>() {\n  return <U extends T>(constructor: U, _context: ClassDecoratorContext) => {\n    constructor;\n  };\n}\n\n// vector types\ninterface Vector<V> {\n  /** Add two vectors together */\n  add(other: V): V;\n\n  /** Scale a vector by a number */\n  scale(factor: number): V;\n}\n\ninterface VectorStatic<V> extends Type<Vector<V>> {\n  zero: V;\n}\n\n// implementation\n@staticImplements<VectorStatic<Vector2>>()\nexport class Vector2 {\n  constructor(\n    public x: number,\n    public y: number,\n  ) {}\n\n  static zero = new Vector2(0, 0);\n\n  /** Add two vectors together */\n  add(other: Vector2) {\n    return new Vector2(this.x + other.x, this.y + other.y);\n  }\n  \n  /** Scale a vector by a number */\n  scale(factor: number) {\n    return new Vector2(this.x * factor, this.y * factor);\n  }\n\n  /** Whether two vectors are equal */\n  static eq(u: Vector2, v: Vector2) {\n    return u.x === v.x && u.y === v.y;\n  }\n}\n\n// affine types\ninterface Affine<V, A> {\n  /** Add a vector to a point to get another point */\n  add(other: V): A;\n\n  \n  /** Subtract two points to get a vector */\n  sub(other: A): V;\n}\n\n@staticImplements<Type<Affine<Vector2, Point2>>>()\nexport class Point2 {\n  constructor(\n    public x: number,\n    public y: number,\n  ) {}\n\n  /** Add a vector to a point to get another point */\n  add(other: Vector2) {\n    return new Point2(this.x + other.x, this.y + other.y);\n  }\n\n  /** Subtract two points to get a vector */\n  sub(other: Point2) {\n    return new Vector2(this.x - other.x, this.y * other.y);\n  }\n  \n  /** Whether this point is equal to another */\n  eq(other: Point2) {\n    return this.x === other.x && this.y === other.y;\n  }\n}\n```\n\nNote we have to do a little bit of decorator weirdness to express this in TypeScript. Also, TypeScript has no way of expressing the constraints (axioms) these operations need to specify, e.g.\n\\[ a+(u+v) = (a+u)+v\\quad a\\In A;\\ u,\\,v\\In V \\]\nThe closest code equivalent would be\n```ts\nfunction assertVectorSpaceAxioms(u: Vector2, v: Vector2, w: Vector2, r: number) {\n  // zero vector is identity element for addition\n  // u + 0 = u\n  assert(Vector2.eq(\n    u.add(Vector2.zero),\n    u,\n  );\n  // 0 + u = u\n  assert(Vector2.eq(\n    Vector2.zero.add(u), // 0 + v\n    u,\n  );\n\n  // associativity: (u + v) + w = u + (v + w)\n  assert(Vector2.eq(\n    u.add(v).add(w), // (u + v) + w\n    u.add(v.add(w)), // u + (v + w)\n  ));\n\n  // commutativity: u + v = v + u\n  assert(Vector2.eq(\n    u.add(v),\n    v.add(u)\n  ));\n\n  // ...and so on (see Exercises)\n}\n```\n\nThese limitations are deficiencies of TypeScript, not of mathematics.\n\n## Dictionary\n\nOne of the reasons the distinction between points and vectors is confusing is that it's possible to convert between the two. However, there are **many** different ways to do this—more precisely, every point gives a _different_ way to convert between points and vectors. It works as follows:\n\nLet $V$ be a vector space, let $A$ be an affine space over $V$, and let $\\O$ be a point of $A$. The choice of $\\O$ gives a way to go back and forth between $A$ and $V$:\n\\[\\begin{align*}\n  f_\\O\\colon & A\\to V & g_\\O\\colon & V\\to A\\\\\n  f_\\O(a) &= a-\\O & g_\\O(v) &= \\O+v\n\\end{align*}\\]\nWe include the subscript $\\O$ to emphasize that these functions depend on the choice of \"origin\" point $\\O$. These functions are [bijections](https://mutualed.test/gng/cg/maps#terminology):\n\\[\\begin{align*}\n  g_\\O(f_\\O(a)) &= g_\\O(a-\\O) &\n  f_\\O(g_\\O(v)) &= f_\\O(\\O+v)\\\\\n    &= \\O + (a-\\O) &&= (\\O+v)-\\O\\\\\n    &= a &&= v\n\\end{align*}\\]\nso no information is lost in this process.\n\nThe rub is that this dictionary **depends on the chosen point $\\O$**. In some situations there may be an obvious \"origin\" point, but in others there may be none, and in most there are several. For example, in computer graphics our \"default\" origin is the top-left corner of the screen. But if you want to animate a fireball circling around a character, you want to position the fireball _relative to_ that character, meaning the center of that character's bounding box will be your origin.\n\nNote that every vector space is an affine space _over itself_: we already know how to add vectors to vectors, and we can define subtraction of vectors by combining addition and scalar multiplication:\n\\[ u - v \\Defeq u + (-1\\cdot v). \\]\n\n<!-- #tab videos -->\n<iframe allow=\"fullscreen\" class=\"w-full\" src=\"https://epiplexis.xyz/a/w7s/lesson/\" style=\"aspect-ratio: 8/5;\"></iframe>\n\n<!-- #tab exercises  -->\n\n1. Compute the following expressions if they make sense, or answer \"meaningless\" if they do not make sense.  \n    1. $\\pt12 - \\pt21$\n    2. $\\pt{-1}{\\frac12} + \\vec1{\\frac32}$\n    3. $\\pt10 + \\pt01$\n    4. $\\vec{-3}1 + \\vec22$\n    5. $\\vecc111 + \\vec21$\n    6. $2\\vec1{\\frac12}$\n    7. $2\\pt1{\\frac12}$\n    8. $2\\vecc1{\\frac32}{-1} - \\vecc0{\\frac12}{-1}$\n    \n    :::popup{trigger=Answer}\n    1. $\\vec{-1}1$\n    \n    2. $\\pt02$\n    \n    3. meaningless: can't add a point to a point\n    \n    4. $\\vec{-1}3$\n    \n    5. meaningless: can't add vectors of different sizes (more abstractly, can't add vectors belonging to different vector spaces)\n    \n    6. $\\vec21$\n    \n    7. meaningless: can't scale a point\n    \n    8. $\\vecc2{\\frac52}{-1}$\n    :::\n  \n2. \n    1. Write code equivalents (as in the `assert()` example) for the full list of [vector space axioms](https://en.wikipedia.org/wiki/Vector_space#Definition_and_basic_properties). For convenience, those axioms are:  \n       $$\n       \\begin{align*}  \n         0 + v &= v &&\\text{(identity for +)}\\\\  \n         (u+v)+w &= u+(v+w) &&\\text{(associativity of +)}\\\\  \n         u + v &= v + u &&\\text{(commutativity of +)}\\\\  \n         v+(-1\\cdot v) &= 0 &&\\text{(inverses for +)}\\\\  \n          1\\cdot v&=v &&\\text{(identity for multiplication)}\\\\  \n          (rs)v&=r(sv) &&\\text{(associativity for multiplication)}\\\\  \n          r(u+v) &= ru+rv &&\\text{(distributivity)}  \n       \\end{align*}\n       $$\n       Here $u,v,w\\In V$ and $r,s\\In\\R$, where $V$ is a vector space. Write code equivalents for these, as in the `assert()` example.\n       \n       :::popup{trigger=Answer}\n       ```ts\n       function assertVectorSpaceAxioms(\n         u: Vector2, v: Vector2, w: Vector2,\n         r: number, s: number,\n       ) {\n         // 1. identity for addition\n         assert(Vector2.eq(\n           v.add(Vector2.zero),\n           v,\n         );\n       \n         // 2. associativity\n         assert(Vector2.eq(\n           u.add(v).add(w), // (u + v) + w\n           u.add(v.add(w)), // u + (v + w)\n         ));\n       \n         // 3. commutativity\n         assert(Vector2.eq(\n           u.add(v),\n           v.add(u)\n         ));\n       \n         // 4. inverses\n         assert(Vector2.eq(\n           v.add(v.scale(-1)),\n           Vector2.zero\n         ));\n    \n         // 5. identity for multiplication\n         assert(Vector2.eq(\n           v.scale(1),\n           v\n         ));\n    \n         // 6. associativity for multiplication\n         assert(Vector2.eq(\n           v.scale(r*s), // (rs)v\n           v.scale(s).scale(r), // r(sv)\n         ));\n    \n         // 7. distributivity\n         assert(Vector2.eq(\n           (u+v).scale(r), // r(u+v)\n           u.scale(r).add(v.scale(r)), // ru + rv\n         ));\n       }\n       ```\n       :::\n   2. The full list of affine space axioms is:\n      $$\n       \\begin{align*}  \n         a + 0 &= a &&\\text{(identity for +)}\\\\  \n         (a+u)+v &= a+(u+v) &&\\text{(associativity of +)}\\\\  \n         a + (b-a) &= b &&\\text{(transitivity)}\\\\  \n         a + v = a &\\implies v=0 &&\\text{(freeness)}\n       \\end{align*}\n      $$  \n      Here $a,b\\In A$ and $u,v\\in V$, where $A$ is an affine space over $V$. Write code equivalents for these, as in the `assert()` example.\n     \n      :::popup{trigger=Answer}\n      ```ts\n      function assertAffineSpaceAxioms(\n        u: Vector2, v: Vector2,\n        a: Point2, b: Point2,\n      ) {\n        // 1. identity\n        assert(Point2.eq(\n          a.add(Vector2.zero),\n          a,\n        );\n      \n        // 2. associativity\n        assert(Point2.eq(\n          a.add(u).add(v), // (a + u) + v\n          a.add(u.add(v)), // a + (u + v)\n        ));\n      \n        // 3. transitivity\n        assert(Point2.eq(\n          a.add(b.sub(a)), // a + (b - a)\n          b,\n        ));\n\n        // 4. freeness\n        assert(\n          Point2.eq(a.add(v), a)\n          ===\n          Vector2.eq(v, Vector2.zero)\n        );\n      }\n      ```\n      :::\n      There are many equivalent ways of defining affine spaces, so you might see these stated a little differently in other places.\n      \n3. Verify the vector space axioms for the vector space $(\\R_{>0}, 1, \\oplus, \\odot)$ where $x\\oplus y=xy$ and $r\\odot x=x^r$ for $x,y\\In \\R_{>0}$ and $r\\in\\R$. Can you see how this vector space is secretly the usual vector space $(\\R,0,+,\\cdot)$ \"in disguise\"?  \n\n     :::popup{trigger=Solution}\n     The easiest way to do this is to use the [bijection](/gng/cg/maps#terminology)\n     $$\n       2^\\bullet\\colon \\R \\to \\R_{>0}\n     $$\n     (Any other base would do just as well, $2$ isn't special here.) This takes the vector space structure on $\\R$ into the vector space structure on $\\R_{>0}$, in the sense that\n     $$\n     \\begin{align*}\n       2^0 &= 1\\\\\n       2^{x+y} &= 2^x 2^y \\\\&= 2^x\\oplus 2^y\\\\\n       2^{rx} &= (2^x)^r \\\\&= r\\odot 2^x\n     \\end{align*}\n     $$\n     :::\n",
    "description": "",
    "duration": null,
    "meta": {
      "math": {
        "macros": "\\newcommand{\\vecc}[3]{\\begin{bmatrix}#1\\\\#2\\\\#3\\end{bmatrix}}\n\\newcommand{\\ptxt}[1]{\\text{\\red{#1}}}\n\\newcommand{\\vtxt}[1]{\\text{\\green{#1}}}\n"
      }
    },
    "ownerId": "41786b7c-b873-4373-8ede-477bf85070a1",
    "publicationDate": "2024-06-15 23:40:16.340316 UTC",
    "slug": "points-vectors",
    "title": "Points and vectors",
    "type": "article"
  },
  {
    "id": "90223085-936e-4026-a9d5-274685666450",
    "content": "Over the years, friends, family, and strangers have asked me if I can explain the math that I do. This is tricky; because math is so cumulative, even professional mathematicians usually can't understand each other's work very well unless they work in the same field. (This has the advantage of making it difficult to talk about work at parties.) This series is my attempt to share the stuff I think about and why I think it's so fun.\n\nMy area of math is called **homotopy theory**. Historically, this grew out of **topology**, which is a form of **geometry**. Nowadays, it's increasingly viewed as foundational to math itself, so it interacts with a lot of other fields. In particular, I'm very interested in how it interacts with a subject called **arithmetic geometry**, which tries to incorporate things like prime numbers into geometry. The field is in a bit of a golden age right now: major papers are being posted nearly every month, and decades-old problems are falling one after another. \n\n What I mainly do is study **prismatic cohomology** (a hot new thing in arithmetic geometry) from the perspective of **equivariant** homotopy theory. *Equivariant* means having to do with symmetry—in this case the rotational symmetry of a circle.\n\nI'll explain all these fancy words over the course of many posts! A hyper-condensed overview is at the end of this post.\n\nHomotopy theory has a very theoretical side and a heavily computational side; I started out more on the theory side, but now lean more towards calculations. I often make interactive widgets and pretty pictures to help myself understand what I'm doing; pictures are maybe a good thing to organize this series around. My first goal is to explain what's going on in the following diagram:\n\n<figure class=\"rounded-md bg-gray-200 shadow-md border-stone-900 p-2 mx-auto\">\n  <object\n    title=\"Numbers 1 through 27 with colored bars stacked on top. Every number has a red bar; multiples of 3 (additionally) have an orange bar; multiples of 9 have a yellow bar; and 27 has a green bar.\"\n    data=\"https://ysulyma.github.io/assets/q-legendre-3.svg\" width=\"100%\"></object>\n</figure>\n\nLater, I'll talk about this one:\n\n\n<figure class=\"rounded-md bg-gray-200 shadow-md border-stone-900 p-2 mx-auto max-w-xl\">\n  <img\n    class=\"w-full\"\n    alt=\"\"\n    src=\"https://ysulyma.github.io/assets/grid.svg\" />\n</figure>\n\nand maybe eventually these guys (zoom in or open in new tab):\n\n<div class=\"flex justify-between gap-4 my-4 mx-auto\">\n  <figure class=\"bg-gray-100 rounded-md p-2\">\n    <img\n      alt=\"64x64 checkerboard, light squares filled with colored shapes\"\n      src=\"https://ysulyma.github.io/assets/slice-2-perfd.svg\" />\n  </figure>\n    \n  <figure class=\"bg-gray-100 rounded-md p-2\">\n    <img\n      alt=\"64x64 checkerboard, light squares filled with colored shapes\"\n      src=\"https://ysulyma.github.io/assets/slice-good-2.svg\" />\n  </figure>\n</div>\n\n:::think\nWhat patterns can you find in the above charts? For the last two, the specific shapes used don't mean anything; all that matters is the distribution of colors and shape families.\n:::\n\n## Topology\n\nLet's start by thinking about how we represent points on a shape:\n\n<iframe class=\"aspect-video w-full\" src=\"https://ysulyma.github.io/epiplexis/what-study/topology-demo/dist/\"></iframe>\n\n[Source](https://github.com/ysulyma/epiplexis/tree/main/what-study/topology-demo)\n\nWe can represent a point on the blue curve by a number between 0 and 1 (between 0% and 100% along the curve, starting from the left). This is the same way we'd represent points on a straight line segment. We can _almost_ do the same thing on the purple star, but now 0% and 100% represent the same point. This is similar to how $0^\\circ,$ $360^\\circ,$ $720^\\circ,$ etc. all correspond to the same point on the circle.\n\n:dfn[Topology] is the study of \"how data gets represented\". The blue curve is topologically equivalent to a straight line, and the purple curve is topologically equivalent to a circle. Topology is also often described as \"rubber-band geometry\": topology considers two shapes to be the same if each can be transformed into the other by twisting or bending, _but no cutting or tearing_.\n\nHowever, the difference between _the straight line and the circle_ is very important. To some extent, \"every problem that can be described using numbers, we can solve, and there's a unique solution\". (This is extremely vague, but I have precise statements in mind.) But suppose the solution involves dividing by $3$. Well, $0/3$ is just $0,$ but $0^\\circ/3$ is $\\\\{0^\\circ,120^\\circ,240^\\circ\\\\}.$ When the basic operations we do on numbers are unavailable, or behave differently than usual, we're no longer able to \"solve every problem\".\n\n:dfn[Homotopy theory] goes a step further than topology and adds \"inflating and deflating\" to the list of operations that \"don't change a shape\". We can shrink a straight line down to a single point (the most trivial shape there is), so these are _homotopically_ equivalent (but not topologically). We can build a circle by taking a straight line and gluing the ends together. When we pass from topology to homotopy, we \"delete\" the straight line, so the gluing is the only information that's left. I like to think about this as: we understand numbers pretty well, so we want to ignore those and just focus on the \"redundancies\" or \"wrinkles\" in the representation of data.\n\n## Cohomology\n:dfn[Cohomology] is a quantitative way to describe these \"wrinkles\" or \"redundancies\". In its crudest form, cohomology associates a sequence of numbers (called :dfn[Betti numbers]) to every shape. Here are some examples:\n\n<object\n  class=\"magic-svg\"\n  data=\"/assets/betti-numbers.svg\" type=\"image/svg+xml\"\n  aria-label=\"Numbers of various shapes. A string with no crossings: 1; a string with one loop: 1, 1; one string with three loops and another with one loop: 2, 4; a sphere: 1, 0, 1; a torus: 1, 2, 1\"></object>\n\n(The two shapes above the $2,\\,4$ are considered a single shape; the $2$ means there are two pieces, or :dfn[connected components]. Also, $2,\\,4$ is really short for $2,\\,4,\\,0,\\,0,\\,0,\\,\\dotsc$)\n\nThere are many different :dfn[cohomology theories] that offer different interpretations of what these numbers mean, and also provide richer information beyond these numbers.\n\n- from the perspective of :dfn[singular cohomology], these numbers are counting the number of (higher-dimensional) \"holes\" or \"loops\" in a shape.\n\n- :dfn[de Rham cohomology] is based on *calculus*[^calculus]. Calculus is about *change*: e.g. *velocity* as the rate of change of *position*, or *acceleration* as the rate of change of velocity. Although $0^\\circ$ and $360^\\circ$ represent the same point on a circle, an angular **_velocity_** of $360^\\circ\\text{ / sec}$ is very different from an angular velocity of $0^\\circ\\text{ / sec}$. So de Rham cohomology sees a numeric quantity (angular velocity) that looks like the rate of change of some other quantity (angle), but the original quantity is \"missing\".\n\nIf you kind of already know what your shape looks like, you can calculate its cohomology using any cohomology theory. But what if someone just hands you some random equations? De Rham cohomology is fairly easy to calculate \"mechanically\"—we can program computers to do calculus. But singular cohomology is very abstract, and literally impossible to calculate directly for anything beyond discrete points.\n\nDespite this, singular cohomology has some advantages over de Rham cohomology. Think about the distinction between a **line** (through the origin) and a **direction**: you can travel in two directions on every line. This \"2:1 redundancy\" shows up in many places: it's responsible for the \"plate trick\" seen below, as well as the phenomenon of [gimbal lock](https://en.wikipedia.org/wiki/Gimbal_lock). Gimbal lock causes problems in aviation and 3d graphics, necessitating the use of [quaternions](https://en.wikipedia.org/wiki/Quaternions) for doing rotations. (Rotations in 3d space are (non-obviously) topologically equivalent to lines through the origin in 4d space; unit quaternions are directions in 4d space.)\n\n<figure class=\"mx-auto my-2 max-w-[400px] text-center\">\n  <img alt=\"Woman rotating a coffee mug in her hand. Once the cup is returned to its original position, her arm is still twisted. After another full rotation, her arm is in a normal position.\" src=\"https://ysulyma.github.io/assets/plate-trick.png\" />\n  <figcaption>Taken from Bredon, <cite>Topology and Geometry</cite>.</figcaption>\n</figure>\n\nHopefully this convinces you that understanding \"2:1\" redundancies is important. Unfortunately, de Rham cohomology can only detect \"∞:1\" redundancies; singular cohomology can detect \"finite:1\" redundancies, but is much harder to compute. **Prismatic cohomology** is a fancier version of de Rham cohomology, based on a fancier version of calculus, which is able to detect \"finite:1\" redundancies, while remaining fairly computable.\n\nThe circle (infinitely many angles corresponding to the same point) is the simplest example of cohomology. It is also the _universal_ example: if you think hard enough about the circle, you can deduce the entire theory of de Rham cohomology. (I don't know why this should be true, or if this is even a good way of thinking about it.) In particular, the **rotational symmetries** of the circle play a central role in prismatic cohomology.\n\nWhat I mainly do these days is think about prismatic cohomology from the perspective of these rotational symmetries. There are many other perspectives; this one is historically the first, but the subsequent ones that were discovered are much simpler for most purposes, so this one has been neglected. However, I've shown that it illuminates some of the more advanced aspects of the theory.\n\nMy main project right now is trying to generalize prismatic cohomology to accommodate other kinds of symmetry. Circles also have **reflectional** symmetry, in addition to rotational. It's slightly harder to get \"even:1\" information out of prismatic cohomology than \"odd:1\", and it's thought that incorporating the reflectional symmetries might explain this. There are several people working on this, from different perspectives than mine, and I'm trying to understand how my approach compares to theirs.\n\nI'm also interested in plugging in completely different kinds of symmetry, like that of a triangle or square. It's less clear what this would be useful for.\n\n[^calculus]: I mean *differential* calculus here, which is about instantaneous rates of change. There's also *integral* calculus which is about the reverse: accumulated change over time. In cohomology land, the connection between differential and integral calculus (the fundamental theorem of calculus) translates to the fact that singular and de Rham cohomology give the same Betti numbers.\n",
    "description": "",
    "duration": null,
    "meta": {
      "math": {
        "macros": ""
      }
    },
    "ownerId": "41786b7c-b873-4373-8ede-477bf85070a1",
    "publicationDate": "2024-06-15 23:40:16.340316 UTC",
    "slug": "intro",
    "title": "Introduction",
    "type": "article"
  },
  {
    "id": "eeb4e10a-9637-49e6-9af3-3e1440238f56",
    "content": "Now for a definition. Let $X$ and $Y$ be spaces. A map $f\\colon X\\to Y$ is called an :dfn[isomorphism] if there is a map $g\\colon Y\\to X$ such that\n\\[ g\\circ f = \\id_X \\quad\\text{and}\\quad f\\circ g = \\id_Y. \\]\nMore explicitly,\n\\[\\begin{align*}\n  g(f(x)) &= x \\quad\\text{for all }x\\in X\\\\\n  f(g(y)) &= y \\quad\\text{for all }y\\in Y\n\\end{align*}\\]\nBasically, $f$ is a way to transport problems in $X$ to problems in $Y$. The identity $g(f(x))=x$ says that you can still recover $x$ after running it through $f$, so \"no information is lost\" about your original equation.\n\n<!-- need xymatrix for commutative diagrams here -->\n\n## Uniqueness\n\nAbove, we asked for **some** $g$ to exist, such that $gf=\\id_X$ and $fg=\\id_Y$. Could there be multiple of them?\n\n:::proposition\n  Let $f\\colon X\\to Y$, and let $g,h\\colon Y\\to X$ be a left and right inverse of $f$ respectively (meaning that $g\\circ f=\\id_X$ and $f\\circ h=\\id_Y$). Then $g=h$.\n\n  :::proof\n    We want to show that $g(y)=h(y)$ for all $y\\in Y$. We know that\n    \\[\n      \\blue{f(h(y)) = y}\n      \\quad\\text{and}\\quad\n      \\red{g(f(x)) = x}\n    \\]\n    for all $x\\in X$ and all $y\\in Y$. We can write\n    \\[\\begin{align*}\n      g(y)\n        &= g(f(h(y))) &&\\text{since } \\blue{y = f(h(y))}\\\\\n        &= g(f(x)) &&\\text{with } x = h(y)\\\\\n        &= x &&\\text{since } \\red{g(f(x)) = x}\\\\\n        &= h(y) &&\\text{by definition of }x\n    \\end{align*}\\]\n:::\n\nWe also could have written the above proof in \"functional notation\"\n\\[\\begin{align*}\n  g &= g\\circ\\id_Y\\\\\n    &= g\\circ(f\\circ h)\\\\\n    &= (g\\circ f)\\circ h\\\\\n    &= \\id_X\\circ h\\\\\n    &= h\n\\end{align*}\\]\n\nSince inverses are unique if they exist, we'll write $f^{-1}$ for the inverse of a map $f$.\n\n<!-- insert warning about f^-1 applied to sets -->\n\n<!-- left vs right inverses (above) -->\n\n## Equality\n\n<!-- bill clinton quote -->\n\nWhen we talked about [products](./products), we noted that the spaces\n\\[ (X\\times Y)\\times Z \\quad\\text{and}\\quad X\\times(Y\\times Z) \\]\nor the types\n<div class=\"text-center\">\n <code>[[X, Y], Z]</code> and <code>[X, [Y, Z]]</code> \n</div>\nwere technically different, but \"equivalent for all purposes\", since there's an obvious way to convert between them:\n\\[ ((x, y), z) \\leftrightarrow (x, (y, z)) \\]\n\nAbove, we saw that an arbitrary interval $\\CIntvl ab$ is essentially interchangeable with the unit interval $\\CIntvl01$.\n\n",
    "description": "",
    "duration": null,
    "meta": {
      "math": {
        "macros": "\\newcommand{\\id}{\\mathrm{id}}\n"
      }
    },
    "ownerId": "41786b7c-b873-4373-8ede-477bf85070a1",
    "publicationDate": "2024-06-15 23:40:16.340316 UTC",
    "slug": "isos",
    "title": "Isomorphism",
    "type": "article"
  },
  {
    "id": "4a1291cc-75e5-4ad7-9af7-e8a3f1092cd8",
    "content": "::unit[gng]\n\n::unit[what-study]\n\n::unit[logs]\n\n[Old site](https://epiplexis.xyz)\n",
    "description": "",
    "duration": null,
    "meta": {
      "math": {
        "macros": "% misc\n\\newcommand{\\twopi}{\\varpi}\n\\newcommand{\\twopi}{\\varpi}\n\\newcommand{\\<}{\\left\\langle}\n\\newcommand{\\>}{\\right\\rangle}\n\\newcommand{\\In}{\\htmlData{annotation_text=in / element of}{\\in}}\n\n\n\\newcommand{\\<}{\\left\\langle}\n\\newcommand{\\>}{\\right\\rangle}\n\\newcommand{\\In}{\\htmlData{annotation_text=in / element of}{\\in}}\n\n% algebra\n\\newcommand{\\im}{\\operatorname{im}}\n\n% prisms and THH\n\\ktxnewcommand{\\prism}{\\htmlClass{prism}}{\\Delta}\n\n\\newcommand{\\THH}{\\operatorname{THH}}\n\\newcommand{\\TC}{\\operatorname{TC}}\n\\newcommand{\\TCmin}{\\TC^-}\n\\newcommand{\\TP}{\\operatorname{TP}}\n\\newcommand{\\TF}{\\operatorname{TF}}\n\\newcommand{\\TR}{\\operatorname{TR}}\n\n% equivariant\n\\newcommand{\\rog}{\\bigstar}\n\n\\newcommand{\\m}{\\underline}\n\\newcommand{\\mpi}{\\m\\pi}\n\n% sets\n\\newcommand{\\A}{\\mathbf A}\n\\newcommand{\\C}{\\mathbf C}\n\\newcommand{\\F}{\\mathbf F}\n\\newcommand{\\G}{\\mathbf G}\n\\newcommand{\\L}{\\mathrm L}\n\\newcommand{\\H}{\\mathbf H}\n\\newcommand{\\N}{\\mathbf N}\n\\newcommand{\\O}{\\mathcal O}\n\\newcommand{\\P}{\\mathbf P}\n\\newcommand{\\Q}{\\mathbf Q}\n\\newcommand{\\R}{\\mathbf R}\n\\newcommand{\\T}{\\mathbf T}\n\\newcommand{\\Z}{\\mathbf Z}\n\n\\newcommand{\\RP}{\\mathbf{RP}}\n\\newcommand{\\CP}{\\mathbf{CP}}\n\n\n% TODO move these to per-unit\n\\newcommand{\\green}[1]{\\htmlStyle{color: ##16a34a;}{#1}}\n\\newcommand{\\red}[1]{\\htmlStyle{color: ##dc2626;}{#1}}\n\\newcommand{\\blue}[1]{\\htmlStyle{color: ##2563eb;}{#1}}\n\\newcommand{\\indigo}[1]{\\htmlStyle{color: ##6366f1;}{#1}}\n\\newcommand{\\violet}[1]{\\htmlStyle{color: ##8b5cf6;}{#1}}\n\n\\newcommand{\\Twopi}{\\htmlData{annotation_text=ratio of a circle's circumference to its radius, $\\approx6.28\\dots$}{\\twopi}}\n\n\\newcommand{\\Defeq}{\\htmlData{annotation_text=defined to be equal to}{\\mathrel{:=}}}\n\n\\newcommand{\\Restrict}[2]{\\htmlData{annotation_text=$#1$ with domain restricted to $#2$}{{#1}|_{#2}}}\n\n\\newcommand{\\comma}{,}\n"
      }
    },
    "ownerId": "41786b7c-b873-4373-8ede-477bf85070a1",
    "publicationDate": "2024-06-15 23:40:16.340316 UTC",
    "slug": "#",
    "title": "Epiplexis",
    "type": "root"
  },
  {
    "id": "ed4972a8-cc94-4255-b5df-0aa56e69c0c5",
    "content": "This is a series of \"research diary\" entries. Here, rather than trying to deeply explain the math, I just want to give a window into the _process_ of math research—especially how winding and full of confusion it is, and how it intertwines with the rest of my life.\n\n::unit[crystalline]\n",
    "description": "",
    "duration": null,
    "meta": {
      "math": {
        "macros": ""
      }
    },
    "ownerId": "41786b7c-b873-4373-8ede-477bf85070a1",
    "publicationDate": "2024-06-15 23:40:16.340316 UTC",
    "slug": "logs",
    "title": "Research logs",
    "type": "collection"
  },
  {
    "id": "73320725-bb2d-479f-97d1-daa14a4d0874",
    "content": "In this post I'm going to talk about writing numbers in different bases.\n\nOur usual way of writing numbers is in _base 10_. This means we represent a number as a sum of multiples of powers of 10. For example,\n\n\\[\\begin{align*}\n  324 &= 300 + 20 + 4\\\\\n      &= 3\\cdot100 + 2\\cdot 10 + 4\\cdot1\\\\\n      &= \\mathbf 3\\cdot10^2 + \\mathbf 2\\cdot 10^1 + \\mathbf 4\\cdot10^0\n\\end{align*}\\]\n\nWriting numbers in another base means we replace 10 with some other number. For example, $13$ is written as $1101$ in binary (base 2), because\n\n\\[\\begin{align*}\n  13 &= 8 + 4 + 1\\\\\n     &= 1\\cdot8 + 1\\cdot4 + 0\\cdot2 + 1\\cdot1\\\\\n     &= \\mathbf 1\\cdot2^3 + \\mathbf 1\\cdot2^2 + \\mathbf 0\\cdot2^1 + \\mathbf 1\\cdot2^0\n\\end{align*}\\]\n\nWe can indicate the base with a subscript: $13_{10} = 1101_{2}$. Note we're still using base 10 to write the subscript.\n\nIf the base is bigger than 10, we need symbols to go beyond the existing digits $0,1,2,3,4,5,6,7,8,9$. Traditionally, this is done using letters. So for instance, A represents 10, B represents 11, and so on, and F represents 15. For example, $173$ in \"hexadecimal\" (base 16) is $\\mathrm{AD}_{16}$, because\n\n\\[\\begin{align*}\n  173_{10} &= 10\\cdot 16 + 13\\cdot 1\\\\\n           &= \\mathbf A\\cdot16^1 + \\mathbf D\\cdot16^0\n\\end{align*}\\]\n\n:::think\n  How many words can you spell in hexadecimal? What are their decimal values? For example, $\\mathrm{BEEF}_{16}=48,879$.\n:::\n\nHere's a demo so you can see how this works with different numbers:\n\n::embed[{epiplexis-content}/what-study/01-legendre/02-digits/table]{inline source}\n\nThere's no _mathematical_ reason to choose 10 as our base, it's just a _cultural_ convention (probably due to us having ten fingers). For example, the Babylonians used base 60 (\"sexagesimal\"), and the Mayans used base 20 (\"vigesimal\"). Hexadecimal is used fairly often in computing.\n\nThe same idea works to the right of the \"decimal point\". For instance, $0.75_{10} = 0.11_{2}$, because\n\n\\[\\begin{align*}\n  0.75_{10} &= 0.5 + 0.25\\\\\n             &= \\mathbf 1\\cdot 2^{-1} + \\mathbf1 \\cdot{2^{-2}}\n\\end{align*}\\]\n\n## Converting\n:::example\n  Let's see how to convert bases by hand. We'll write $\\red{420}$ in base $\\blue{16}$. The remainder when $\\red{420}$ is divided by $\\blue{16}$ is $\\green4$, which we write as $\\red{420}\\equiv\\green4\\bmod\\blue{16}$. This tells us that the last hexadecimal digit of $\\blue{16}$ is $\\green4$.\n\n  Next, $\\red{420}-\\green4=\\red{416}$ is divisible by $\\blue{16}$. We divide $\\red{416}$ by $\\blue{16}$ to get $\\frac{\\red{416}}{\\blue{16}}=\\red{26}$. Now we have $\\red{26}\\equiv\\green{10}\\bmod\\blue{16}$, so the second-last (\"tens\") hexadecimal digit of $\\red{420}$ is $\\green{\\mathrm A}$ (which we use for the number $\\green{10}$).\n\n  Again we subtract $\\red{26}-\\green{10}=\\red{16}$, which divided by $\\blue{16}$ is $\\green1$. So $\\red{420}$ in hexadecimal is\n \\[ \\red{420}_{10} = \\green{\\mathrm{1A4}}_{\\blue{16}}. \\] \n Again, remember that this means\n \\[ \\red{420} = \\green4\\cdot\\blue{16}^0 + \\green{10}\\cdot\\blue{16}^1 + \\green1\\cdot\\blue{16}^2 \\fade{{}+\\green0\\cdot\\blue{16}^3+\\dotsb} \\]\n The algorithm we used above basically works by writing this as\n \\[ \\red{420} = \\green4\\cdot\\blue{16}^0 + \\blue{16}\\cdot(\\green{10} + \\blue{16}\\cdot(\\green1\\fade{{} + \\blue{16}\\cdot(\\green0 + \\dotsb)})). \\]\n:::\n\nHere's an implementation of that in code. We can check our work against the built-in [`Number.prototype.toString()`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number/toString) method.\n\n```ts\n// !interactive\nconst num = 420;\nconst base = 16;\n\n// built-in function\nconsole.log(`built-in: ${num.toString(base)}`);\n// implementing it ourselves\nconsole.log(`    ours: ${writeInBase(num, base)}`)\n\n/** Write a number in another base. */\nfunction writeInBase(\n  num,\n  base,\n  alphabet = \"0123456789abcdefghijklmnopqrstuvwxyz\"\n) {\n  if (base > alphabet.length) {\n    throw new RangeError(`Maximum base is ${alphabet.length}`);\n  }\n  \n  const digits = [];\n\n  // handle 0\n  if (num === 0) return \"0\";\n\n  // handle negative numbers\n  if (num < 0) return \"-\" + writeInBase(num, base);\n  \n  while (num > 0) {\n    const remainder = num % base;\n    digits.push(alphabet[remainder]);\n\n    num = (num - remainder) / base;\n  }\n\n  return digits.reverse().join(\"\");\n}\n```\n\n:::think\n  Can you modify the above algorithm to handle decimals, e.g. $420.1137$?\n:::\n\n## Uses\n\nAlthough the vast majority of what we do is in base 10, there are a handful of places where we make use of other bases. Here are a few:\n\n### Colors\nIf you grew up in the 90s, you may remember `[color=#FF0000]` or `<FONT COLOR=\"#ffffff\">` from forums and GeoCities. What do these mean?\n\nOn a computer, colors are represented by red, blue, and green (RGB) components, each between $0$ and $255$. Since $255 = 256 - 1 = 2^8 - 1 = 100_{16}-1$, this is between $0$ and $\\mathrm{FF}_{16}$ when written in hexadecimal. For example, <span style=\"color:#FF0060;\">#FF0060</span> is $255$ red, $0$ green, and ${60}_{16}=96$ blue. Here's a demo where you can experiment with this in general: \n\n::embed[{epiplexis-content}/what-study/01-legendre/02-digits/colors]{class=mt-2 inline source}\n\n### URLs\nVery high bases are sometimes used to make short URLs, e.g. [https://old.reddit.com/11jznte/](https://old.reddit.com/11jznte/) or [https://youtu.be/dQw4w9WgXcQ](https://youtu.be/dQw4w9WgXcQ). In their database, this thread has some numeric ID like `1298482891`, and `11jznte` is that number written in some base. I'm not sure exactly which base they chose: if we use capital and lower letters, the digits 0–9, and hyphens and underscores, then we get\n\\[ 2\\cdot26 + 10 + 2 = 64 \\]\nas a base. But it's best to omit e.g. capital O and lowercase l, so we don't get confused between `0O1l`, so in practice it's more likely to be base 62 or smaller.\n\n<!-- ::embed[{epiplexis-content}/what-study/01-legendre/02-digits/switches]{aspect-ratio=2.5} -->\n\n## What does it mean?\n\nSo, a given number can be represented many different ways. What can we learn about a given number by writing in various different bases? Let's look at a few different examples of this, and then a conceptual way of organizing it.\n\n### Rationality\n\nWe have names for different kinds of numbers.\n\n- the :dfn[natural numbers] are $0,1,2,\\dots$\n- the :dfn[integers] are $\\dots,-2,-1,0,1,2,\\dots$\n- a :dfn[rational] number is one that can be expressed as a _ratio_ of integers. For example, $\\frac12$, $\\frac53$, $-\\frac{12}7$, and so on.\n- numbers which aren't rational are called :dfn[irrational]. For example, $\\pi$ and $\\sqrt2$ are irrational.\n\nRationality can be seen in the digit representation of a number: a _rational_ number will always have a repeating pattern of digits. For example,\n\n\\[\\begin{align*}\n  \\frac{4}{11} &= 0.36363636\\dots\\\\\n\\end{align*}\\]\nwhich we write as\n\\[\\begin{align*}\n  \\phantom{\\frac{4}{11}} &= 0.\\overline{36}\\phantom{363636\\cdots}\n\\end{align*}\\]\n\nThis includes the case of a _terminating_ expression, which we can think of as a repeating $0$. In fact, every rational number has a _terminating_ expression in _some_ base. For example, we have\n\\[ 11/9 = 1.\\overline2_{10} = 1.12_6 = 1.02_3. \\]\nwhich terminates in bases 3 and 6 but repeats infinitely in base 10.\n\nIrrational numbers, on the other hand, never fall into a repeating pattern. (This doesn't mean there's \"no pattern\" to their digits, just that it can't be expressed so simply.)\n\n### Last digits\n\nLet's start by thinking about what the _last_ digit of an integer written in binary means. The numbers $0$ through $7$ written in binary are\n\\[ \\blue0,\\, \\red1,\\, 1\\blue0,\\, 1\\red1,\\, 10\\blue0,\\, 10\\red1,\\, 11\\blue0,\\, 11\\red1 \\]\nNotice that: **the last binary digit of a number tells us whether it's odd or even!**\n\nIn many situations, this is all we need to know about the number. For example, suppose you leave a room with the lights on, and come back later and the lights are off. You know that the light switch must have been flipped an **odd** number of times, but the exact number of times isn't relevant.\n\nIn general: the last digit of a number in base $b$ is its **remainder** when divided by $b$.\n\nWhat about, say, the first digit? It turns out that this is harder to interpret. To see why, let's consider two addition problems, where some of the numbers are covered up.\n\n\\[\n  \\begin{align*}\n        ?7\\\\\n    {}+{?4}\\\\\\hline\n    ??1\n  \\end{align*}\n  \\qquad\n  \\begin{align*}\n        7?\\\\\n    {}+{2?}\\\\\\hline\n    ???\n  \\end{align*}\n\\]\n\nFor example, the first of these could be either of the concrete problems\n\n\\[\n  \\begin{align*}\n       37\\\\\n    {}+64\\\\\\hline\n    101\n  \\end{align*}\n  \\qquad\n  \\begin{align*}\n       17\\\\\n    {}+24\\\\\\hline\n    41\n  \\end{align*}\n\\]\n\nAlthough these give different answers, the _last digit_ is the same between the two answers.  But in the second case, we can't pin down any of the digits for sure, not even the tens. For example, we could have either of\n\\[\n  \\begin{align*}\n       73\\\\\n    {}+25\\\\\\hline\n       98\n  \\end{align*}\n  \\qquad\n  \\begin{align*}\n       75\\\\\n    {}+29\\\\\\hline\n      104\n  \\end{align*}\n\\]\nAt most we can say that the middle $?$ is either $9$ or $0$.\n\nIn other words: to figure out the last digit of $a+b$, you just need to know the last digit of $a$ and of $b$. But to know the _second-last_ digit of $a+b$, you need to know the _last two_ digits of $a$ and $b$, since there could be _carries_ from the last digit.\n\n:::yell\n  Knowing the last $k$ digits of a number written in base $b$ is the same as knowing its remainder when divided by $b^k$.\n:::\n\nHow do different bases relate? Let's write the last digits of the numbers $0$ through $9$ in bases $2$, $5,$ and $10$.\n\n::embed[{epiplexis-content}/what-study/01-legendre/02-digits/endings]{inline}\n\nNotice that: **knowing the last digit of $n$ in base $10$ is the same as knowing its last digit in base $2$ and in base $5$!**\n\nLet's try this for $2$ and $4$:\n\n::embed[{epiplexis-content}/what-study/01-legendre/02-digits/endings-24]{inline}\n\nHere we don't have quite the same pattern as above: knowing the last digit in base $4$ isn't the same as \"knowing the last digit in base $2$ and also in base $2$.\" Instead, **knowing the last digit of $n$ in base $4$ is the same as knowing its last _two_ digits in base $2$**.\n\n:::yell\n  If $b$ and $c$ have no factors in common, then knowing the last however many digits in base $bc$ is the same as knowing the last that many digits in bases $b$ and $c$.\n\n  At the opposite end, knowing the last $k$ digits in base $b^r$ is the same as knowing the last $rk$ digits in base $b$.\n:::\n\n:::example\n  Let's take $b=360$. The prime factorization of this is $360=2^3 \\cdot 3^2 \\cdot 5$. Thus, to know the last $2$ digits of a number in base $360$ is the same as knowing\n  - its last $6$ digits in base $2$, i.e. its remainder when divided by $2^6=64$; \n  \n  - its last $4$ digits in base $3$, i.e. its remainder when divided by $3^4=81$;\n  \n  - its last $2$ digits in base $5$, i.e. its remainder when divided by $5^2=25$.\n:::\n\n### The function analogy\n\nWriting a number in base $b$,\n\\[ n = n_0 b^0 + n_1 b^1 + n_2 b^2 + \\dotsb \\]\nlooks very similar to writing a polynomial in one variable $x$:\n\\[ f(x) = a_0 x^0 + a_1 x^1 + a_2 x^2 + \\dotsb \\]\n\nFor example, the number\n\\[ 4,321 = 1 + 2\\cdot 10 + 3\\cdot10^2 + 4\\cdot10^3 \\]\nlooks very similar to the polynomial\n\\[ f(x) = 1 + 2x + 3x^2 + 4x^3. \\]\nIn particular, $4,321=f(10)$.\n\nSo, is it possible to either view\n- polynomials as \"numbers in base $x$\", or alternatively\n- integers as \"functions in the variable $b$\"?\n\nThe main difference between the two situations is that to add two polynomials, you just add the coefficients together:\n\\[\\begin{align*}\n    &{}\\phantom= (1+2x+3x^2+4x^3) + (5+9x+6x^2+x^3)\\\\\n    &= (1+5) + (2+9)x + (3+6)x^2 + (4+1)x^3\\\\\n    &= 6 + 11x + 9x^2 + 5x^3\n\\end{align*}\\]\nbut when adding two numbers, we have to **carry**:\n\\[\\begin{align*}\n  4,321 + 1,695\n    &= (1+5) + (2+9)\\cdot10 + (3+6)\\cdot10^2 + (4+1)\\cdot10^3\\\\\n    &= 6 + \\red11\\cdot10 + 9\\cdot10^2 + 5\\cdot10^3\\\\\n    &= 6 + 1\\cdot10 + \\red10\\cdot10^2 + 5\\cdot10^3\\\\\n    &= 6 + 1\\cdot10 + 0\\cdot10^2 + 6\\cdot10^3\\\\\n    &= 6,016\n\\end{align*}\\]\n\nSo in this analogy, polynomials are actually easier to work with than numbers! So we should take the _second_ of the above suggestions: that is, try to understand integers as ``functions in the variable $b$''.\n\nThere's a ton of math research around trying to flesh out this analogy; it broadly goes under the name of the \"function analogy\" or the \"philosophy of the [field with one element](https://en.wikipedia.org/wiki/Field_with_one_element)\" (but it will take quite a while to explain that name). The stuff I think about is part of or adjacent to one of the main approaches to doing so (but there are several others). Basically, we understand polynomials very very well, so we could try to take the tools we have for working with polynomials and translate them through this analogy to get very powerful tools for understanding integers and prime numbers and so on.\n\nCarrying is just one way that base expansions are harder to work with than polynomials. Another major one is that we can contemplate polynomials in _multiple variables_, e.g.\n\\[\n  x^2 + 2xy + y^2\n  \\quad\\text{or}\\quad\n  z^2-xy\n\\]\nWe really don't know what the analogue of this would be for numbers, i.e. how to \"mix bases\". In the past 10 years, there's been an explosion of activity in this area, and we now have very precise _glimpses_ of _parts_ of what this ought to be. These are very exciting, but we definitely don't have the full picture yet.\n\nWhat would be a satisfactory answer to \"fleshing this out\"? And relatedly, what would such a thing be good for?\n\nThe [Riemann hypothesis](https://en.wikipedia.org/wiki/Riemann_hypothesis) is widely considered the most important unsolved problem in math. It's a technical statement about complex numbers, but basically it gives an extremely precise description of the distribution of prime numbers, i.e. what is the probability that a randomly chosen number will be prime? There's a \"polynomial\" version of the Riemann hypothesis, which is still extremely difficult, but was proven in 1974. So one proposed strategy for proving the original Riemann hypothesis is to take that proof and translate it through this analogy—but that gets stuck due to not being able to talk about \"multi-base numbers\".\n\nConversely, this provides a way of assessing claims of \"making sense of the function analogy\". There's lots and lots of ideas about how to do this—but until we can prove the Riemann hypothesis, we haven't found the \"one true way\" (if there is one).\n\nI'll devote a future chapter to explaning the function analogy in more detail.",
    "description": "",
    "duration": null,
    "meta": {
      "math": {
        "macros": "\\newcommand{\\fade}[1]{\\htmlStyle{opacity:0.2;}{#1}}}"
      }
    },
    "ownerId": "41786b7c-b873-4373-8ede-477bf85070a1",
    "publicationDate": "2024-06-15 23:40:16.340316 UTC",
    "slug": "bases",
    "title": "Different bases",
    "type": "article"
  },
  {
    "id": "83831908-8ad2-4a60-b457-36c3b0752c14",
    "content": "Last time we saw that we could animate a point moving from $a$ to $b$ via\n\n\\[ \\lerp_\\t(\\a, \\b) = \\a + \\t(\\b - \\a) \\]\n\nWhile this formula is simple, the resulting motion doesn't look very realistic. Real objects don't move at a constant speed: they **accelerate** from rest, and **decelerate** before coming to a stop.\n\nWe can make this more realistic by using what's called an :dfn[easing function]. An easing function is essentially a function\n\\[ f\\colon \\CIntvl01 \\to \\CIntvl 01 \\quad \\text{ with $f(0)=0$ and $f(1)=1$}\\]\nthat tells you how fast you should be moving. Some examples are\n\\[ f(t) = t^3, \\qquad g(t)=\\sin\\frac{\\pi t}2 \\]\n(Again, we'll cover trig functions in the next chapter.)\n\nOur formulas become\n\\[\\begin{align*}\n  \\a + \\t^3(\\b - \\a) \n  &\\quad\\text{or}\\quad\n  (1-\\t^3)\\a + \\t^3\\b\\\\\n  \\a + \\sin\\frac{\\pi\\t}2(\\b-\\a)\n  &\\quad\\text{or}\\quad\n  \\left(1-\\sin\\frac{\\pi\\t}2\\right)\\a + \\sin\\frac{\\pi\\t}2\\b\n\\end{align*}\\]\n\nBut these formulas are very complicated. We don't actually need to expand the formula like this: we already understand $\\lerp_\\t(\\a,\\b)$, so we can just focus on the easing function.\n\n## Easing functions\n\nBefore launching into the theoretical discussion, let's cover practical resources on using easing functions.\n\n(easings.net, CSS functions)\n\n## Composition\n\nLet's take a more formal look at this.\n\n:::definition\n  Given two functions\n  \\[\\begin{align*}\n    f \\colon X &\\to Y\\\\\n    g \\colon Y &\\to Z,\n  \\end{align*}\\]\n  their :dfn[composite] $g\\circ f$ is the function\n  \\[ g\\circ f\\colon X\\to Z \\]\n  given by\n  \\[ (g\\circ f)(x) = g(\\underbrace{f(x)}_{{}\\in Y}) \\]\n  We sometimes write the composite as simply $gf$, omitting the $\\circ$.\n:::\n\nNote the order of composition is backwards to how we might say it out loud: $g\\circ f$ means apply $f$ first, then feed the result of that into $g$. However, the order $g\\circ f$ lines up with how we apply the function to an input (either in math or in programming).\n\n```ts\n/** Compose two functions */\nfunction compose<X, Y, Z>(g: (y: Y) => Z, f: (x: X) => Y): (x: X) => Z {\n  return (x) => g(f(x));\n}\n```\n\n**Functional** programming emphasizes composition more than imperative style programming. For example, here are two ways to sum the list of the first $n$ squares:\n\n```ts\n/** Sum the first n integers, 0^2 + 1^2 + 2^2 + ... + n^2 */\nfunction imperativeStyle(n: number) {\n  let sum = 0;\n\n  for (let i = 1; i <= n; ++i) {\n    sum += i ** 2;\n  }\n  \n  return sum;\n}\n\n/** Sum an array of numbers */\nfunction sum(arr: number[]) {\n  return arr.reduce((a, b) => a + b, 0);\n}\n\n/** Get an array of the integers 0, 1, ..., n */\nfunction range(n: number) {\n  return Array.from({length: n + 1}).map((_, i) => i)\n}\n\n/** Sum the first n integers, 0^2 + 1^2 + 2^2 + ... + n^2 */\nconst functionalStyle = compose(\n  sum,\n  compose(\n    // square entries\n    (arr) => arr.map(i => i ** 2),\n    range\n  )\n);\n```\n\n## Isomorphism\n\nTime to learn a fancy new word!\n\nYou might wonder why easing functions are only defined as functions\n\\[ \\CIntvl01 \\to \\CIntvl01 \\]\nIf we're animating something that lasts $5$ seconds, we might instead want to use a function\n\\[ \\CIntvl05 \\to \\CIntvl01 \\]\nif measuring time in seconds, or $\\CIntvl0{5000}\\to\\CIntvl01$ if measuring time in milliseconds. Similarly, if the character we're animating is traveling from point $1$ to point $8$, it might make more sense to use a map\n\\[ \\CIntvl05 \\to \\CIntvl18. \\]\n\nHowever, there's an easy way to convert between these. For any $\\CIntvl ab$, we have a map\n\\[\\begin{align*}\n  \\gamma_{a,b}\\colon \\CIntvl01 &\\to \\CIntvl ab\\\\\n  \\gamma_{a,b}(t) &= a+t(b-a)\n\\end{align*}\\]\nWe can also convert back: to do this, let's write $y=\\gamma_{a,b}(t)$, and then solve for $t$ in terms of $y$:\n\\[\\begin{align*}\n  y &= a+t(b-a)\\\\\n  y - a &= t(b-a)\\\\\n  t &= \\frac{y-a}{b-a}\n\\end{align*}\\]\nWe'll call this $\\gamma_{a,b}^{-1}\\colon\\CIntvl ab\\to\\CIntvl01$.\n\nWe can turn our function\n\\[ f\\colon \\CIntvl05 \\to \\CIntvl{75}{100} \\]\ninto a function $g\\colon \\CIntvl01\\to\\CIntvl01$ via\n\\[\\begin{CD}\n  \\CIntvl01 @>g>> \\CIntvl01\\\\\n  @V{\\gamma_{0,5}}VV @AA{\\gamma_{75,100}^{-1}}A\\\\\n  \\CIntvl05  @>>f> \\CIntvl{75}{100} \n\\end{CD}\\]\nThat is, $g=\\gamma_{75,100}^{-1}\\circ f\\circ\\gamma_{0,5}$.\n\nSo, in complete generality we might want to consider functions\n\\[ \\CIntvl ab \\to \\CIntvl cd \\]\nBut we can \"normalize\" these down to only considering functions\n\\[ \\CIntvl01 \\to \\CIntvl 01. \\]\nNote that we needed **both** $\\gamma$ and $\\gamma^{-1}$ to do this.\n\n",
    "description": "",
    "duration": null,
    "meta": {
      "math": {
        "macros": "\\newcommand{\\a}{\\red a}\n\\newcommand{\\b}{\\blue b}\n\\newcommand{\\t}{{\\color{gold} t}\n\\newcommand{\\id}{\\mathrm{id}}"
      }
    },
    "ownerId": "41786b7c-b873-4373-8ede-477bf85070a1",
    "publicationDate": "2024-06-15 23:40:16.340316 UTC",
    "slug": "easings",
    "title": "Composition / Easings",
    "type": "article"
  },
  {
    "id": "f173d254-8dbe-4425-8c65-454b16e4c95f",
    "content": "::unit[cg]\n\n::unit[trig]\n",
    "description": "",
    "duration": null,
    "meta": {
      "math": {
        "macros": "\\newcommand{\\I}{\\htmlData{annotation_text=unit interval}{I}}\n\n\\newcommand{\\cl}[2]{\\htmlClass{__ktx-content-#1}{#2}}\n\n% linear algebra\n\n\\newcommand{\\vec}[2]{\\begin{bmatrix}#1\\\\#2\\end{bmatrix}}\n\\newcommand{\\pt}[2]{\\begin{pmatrix}#1\\\\#2\\end{pmatrix}}\n\n\\newcommand{\\ivec}[1]{\\left(#1\\right)}\n\\newcommand{\\ipt}[1]{\\<#1\\>}\n\n\\newcommand{\\matr}[4]{\\begin{bmatrix}#1&#2\\\\#3&#4\\end{bmatrix}}\n\\newcommand{\\Matr}[1]{\\htmlData{annotation_text=matrix of linear transformation $#1$}{[#1]}}\n\n\\newcommand{\\dist}[2]{d(#1, #2)}\n\\newcommand{\\Dist}[2]{\\htmlData{annotation_text=distance from $#1$ to $#2$}{\\dist{#1}{#2}}}\n\n\\newcommand{\\norm}[1]{\\|#1\\|}\n\\newcommand{\\Norm}[1]{\\htmlData{annotation_text=length of vector $#1$}{\\norm{#1}}}\n\n\\newcommand{\\Dir}[1]{\\htmlData{annotation_text=normalization of $#1$}{\\widehat{#1}}}\n\n\\newcommand{\\Rot}[1]{\\htmlData{annotation_text=rotation by $#1$ ccw around the origin}{R_{#1}}}\n\\newcommand{\\ARot}[3]{\\htmlData{annotation_text=rotation of point $#2$ around point $#3$ by $#1$ (counter-clockwise)}{R_{#1}(#2;#3)}}\n\n\\newcommand{\\Refl}[1]{\\htmlData{annotation_text=reflection across the line through the origin at angle $#1$}{F_{#1}}}\n\n% graphics\n\\newcommand{\\lerp}{\\operatorname{lerp}}\n\n\\newcommand{\\ClsdIntvl}{\\CIntvl}\n\\newcommand{\\CIntvl}[2]{\\htmlData{annotation_text=$\\{x\\mid{#1}\\le{x}\\le {#2}\\}$}{[#1,#2]}}\n\\newcommand{\\OIntvl}[2]{\\htmlData{annotation_text=$\\{x\\mid{#1}<{x}<{#2}\\}$}{[#1,#2]}}\n\\newcommand{\\LIntvl}[2]{\\htmlData{annotation_text=$\\{x\\mid{#1}\\le{x}<{#2}\\}$}{[#1,#2]}}\n\\newcommand{\\RIntvl}[2]{\\htmlData{annotation_text=$\\{x\\mid{#1}<{x}\\le{#2}\\}$}{[#1,#2]}}\n\n% spaces\n\\newcommand{\\AffR}[1]{\\htmlData{annotation_text=$#1$-dimensional real affine space}{\\cl{A}{\\A^{#1}}}}\n\\newcommand{\\VecR}[1]{\\htmlData{annotation_text=$#1$-dimensional real vector space}{\\cl{R}{\\R^{#1}}}}\n\\newcommand{\\S}[1]{\\htmlData{annotation_text=$#1$-dimensional unit sphere}{S^{#1}}}\n\n"
      }
    },
    "ownerId": "41786b7c-b873-4373-8ede-477bf85070a1",
    "publicationDate": "2024-06-15 23:40:16.340316 UTC",
    "slug": "gng",
    "title": "Geometry & Graphics",
    "type": "collection"
  },
  {
    "id": "567e4f9b-ea31-4eb0-9bd2-0d6e0784f9f8",
    "content": "<!-- #tab notes -->\nThe content so far has been rather abstract and philosophical. In this post, we're going to get our hands dirty and implement drag functionality on a popup. We'll apply ideas from the previous post on [points and vectors](./points-vectors) to figure out the math.\n\n\nHere's the basic code we'll be starting with.\n\n## Initial code\n\n```tsx\n// !interactive\nimport {useId} from \"react\";\n\nexport default function Demo() {\n  return (\n    <Popup title=\"Demo\">\n      Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod\n      tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim\n      veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea\n      commodo consequat. Duis aute irure dolor in reprehenderit in voluptate\n      velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat\n      cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id\n      est laborum.\n    </Popup>\n  );\n}\n\n/** Draggable popup */\nfunction Popup({\n  children,\n  title,\n}: {\n  children: React.ReactNode;\n  title: React.ReactNode;\n}) {\n  const headerId = useId();\n\n  return (\n    <aside\n      aria-labelledby={headerId}\n      className=\"w-[600px] max-w-[100vw] rounded-md border border-solid border-gray-200 shadow dark:border-gray-700\"\n      role=\"dialog\"\n    >\n      <header\n        className=\"select-none rounded-t-md bg-purple-600 px-2 py-1 text-white\"\n        id={headerId}\n      >\n        {title}\n      </header>\n      <div className=\"px-2 py-1\">{children}</div>\n    </aside>\n  );\n}\n```\n\nWe want to add the ability to drag this popup while holding onto the title bar.\n\nThis is a pretty simple component; the only interesting thing to point out is the use of the [dialog role](https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/Roles/dialog_role) and the [aria-labelledby](https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/Attributes/aria-labelledby) attribute, which are used for accessibility. These aren't relevant to the mathematical content of what we're doing, but I'm including them anyway because accessibility gets skipped over far too often.\n\n## A basic attempt\n\nBefore getting into the vector math, we'll start by wiring up the event listeners. I'm going to intentionally make several errors in order to point them out / warn you about them.\n\n### onPointerMove\n\nTo respond to mouse movement, we use the [`pointermove` event](https://developer.mozilla.org/en-US/docs/Web/API/Element/pointermove_event). Let's try adding that to the title bar:\n\n```tsx\n// !interactive\nimport {useId, useRef} from \"react\";\n\nexport default function Demo() {\n  return (\n    <Popup title=\"Demo\">\n      Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod\n      tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim\n      veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea\n      commodo consequat. Duis aute irure dolor in reprehenderit in voluptate\n      velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat\n      cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id\n      est laborum.\n    </Popup>\n  );\n}\n\n/** Draggable popup */\nfunction Popup({\n  children,\n  title,\n}: {\n  children: React.ReactNode;\n  title: React.ReactNode;\n}) {\n  const headerId = useId();\n\n  const onPointerMove: React.PointerEventHandler = (e) => {\n    console.log(e.clientX, e.clientY);\n  };\n\n  return (\n    <aside\n      aria-labelledby={headerId}\n      className=\"absolute w-[600px] max-w-[100vw] rounded-md border border-solid border-gray-200 shadow dark:border-gray-700\"\n      role=\"dialog\"\n    >\n      <header\n        className=\"select-none rounded-t-md bg-purple-600 px-2 py-1 text-white\"\n        id={headerId}\n        onPointerMove={onPointerMove}\n      >\n        {title}\n      </header>\n      <div className=\"px-2 py-1\">{children}</div>\n    </aside>\n  );\n}\n```\n\nOpen up your browser console to see the results. We're getting the $(x,y)$ coordinates of the pointer (cursor/finger/stylus), but only when we're over the title bar. When we try to drag the dialog into a new position, the pointer will come off of the title bar.\n\n### Body event handlers\n\nTo fix this, we'll add the `pointermove` event on `document.body`. This needs to be done imperatively, not through a React prop. We'll add a [`pointerdown`](https://developer.mozilla.org/en-US/docs/Web/API/Element/pointerdown_event) event to the title bar, and that will set up the necessary subscriptions. We can also get it to transate the dialog now.\n\n```tsx\n// !interactive\nimport {useId, useRef} from \"react\";\n\nexport default function Demo() {\n  return (\n    <Popup title=\"Demo\">\n      Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod\n      tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim\n      veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea\n      commodo consequat. Duis aute irure dolor in reprehenderit in voluptate\n      velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat\n      cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id\n      est laborum.\n    </Popup>\n  );\n}\n\n/** Draggable popup */\nfunction Popup({\n  children,\n  title,\n}: {\n  children: React.ReactNode;\n  title: React.ReactNode;\n}) {\n  const headerId = useId();\n\n  const ref = useRef<HTMLElement>(null);\n\n  const onPointerMove = (e: PointerEvent) => {\n    if (!ref.current) return;\n    ref.current.style.translate = `${e.clientX}px ${e.clientY}px`;\n  };\n\n  const onPointerDown: React.PointerEventHandler = (e) => {\n    document.body.addEventListener(\"pointermove\", onPointerMove);\n    document.body.addEventListener(\"pointerup\", onPointerUp);\n  };\n\n  const onPointerUp: React.PointerEventHandler = (e) => {\n    document.body.removeEventListener(\"pointermove\", onPointerMove);\n    document.body.removeEventListener(\"pointerup\", onPointerUp);\n  };\n\n  return (\n    <aside\n      aria-labelledby={headerId}\n      className=\"absolute w-[600px] max-w-[100vw] rounded-md border border-solid border-gray-200 shadow dark:border-gray-700\"\n      ref={ref}\n      role=\"dialog\"\n    >\n      <header\n        className=\"select-none rounded-t-md bg-purple-600 px-2 py-1 text-white\"\n        id={headerId}\n        onPointerDown={onPointerDown}\n        onPointerUp={onPointerUp}\n      >\n        {title}\n      </header>\n      <div className=\"px-2 py-1\">{children}</div>\n    </aside>\n  );\n}\n```\n\nIf you try this, you'll notice several issues. Take a minute to try diagnosing (and fixing) them yourself before looking at the solution.\n\n- the top-left corner of the dialog is following the pointer position, rather than the pointer staying in the same place as when you pressed down initially. We'll fix this in [the next section](#figuring-out-the-math).\n- the `onPointerUp` event doesn't seem to be working, and the dialog can only be \"pushed\" down and right.  \n  Hint 1: use the Inspector.  \n  Hint 2: this is unlikely to occur in a real-world application.  \n  \n   :::popup{trigger=Solution}\n     The issue is that the `<body>` tag doesn't have a width, since its only child is the absolutely positioned popup. We can fix this by wrapping the content in a tag with `min-h-screen` and `min-w-screen` applied. (Probably you should use the [new viewport units](https://dev.to/frehner/css-vh-dvh-lvh-svh-and-vw-units-27k4) here.)\n   :::\n\n- after fixing the above issue, notice that when you drag your pointer outside of the preview window and release it, you're still dragging when you move your pointer back into the preview window.\n   :::popup{trigger=Solution}\n     Lifting outside of the preview window means that `pointerup` never fires on `document.body`. This happens because the preview is in an iframe, but could also happen if the user drags their pointer out of the browser window or onto the browser chrome. We can fix it by adding a `pointerleave` event handler to `document.body`.\n   :::\n\nHere's the code with fixes for the latter two issues. Don't peek until you've tried diagnosing+fixing them yourself!\n\n```tsx\n// !interactive\nimport {useId, useRef} from \"react\";\n\nexport default function Demo() {\n  return (\n    <main className=\"min-w-screen min-h-screen\">\n      <Popup title=\"Demo\">\n        Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod\n        tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim\n        veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea\n        commodo consequat. Duis aute irure dolor in reprehenderit in voluptate\n        velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint\n        occaecat cupidatat non proident, sunt in culpa qui officia deserunt\n        mollit anim id est laborum.\n      </Popup>\n    </main>\n  );\n}\n\n/** Draggable popup */\nfunction Popup({\n  children,\n  title,\n}: {\n  children: React.ReactNode;\n  title: React.ReactNode;\n}) {\n  const headerId = useId();\n\n  const ref = useRef<HTMLElement>(null);\n\n  const onPointerMove = (e: PointerEvent) => {\n    if (!ref.current) return;\n    ref.current.style.translate = `${e.clientX}px ${e.clientY}px`;\n  };\n\n  const endDrag = () => {\n    document.body.removeEventListener(\"pointerleave\", endDrag);\n    document.body.removeEventListener(\"pointermove\", onPointerMove);\n    document.body.removeEventListener(\"pointerup\", endDrag);\n  };\n\n  const onPointerDown = () => {\n    document.body.addEventListener(\"pointerleave\", endDrag);\n    document.body.addEventListener(\"pointermove\", onPointerMove);\n    document.body.addEventListener(\"pointerup\", endDrag);\n  };\n\n  return (\n    <aside\n      aria-labelledby={headerId}\n      className=\"absolute w-[600px] max-w-[100vw] rounded-md border border-solid border-gray-200 shadow dark:border-gray-700\"\n      ref={ref}\n      role=\"dialog\"\n    >\n      <header\n        className=\"select-none rounded-t-md bg-purple-600 px-2 py-1 text-white\"\n        id={headerId}\n        onPointerDown={onPointerDown}\n      >\n        {title}\n      </header>\n      <div className=\"px-2 py-1\">{children}</div>\n    </aside>\n  );\n}\n```\n\n## Figuring out the math\n\nTo figure out how to position the popup correctly, let's introduce some notation. Let\n\n- $t\\in\\R$ denote the time since the `pointerdown` event\n- $p(t)\\in \\AffR 2$ denote the coordinates of the pointer at time $t$\n- $c(t)\\in\\AffR 2$ denote the desired coordinates of the top-left corner of the popup at time $t$\n\nTo keep the pointer \"in the same place\" on the title bar, the relationship we want is\n\\[ p(0) - c(0) = p(t) - c(t) \\quad\\text{for all }t \\]\nNote that $c(t)$ and $p(t)$ are **points**, but the common difference here is a **vector**.\n\nWhich of these do we know?\n\n- we get $p(t)$ from `e.clientX` and `e.clientY`. For $t=0$, `e` is the `pointerdown` event, for $t>0$ it's the `pointermove` event.\n\n- we can get $c(0)$ from [`getBoundingClientRect()`](https://developer.mozilla.org/en-US/docs/Web/API/Element/getBoundingClientRect) on the popup `ref`\n\n- what we need to calculate is $c(t)$ for $t>0$\n\nWe can rearrange the above formula to isolate what we want to calculate:\n\n\\[ c(t) = p(t) + \\underbrace{(c(0) - p(0))}_{\\mathtt{offset}} \\]\n\nHere's the final code:\n\n```tsx\n// !interactive\nimport {useId, useRef} from \"react\";\n\nexport default function Demo() {\n  return (\n    <main className=\"min-w-screen min-h-screen\">\n      <Popup title=\"Demo\">\n        Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod\n        tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim\n        veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea\n        commodo consequat. Duis aute irure dolor in reprehenderit in voluptate\n        velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint\n        occaecat cupidatat non proident, sunt in culpa qui officia deserunt\n        mollit anim id est laborum.\n      </Popup>\n    </main>\n  );\n}\n\n/** Draggable popup */\nfunction Popup({\n  children,\n  title,\n}: {\n  children: React.ReactNode;\n  title: React.ReactNode;\n}) {\n  const headerId = useId();\n\n  const ref = useRef<HTMLElement>(null);\n\n  const offset = useRef({x: 0, y: 0});\n\n  const onPointerMove = (e: PointerEvent) => {\n    if (!ref.current) return;\n    ref.current.style.translate = `${e.clientX + offset.current.x}px ${e.clientY + offset.current.y}px`;\n  };\n\n  const endDrag = () => {\n    document.body.removeEventListener(\"pointerleave\", endDrag);\n    document.body.removeEventListener(\"pointermove\", onPointerMove);\n    document.body.removeEventListener(\"pointerup\", endDrag);\n  };\n\n  const onPointerDown: React.PointerEventHandler = (e) => {\n    if (!ref.current) return;\n\n    // record offset\n    // [rect.x, rect.y] is what we called c(0) in the formulas\n    // [e.clientX, e.clientY] is what we called p(0) in the formulas\n    const rect = ref.current.getBoundingClientRect();\n    offset.current = {x: rect.x - e.clientX, y: rect.y - e.clientY};\n\n    // attach event handlers\n    document.body.addEventListener(\"pointerleave\", endDrag);\n    document.body.addEventListener(\"pointermove\", onPointerMove);\n    document.body.addEventListener(\"pointerup\", endDrag);\n  };\n\n  return (\n    <aside\n      aria-labelledby={headerId}\n      className=\"absolute w-[600px] max-w-[100vw] rounded-md border border-solid border-gray-200 shadow dark:border-gray-700\"\n      ref={ref}\n      role=\"dialog\"\n    >\n      <header\n        className=\"select-none rounded-t-md bg-purple-600 px-2 py-1 text-white\"\n        id={headerId}\n        onPointerDown={onPointerDown}\n      >\n        {title}\n      </header>\n      <div className=\"px-2 py-1\">{children}</div>\n    </aside>\n  );\n}\n```\n\n## Extracting Hooks\n\nNow that we have the functionality in place, let's refactor things a little bit to split out logic that's not specific to our app.\n\nFirst let's extract the logic of starting a drag operation on `pointerdown`, and ending it on `pointerup` or `pointerleave`. It's conceivable that a consumer will want to distinguish between the latter two events, so we'll make them separate.\n\n```ts\nimport {useCallback} from \"react\";\n\n/**\n * Provides generic drag functionality\n * @returns An object of event handlers to spread onto the target\n */\nfunction useDrag<T = Element>(opts: {\n  down?: React.PointerEventHandler<T>;\n  leave?: (e: PointerEvent) => unknown;\n  move: (e: PointerEvent) => unknown;\n  up?: (e: PointerEvent) => unknown;\n}) {\n  // pointer event handlers\n  const onPointerUp = useCallback(\n    (e: PointerEvent) => {\n      opts.up?.(e);\n      unsubscribe();\n    },\n    [opts.up],\n  );\n\n  const onPointerLeave = useCallback(\n    (e: PointerEvent) => {\n      opts.leave?.(e);\n      unsubscribe();\n    },\n    [opts.leave],\n  );\n\n  /** Remove event handlers from document.body */\n  const unsubscribe = useCallback(() => {\n    document.body.removeEventListener(\"pointerleave\", onPointerLeave);\n    document.body.removeEventListener(\"pointermove\", opts.move);\n    document.body.removeEventListener(\"pointerup\", onPointerUp);\n  }, [opts.move, onPointerLeave, onPointerUp]);\n\n  const onPointerDown: React.PointerEventHandler<T> = useCallback(\n    (e) => {\n      opts.down?.(e);\n\n      // attach event handlers\n      document.body.addEventListener(\"pointerleave\", onPointerLeave);\n      document.body.addEventListener(\"pointermove\", opts.move);\n      document.body.addEventListener(\"pointerup\", onPointerUp);\n    },\n    [opts.move, onPointerUp, onPointerLeave],\n  );\n\n  return {onPointerDown};\n}\n```\n\nNext, let's address the specific case of dragging an element. We can build on what we did above:\n\n```ts\n/** Provides functionality to drag an element */\nfunction useDragElement<TRoot extends HTMLElement, TAnchor extends Element>(): {\n  /** Events to spread onto the dragging \"anchor\" */\n  anchorEvents: {\n    onPointerDown: React.PointerEventHandler<TAnchor>;\n  };\n\n  /** Ref to attach to the object you wish to make draggable. */\n  ref: React.RefObject<TRoot>;\n} {\n  const ref = useRef<TRoot>(null);\n\n  const offset = useRef({x: 0, y: 0});\n\n  const anchorEvents = useDrag(\n    useMemo(\n      () => ({\n        down: (e: React.PointerEvent<TAnchor>) => {\n          if (!ref.current) return;\n\n          // set offset\n          const rect = ref.current.getBoundingClientRect();\n          offset.current = {x: rect.x - e.clientX, y: rect.y - e.clientY};\n        },\n        move: (e: PointerEvent) => {\n          if (!ref.current) return;\n          const x = e.clientX + offset.current.x;\n          const y = e.clientY + offset.current.y;\n          ref.current.style.translate = `${x}px ${y}px`;\n        },\n      }),\n      [],\n    ),\n  );\n\n  return {\n    anchorEvents,\n    ref,\n  };\n}\n```\n\nThe complete refactored version is at the GitHub link below.\n\n::embed[{epiplexis-content}/gng/01-coordinates/07-dragging/demo]{source aspect-ratio=1.5}\n\n## Remarks\n\nTo get a full-featured dialog component (accessibility, focus guard, etc.), I recommend the [Radix Dialog](https://www.radix-ui.com/primitives/docs/components/dialog) component. You can attach this behavior onto one of those.\n\nDid we really need the abstract math perspective to figure the formula for the translation? Not really, we'd have eventually gotten there by trial and error + drawing some pictures. But getting comfortable with manipulating these makes it easier to just sit down and derive the formula and feel confident in it. The \"type safety\" of the points-vs-vectors distinction can also rule out faulty guesses.\n\n<!-- #tab exercises -->\n\n1. Modify the code to prevent the user from dragging the popup offscreen. You will need [`window.innerWidth`](https://developer.mozilla.org/en-US/docs/Web/API/Window/innerWidth) and [`window.innerHeight`](https://developer.mozilla.org/en-US/docs/Web/API/Window/innerHeight).\n\n2. Add functionality to resize the popup. You can make drag handles like so:  \n   ```tsx\n   // !interactive\n    import {useId} from \"react\";\n   \n   export default function Demo() {\n     return (\n       <Popup title=\"Demo\">\n         Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod\n         tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim\n         veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea\n         commodo consequat. Duis aute irure dolor in reprehenderit in voluptate\n         velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat\n         cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id\n         est laborum.\n       </Popup>\n     );\n   }\n   \n   /** Draggable popup */\n   function Popup({\n     children,\n     title,\n   }: {\n     children: React.ReactNode;\n     title: React.ReactNode;\n   }) {\n     const headerId = useId();\n   \n     return (\n       <aside\n         aria-labelledby={headerId}\n         className=\"max-w-[100vw] w-[600px] absolute rounded-md border border-solid border-gray-200 shadow dark:border-gray-700\"\n         role=\"dialog\"\n       >\n         <header\n           className=\"select-none rounded-t-md bg-purple-600 px-2 py-1 text-white\"\n           id={headerId}\n         >\n           {title}\n         </header>\n         <div className=\"px-2 py-1\">{children}</div>\n         {/* drag handles */}\n         <div className=\"absolute bottom-0 left-0 h-2 w-full cursor-ns-resize\" />\n         <div className=\"absolute right-0 top-0 h-full w-2 cursor-ew-resize\" />\n       </aside>\n     );\n   }\n   ```\n",
    "description": "",
    "duration": null,
    "meta": {
      "math": {
        "macros": ""
      }
    },
    "ownerId": "41786b7c-b873-4373-8ede-477bf85070a1",
    "publicationDate": "2024-08-19 05:26:12.146533 UTC",
    "slug": "dragging",
    "title": "Drag functionality",
    "type": "article"
  },
  {
    "id": "3871a07c-a634-45b5-b564-aba7ae31d656",
    "content": "",
    "description": "",
    "duration": 280962,
    "meta": {},
    "ownerId": "41786b7c-b873-4373-8ede-477bf85070a1",
    "publicationDate": "2025-01-12 08:19:04.766 UTC",
    "slug": "",
    "title": "SIR test",
    "type": "recording"
  },
  {
    "id": "b66bfba4-9b5e-4092-914d-d149b280f9f0",
    "content": "",
    "description": "",
    "duration": 368674,
    "meta": {},
    "ownerId": "41786b7c-b873-4373-8ede-477bf85070a1",
    "publicationDate": "2025-01-16 19:04:33.163 UTC",
    "slug": "",
    "title": "SIR Python (no audio)",
    "type": "recording"
  },
  {
    "id": "8d49cb26-4c86-4667-944a-d9b18c1fd886",
    "content": "",
    "description": "",
    "duration": 589960,
    "meta": {
      "tracks": [
        {
          "kind": "captions",
          "srclang": "en"
        }
      ]
    },
    "ownerId": "41786b7c-b873-4373-8ede-477bf85070a1",
    "publicationDate": "2025-02-07 19:12:04.049 UTC",
    "slug": "",
    "title": "SIRPLOT",
    "type": "recording"
  },
  {
    "id": "bbf997e7-df65-4d03-8eb5-304fabff55a5",
    "content": "",
    "description": "",
    "duration": 460130,
    "meta": {},
    "ownerId": "41786b7c-b873-4373-8ede-477bf85070a1",
    "publicationDate": "2025-02-08 08:56:09.323 UTC",
    "slug": "",
    "title": "SEQUENCE",
    "type": "recording"
  },
  {
    "id": "94560ee1-a7b5-432f-9de0-3a137c500e5e",
    "content": "",
    "description": "",
    "duration": 6940,
    "meta": {},
    "ownerId": "4a4d8990-1de7-481e-be21-17d46c119e88",
    "publicationDate": "2025-02-08 12:49:50.536499 UTC",
    "slug": "",
    "title": "",
    "type": "recording"
  },
  {
    "id": "2d047bf3-7134-4f29-8dde-022274b43e13",
    "content": "",
    "description": "",
    "duration": 1256463,
    "meta": {},
    "ownerId": "41786b7c-b873-4373-8ede-477bf85070a1",
    "publicationDate": "2025-02-09 02:45:48.565 UTC",
    "slug": "",
    "title": "LENGTH (too long)",
    "type": "recording"
  },
  {
    "id": "a0ff0333-817a-4258-aeb3-97059b823fe8",
    "content": "",
    "description": "",
    "duration": 614006,
    "meta": {},
    "ownerId": "41786b7c-b873-4373-8ede-477bf85070a1",
    "publicationDate": "2025-02-09 05:44:52.733 UTC",
    "slug": "",
    "title": "LENGTH",
    "type": "recording"
  }
]

Ambiguous slug:

what-study
[
  {
    "id": "9877232c-d6e3-46c1-a140-3be13685ae82",
    "content": "",
    "description": "",
    "duration": null,
    "meta": {},
    "ownerId": "41786b7c-b873-4373-8ede-477bf85070a1",
    "publicationDate": "2024-06-15 23:40:16.340316 UTC",
    "slug": "",
    "title": "Triangle inequality",
    "type": "article"
  },
  {
    "id": "22a7b232-f4d0-492f-8249-5f2f7bf0d9f7",
    "content": "\\[ f(t) = \\cos t + i\\sin t \\]\n\n\\[\\begin{align*}\n  \\frac d{dt}\\cos t &= -\\sin t\\\\[.5em]\n  \\frac d{dt}\\sin t &=  \\cos t\n\\end{align*}\\]\n\n\\[ f'(t) = ci f(t) \\]\nfor some constant $c>0$. In fact, we have $c=1$ since blah. Thus, $f(t)$ satisfies the **initial value problem**\n\\[\\begin{aligned}\n  f'(t) &= i f(t)\\\\\n   f(0) &= 1. \\]\n\\end{aligned}\\]\n\nWe know that the unique solution to the equation\n\\[\\begin{aligned}\n  f'(t) &= k f(t)\\\\\n   f(0) &= a. \\]\n\\end{aligned}\\]\nis\n\\[ f(t) = ae^{kt} \\]\n\n\\[ e^{it} = \\cos t + i \\sin t \\]\n\nThis is known as **Euler's formula**.\n\n### A note on definitions\nDepending on your definition of $e^x$, the above equation may or may not be meaningful. There's no problem with the right-hand side: we already know what $\\cos(t)$ and $\\sin(t)$ mean for $t\\in\\R$.\n\\[ \\exp(z) = \\sum_{n=0}^\\infty \\frac{z^n}{n!} \\]\n\nIt might be better to write\n\\[ \\exp(it) = \\cos t + i\\sin t \\]\n\n## The kernel\n\n\\[ e^{\\Twopi i} = 1 \\]\n\nMore specifically,\n\n\\[ e^{i\\theta_1} = e^{i\\theta_2} \\iff \\theta_1 - \\theta_2 \\in \\Twopi\\Z \\]\n\n(rant about abelian groups?)\n\n## Trigonometric identities\n\\[\\begin{align*}\n  \\cos(\\alpha+\\beta) + i\\sin(\\alpha+\\beta)\n    &= e^{i(\\alpha+\\beta)}\\\\\n    &= e^{i\\alpha} e^{i\\beta}\\\\\n    &= (\\cos\\alpha+i\\sin\\alpha)(\\cos\\beta+i\\sin\\beta)\\\\\n    &= (\\cos\\alpha\\cos\\beta - \\sin\\alpha\\sin\\beta)+i(\\sin\\alpha\\cos\\beta+\\cos\\alpha\\sin\\beta)\n\\end{align*}\\]\n\nSetting real and imaginary parts equal to each other, we get\n\n\\[\\begin{align*}\n  \\cos(\\alpha+\\beta) &= \\cos\\alpha\\cos\\beta - \\sin\\alpha\\sin\\beta\\\\\n  \\sin(\\alpha+\\beta) &= \\sin\\alpha\\cos\\beta + \\cos\\alpha\\sin\\beta\n\\end{align*}\\]\n\n<iframe src=\"https://www.desmos.com/calculator/vtoks21fah\"></iframe>",
    "description": "",
    "duration": null,
    "meta": {},
    "ownerId": "41786b7c-b873-4373-8ede-477bf85070a1",
    "publicationDate": "2024-06-15 23:40:16.340316 UTC",
    "slug": "euler",
    "title": "Euler's formula",
    "type": "article"
  },
  {
    "id": "e3772289-b7b0-4b9c-997f-0c1e448525da",
    "content": "",
    "description": "",
    "duration": null,
    "meta": {},
    "ownerId": "41786b7c-b873-4373-8ede-477bf85070a1",
    "publicationDate": "2024-06-15 23:40:16.340316 UTC",
    "slug": "trinequality",
    "title": "Triangle inequality",
    "type": "article"
  },
  {
    "id": "3a48eda2-c609-415b-abde-76be30a97ba3",
    "content": "Define oh no\n\nis it broken",
    "description": "",
    "duration": null,
    "meta": {},
    "ownerId": "41786b7c-b873-4373-8ede-477bf85070a1",
    "publicationDate": "2024-06-15 23:40:16.340316 UTC",
    "slug": "tan",
    "title": "tan and atan2",
    "type": "article"
  },
  {
    "id": "c486f03e-b8c0-44bd-b461-f6da8656e14c",
    "content": "",
    "description": "",
    "duration": null,
    "meta": {},
    "ownerId": "41786b7c-b873-4373-8ede-477bf85070a1",
    "publicationDate": "2024-06-15 23:40:16.340316 UTC",
    "slug": "complex",
    "title": "Complex numbers",
    "type": "article"
  },
  {
    "id": "04686363-c824-4cc8-a90c-8342bac06dd5",
    "content": "",
    "description": "",
    "duration": null,
    "meta": {},
    "ownerId": "41786b7c-b873-4373-8ede-477bf85070a1",
    "publicationDate": "2024-06-15 23:40:16.340316 UTC",
    "slug": "mandelbrot",
    "title": "Mandelbrot set",
    "type": "article"
  },
  {
    "id": "bced6fd2-30fd-4fa1-8db4-1b89d8bac593",
    "content": "",
    "description": "",
    "duration": null,
    "meta": {},
    "ownerId": "41786b7c-b873-4373-8ede-477bf85070a1",
    "publicationDate": "2024-06-15 23:40:16.340316 UTC",
    "slug": "reflections",
    "title": "Reflections",
    "type": "article"
  },
  {
    "id": "04e1b41e-8fdd-4fd3-a7b5-49433e5b6b02",
    "content": "In this post and [the next](./maps) we'll introduce the idea of *functions* or *maps* between spaces. This is where things start to get more interesting and dynamic. The sequel will dive into the theoretical ideas around functions; in this post, we'll focus more concretely on how to *graph* or *plot* them.\n\n## 2d graphing\n\nIf $f\\colon\\R\\to\\R$ is a function, its :dfn[graph] is the set\n\n\\[ \\{(x, f(x)) \\mid x \\in \\R \\} \\subset \\R^2. \\]\n\nThat is, we plot the input on the horizontal axis and the output on the vertical axis.\n\nA parametric plot involves _two_ functions $g,h\\colon\\R\\to\\R;$ in this case, we visualize these using the set\n\n\\[ \\{(g(t), h(t)) \\mid t\\in \\R\\} \\subset \\R^2. \\]\n\nNote that the graph of a function is a special case of parametric plotting via\n\n\\[ g(t) = t, \\quad h(t) = f(t). \\]\n\nHowever, on a general parametric plot, it's not possible to read off the input value $t$ which produced a given output value $(x,y).$\n\n### Desmos\n\n[Desmos](https://www.desmos.com/calculator) is the best 2d graphing calculator on the internet. Here's an example of explicit and parametric plotting in Desmos:\n\n<iframe class=\"w-full\" src=\"https://www.desmos.com/calculator/gshejpaijs\" height=\"500\"></iframe>\n\nIt's also possible to use Desmos programmatically. They provide an API that will embed the calculator directly into your webpage (not an iframe!)\n\n- [Desmos API docs](https://www.desmos.com/api/v1.7/docs/index.html#self-hosting)\n\n- in a TypeScript project, you can install [`@types/desmos`](https://www.npmjs.com/package/@types/desmos)\n\n- [`desmos-react`](https://github.com/ysulyma/desmos-react) provides a React wrapper around the Desmos APIs\n\nHere's an example of using `desmos-react` to embeds Desmos in a video:\n\n<iframe class=\"w-full\" src=\"https://liqvidjs.org/r/ex-desmos/\" allowfullscreen=\"\" style=\"aspect-ratio: 16 / 10;\"></iframe>\n\n[Source](https://github.com/ysulyma/ex-desmos)\n\n### SVG and Canvas\n\nSince this is a series about programming, we want to be able to plot things programmatically, without relying on GUI tools. There are two options for doing so: [SVG](https://developer.mozilla.org/en-US/docs/Web/SVG/Tutorial) and [`<canvas>`](https://developer.mozilla.org/en-US/docs/Web/API/Canvas_API). However, plotting functions directly using the APIs (rather than a library) is a bit manual, so I'll show how to do it after we cover linear interpolation (a few posts from now).\n\nAlso, for experimenting, using a GUI tool like Desmos is usually faster.\n\n## 3d graphing\n\nThere are two kinds of plotting we can do in 3d: curves and surfaces. Curves involve _three_ functions of _one_ variable:\n\n\\[\\begin{align*}\n  x &= f(t)\\\\\n  y &= g(t)\\\\\n  z &= h(t)\n\\end{align*}\\]\n\nSurfaces involve _three_ functions of _two_ variables:\n\n\\[\\begin{align*}\n  x &= f(u, v)\\\\\n  y &= g(u, v)\\\\\n  z &= h(u, v)\n\\end{align*}\\]\n\nIn 2d, a special kind of parametric curve was the graph of a single function. Similarly, if we have a _single_ function of _two_ variables $f(x, y),$ then we can visualize it using the parametric surface\n\n\\[\\begin{align*}\n  x &= u\\\\\n  y &= v\\\\\n  z &= f(u, v)\n\\end{align*}\\]\n\n### THREE.js\n\nIn this series, we'll use [THREE.js](https://threejs.org/docs/) for all our 3d examples. I'll also (usually) use it in conjunction with [React Three Fiber](https://docs.pmnd.rs/react-three-fiber/), which provides a nice declarative way to use THREE inside React.\n\nWe use [`TubeGeometry`](https://threejs.org/docs/#api/en/geometries/TubeGeometry) to plot curves, and [`ParametricGeometry`](https://threejs.org/docs/?q=parametric#examples/en/geometries/ParametricGeometry) to plot surfaces. Here's a demonstration of using THREE.js to plot the parametric curve\n\n\\[\n  \\vcenter{\n    \\begin{align*}\n      x &= 5\\cos(4\\pi t)\\\\\n      y &= 5\\sin(4\\pi t)\\\\\n      z &= -3 + 6t\n    \\end{align*}\n  }\\qquad 0 \\le t \\le 1\n\\]\n\nand the graph of the function\n\n\\[\n  z = \\cos(x)\\sin(y),\\qquad -2\\pi \\le x,\\, y\\le 2\\pi\n\\]\n\n::embed[{epiplexis-content}/gng/01-coordinates/03-plotting/three-plotting]{aspect-ratio=2.5 inline source appDir}\n\n(I'll explain in the next chapter how I came up with these formulas.)\n\n### WebGL / WebGPU\n\nTHREE.js is a friendly API over [WebGL](https://developer.mozilla.org/en-US/docs/Web/API/WebGL_API). There's also a fancy new thing called [WebGPU](https://developer.mozilla.org/en-US/docs/Web/API/WebGPU_API). It's probably worth getting familiar with using these technologies directly. If I ever get around to doing so, I'll talk about it in this series.\n\n### Grapher\n\nIf you're on OS X, it comes with a great piece of software called Grapher. It can do 2d and 3d graphing, as well as animations; it was hugely important for me when I was learning math growing up. Here's a tutorial video I recorded on how to use it:\n\n<iframe class=\"w-full\" src=\"https://www.youtube.com/embed/2zFUeiynYqc\" style=\"aspect-ratio: 16 / 10\" allowfullscreen></iframe>\n",
    "description": "",
    "duration": null,
    "meta": {
      "math": {
        "macros": ""
      }
    },
    "ownerId": "41786b7c-b873-4373-8ede-477bf85070a1",
    "publicationDate": "2024-06-15 23:40:16.340316 UTC",
    "slug": "plotting",
    "title": "Plotting",
    "type": "article"
  },
  {
    "id": "938e7233-5626-4ba3-9f29-4f322119d471",
    "content": "So far we've talked about representing data using ($n$-tuples of) numbers. In this post I want to take a closer look at how we do this, and distinguish between two different ways of describing spaces.\n\n## Example: the unit circle\n\nLet's start with the example of the unit circle (which we are calling $S^1$). This is defined to be the set of points in the plane which are at distance 1 from the origin $(0, 0).$ Using the Pythagorean theorem (to be discussed in [the next chapter](/gng/trig/pythagoras)), this translates to\n\n\\[ \\{(x, y)\\In\\R^2 \\mid \\red{x^2 + y^2 = 1}\\}. \\]\n\n\n<iframe class=\"w-full\" src=\"https://www.desmos.com/calculator/k9frdjmhuc\" height=\"450\"></iframe>\n\nFor example, $(1,0),\\,(0, -1)$, and $\\left(\\frac{\\sqrt2}2,\\frac{\\sqrt2}2\\right)$ are in the unit circle since\n\n\\[\\begin{align*}\n  1^2 + 0^2 &= 1\\\\\n  0^2 + (-1)^2 &= 1\\\\\n  \\left(\\tfrac{\\sqrt2}2\\right)^2 + \\left(\\tfrac{\\sqrt2}2\\right)^2\n    &= \\tfrac12 + \\tfrac12\\\\\n    &= 1\n\\end{align*}\\]\nand $(0.3, 0.7)$ is not since\n\\[\\begin{align*}\n  0.3^2 + 0.7^2 &= 0.09 + 0.49\\\\\n  &= 0.58\\\\\n  &\\ne 1.\n\\end{align*}\\]\n\nSo this description of the unit circle makes it easy to _check_ whether a given point $(x, y)$ is in $S^1$ or not. But it's not easy to _come up_ with examples of points on the circle. Let's start by picking a value for $x$, e.g. $x=0.3$. We can rearrange the equation for the circle as follows:\n\n\\[\\begin{align*}\n  x^2 + y^2 &= 1\\\\\n  y^2 &= 1 - x^2\\\\\n  y &= \\pm\\sqrt{1 - x^2}\n\\end{align*}\\]\n\nIn our case $x=0.3$, the possibilities for $y$ are $\\pm0.7$. In general, once we fix a value of $x$, we get either one or two options for $y$ (one option if $1-x^2=0$, i.e. when $x=\\pm1$.\n\nHowever, not every value of $x$ is possible, since we can't take the square root of a negative number. Let's solve for the constraint on $x:$\n\n\\[\\begin{align*}\n  1 - x^2 &\\ge 0\\\\\n  1 &\\ge x^2\\\\\n  1 &\\ge |x|\n\\end{align*}\\]\nwhich is equivalent to\n\\[ -1 \\le x \\le 1 .\\]\n\nIn other words, $x\\In[-1, 1].$\n\nWe now have two maps\n\n\\[ \\fplus ,\\, \\fminus \\colon [-1, 1] \\to S^1 \\subset \\R^2 \\]\n\ngiven by\n\n\\[\\begin{align*}\n  \\fplus(x) &\\blue{{}= \\left(x, \\phantom-\\sqrt{1 - x^2}\\right)}\\\\\n  \\fminus(x) &\\purple{{}= \\left(x, -\\sqrt{1 - x^2}\\right)}\n\\end{align*}\\]\n\nWith this description, it's easy to _produce_ examples of points on the unit circle: we just plug in any value of $x$ between $-1$ and $1.$ On the other hand, it's difficult to _check_ whether a given point, say $(0.71, 0.73),$ is on the unit circle: we'd need to reverse the above derivation.\n\n<iframe class=\"w-full\" src=\"https://www.desmos.com/calculator/eu5pxeb3yb\" height=\"500\"></iframe>\n\n## Implicit, parametric, and explicit descriptions\n\nLet's generalize what we saw in the above example. \n\n:::definition\nLet $X$ be a subspace of $\\R^n;$ in the example above, $n=2$ and $X=S^1.$\n\n- an :dfn[implicit] description of $X$ is a system of equations and inequalities whose solutions are exactly $X.$  \n\n  In the above example, this was $\\red{x^2 + y^2 = 1}.$\n\n- a :dfn[local parametrization] of $X$ is a subset $U\\subset\\R^d$ along with a map $f\\colon U\\to X.$  \n\n  In the above example, $d=1,$ $U=[-1, 1],$ and both $\\fplus$ and $\\fminus$ are local parametrizations.\n\n  The _local_ is there because a local parametrization may not see all of $X,$ e.g. $\\fplus$ only sees the top half of the circle, and $\\fminus$ only sees the bottom half.\n\n- a :dfn[parametric] description of $X$ is a collection of local parametrizations of $X$ which are \"_jointly_ surjective\" in the sense that every $x\\In X$ is in the image of _at least one_ local parametrization.\n\n  In the example above, $(0, -1)$ is not in the image of $\\fplus,$ but it is in the image of $\\fminus.$\n\n- an :dfn[explicit] description is when we can isolate one variable as a (single-valued) function of the others, such as  \n  \\[ z = -y + x \\]   \n  This is both a parametric equation _and_ an implicit equation: viewing $x$ and $y$ as parameters, we can plug in any value for them and then find the necessary value of $z;$ and we can easily check whether any given $(x,y,z)$ satisfies the equation.\n:::\n\n  Being able to find an explicit description of a space is rare, since it implies that if you fix all but one coordinate, there is at most one possibility for the last coordinate. This is not true for the circle, since e.g. there are two possibilities for $(0, \\mathord ?),$ namely $(0,1)$ and $(0,-1).$ However, it's always possible to find explicit descriptions _locally_:\n  \\[ y = \\sqrt{1-x^2} \\]\n  is an explicit description of the _top half_ of the circle, even though an explicit description can't exist for the _entire_ circle.\n\nWe can think about \"solving equations\" very generally as trying to convert between implicit and parametric descriptions of a space.\n\n<table>\n  <thead>\n    <tr>\n      <th></th>\n      <th>Check membership</th>\n      <th>Produce examples</th>\n    </tr>\n  </thead>\n  <tbody>\n    <tr>\n      <th>Parametric</th>\n      <td class=\"text-red-600\">✗</td>\n      <td class=\"text-green-600\">✓</td>\n    </tr>\n    <tr>\n      <th>Implicit</th>\n      <td class=\"text-green-600\">✓</td>\n      <td class=\"text-red-600\">✗</td>\n    </tr>\n    <tr>\n      <th>Explicit</th>\n      <td class=\"text-green-600\">✓</td>\n      <td class=\"text-green-600\">✓</td>\n    </tr>\n  </tbody>\n</table>\n\n:::remark\n  A given space will admit many different parametrizations, and we often need to convert between two different parametrizations. The more common way of parametrizing the unit circle, which we will discuss in the next chapter, is by **angles**. For _nearly_ all purposes, this is a more convenient parametrization than the one we found above.\n:::\n\n:::remark\n  There are typically some other assumptions that we impose on parametrizations.\n\n  - $f$ is supposed to be \"injective away from the boundary of $U$\". I don't want to give a precise definition of this; in the case of $U=[-1, 1],$ it means we'd allow $f(-1)=f(1),$ but we'd require that $f$ be [injective](./maps#terminology) when restricted to $(-1, 1).$\n  - $U$ is supposed to be \"full-dimensional\", i.e. \"$d$-dimensional\". Again, I don't want to make this precise here, but for example a finite set of points $\\{0,0.5,1\\}$ would not be an allowed subset of $\\R^1$.\n  \n  The first condition puts an upper bound on the value of $d\\colon$ for example, there are no injective maps $\\R^2 \\to S^1$ (this is maybe intuitively true, but very hard to prove). The maximum value of $d$ is called the :dfn[dimension] of $X.$ For example, the unit circle is considered 1-dimensional (even though it lives in 2-dimensional space).\n:::\n\n## Coordinates\n\nLet me give a slightly different perspective on implicit descriptions which is more symmetric with parametric descriptions.\n\nLet's think an object in motion, e.g. a cow hurtling through the air, and freeze at a particular moment in time. Let $S$ be the space of all possible situations like this. Given such a situation $s\\In S,$ there are various quantities we can measure:\n\n- the kinetic energy $E(s)$ of the object;\n- the mass $m(s)$ of the object;\n- the speed $v(s)$ of the object.\n\nIf we pick units of measurement, (say joules for energy, kilograms for mass, and meters per second for speed), then we can view these as three maps\n\\[ E,m,v\\colon S \\to \\R. \\]\n[Recall](./maps#maps-into-a-product) that three maps $S\\to\\R$ can equivalently be viewed as a _single_ map\n\\[ (E,m,v)\\colon S\\to\\R^3. \\]\nNot every point $(x,y,z)\\In\\R^3$ can be hit by this map: physics tells us that these quantities must satisfy the constraint\n\\[ E = \\frac12 mv^2 \\]\nso we will only hit points in\n\\[ \\{ (x,y,z) \\In \\R^3 \\mid x = \\tfrac12 yz^2 \\}. \\]\n\n:::definition\n  A :dfn[coordinate] on a space $S$ is a map $S\\to\\R.$\n  \n  A :dfn[coordinate system] is a collection of coordinates $x_1,\\dotsc,x_n\\colon S\\to \\R$ such that the induced map\n  \\[ (x_1,\\dotsc,x_n)\\colon S\\to \\R^n \\]\n  is injective.\n:::\n\nIn many cases, it is difficult to find a \"global\" coordinate system, but we may be able to find a _local_ coordinate system\n\\[ (x_1, \\dotsc, x_n) \\colon U \\to \\R^n \\]\nwhere $U\\subset S$ is a subset of $S$ (similar to local parametrizations, above).\n\nThe upshot of this discussion is that we can view parametrizations of $X$ as maps $\\R^n\\to X,$ and coordinate systems on $X$ as maps $X\\to\\R^n.$ This also applies to local parametrizations/coordinate systems if we allow a subspace $U\\subset X$ in place of the entire $X.$\n\n## Marching squares / cubes\n\nWe won't be able to solve every system of equations algebraically---in fact, it's extremely rare that we can. So how can we visualize spaces that are given to us implicitly?\n\nWe take advantage of the fact that it's easy to _test_ whether a given point belongs to an implicitly defined subspace. Let's take the example\n\\[ 2y(y^{2}-3x^{2})(1-z^{2})+(x^{2}+y^{2})^{2}-(9z^{2}-1)(1-z^{2})=0 \\]\n(I just took this example from Wikipedia). If we plug in the point $(0.5,0.9,0.9),$ the left-hand side works out to $\\approx-0.051.$ That means this point is _not_ in $S$. But $-0.051$ is _close_ to $0$, so there's probably a point _near_ $(0.5,0.9,0.9)$ which _is_ in $S.$\n\nTherefore, we can try to graph an implicit equation as follows. We'll restrict our attention to some box, like the cube $[-1,1]^3$; maybe we know ahead of time that our space is contained in this box, or maybe it's not and we'll only be graphing part of it. We can subdivide this box, take a bunch of sample points from it, and plug them into our equation. Our sample points will almost certainly not satisfy the equation, but we can use how close/far they are from satisfying the equation to get a good idea of what our shape must look like.\n\nThe :dfn[marching squares] / :dfn[marching cubes] algorithms are sophisticated implementations of this basic idea. They let us graph implicitly defined shapes _without_ finding a parametrization, and are used internally by tools like [Desmos and Grapher](./plotting). We need to cover a bit more math in order to fully understand how these algorithms work, but I can give you source code right now:\n\n::embed[{epiplexis-content}/gng/01-coordinates/05-params-coords/implicit]{appDir aspect-ratio=1.5 inline source}\n",
    "description": "",
    "duration": null,
    "meta": {
      "math": {
        "macros": "\\newcommand{\\fplus}{\\blue{f_+}}\n\\newcommand{\\fminus}{\\purple{f_-}}"
      }
    },
    "ownerId": "41786b7c-b873-4373-8ede-477bf85070a1",
    "publicationDate": "2024-06-15 23:40:16.340316 UTC",
    "slug": "params-coords",
    "title": "Parameters & Coordinates",
    "type": "article"
  },
  {
    "id": "6a4ab0e5-92e6-4921-9520-d00e20c2cb3d",
    "content": "<iframe allow=\"fullscreen\" class=\"w-full\" src=\"https://epiplexis.xyz/a/8xw/lesson/\" style=\"aspect-ratio: 8/5;\"></iframe>\n\nTODO input article",
    "description": "",
    "duration": null,
    "meta": {
      "math": {
        "macros": ""
      }
    },
    "ownerId": "41786b7c-b873-4373-8ede-477bf85070a1",
    "publicationDate": "2024-06-15 23:40:16.340316 UTC",
    "slug": "rotations",
    "title": "Rotations",
    "type": "article"
  },
  {
    "id": "9d312ac2-d367-49c2-be34-c931e1db8806",
    "content": "Previously, we learned to calculate the length of vectors in $\\VecR n$, and thus the distance between *points* in $\\AffR n$. It's often useful to express a vector in terms of its __length__ and its _direction_.\n\nLet's start by defining direction.\n\n:::definition\nA vector $u\\In\\VecR n$ is said to be a :dfn[unit vector] if $\\Norm u=1$. A unit vector is also called a :dfn[direction].\n:::\n\nIf $v\\In\\VecR n$ is any _nonzero_ vector, its _direction_ is\n\n\\[ \\Dir v \\Defeq \\frac v{\\Norm v} \\]\n\nThis is also called the :dfn[normalization] of $v$. By definition, we have\n\n\\[ v = \\Norm v \\Dir v, \\]\n\nwhich expresses $v$ as its direction times its length. The $0$ vector has no direction.\n\n:::example\n  \\[ v = \\begin{bmatrix*}[r]-1\\\\2\\\\2\\\\0\\end{bmatrix*} \\]\n  :::solution\n  The length of $v$ is\n  \\[\\begin{aligned}\n  \\Norm v &= \\sqrt{(-1)^2 + 2^2 + 2^2 + 0^2}\\\\\n  &= \\sqrt9\\\\\n  &= 3\n  \\end{aligned}\\]\n  Thus\n  \\[ \\Dir v = \\begin{bmatrix*}[r]-1/3\\\\2/3\\\\2/3\\\\0\\end{bmatrix*} \\]\n:::\n\n## Spheres\n\nWe can now give a formal definition of one of the most important spaces in geometry: the $n$-sphere. This is defined to be the set of unit vectors in $\\VecR{n+1}$:\n\n\\[\\begin{aligned}\n  \\S n\n    &\\Defeq \\{v\\In\\VecR{n+1} \\mid \\Norm v = 1\\}\\\\\n    &= \\left\\{\\ivec{x_0,\\dotsc,x_n}\\In\\VecR{n+1} \\mid \\sqrt{\\sum_{i=0}^n x_i^2} = 1\\right\\}\n\\end{aligned}\\]\n\nSince $1^2 = 1$, this is equivalent to\n\n\\[ \\S n = \\left\\{\\ivec{x_0,\\dotsc,x_n} \\In \\VecR{n+1} \\mid \\sum_{i=0}^n x_i^2 = 1\\right\\}\\]\n\nNote the shift in indexing: $\\S1\\subset\\VecR 2$ is the usual unit circle in 2d, while $\\S2\\subset\\VecR3$ is the usual unit sphere in 3d.\n\nIt's worth looking at the edge case\n\\[\\begin{aligned}\n  \\S 0 &= \\{v\\In\\VecR1 \\mid \\Norm v = 1\\}\\\\\n      &= \\{\\pm1\\} \\subset \\R\n\\end{aligned}\\]\n\nThat is, the $0$-sphere consists of exactly two points! While this may seem strange, it fits nicely into a pattern about spheres in general:\n\n- every \"slice\" or \"cross-section\" of $\\S2$ is a $1$-sphere, except for the \"north and south poles\" $\\ivec{0,0,\\pm1}$.\n\n  <iframe class=\"w-full mx-auto\" src=\"https://www.desmos.com/3d/24d3d54b26?embed\" height=\"500\"></iframe>\n\n- every \"slice\" or \"cross-section\" of $\\S1$ is a $0$-sphere, except for the \"north and south poles\" $\\ivec{0,\\pm1}$;\n\n  <iframe class=\"w-full mx-auto\" src=\"https://www.desmos.com/calculator/baghu7bqdv?embed\" height=\"500\"></iframe>\n\nLet's prove this in general! This is a nice example of how we can use mathematical formalism to prove statements in $n$ dimensions based on our intuition in $\\le 3$ dimensions.\n\n:::proposition\n  Consider the cross section\n  \\[ S^n_t \\Defeq \\{\\ivec{x_0,\\dotsc,x_n}\\In S^n \\mid x_n = t \\} \\]\n  Then $S^n_t$ consists of a single point when $t=\\pm1$, and is isomorphic to $S^{n-1}$ when $|t|<1$.\n  \n  :::proof\n  \n  By definition,\n  \\[ S^n_t = \\{\\ivec{x_0,\\dotsc,x_{n-1},t} \\In \\VecR{n+1} \\mid \\sum_{i=0}^{n-1} x_i^2 + t^2 = 1\\} \\]\n  Let $v=\\ivec{x_0,\\dotsc,x_{n-1}} \\In \\VecR n$. We can rearrange the above condition to\n  \\[\\begin{aligned}\n    \\sum_{i=0}^{n-1} x_i^2 &= 1-t^2\\\\\n    \\sqrt{\\sum_{i=0}^{n-1} x_i^2} &= \\sqrt{1-t^2}\\\\\n    \\Norm v &= \\sqrt{1-t^2}\n  \\end{aligned}\\]\n  When $t=\\pm1$, this becomes $\\Norm v=0$, which implies $v=0$. This means that $S^n_t$ consists of the single point\n  \\[ \\ivec{0,\\dotsc,0,t}. \\]\n  When $|t|<1$, we have that $S^n_t$ is isomorphic to the sphere of radius $\\sqrt{1-t^2}$ in $\\VecR n$.\n:::\n\n## Parametrization\n\nWe can use the defining equation of $\\S n$ to find a parametrization of it. Let's start with the case of $\\S1$. Its defining equation is\n\n\\[ x^2 + y^2 = 1 \\]\n\nLet's rearrange this to solve for $y$ in terms of $x$:\n\n\\[\\begin{aligned}\n  x^2 + y^2 &= 1\\\\\n  y^2 &= 1 - x^2\\\\\n  y^2 &= \\pm\\sqrt{1 - x^2}\n\\end{aligned}\\]\n\nSo we can take $x=t$ as our parameter variable. We also need to find the domain of $t$ (equivalently $x$). Remember that we can only take square roots of non-negative numbers. So we need to have\n\n\\[\\begin{aligned}\n  0 &\\le 1-x^2\\\\\n  x^2 &\\le 1\\\\\n  |x| &\\le 1\n\\end{aligned}\\]\nor equivalently\n\\[ -1 \\le x \\le 1. \\]\n\nLet's try this in Desmos:\n<iframe class=\"w-full mx-auto mt-2 mb-4\" src=\"https://www.desmos.com/calculator/km7gkuq0ra?embed\" height=\"500\"></iframe>\n\n<iframe class=\"w-full mx-auto my-2\" src=\"https://www.desmos.com/3d/687d619b00?embed\" height=\"500\"></iframe>\n",
    "description": "",
    "duration": null,
    "meta": {
      "math": {
        "macros": ""
      }
    },
    "ownerId": "41786b7c-b873-4373-8ede-477bf85070a1",
    "publicationDate": "2024-06-15 23:40:16.340316 UTC",
    "slug": "unit-vectors",
    "title": "Unit vectors",
    "type": "article"
  },
  {
    "id": "e644f2c2-617f-4bd0-87b2-98e16a467c6d",
    "content": "## Distance\n\n::unit[pythagoras]\n\n::unit[unit-vectors]\n\n::unit[arclength]\n\n## Trig functions\n::unit[cos-sin]\n\n::unit[rotations]\n\n::unit[2x2-matrices]",
    "description": "",
    "duration": null,
    "meta": {
      "math": {
        "macros": ""
      }
    },
    "ownerId": "41786b7c-b873-4373-8ede-477bf85070a1",
    "publicationDate": "2024-06-15 23:40:16.340316 UTC",
    "slug": "trig",
    "title": "Trigonometry",
    "type": "collection"
  },
  {
    "id": "3ff98f24-6b94-4fef-9cf4-1ce3be1993ba",
    "content": "The Pythagorean theorem allowed us to calculate the length of straight line segments. In this post, we'll see how to extend this to calculate the length of _curved_ paths.\n\nLet's consider this curved path:\n\n::embed[{epiplexis-content}/gng/02-trigonometry/03-arclength/curve]{class=my-4 inline width=80%}\n\nWe can sample points along this curve and connect them by line segments:\n\n::embed[{epiplexis-content}/gng/02-trigonometry/03-arclength/approx]{class=my-4 inline source}\n\nThe result is a \"piecewise linear\" curve, shown in red. Since each piece of this is a line segment, we can calculate its length by applying the Pythagorean theorem to each segment and summing the results.\n\nAs we increase the density of the sample points, the piecewise linear curve becomes a better and better approximation of the original curve, and is length becomes a better and better approximation of the length of the original curve.\n\nWe can do the same thing in three dimensions:\n\n::embed[{epiplexis-content}/gng/02-trigonometry/03-arclength/3d]{aspect-ratio=2 class=my-4 inline source}\n\nThere are several delicate questions raised by this procedure.\n\n- Are we calculating the \"true\" answer, or just approximations to it?\n\n- If we sample points differently, will we get a different answer?\n\n- If we use a different [parametrization](/gng/cg/params-coords) of the same curve, does the answer change?\n\nThe first point gets at the heart of what \"real numbers\" actually are. Think about how we use numbers in practice: we might only care about the value within $0.01$. If the values produced by the algorithm are guaranteed to stay within that error tolerance once the number of steps is big enough, we can use any of the values beyond that point as our answer.\n\nA thorough answer to these questions involves **limits**, which we'll discuss in Chapter 5.\n\n<!-- define this in earlier unit I guess -->\n\n## Arclength parametrization\n\nRecall that a _curve_ $C$ in $\\AffR n$ is the image of _some_ map\n\n\\[ f\\colon \\CIntvl ab \\to \\AffR n \\]\n\nA choice of such an $f$ is called a _parametrization_ of the curve $C$. For example, we can pre-compose $f$ with an easing function to get many other parametrizations.\n\nA curve has lots and lots of different parametrizations; which one is best depends on the situation at hand and the nature of the curve. However, every curve has a _canonical_ parametrization, called the :dfn[arclength] parametrization, and this is usually the best option. The definition is as follows:\n\n:::definition\n  Let $C$ be an oriented curve from $P$ to $Q$ in $\\AffR n$. Suppose the arclength of $C$ is $s$. The :dfn[arclength parametrization] of $C$ is the function\n  \\[ f\\colon \\CIntvl 0s \\to \\AffR n \\]\n  such that the image of $f$ is $C$, and the arclength of the restriction $\\Restrict{f}{[0;t]}$ is $t$.\n:::\n\n:::example\n  Find the arclength parametrization of the line segment from $\\ipt{1,1}$ to $\\ipt{2,3}$ in $\\AffR 2$.\n  \n  :::solution\n  Let's start by finding the arclength. Since this is a straight line segment, the length is\n  \\[\\begin{align*}\n    \\|\\ipt{2,3} - \\ipt{1,1}\\|\n      &= \\|\\ivec{1, 2}\\|\\\\\n      &= \\sqrt{1^2 + 2^2}\\\\\n      &= \\sqrt5\n  \\end{align*}\\]\n  So the arclength parametrization is going to be parametrized on $\\CIntvl 0{\\sqrt5}$. Let's start with the parametrization given by linear interpolation,\n  \\[\\begin{align*}\n    f(t)\n      &= \\ipt{1, 1} + t(1, 2) & t&\\in\\CIntvl01\\\\\n      &= \\ipt{1+t,1+2t}\n  \\end{align*}\\]\n  To reparametrize this to $\\CIntvl0{\\sqrt5}$, we pre-compose with the map\n  \\[\\begin{align*}\n    g\\colon\\CIntvl0{\\sqrt5} &\\xrightarrow\\sim \\CIntvl01\\\\\n    g(t) &= \\frac t{\\sqrt5}\n  \\end{align*}\\]\n  The final arclength parametrization is therefore\n  \\[\\begin{align*}\n    s(t)\n      &= \\ipt{1, 1} + \\frac t{\\sqrt5}\\ivec{1,2} &t&\\in\\CIntvl0{\\sqrt5}\\\\\n      &= \\ipt{1+\\frac t{\\sqrt5}, 1+\\frac{2t}{\\sqrt5}}\n  \\end{align*}\\]\n:::\n\nLater, we will learn to find the arclength parametrization of more complicated curves; however, it is usually not possible to find an exact formula. It is doable by computer, however. As the above example shows, even in cases when we can find an exact formula for the arclength parametrization, it is often ugly (when written out in full).\n\n## APIs\n\n- [`getTotalLength()`](https://developer.mozilla.org/en-US/docs/Web/API/SVGGeometryElement/getTotalLength)\n- [`getPointAtLength()`](https://developer.mozilla.org/en-US/docs/Web/API/SVGGeometryElement/getPointAtLength)\n\n## Exercises\n\n1. In [Parameters and coordinates](/gng/cg/params-coords#example-the-unit-circle), we found a parametrization of the unit circle given by\n\n\\[\n  f_+(x) = \\ivec{x,\\sqrt{1 - x^2}},\\qquad\n  f_-(x) = \\ivec{x,-\\sqrt{1 - x^2}}\n\\]\n\nUsing this parametrization, write code to calculate (approximate) the arclength of the unit circle.\n\n```js\n// !interactive\n/** Parametrization of the top half of the unit circle. */\nconst unitSemiCircle = (t) => [t, Math.sqrt(1 - t ** 2)];\n\n/**\n * Compute the arclength of a parametrized curve.\n * @param f Parametrization of the curve\n * @param a Starting point\n * @param b Ending point\n * @param samples Number of samples\n */\nfunction arclength(f, a, b, samples) {\n  let sum = 0;\n  const mesh = (b - a) / samples;\n  for (let i = 0; i < samples; ++i) {\n    const ti = a + i * mesh;\n    const tNext = ti + mesh;\n    const [x, y] = f(ti);\n    const [xNext, yNext] = f(tNext);\n    sum += Math.hypot(xNext - x, yNext - y);\n  }\n  return sum;\n}\n\n// since it is a bit messy to combine the parametrizations of the top\n// and bottom halves of the unit circle into a single parametrization,\n// we will calculate the arclength of just the top half and multiply\n// that by 2\nconsole.log(2 * arclength(unitSemiCircle, -1, 1, 10_000));\n```\n",
    "description": "",
    "duration": null,
    "meta": {
      "math": {
        "macros": ""
      }
    },
    "ownerId": "41786b7c-b873-4373-8ede-477bf85070a1",
    "publicationDate": "2024-06-15 23:40:16.340316 UTC",
    "slug": "arclength",
    "title": "Arclength",
    "type": "article"
  },
  {
    "id": "54d3cfd7-e370-43ba-a0c4-201922ec154b",
    "content": "::unit[spaces]\n\n::unit[products]\n\n::unit[plotting]\n\n::unit[maps]\n\n::unit[params-coords]\n\n::unit[points-vectors]\n\n::unit[dragging]",
    "description": "",
    "duration": null,
    "meta": {
      "math": {
        "macros": ""
      }
    },
    "ownerId": "41786b7c-b873-4373-8ede-477bf85070a1",
    "publicationDate": "2024-06-15 23:40:16.340316 UTC",
    "slug": "cg",
    "title": "Coordinate geometry",
    "type": "collection"
  },
  {
    "id": "4b5cebea-f831-4e18-92ab-b57bea11e359",
    "content": "<!-- #tab notes -->\n\n:::yell\n  $\\cos$ and $\\sin$ are what you use when you want to draw a circle, or animate something moving in a circle.\n:::\n\nIn the post on [unit vectors](./unit-vectors), we defined the unit $n$-sphere and found a parametrization of it. In the [previous post](./arclength), we encountered the **arclength parametrization**, which for most purposes is more convenient than other parametrizations. In this post, we discuss the arclength parametrization of the unit circle $\\cl{S}{S^1}$, which is given by the $\\cos$ and $\\sin$ functions. This will be useful for drawing things along a circle or animating something that's rotating.\n\n## Radians\n\nWe need to start by naming the length of the unit circle.\n\n:::definition\n  We write $\\Twopi$ (pronounced either \"circle\", \"var-pi\", or \"two-pi\") for the arclength, or :dfn[circumference], of the unit circle\n  \\[ \\cl{S}{S^1} \\Defeq \\{(x, y) \\in \\VecR2 \\mid x^2 + y^2 = 1 \\}. \\]\n  In the [exercises](./arclength#exercises) of the previous unit, you calculated that $\\Twopi\\approx6.28\\dotsc$\n:::\n\nBy scaling, it follows that the circumference of a circle of radius $r$ is given by $\\Twopi r$. For example, the circumference of a circle of radius $4$ is $4\\Twopi\\approx25.13\\dots$. Equivalently, we could define $\\Twopi$ as the ratio of _any_ circle's circumference to its radius.\n\n:::remark\n  You may be more used to the constant $\\pi=\\Twopi/2\\approx3.14\\dots$, which is the ratio of a circle's circumference to its **diameter** (twice the radius). It turns out the ancient Greeks made a mistake in defining $\\pi$: while diameter is relevant in real-life situations, mathematically it's much more convenient to index circles by their radius rather than their diameter.\n  \n  This is not something to get too worked up about, however: although $\\Twopi$ is an important number, numbers are not that important in mathematics.\n  \n  Many sources use the letter $\\tau$ instead of $\\varpi$. This is patently absurd: on top of having completely the wrong vibes to be a circle constant, $\\tau$ is a B-tier Greek letter while $\\Twopi$ is an S-tier constant.\n:::\n\n## cos and sin\n\n:::definition\n  We define the functions $\\cos$ and $\\sin$ such that\n  \\[ \\ivec{\\cos\\theta,\\, \\sin\\theta}, \\qquad \\theta\\in \\ClsdIntvl0{\\twopi} \\]\n  is the arclength parametrization of the unit circle $\\cl{S}{S^1}$, starting at the point $\\ivec{1,0}$ and traveling counterclockwise. Equivalently, $\\ivec{\\cos\\theta,\\sin\\theta}$ is the $\\ivec{x,y}$-coordinates of the point at angle $\\theta$ from the origin.\n:::\n\nHere's a graph to experiment with that.\n\n<iframe class=\"w-full my-4\" height=\"500\" src=\"https://www.desmos.com/calculator/9v62whmuxi\"></iframe>\n\nThis completely defines $\\cos$ and $\\sin$, but doesn't tell us how to compute them. However, in just a few posts we'll derive an algorithm to compute these.\n\nYou may be used to a definition of $\\cos$ and $\\sin$ in terms of ratios of right-angle triangles; I'll review that interpretation [below](#triangle-interpretation). That interpretation is often useful, but it doesn't work for angles larger than $90^\\circ$.\n\n## Animation\n\nLet's say more about animation. So far, $\\cos$ and $\\sin$ tell us how to parametrize the unit circle, i.e. the circle of radius $1$ centered at the origin $\\O=(0,0)$. What about other circles?\n\nLet's do this in steps. First, let\n\\[ \\cl S{S^1}(r) = \\{v\\in\\VecR2 \\mathrel: \\|v\\| = r \\} \\]\nbe the circle of radius $r$ centered at the origin. We have\n\\[\\begin{align*}\n  \\cl S{S^1}(r)\n    &\\phantom:= r \\cl S{S^1}\\\\\n    &\\Defeq \\{rv \\mid v\\in \\cl S{S^1}\\}\n\\end{align*}\\]\nso can parametrize this by\n\\[ r\\ivec{\\cos t,\\sin t} = \\ivec{r\\cos t,r\\sin t}, \\qquad t\\in\\CIntvl0\\twopi. \\]\n\nNext, let's consider circles centered at other points. For a point $P\\in\\AffR2$ and a radius $r>0$, let\n\\[ \\cl S{S^1}(P,r) \\Defeq \\{Q \\in \\AffR2 \\colon \\|P-Q\\| = r \\} \\]\nbe the circle of radius $r$ centered at $P$. Note that $\\cl S{S^1}(r)$ lives in the _vector_ space $\\VecR2$, while $\\cl S{S^1}(P,r)$ lives in the _affine_ space $\\AffR2$; recall that \"the origin\" is a feature of _vector_ space. We can get $\\cl S{S^1}(P, r)$ by **translating** $\\cl S{S^1}(r)$ to the point $P$: in other words,\n\\[\\begin{align*}\n  \\cl S{S^1}(P, r)\n    &\\phantom:= P + \\cl S{S^1}(r)\\\\\n    &\\Defeq \\{P + v \\mid v \\in \\cl S{S^1}(r) \\}\n\\end{align*}\\]\nTherefore, a parametrization of $\\cl S{S^1}(P, r)$ is given by\n\\[ P+r\\ivec{\\cos t,\\sin t} = \\ipt{\\cl{p}{p_1}+r\\cos t,\\cl{p}{p_2}+r\\sin t}, \\qquad t\\in\\CIntvl0\\twopi, \\]\nwhere $P=\\ipt{\\cl{p}{p_1},\\cl{p}{p_2}}$.\n\nThat does everything we need if we want to draw a circle (or a part of a circle). Often though, we want to **animate** something moving in a circle. This means we need to further take into account its **speed** (or **angular velocity**) and its **starting position**.\n\nBy default, $(\\cos t,\\sin t)$ starts at $(1,0)$ and goes around the circle one every $\\Twopi$ units of time, going counterclockwise. To have it start at a different angle $\\cl{θ}{\\theta_0}$, we just add that on to $t$:\n\n\\[ \\ivec{\\cos(\\cl{θ}{\\theta_0} + t), \\sin(\\cl{θ}{\\theta_0} + t)} \\]\n\nTo change the speed, we multiply $t$ by a constant. For example, if $t$ is measured in seconds and we want to go around the circle once every two seconds, we'd use\n\n\\[ \\ivec{\\cos\\left(\\cl{θ}{\\theta_0}+\\frac{\\Twopi t}2\\right), \\sin\\left(\\cl{θ}{\\theta_0}+\\frac{\\Twopi t}2\\right)} \\]\n\nsince going around the circle once every two seconds is the same as going halfway around the circle every second. We can also scale by a negative number to go clockwise instead of counter-clockwise.\n\nTo summarize:\n\n:::proposition\n  The parametrization of a particle travelling:\n  - on a circle of radius $r$\n  - centered at the point $P=\\ipt{\\cl{p}{p_1},\\cl{p}{p_2}}$\n  - starting from angle $\\cl{θ}{\\theta_0}$\n  - making $k$ (counter-clockwise) rotations per unit of time $t$\n  \n  is given by\n  \\[\n    P + r\\ivec{\\cos(\\cl{θ}{\\theta_0}+\\Twopi kt), \\sin(\\cl{θ}{\\theta_0}+{\\Twopi}kt)}\n  \\]\n  which is the same as\n  \\[\n    \\ipt{\\cl{p}{p_1}+r\\cos(\\cl{θ}{\\theta_0}+\\Twopi kt), \\cl{p}{p_2}+r\\sin(\\cl{θ}{\\theta_0}+\\Twopi kt)}.\n  \\]\n:::\n\nHere's some code to try that out:\n\n```tsx\n// !interactive\nimport { useEffect, useRef } from \"react\";\n\n/** Point in 2-dimensional (affine) space */\ntype Pt2 = [number, number];\n\ntype Circle = {\n  /** Measured in [0, 100] x [0, 100] and mapped onto the actual screen later */\n  center: Pt2;\n  radius: number;\n};\n\nconst SECONDS = 1000,\n  MINUTES = 60 * SECONDS;\n\nconst CIRCLE = 2 * Math.PI;\n\n// scene setup\nexport default function Graph() {\n  const items: MovingProps[] = [\n    {\n      children: \"👻\",\n      circle: {\n        center: [50, 50],\n        radius: 25,\n      },\n      rpm: 45,\n    },\n    {\n      children: \"😈\",\n      circle: {\n        center: [25, 25],\n        radius: 20,\n      },\n      // negative to go clockwise\n      rpm: -30,\n    },\n    {\n      children: \"😍\",\n      circle: {\n        center: [75, 40],\n        radius: 10,\n      },\n      rpm: 15,\n    },\n    {\n      children: \"😡\",\n      circle: {\n        center: [30, 60],\n        radius: 20,\n      },\n      rpm: -60,\n    },\n    {\n      children: \"😡\",\n      circle: {\n        center: [70, 60],\n        radius: 20,\n      },\n      // so it will collide with the other one\n      initialAngle: CIRCLE / 2,\n      rpm: 60,\n    },\n  ];\n\n  return (\n    <main>\n      {items.map((props) => (\n        <Moving key={JSON.stringify(props)} {...props} />\n      ))}\n    </main>\n  );\n}\n\n// moving divs\ninterface MovingProps {\n  children: React.ReactNode;\n  circle: Circle;\n\n  /**\n   * Initial angle.\n   * @default 0\n   */\n  initialAngle?: number;\n  \n  /** Revolutions per minute. */\n  rpm: number;\n}\n\nfunction Moving({ children, circle, initialAngle = 0, rpm }: MovingProp) {\n  const ref = useRef<HTMLDivElement>(null);\n\n  useEffect(() => {\n    const start = performance.now();\n\n    let cancelId: number;\n\n    // update handler\n    const update = (t: number) => {\n      if (!ref.current) return;\n\n      const angle = initialAngle + ((CIRCLE * (t - start)) / MINUTES) * rpm;\n      const [x, y] = toScreenCoords(getCoords(circle, angle));\n\n      // we want to position the center rather than the top-left corner\n      const rect = ref.current.getBoundingClientRect();\n      ref.current.style.transform = `translate(\n        ${x - rect.width / 2}px,\n        ${y - rect.height / 2}px\n      )`;\n\n      cancelId = requestAnimationFrame(update);\n    };\n\n    // start animation loop\n    cancelId = requestAnimationFrame(update);\n\n    // cancel animation loop on unmount\n    return () => cancelAnimationFrame(cancelId);\n  }, []);\n\n  return (\n    <div className=\"w-min text-3xl absolute\" ref={ref}>\n      {children}\n    </div>\n  );\n}\n\n/** Get the coordinates of a point on a circle. */\nfunction getCoords(circle: Circle, angle: number): Pt2 {\n  const {\n    center: [cx, cy],\n    radius: r,\n  } = circle;\n\n  // we subtract in the second coordinate because screen y-axis\n  // goes down while math y-axis goes up\n  return [cx + r * Math.cos(angle), cy - r * Math.sin(angle)];\n}\n\n/** Map [0, 100] x [0, 100] onto the actual screen dimensions */\nfunction toScreenCoords([x, y]: Pt2) {\n  return [(window.innerWidth * x) / 100, (window.innerHeight * y) / 100];\n}\n```\n\n## Triangle interpretation\n\nYou may be more used to a definition of $\\cos$ and $\\sin$ in terms of ratios of angles of right-angle triangles.\n\n<div className=\"flex items-center w-2/3 mx-auto\">\n  <svg class=\"mx-auto flex-1\" viewBox=\"0 0 250 100\">\n    <path\n      class=\"stroke-black dark:stroke-white fill-none\"\n      d=\"M 5 80 l 195 -75 v 75 z\"\n    />\n    <g class=\"dark:fill-white\">\n      <text\n        x=\"40\" y=\"80\" dx=\"3\" dy=\"-3\"\n        fill=\"mediumpurple\"\n        font-family=\"KaTeX_Math\"\n        font-size=\"12\"\n      >θ</text>\n      <text\n        text-anchor=\"start\"\n        font-family=\"KaTeX_Main\"\n        transform=\"translate(208, 6) rotate(90)\"\n      >opposite</text>\n      <text\n        x=\"100\" y=\"95\" dy=\"1\"\n        dominant-baseline=\"text-top\" text-anchor=\"middle\"\n        font-family=\"KaTeX_Main\"\n      >adjacent</text>\n      <text\n        font-family=\"KaTeX_Main\"\n        dominant-baseline=\"text-bottom\" text-anchor=\"middle\"\n        transform=\"translate(100, 38) rotate(${Math.atan2(-75, 195) * 180 / Math.PI})\">hypotenuse</text>\n    </g>\n  </svg>\n  <katex class=\"mx-auto text-xl\" display>\n    \\begin{aligned}\n      \\cos\\theta &= \\frac{\\text{adjacent}}{\\text{hypotenuse}}\\\\\n      \\sin\\theta &= \\frac{\\text{opposite}}{\\text{hypotenuse}}\n    \\end{aligned}\n    </katex>\n</div>\n\nThis perspective is often useful, but it doesn't work for angles larger than $90^\\circ$.\n\nHow does this relate to coordinates of points on the unit circle? First, note that for any point on a circle, we can form a right-angle triangle whose hypotenuse is the line segment from the center of the circle to that point (see below). In the case of the unit circle, \n\n\n<iframe class=\"w-full my-4\" height=\"500\" src=\"https://www.desmos.com/calculator/kzhc0ynx0k\"></iframe>\n\n## Special angles\n\nAlthough we don't yet have a general algorithm for computing $\\cos$ and $\\sin$, we can read off the values of the coordinates of East $(0)$, North $(90^\\circ=\\frac\\Twopi4)$, West $(180^\\circ=\\frac\\Twopi2)$, and South $(270^\\circ=\\frac{3\\Twopi}4$).\n\\[\\begin{align*}\n  \\ivec{\\cos0,\\,\\sin0} &= \\ivec{1,0} &\n  \\ivec{\\cos\\frac\\Twopi2,\\,\\sin\\frac\\Twopi2} &= \\ivec{-1,\\, 0}\\\\[.5em]\n  \\ivec{\\cos\\frac\\Twopi4,\\,\\sin\\frac\\Twopi4} &= \\ivec{0,\\, 1} &\n  \\ivec{\\cos\\frac{3\\Twopi}4,\\,\\sin\\frac{3\\Twopi}4} &= \\ivec{0,\\, -1}\n\\end{align*}\\]\n\nWith a bit more work, we can calculate the coordinates of the point at $45^\\circ$, using the triangle interpretation above.\n\n<svg class=\"mx-auto\" width=\"200\" viewBox=\"0 0 110 110\">\n  <g class=\"fill-none stroke-black dark:stroke-white\">\n    <path d=\"M 5 95 l 90 -90 v 90 z\" />\n    <path d=\"M 85 95 v -10 h 10\" />\n  </g>\n  <g class=\"dark:fill-white\">\n    <text\n      x=\"20\" y=\"90\" dx=\"3\" dy=\"-3\"\n      font-family=\"KaTeX_Math\"\n      font-size=\"11\"\n    >45°</text>\n    <text\n      x=\"50\" y=\"100\" dy=\"5\"\n      font-family=\"KaTeX_Math\"\n      font-size=\"11\"\n      dominant-baseline=\"text-top\"\n      text-anchor=\"middle\"\n    >x</text>\n    <text\n      x=\"100\" y=\"50\"\n      font-family=\"KaTeX_Math\"\n      font-size=\"11\"\n      dominant-baseline=\"middle\"\n      text-anchor=\"start\"\n    >x</text>\n    <text\n      x=\"50\" y=\"50\" dx=\"-10\" dy=\"-10\"\n      font-family=\"KaTeX_Math\"\n      font-size=\"12\"\n      dominant-baseline=\"middle\"\n      text-anchor=\"middle\"\n    >1</text>\n  </g>\n</svg>\n\nSince the angles of a triangle add up to $180^\\circ=\\Twopi/2$, the remaining angle is also $45^\\circ=\\Twopi/8$. This implies that the two side lengths $\\cos45^\\circ$ and $\\sin45^\\circ$ are equal; let's call that $x$. By the Pythagorean theorem,\n\\[\\begin{align*}\n  \\cos(45^\\circ)^2 + \\sin(45^\\circ)^2 &= 1\\\\\n  2x^2 &= 1\\\\\n  x^2 &= \\frac12\\\\\n  x &= \\sqrt{\\frac12}\\\\\n    &= \\frac1{\\sqrt2}\\\\\n    &= \\frac{\\sqrt2}2\n\\end{align*}\\]\nTherefore, we have\n\\[ \\cos45^\\circ = \\sin45^\\circ = \\frac{\\sqrt2}2. \\]\n\n<!-- #tab videos -->\n\nThese are some old videos on $\\cos$ and $\\sin$.\n\n<iframe allow=\"fullscreen\" class=\"w-full my-4\" src=\"https://epiplexis.xyz/a/9vg/lesson/?t=3:12\" style=\"aspect-ratio: 8/5;\"></iframe>\n\n<iframe allow=\"fullscreen\" class=\"w-full my-4\" src=\"https://epiplexis.xyz/a/9vb/lesson/\" style=\"aspect-ratio: 8/5;\"></iframe>\n\n<!-- #tab exercises -->\n\n1. Find $\\cos$ and $\\sin$ of $30^\\circ$ and $60^\\circ$.\n\n2. Consider the following diagram:  \n   ::embed[{epiplexis-content}/gng/02-trigonometry/04-cos-sin/exc-minus]{aspect-ratio=2.5 source inline}  \n   By calculating the length of the green line segment in two different ways, establish the identity\n   $$\n   \\begin{equation}\\htmlId{eq-sin-pyth}{}\n   2\\sin\\left(\\frac{\\alpha - \\beta}2\\right) =\n   \\pm\\sqrt{\n     (\\cos\\alpha - \\cos\\beta)^2 + (\\sin\\alpha - \\sin\\beta)^2\n   }\n   \\end{equation}\n   $$\n   :::popup{trigger=Solution}  \n   The horizontal distance between the two points is $(\\cos\\alpha-\\cos\\beta)$, while the vertical distance is $(\\sin\\alpha-\\sin\\beta)$. Applying the Pythagorean theorem, we see that the length of the green segment is\n   $$\n   (\\cos\\alpha-\\cos\\beta)^2 + (\\sin\\alpha-\\sin\\beta)^2.\n   $$\n   ::embed[{epiplexis-content}/gng/02-trigonometry/04-cos-sin/exc-minus?rightAngle]{aspect-ratio=2.5 inline}\n   On the other hand, we can get a right angle triangle by drawing a line from the center of the circle to the midpoint of the green line: \n   ::embed[{epiplexis-content}/gng/02-trigonometry/04-cos-sin/exc-minus?bisect]{aspect-ratio=2.5 inline}\n   Now the angle between the red line and the dashed green line is $\\frac{\\alpha-\\beta}2$, and so the side opposite to it has length $\\sin\\left(\\frac{\\alpha-\\beta}2\\right)$. But this side is exactly half of the length of the green line, so the green line has length\n   $$\n   2\\sin\\left(\\frac{\\alpha-\\beta}2\\right).\n   $$\n   Putting these together, we have \n   $$\n   2\\sin\\left(\\frac{\\alpha-\\beta}2\\right) = (\\cos\\alpha-\\cos\\beta)^2 + (\\sin\\alpha-\\sin\\beta)^2\n   $$\n   :::  \n3. Consider a regular $n$-gon inscribed in a circle of radius 1:  \n   ::embed[{epiplexis-content}/gng/02-trigonometry/04-cos-sin/exc-polygon]{aspect-ratio=2 source inline}  \n   1. Show that its perimeter is given by $2n\\sin\\frac\\Twopi{2n}$.  \n      \n      :::popup{trigger=Hint}\n      Use the angle-bisection trick from the previous exercise.\n      :::\n   2. Show that its area is given by $\\frac n2\\sin\\frac\\Twopi n$.\n\n4. Once we've established [$(1)$](#eq-sin-pyth), we can derive all the usual trigonometric identities using algebraic manipulations, with no further geometric insight required. \n   1. Use [$(1)$](#eq-sin-pyth) to derive the \"half-angle formulas\"\n      $$\n      \\begin{align}\n        \\htmlId{eq-cos-half}{}\\cos(\\theta/2) &= \\pm\\sqrt{\\frac{1+\\cos\\theta}2}\\\\[1em]\n        \\htmlId{eq-sin-half}{}\\sin(\\theta/2) &= \\pm\\sqrt{\\frac{1-\\cos\\theta}2}\n      \\end{align}\n      $$\n   2. Use [$(2)$](#eq-cos-half) and [$(3)$](#eq-sin-half) to derive the \"double-angle formulas\"\n      $$\n      \\begin{align*}\n        \\cos(2\\theta)\n          &= \\cos^2(\\theta)-\\sin^2(\\theta)\\\\\n          &= 2\\cos^2(\\theta) - 1\\\\\n          &= 1 - 2\\sin^2(\\theta)\\\\\n        \\sin(2\\theta) &= 2\\cos(\\theta)\\sin(\\theta)\n      \\end{align*}\n      $$\n   3. Derive the \"angle-difference\" formulas\n      $$\n      \\begin{align*}\n        \\cos(\\alpha-\\beta) &= \\cos(\\alpha)\\cos(\\beta) + \\sin(\\alpha)\\sin(\\beta)\\\\\n        \\sin(\\alpha-\\beta) &= \\sin(\\alpha)\\cos(\\beta) - \\cos(\\alpha)\\sin(\\beta)\n      \\end{align*}\n      $$\n      and the \"angle-sum\" formulas\n      $$\n      \\begin{align*}\n        \\cos(\\alpha+\\beta) &= \\cos(\\alpha)\\cos(\\beta) - \\sin(\\alpha)\\sin(\\beta)\\\\\n        \\sin(\\alpha+\\beta) &= \\sin(\\alpha)\\cos(\\beta) + \\cos(\\alpha)\\sin(\\beta)\n      \\end{align*}\n      $$\n      These are sometimes stated in combined form\n      $$\n      \\begin{align*}\n        \\cos(\\alpha\\pm\\beta) &= \\cos(\\alpha)\\cos(\\beta) \\mp \\sin(\\alpha)\\sin(\\beta)\\\\\n        \\sin(\\alpha\\pm\\beta) &= \\sin(\\alpha)\\cos(\\beta) \\pm \\cos(\\alpha)\\sin\\beta)\n      \\end{align*}\n      $$\n      This is not the best way to derive these formulas, but it works; the point is mainly that you can get them from each other using pure algebra. We'll see a more enlightening explanation of and in a future lesson, and then the rest will follow by algebra in a similar way (in the opposite order as you derived them here).\n",
    "description": "",
    "duration": null,
    "meta": {
      "math": {
        "macros": "\\newcommand{\\Twopi}{\\htmlClass{text-teal-600 dark:text-teal-500}{\\varpi}}\n"
      }
    },
    "ownerId": "41786b7c-b873-4373-8ede-477bf85070a1",
    "publicationDate": "2024-06-15 23:40:16.340316 UTC",
    "slug": "cos-sin",
    "title": "cos and sin",
    "type": "article"
  },
  {
    "id": "3a11bff6-c7cc-44c7-80cd-65d16f0a1642",
    "content": "## Introduction\n\n:::definition\nLet $X$ and $Y$ be sets. A :dfn[function] $f: X \\to Y$ is a rule which assigns to each element of $x$ an element $f(x)$ of $Y$.\n\nWhen $X$ and $Y$ are spaces, a :dfn[map] $f: X \\to Y$ is a function from $X$ to $Y$ which \"preserves the (geometric) structure of $X$\".\n:::\n\nSince I haven't said what \"space\" means, this is kind of meaningless. Once we encounter precise definitions of various types of spaces, they'll be accompanied by precise notions of \"map\". Still, I'm going to use the word \"map\" more than \"function\" because it's shorter and more evocative. Also, sets are one kind of space (with no additional structure), and in that case map does mean any function.\n\n## Terminology\n\n:::definition\nIn the above definition:\n\n- $X$ is called the :dfn[domain] of $f$\n- $Y$ is called the :dfn[codomain] of $f$\n- the :dfn[image] of $f$ is the set of all values taken by $f$,\n  \\[ \\im(f) \\Defeq \\{ f(x) \\mid x \\in Y \\} \\]\n- if $x \\in X$, we call the value $f(x)$ the _image of $x$ under $f$_. We also call $x$ a :dfn[preimage] of $y \\in Y$ if $f(x) = y$.\n:::\n\nThe difference between codomain and range can be hard to appreciate at first. The domain and codomain are part of the \"type\" of $f$, wheras the image might be something difficult to determine.\n\n:::example\nConsider the function\n  \\[\\begin{align*}\n    f\\colon & \\R\\to\\R\\\\\n    f(x) &= x^2\n  \\end{align*}\\]\n  The image of $2$ under $f$ is $f(2)=2^2=4$, so $2$ is a preimage of $4.$ Another preimage of $4$ is $-2.$ The image of $f$ is the set $\\R_{\\ge0}=[0,\\infty)$ of non-negative real numbers.\n:::\n\nIn terms of vibes, the notation $f: X \\to Y$ is approximately equivalent to\n\n```ts\nf: (x: X) => Y;\n```\n\nA more accurate (though still imperfect) translation would be\n\n```ts\nf: Map<X, Y>;\n```\n\nThis is because in math, two functions $f$ and $g$ are considered _equal_ if\n\n- they have the same domain and codomain\n- they map each input to the same output: $f(x) = g(x)$ for all $x \\in X$\n\nThe second point is an important difference between functions in math and functions in programming (which are really _algorithms_). For mathematical functions, there's no such thing as a \"function body\" or \"runtime\".\n\n:::warning\n  Many precalculus/calculus classes ask questions like: \"What is the domain of the function\n  \n  \\[ f(x) = \\frac1{x-1}? \\]\n  \n  This question doesn't make sense: the domain of the function is _part of the data of the function_. What it's really asking is \"what is the largest subspace of $\\R$ on which this expression makes sense?\" (The answer being $\\R - \\{1\\}$, since we can't divide by $0$.)\n:::\n\nSome more terminology.\n\n:::definition\n  A function is:\n- :dfn[injective] if it never sends two different inputs to the same output. This can be phrased as  \n  \\[ x \\ne y \\implies f(x) \\ne f(y) \\]  \n  or equivalently as  \n  \\[ f(x) = f(y) \\implies x = y. \\]  \n  The first form is maybe easier to think about, but the second is easier to work with.\n- :dfn[surjective] if every element of $Y$ is the image of some $x\\in X$.\n- :dfn[bijective] if it is both injective and surjective.\n:::\n\n:::example\n  Let $\\R_{\\ge0} = [0, \\infty)$ be the space of non-negative real numbers. Consider the functions:\n  \n  - $f\\colon \\R\\to\\R,\\quad f(x) = x^2$  \n    This is not injective since $f(2)=f(-2)=4$.\n    It is not surjective since there is no $x$ such that $f(x)=-1$.\n  - $g\\colon \\R\\to\\R_{\\ge0},\\quad g(x) = x^2$  \n    This is surjective but not injective.\n  - $h\\colon \\R_{\\ge0}\\to\\R,\\quad h(x) = x^2$  \n    This is injective but not surjective.\n  - $k\\colon \\R_{\\ge0}\\to\\R_{\\ge0},\\quad k(x) = x^2$  \n    This is bijective.\n:::\n\n## Exponential interpretation\n\nWhen we introduced products of spaces, we saw that that concept was related to multiplication of numbers. Functions are also related to a numeric concept: exponentiation.\n\nFor example, say we have two balls which can be painted any of three colors, red, green, blue. We can represent the possibilities as functions from $\\{B_1, B_2\\}$ to $\\{\\red r,\\green g,\\blue b\\}$, e.g.\n\\[\n  \\vcenter{\\LARGE{\\red\\bullet}{\\blue\\bullet}}\n  \\quad\\text{corresponds to}\\quad\n  f(B_1) = \\red r, \\quad f(B_2) = \\blue b.\n\\]\nThere are $9=3^2$ possibilities in total:\n\n\\[\n  \\Big\\{\n    f\\colon\n    \\{B_1,B_2\\}\n    \\to\n    \\{\\red r ,\\green g, \\blue b\\}\n  \\Big\\}\n  =\n  \\LARGE\n  \\left\\{\\begin{matrix}\n    \\red\\bullet\\red\\bullet & \\green\\bullet\\red\\bullet & \\blue\\bullet\\red\\bullet\\\\\n    \\red\\bullet\\green\\bullet & \\green\\bullet\\green\\bullet & \\blue\\bullet\\green\\bullet\\\\\n    \\red\\bullet\\blue\\bullet & \\green\\bullet\\blue\\bullet & \\blue\\bullet\\blue\\bullet\n  \\end{matrix}\\right\\}\n\\]\n\nIn general, if $X$ and $Y$ are finite sets with $|X|$ and $|Y|$ elements respectively, then the number of functions from $X$ to $Y$ is $|Y|^{|X|}$: there are $|Y|$ options where to send each $x \\in X$, and we can choose those values independently of one another.\n\nThis suggests defining $Y^X$ as the set of functions from $X$ to $Y$, so that\n\\[ |Y^X| = |Y|^{|X|}. \\]\nThis is called the **function set** or **mapping space** from $X$ to $Y$. Although this can be hard to think about, it's very powerful to go from thinking about\n\n- individual elements of $X$ and $Y$, to\n- individual functions $f: X \\to Y$, to\n- considering _all_ functions $X \\to Y$ as a single object.\n\nAnother notation for the mapping space (more common in CS than in math) is $X \\to Y$, in which case the notation $f: X \\to Y$ is literally a type declaration. In any case, the mapping space from $X$ to $Y$ is approximately equivalent to the type `(x: X) => Y` or `Map<X, Y>`.\n\nI'll try to avoid using the concept of mapping space except when we have precise definitions of \"space\" and \"map\", since\n\n- the precise definition of \"map\" will affect what the actual elements of $Y^X$ are. For example,\n  \\[\\begin{align*}\n    f&\\colon \\R \\to \\R\\\\\n    f(x) &= x+1\n  \\end{align*}\\]\n  is considered an _affine_ map but not a _linear_ map.\n- depending on the precise meaning of \"space\", it may be easy, difficult, or impossible to turn the _set_ of maps $X \\to Y$ into a \"space\".\n\n## Maps and products\n\nLet's see how this interacts with the other way we've seen of combining spaces, namely products.\n\n### Repeated multiplication\n\nWhen $x$ is a natural number ($0,1,2,...)$ and $y$ is any number, the exponential $y^x$ is defined as repreated multiplication:\n\n\\[ y^x = \\underbrace{yy\\dotsm y}_{x\\text{ times}} \\]\n\nSomething similar is true for function spaces. Recall that three-dimensional space $\\R^3$ can be understood as the threefold product of $\\R$ with itself,\n\n\\[ \\R^3 = \\R \\times \\R \\times \\R. \\]\n\nWe can also view $\\R^3$ as the function space $\\R^{\\{0,1,2\\}}$. In code, this is saying that the types\n\n```ts\n[number, number, number];\n```\n\nand\n\n```ts\n{\n  0: number;\n  1: number;\n  2: number;\n}\n```\n\nare \"equivalent\".\n\nDepending on your application, you might prefer to have types like\n\n```ts\n{\n  x: number;\n  y: number;\n  z: number;\n}\n```\n\nor\n\n```ts\n{\n  height: number;\n  width: number;\n}\n```\n\nThese can be encoded as the mapping spaces $\\R^{\\{\\r x,\\r y,\\r z\\}}$ and $\\R^{\\{\\r{height},\\r{width}\\}}$.\n\n### Maps into a product\n\nLet $X$, $Y$, and $Z$ be spaces. We can form the product $Y \\times Z$, and then ask what maps $f\\colon X \\to Y \\times Z$ look like.\n\nBy definition, $f$ needs to send each element $x$ of $X$ to an element of $Y \\times Z$. An element of $Y \\times Z$ is a pair $(y, z)$ with $y\\in Y$ and $z\\in Z$. So can define maps $g: X \\to Y$ and $h: X \\to Z$ as the first and second components of $f$:\n\n\\[ f(x) = (g(x), h(x)) \\]\n\nIn other words, _a function from $X$ to $Y \\times Z$ is equivalent to two separate functions $X \\to Y$ and $X \\to Z$_. In terms of mapping spaces, we can express this as\n\n\\[ (Y \\times Z)^X \\qeq Y^X \\times Z^X. \\]\n\n(I'll say more about $\\qeq$ in a future post.) This parallels the identity for numbers\n\n\\[ (yz)^x = y^x z^x. \\]\n\nHere's what this equivalence looks like in code:\n\n```ts\n/** Projection onto first factor */\nconst pr1 = <X, Y>([x, y]: [X, Y]): X => x;\n\n/** Projection onto second factor */\nconst pr2 = <X, Y>([x, y]: [X, Y]): Y => y;\n\n/** Convert a function into a product to a pair of functions **/\nconst split = <X, Y, Z>(f: (x: X) => [Y, Z]): [(x: X) => Y, (x: X) => Z] => [\n  (x) => pr1(f(x)),\n  (x) => pr2(f(x)),\n];\n\n/** Convert a pair of functions to a function into a product */\nconst combine =\n  <X, Y, Z>(g: (x: X) => Y, h: (x: X) => Z): ((x: X) => [Y, Z]) =>\n  (x) =>\n    [g(x), h(x)];\n```\n\n## Maps out of a product\n\nWhat about maps _out of_ a product? That is, for spaces $X$, $Y$, $Z$, let's think about what maps $X \\times Y \\to Z$ look like.\n\nThese correspond to \"functions of two variables\": for example, the function\n\n\\[ f(x, y) = x^2 + y^2 \\]\n\nis a map $\\R^2 \\to \\R$.\n\nThere is another way of encoding a function of two variables: for a fixed value of $x$, we can get a function $f_x: Y \\to Z$ by defining\n\n\\[ f_x(y) = f(x, y) \\]\n\nFor instance, if $f(x, y) = x^2 + y^2$ as above, then $f_2(y) = 4+y^2$. This is saying that a function of two variables can also be expressed as a function from $X$ to _the set of functions from $Y$ to $Z$_. Symbolically, this is\n\n\\[ Z^{X\\times Y} \\qeq (Z^Y)^X \\]\n\nor\n\n\\[ (X \\times Y) \\to Z \\qeq X \\to (Y \\to Z) \\]\n\nThis \"lifts\" the numeric identity\n\n\\[ z^{xy} = (z^y)^x. \\]\n\nIn programming, this equivalence is called \"currying\".\n\n```ts\n/** Convert a function of two variables into a function returning a function. */\nconst curry =\n  <X, Y, Z>(f: ([x, y]: [X, Y]) => Z): ((x: X) => (y: Y) => Z) =>\n  (x) =>\n  (y) =>\n    f([x, y]);\n\n/** Convert a function returning a function to a function of two variables. */\nconst uncurry =\n  <X, Y, Z>(f: (x: X) => (y: Y) => Z): (([x, y]: [X, Y]) => Z) =>\n  ([x, y]) =>\n    f(x)(y);\n```\n\n## Coproducts\n\nThere's one more exponential identity remaining,\n\n\\[ z^{x + y} = z^x z^y \\]\n\nTo get an analogue of this for mapping spaces, we need the concept of the _coproduct_ $X \\amalg Y$. I don't want to really get into this concept right now, but it corresponds to the union type `X | Y`. The relevant identity is\n\n\\[ Z^{X\\amalg Y} \\qeq Z^X \\times Z^Y \\]\n\nOr if you prefer, this is saying that the types `Map<X | Y, Z>` and `[Map<X, Z>, Map<Y, Z>]` are \"equivalent\".\n\n:::exercise\n  Convince yourself of the above, and implement the conversion in code.\n:::\n",
    "description": "",
    "duration": null,
    "meta": {
      "math": {
        "macros": "\\newcommand{\\r}{\\mathrm}\n\\newcommand{\\qeq}{\\cong}\n"
      }
    },
    "ownerId": "41786b7c-b873-4373-8ede-477bf85070a1",
    "publicationDate": "2024-06-15 23:40:16.340316 UTC",
    "slug": "maps",
    "title": "Maps",
    "type": "article"
  },
  {
    "id": "7e063b2d-2406-4557-a8ff-7e8a5a02b731",
    "content": "This will be a series on *geometry* (broadly speaking), applied to and demonstrated through *web graphics*. The code samples will be in TypeScript/React/THREE.js/react-three-fiber, but the concepts are completely general and applicable to many other areas (machine learning, modelling, optimization, …)\n\n## Geometry \nFor starters, what do I mean by *geometry*? Well, 2d and 3d geometry are particularly relevant to us because we live in 3d space. 2d shapes appear on screens and flat surfaces, while the objects around us have 3d shapes.\n\nBut geometry also comes from more abstract sources. Consider the following situations:\n\n- in physics, the kinetic energy $E$ of an object is related to its mass $m$ and its speed $v$ by the formula\n\n  \\[ E = \\frac12mv^2; \\]\n\n- again in physics: say an object starts from rest, and has constant acceleration $a$ (e.g. $a=9.8\\text{ m/s}^2$ for gravity). The distance $s$ it travels after time $t$ is given by\n\n  \\[ s = \\frac12at^2; \\]\n\n- in geometry: we consider the set of points $(x,y,z)$ in 3d space which satisfy the condition\n\n  \\[ z = \\frac12xy^2. \\]\n  \n  Here's what that looks like:\n  <iframe class=\"w-full mx-auto my-2\" src=\"https://www.desmos.com/3d/2875b3713c\" height=\"600\"></iframe>\n\n\nThese are all different physical situations. But mathematically, they're all equivalent: all that matters is the relations between the numbers, not what the numbers represent.\n:::yell\nUnderstanding the geometry of the above shape is equivalent to understanding any (and all) of the more concrete situations.\n:::\nFor instance, an object of mass $4\\text{ kg}$ and velocity $3\\text{ m/s}$ corresponds to the point $(4,3,18)$.\n\nComplex problems may involve more than three dimensions; search algorithms routinely calculate in thousands or millions of dimensions. It's harder to visualize these problems. But we can use our physical intuition from 2d and 3d space to develop formulas that make sense in any number of dimensions. For example, in just a few posts we'll see how to talk about *lines* in any-dimensional space.\n\nEven \"spatial\" geometry in 2d and 3d space naturally leads us to consider higher dimensions. As a simple example, a point in 6-dimensional space is equivalent to two points in 3d space, or three points in 2d space:\n\n\\[\n  \\begin{bmatrix*}[r]\n    1\\\\-3\\\\2\\\\4.1\\\\0\\\\1\n  \\end{bmatrix*}\n  \\leftrightarrow\n  \\begin{bmatrix*}[r]\n    1&4.1\\\\-3&0\\\\2&1\n  \\end{bmatrix*}\n  \\leftrightarrow\n  \\begin{bmatrix*}[r]\n     1 & 2 & 0\\\\\n    -3 & 4.1 & 1\\\\\n  \\end{bmatrix*}\n\\]\n\n## Spaces\n\nThis brings us to our first definition.\n\n:::definition\n  A **space** is any concept that can be described using numbers.\n:::\n\n### Subsets of $\\mathbf R^n$\n\nThe above \"definition\" is extremely vague. Let me be more precise:  \n\n:::definition\n  $\\R^n$ (\"arr-enn\") is the set of $n$-tuples of real numbers:  \n  \\[ \\R^n = \\{(x_1,\\dotsc,x_n)\\mid x_i\\in \\R\\text{ for } i = 1,\\dotsc,n\\} \\]\n:::\n\n($\\in$ means \"in\" or \"is an element of\"). For example, $(0,0)$ is a point in $\\R^2,$ and $(3,0,1)$ is a point in $\\R^3.$ I might also write these vertically, e.g.\n  \n\\[ \\vec00 \\quad\\text{or}\\quad \\vecc301. \\]\n\n$\\R^n$ is one of the most important examples of a space. Any subset of $\\R^n$ is a space, and you could well take that as the precise definition. For example, the blue shape above is a subset (I could also say subspace) of $\\R^3$.\n\nActually, the term *space* doesn't have a precise definition in math (neither does *number*). There are a lot of technical concepts that have *space* in their name, which do have precise definitions, depending on what aspect of geometry we're focusing on or what tools we're using:\n  - *affine/vector spaces* are used when studying *translation* and *scaling*;\n  - *metric spaces* are for studying the concept of *distance*;\n  - *inner product spaces* incorporate all of the above and also *angles*;\n  - …\n  \n(We'll learn about these in due time.) But \"space\" on its own is just a vibe.\n\n### Coordinates\nNotice the word *can* in the definition. There are many different ways to represent any given situation, and rarely is there a single best one. For example, $10\\text{ cm}$, $3.94\\text{ in}$, and $0.33\\text{ ft}$ are three different numbers corresponding to the same concept.\n\nSo, there's a space of physical distances. This space \"is\" the same as $\\R$, but it is \"equivalent to $\\R$ in many ways\". Moreover, notice that \"equations\" like\n\n\\[ \n\\begin{align*}\n  \\line{2em} + \\line{1em} &= \\line{3em}\\\\\n  3\\times\\line{1.5em} &= \\line{4.5em}\n\\end{align*}\n\\]\n\nare meaningful, without even needing to assign numbers to the lengths. (Although this may be useful in *verifying* that the equations are true.)\n\nIn this series, I'll try to take a *coordinate-free* approach where we focus on the *intrinsic* properties of things. How we describe those spaces numerically will then be a separate step. In particular, a big chunk of geometry is just converting between different coordinate systems.\n\nWhen we do calculations, they're always going to be with $n$-tuples of numbers, and you can write your programs thinking this way. The benefit of the more abstract perspective is similar to the benefit of having types in your code.\n\n### Intrinsic / Extrinsic\n*Space* in the mathematical sense means basically the same thing as *shape*. In everyday language, we tend to think of *space* as an ambient medium which is populated by *shapes*. It's very powerful to get rid of that distinction as every shape as a space in its own right, and then one space can *embed* in another in many different ways.\n\nFor instance, the following depicts two circles drawn on a torus in 3d space. We can think of the circles as living in 3d space, occupying some of the same space as the torus. But we can also *forget* about ambient 3d space and just think about the torus as the ambient space. Furthermore, we can think of both these circles as different embeddings of one \"platonic\" circle into the torus.\n\n::embed[{epiplexis-content}/gng/01-coordinates/01-spaces/torus]{aspect-ratio=2.5 inline source} \n\n## Important Examples\n\nFinally, let me introduce notation for some important examples.\n\n- as we have already seen, $\\R^n$ is \"$n$-dimensional space\". For many purposes we are especially interested in the cases $\\R^2$ and $\\R^3$.\n\n- Frequently, we want to put bounds on the numbers we use. An :dfn[interval] consists of all numbers between two numbers $a$ and $b;$ the numbers $a$ and $b$ are called the :dfn[endpoints] of the interval. There are different versions depending on whether we want to include the endpoints or not:\n  \\[\\begin{align*}\n    [a, b] \\Defeq \\{ x \\in \\R \\mid a\\le x\\le b \\}\\\\\n    (a, b) \\Defeq \\{ x \\in \\R \\mid a < x < b \\}\n  \\end{align*}\\]\n  We call $[a, b]$ a :dfn[closed interval] and $(a,b)$ an :dfn[open interval]. There are also variants where we want to include one endpoint but not the other:\n  \\[\\begin{align*}\n    [a, b) \\Defeq \\{ x \\in \\R \\mid a\\le x < b \\}\\\\\n    (a, b] \\Defeq \\{ x \\in \\R \\mid a < x\\le b \\}\n  \\end{align*}\\]\n  These are sometimes called :dfn[half-open intervals] but there aren't individual names for them. For example, when describing angles in degrees, we're interested in the interval $[0,360).$\n\n- In particular, the :dfn[unit interval]\n  \\[ \\I \\Defeq [0, 1] \\]\n  consists of all numbers between 0 and 1, inclusive of both. This space comes up a lot when dealing with paths and animation (= paths in time).\n\n- we write $\\Sone$ for a :dfn[circle]. This means the *edge* of a circle, not the points inside; a filled circle is called a :dfn[disk] and denoted by $\\Dtwo$. Below, I've drawn a *circle* on the left and a *disk* on the right:\n\n<iframe class=\"w-full\" src=\"https://www.desmos.com/calculator/m4kxsba4su?embed\" height=\"500\"></iframe>\n\n  The notation $S^1$ means a one-dimensional *sphere*. Even though it lives in _two_-dimensional space, the circle is itself considered _one_-dimensional since you can only move backwards/forwards along it. The disk, on the other hand, is considered two-dimensional.\n\n  The notations extend to higher dimensions: $\\Stwo$ refers to a (hollow) :dfn[sphere] in $\\R^3$, while $D^3$ refers to a filled-in :dfn[ball]. Once we learn how to make sense of \"distance\" in higher dimensions, we'll be able to define $\\S n$ and $D^n$ for all $n$.\n",
    "description": "",
    "duration": null,
    "meta": {
      "math": {
        "macros": "\\newcommand{\\vec}[2]{\\begin{bmatrix}#1\\\\#2\\end{bmatrix}}\n\\newcommand{\\vecc}[3]{\\begin{bmatrix}#1\\\\#2\\\\#3\\end{bmatrix}}\n\\newcommand{\\line}[1]{\n  \\mathord{\n    \\raisebox{.2em}{\n      $\\rule{#1}{2px}$\n    }\n  }\n}\n\n\\newcommand{\\Sone}{S^1}\n\\newcommand{\\Stwo}{S^2}\n\\newcommand{\\Dtwo}{D^2}"
      }
    },
    "ownerId": "41786b7c-b873-4373-8ede-477bf85070a1",
    "publicationDate": "2024-06-15 23:40:16.340316 UTC",
    "slug": "spaces",
    "title": "Spaces",
    "type": "article"
  },
  {
    "id": "a5f12e03-5616-499d-a349-5d82fcd00550",
    "content": "In the [last post](/gng/cg/spaces) we encountered the notion of _spaces_, which are a way of thinking about situations numerically and geometrically. We saw a few examples of spaces:\n\n- $\\R^n$ is the set of all $n$-tuples of real numbers, which we think of as $n$-dimensional space\n\n- $\\ClsdIntvl ab$ is the interval of numbers between $a$ and $b$ (inclusive on both sides).\n\n- in particular, $\\I\\Defeq\\ClsdIntvl01$ consists of all $x$ with $0\\le x\\le 1$\n\n- $S^1$ is the unit circle in $\\VecR 2$\n\nIn this post, we'll discuss a way to combine two (or more) spaces $X$ and $Y$ into a new space $X\\times Y$, called the :dfn[product] of $X$ and $Y$. There are two reasons to do this:\n\n- it gives us more interesting examples of spaces;\n\n- conversely, we understand complicated spaces by expressing them in terms of simpler \"building block\" spaces. Most questions about $X\\times Y$ can be answered by answering the same question for the spaces $X$ and $Y$, and combining the answers somehow.\n\n:::definition\n  Let $X$ and $Y$ be spaces. The **product** $X\\times Y$ consists of all pairs of elements from $X$ and $Y$:\n  \\[ X \\times Y \\Defeq \\{(x,y) \\mid x\\in X,\\, y\\in Y \\}. \\]\n:::\n\nThe space $X\\times Y$ is analogous to the tuple type `[X, Y]`.\n\n### Examples\n\n:::example\nSuppose a user's screen is $w$ pixels wide by $h$ pixels tall. The screen can be modelled by the space\n  \\[ \\ClsdIntvl 0w\\times \\ClsdIntvl0h. \\]\n  The usual convention is that $(0,0)$ corresponds to the top left corner, but this is arbitrary. The order of the coordinates is also arbitrary: $\\ClsdIntvl 0h\\times\\ClsdIntvl 0w$ would work just as well.\n:::\n\n:::example\nThe set of playing cards can be viewed as\n  \\[\n    \\{ \\spadesuit, \\heartsuit, \\clubsuit, \\diamondsuit \\}\n    \\times\n    \\{\\mathrm A,2,3,4,5,6,7,8,9,10,\\mathrm J,\\mathrm Q,\\mathrm K\\}\n  \\]\n:::\n\n:::example\n$\\VecR2=\\R\\times\\R,\\ \\VecR3=\\R\\times\\R\\times\\R$, and so on. (See below about products of more than two spaces.)\n:::\n\n:::example\n  - a cube is $I\\times I\\times I$,\n  \n  - $I\\times S^1$ is a (hollow) cylinder,\n\n  - $S^1\\times S^1$ is a (hollow) torus:\n\n  ::embed[{epiplexis-content}/gng/01-coordinates/02-products/examples]{aspect-ratio=2 source appDir}\n:::\n\n:::example\nThe $n$-dimensional unit cube is\n  \\[ I^n = \\underbrace{I\\times\\dotsb\\times I}_{n\\text{ times}} \\]\n  This is harder to visualize in the same way as the cube above. But we can visualize it as $n$ slider controls.\n:::\n\n## Multiplication\n\nLet's explain why this operation is called multiplication. If $X$ is a finite set, we write $|X|$ for the number of elements of $X$, also called the :dfn[cardinality] or :dfn[size] of $X.$ For example, $|\\{a,b,c\\}|=3.$\n\nWhen $X$ and $Y$ are finite sets, the size of $X\\times Y$ is the product of the sizes of $X$ and $Y:$\n\n\\[ |X\\times Y| = |X||Y|. \\]\n\nFor instance, say we have three possible colors and four shapes. The number of possible colored shapes is $3\\times4=12:$\n\n\\[\n  \\Large\n  \\{\\red{\\mathrm{red}},\\, \\green{\\mathrm{green}},\\, \\blue{\\mathrm{blue}}\\}\n  \\times\n  \\{\\blacktriangle,\\, \\blacksquare,\\, \\bigstar,\\, \\bullet\\}\n  =\n  \\left\\{\\begin{matrix}\n  \\red\\blacktriangle&\\red\\blacksquare&\\red\\bigstar&\\red\\bullet\\\\\n  \\green\\blacktriangle&\\green\\blacksquare&\\green\\bigstar&\\green\\bullet\\\\\n  \\blue\\blacktriangle&\\blue\\blacksquare&\\blue\\bigstar&\\blue\\bullet\n  \\end{matrix}\\right\\}\n\\]\n\n## Associativity\n\nOne of the most important properties of ordinary multiplication (of numbers) is _associativity_: this is the property\n\\[ (ab)c = a(bc). \\]\nwhich means that the expression $abc$ is unambiguous. For example, we could evaluate $2\\cdot3\\cdot4$ as\n\\[\\begin{align*}\n  (2\\cdot3)\\cdot4 &= 6\\cdot4 = 24\\\\\n  2\\cdot(3\\cdot4) &= 2\\cdot12 = 24\n\\end{align*}\\]\nand both give the same result.\n\nSomething similar is true for the product of spaces, but we have to be more careful. We can give a direct definition of $X\\times Y\\times Z$ a space of 3-tuples\n\\[ X\\times Y\\times Z \\Defeq \\{(x,y,z) \\mid x\\in X,\\, y\\in Y,\\, z\\in Z\\}, \\]\nor we can build it out of products of two spaces at a time:\n\\[\\begin{align*}\n  (X\\times Y)\\times Z &= \\{((x, y), z) \\mid x\\in X,\\, y\\in Y,\\, z\\in Z\\}\\\\[.5em]\n  X\\times (Y\\times Z) &= \\{(x, (y, z)) \\mid x\\in X,\\, y\\in Y,\\, z\\in Z\\}\n\\end{align*}\\]\n\nThese three options aren't \"literally\" equal. As an analogy, in TypeScript, `[X, Y, Z]`, `[[X, Y], Z]`, and `[X, [Y, Z]]` are all different types. But there is an obvious way to go between them:\n\\[ (x,y,z) \\longleftrightarrow ((x,y),z) \\longleftrightarrow (x,(y,z)). \\]\nIn math, we generally leave these conversions implicit, so we will write\n\\[ (X\\times Y)\\times Z = X\\times Y\\times Z = X\\times(Y\\times Z). \\]\n\nI'll say a bit more about this expanded view of equality a few posts from now.\n\nIn my area of math (homotopy theory), there's often a lot of work that needs to be done to keep track of all these implicit conversions. One of the difficulties is that when converting between $(X\\times X)\\times X$ and $X\\times(X\\times X)$, you don't want to accidentally use the \"wrong\" conversion\n\\[ ((x,y),z) \\longleftrightarrow (z,(y,x)) \\]\n(which wouldn't typecheck for $(X\\times Y)\\times Z$ versus $X\\times(Y\\times Z)$)\n",
    "description": "",
    "duration": null,
    "meta": {
      "math": {
        "macros": ""
      }
    },
    "ownerId": "41786b7c-b873-4373-8ede-477bf85070a1",
    "publicationDate": "2024-06-15 23:40:16.340316 UTC",
    "slug": "products",
    "title": "Products",
    "type": "article"
  },
  {
    "id": "8dd0419d-b2d7-4685-9cdb-575eed7a983c",
    "content": "<iframe class=\"w-full h-[1000px]\" src=\"https://epiplexis.xyz/a/fxh/2d/\"></iframe>\n\nTODO migrate article",
    "description": "",
    "duration": null,
    "meta": {
      "math": {
        "macros": ""
      }
    },
    "ownerId": "41786b7c-b873-4373-8ede-477bf85070a1",
    "publicationDate": "2024-06-15 23:40:16.340316 UTC",
    "slug": "2x2-matrices",
    "title": "$2\\times2$ matrices",
    "type": "article"
  },
  {
    "id": "ccbd70d8-9b8d-470c-95d9-77335d78e0a7",
    "content": "## Episode 1: The $q$-Legendre principle\n\n::unit[intro]\n\n::unit[bases]",
    "description": "",
    "duration": null,
    "meta": {
      "math": {
        "macros": ""
      }
    },
    "ownerId": "41786b7c-b873-4373-8ede-477bf85070a1",
    "publicationDate": "2024-06-15 23:40:16.340316 UTC",
    "slug": "what-study",
    "title": "What do I study?",
    "type": "collection"
  },
  {
    "id": "6a3c0838-f88e-4fdc-ace7-4ecbdf951a0c",
    "content": "Consider a right-angle triangle with side lengths as indicated:\n\n::embed[{epiplexis-content}/gng/02-trigonometry/01-pythagoras/setup]{class=my-4 inline width=50%}\n\nThe lengths $a$ and $b$ are called the _side lengths_, and $c$ is called the (length of the) _hypotenuse_. The Pythagorean theorem says that these are related by the equation\n\\[ a^2 + b^2 = c^2. \\]\n\nThis can be visualized in terms of the areas formed by squares drawn on the sides of the triangle:\n::embed[{epiplexis-content}/gng/02-trigonometry/01-pythagoras/statement]{class=my-4 inline width=75%}\n\n:::example\n  Find the length of the hypotenuse of a triangle with side lengths 3 and 4.\n  :::solution\n  The hypotenuse has length $\\sqrt{3^2 + 4^2} = \\sqrt{9 + 16} = \\sqrt{25} = 5$.\n:::\n\n:::example\n  If a right-angle triangle has a hypotenuse of length 6, and one side of length 3, find the remaining side length.\n  :::solution\n  Taking $a=3$, $c=6$, we have\n  \\[\\begin{aligned}\n    3^2 + b^2 &= 6^2\\\\\n    b^2 &= 36 - 9\\\\\n        &= 27\\\\\n    b &= \\sqrt{27}\\\\\n      &= 3\\sqrt 3.\n  \\end{aligned}\\]\n:::\n\n## Proof\n\nLet's see why the Pythagoream theorem is true. We'll draw two squares, both having side length $a+b$, and divide them in different ways:\n\n::embed[{epiplexis-content}/gng/02-trigonometry/01-pythagoras/proof]{inline}\n\nThe left square says that\n\\[ (\\red a + \\blue b)^2 = \\red{a^2} + \\violet{2ab} + \\blue{b^2} \\]\nThe right square says that\n\\[ (\\red a + \\blue b)^2 = \\green{c^2} + \\violet{2ab} \\]\n\nSetting these equal to each other, we get\n\\[\\begin{aligned}\n  \\red{a^2} + \\violet{2ab} + \\blue{b^2} &= \\green{c^2} + \\violet{2ab}\\\\\n  \\red{a^2} + \\xcancel{\\violet{2ab}} + \\blue{b^2} &= \\green{c^2} + \\xcancel{\\violet{2ab}}\\\\\n  \\red{a^2} + \\blue{b^2} &= \\green{c^2}.\n\\end{aligned}\\]\n\n## Three dimensions\n\nIf $v=\\ivec{x,y}$ is a vector in $\\VecR2$, the Pythagorean theorem implies that the _length_ of $v$ is\n\\[ \\sqrt{x^2+y^2}. \\]\nSimilarly, if $A=\\ipt{x_1,y_1}$ and $B=\\ipt{x_2,y_2}$ are points in $\\AffR 2$, the Pythagorean theorem tells us that the _distance_ between these is\n\\[\n  \\sqrt{(x_1-x_2)^2 + (y_1-y_2)^2}\n\\]\n\nHow can we extend this to higher dimensions? That is, if $A=\\ipt{x_1,y_1,z_2}$ and $B=\\ipt{x_2,y_2,z_2}$ are points in $\\AffR3$, what is $\\Dist AB$? Writing $A-B=v=\\ivec{x,y,z}$, this is the same as asking for the length of $v$.\n\nA naive guess is that the length of $v=\\ivec{x,y,z}$ might be\n\\[ \\sqrt[3]{x^3+y^3+z^3}. \\]\nBut this can't be true, since the length of $\\ivec{x,y,0}$ should be the same as the length of $\\ivec{x,y}$. That is, the appearance of the number $2$ in the Pythagorean theorem isn't related to the problem being in two dimensions.\n\nInstead, we can introduce the point \\[ C=\\ipt{x_2,y_2,z_1},\\] which has $1$ component in common with $A$ and $2$ components in common with $B$. The points $A$, $B$, and $C$ lie in a common plane, and we can apply the \"2d\" Pythagorean theorem within this plane to get $\\Dist AB$ in terms of $\\Dist AC$ and $\\dist BC$. The vertical distance $\\dist BC$ is just $|z_2-z_1|$, and we can compute $\\Dist AC$ by the \"2d\" Pythagorean theorem. This is illustrated in the animation below.\n\n::embed[{epiplexis-content}/gng/02-trigonometry/01-pythagoras/3d]{aspect-ratio=1.6 class=my-2 source}\n\n## Distance\n\n:::definition\n  The **length** of a vector $v=\\ivec{v_1,\\dotsc,v_n}\\in\\VecR n$ is defined to be\n  \\[\n    \\Norm v \\Defeq \\sqrt{v_1^2 + \\dotsc + v_n^2}.\n  \\]\n  This is also sometimes called the **norm** of $v$.\n:::\n\n:::definition\n  If $p,q\\in\\AffR n$ are two points in _affine_ space, then the distance between them is\n  \\[\\begin{align*}\n    \\Dist pq\n      &\\Defeq \\Norm{p-q}\\\\\n      &= \\sqrt{(p_1-q_1)^2 + \\dotsb + (p_n-q_n)^2}\n  \\end{align*}\\]\n:::\n\n:::remark\n  If $v=\\ivec{x}\\in\\VecR1$, then $\\Norm v=\\sqrt{x^2}=|x|$ is the absolute value of $x$. This explains the double-bars notation for length, and you may sometimes see $|v|$ instead of $\\|v\\|$.\n:::\n\n:::example\n  Find the length of the vector $v=\\ivec{-1,2,3,-4}\\in\\VecR 4$.\n  :::solution\n    \\[\\begin{aligned}\n      \\Norm v\n        &= \\sqrt{(-1)^2 + 2^2 + 3^2 + (-4^2)}\\\\\n        &= \\sqrt{1 + 4 + 9 + 16}\\\\\n        &= \\sqrt{30}.\n    \\end{aligned}\\]\n:::\n\n:::example\n  Find the distance between the points $p=\\ipt{1,4,2,5}$ and $q=\\ipt{-1, 3, 0, 1}$.\n  \n  :::solution\n    By definition, $\\Dist pq = \\Norm{p-q}$. We have\n    \\[\\begin{aligned}\n      p-q\\\\\n        &= \\begin{pmatrix}1\\\\4\\\\2\\\\5\\end{pmatrix} - \\begin{pmatrix}-1\\\\3\\\\0\\\\1\\end{pmatrix}\\\\\n        &= \\begin{bmatrix}2\\\\1\\\\2\\\\4\\end{bmatrix}\n    \\end{aligned}\\]\n    We thus get\n    \\[\\begin{aligned}\n      \\Dist pq\n        &= \\sqrt{2^2+1^2+2^2+4^2}\\\\\n        &= \\sqrt{4+1+4+16}\\\\\n        &= \\sqrt{25}\\\\\n        &= 5\n  \\end{aligned}\\]\n:::\n\n## APIs\n\nIn Javascript, we can compute the lengths of vectors using [`Math.hypot()`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/hypot).\n\n```js\n// !interactive\n// finding the length of a vector in R^4\nconsole.log(\"Finding the length of a vector in R^4\");\nconsole.log(Math.hypot(-1, 2, 3, -4));\n\n// finding the distance between two points in A^4\nconsole.log(\"Finding the distance between points in A^4\");\nvar p = [1, 4, 2, 5];\nvar q = [-1, 3, 0, 1];\nconsole.log(Math.hypot(...p.map((pi, i) => pi - q[i])));\n```\n\n\nIn THREE.js, we have the following APIs for calculating distances and lengths:\n- [`Vector3.prototype.distanceTo()`](https://threejs.org/docs/?q=vector3#api/en/math/Vector3.distanceTo)\n- [`Vector3.prototype.distanceToSquared()`](https://threejs.org/docs/?q=vector3#api/en/math/Vector3.distanceToSquared)\n- [`Vector3.prototype.length()`](https://threejs.org/docs/?q=vector3#api/en/math/Vector3.length)\n- [`Vector3.prototype.lengthSq()`](https://threejs.org/docs/?q=vector3#api/en/math/Vector3.lengthSq)\n\nFor the \"squared\" methods, note that when $x,y\\ge 0$ we have $x\\ge y$ if and only iff $x^2 \\ge y^2$.\n\n## Exercises\n\n1. Make an app to draw circles like below. (Don't look at the source until you've tried it yourself.)   \n   ::embed[{epiplexis-content}/gng/02-trigonometry/01-pythagoras/drawing]{aspect-ratio=2 class=mt-2 source}\n\n2. Extend the above app to disallow drawing circles which overlap.\n",
    "description": "",
    "duration": null,
    "meta": {
      "math": {
        "macros": ""
      }
    },
    "ownerId": "41786b7c-b873-4373-8ede-477bf85070a1",
    "publicationDate": "2024-06-15 23:40:16.340316 UTC",
    "slug": "pythagoras",
    "title": "Pythagorean theorem",
    "type": "article"
  },
  {
    "id": "ef4b41a0-e507-456c-840d-e420ffddd37a",
    "content": "<iframe class=\"mx-auto aspect-video w-3/4\" width=\"75%\" src=\"https://www.youtube.com/embed/rjmQ5tT1aso?si=Trs18laFx3V7_Gq3\" title=\"YouTube video player\" frameborder=\"0\" allow=\"accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share\" referrerpolicy=\"strict-origin-when-cross-origin\" allowfullscreen></iframe>\n\n## Week of Monday, June 5, 2023\nThis week I've been stuck trying to prove something that I left til the last stages of writing my paper, because I thought it would be very quick to prove, and it's turning out to be extremely difficult.\n\nRoughly speaking, I have these two axes, and I have this operation that pulls you towards the $x$-axis. If you're already on the $x$-axis, it does nothing. And I need to show that, although this operation pulls you _toward_ the $x$-axis, it can't pull you _in_ if you're not already there.\n\n<figure class=\"mx-auto my-4 text-center w-1/2\">\n  <me-embed inline aspect-ratio=\"1\" width=\"100%\" src=\"{epiplexis-content}/logs/crystalline/diagram\"></me-embed>\n  <figcaption class=\"mt-2 text-sm\">Adapted from Figure 11.1 of the <cite><a href=\"https://people.mpim-bonn.mpg.de/scholze/Berkeley.pdf#page=102\">Berkeley lectures on p-adic geometry</a></cite>\n</figure>\n\n<p class=\"opacity-20 text-xs\" style=\"opacity:0.2;\">(Math ppl: I want to show that a prism <katex>(A,I)</katex> is crystalline if and only if <katex>(A,\\phi(I)A)</katex> is crystalline)</p>\n\nThe reason I'm doing this is that there's these mathematical objects called **prisms** that were invented in 2019, and have been pretty revolutionary. Many problems that were considered untouchable for decades have been solved just in the past few years, largely coming out of this circle of ideas. I'm developing a different perspective on prisms, which is somehow based on the rotational symmetries of the circle.\n\nIn order to justify my perspective, I have to explain how to see various aspects of the theory of prisms in my language—actually, not just show that it's possible, but that it's _natural_ to do so. In the diagram above, I have a natural candidate for prisms which \"lie on the $x$-axis\" (called **crystalline** prisms), but it turns out to actually correspond to things whose _twist_ ends up on the $x$-axis. So I have to show that this is actually the same as already being on the $x$-axis.\n\nFor comparison, there _wasn't_ any existing concept in the \"symmetry world\" to correspond to prisms on the $y$-axis (called **transversal** prisms). But I invented (or discovered) something to correspond to these, and these turned out to be something extremely fundamental that no one had noticed before, and which _massively_ simplify a lot of things in \"symmetry world\".\n\n## Wednesday, June 7, 2023\n\nAnyway, I've been trying and failing to prove this for several days. I messaged Ben on Discord to explain my problem and ask if he had any ideas. Ben suggested I first try to prove this for transversal ($y$-axis) prisms, then extend from that case.\n\nThis is a standard technique: often you can use the transversal guys to control all the others. But it doesn't work in this case, basically because the only thing which is on both the $x$-axis and the $y$-axis is $(0,0)$, and that's boring. So I told Ben \"no, that will never work\", he said \"oh yeah, whoops, sorry that was silly\", and I said \"no worries, I totally tried the same thing before realizing it was nonsense\".\n\nNow, there's a prime number involved in all of this, and I _have_ managed to make this work for the prime number $2$. There's a bunch of stuff in this field that works for any prime number _except_ $2$, so maybe I could use that to deal with the remaining primes? But that stuff goes over my head, so I spent a few hours trying to understand it better.\n\n<p class=\"opacity-20 text-xs\">(Math ppl: I'm referring to obtaining prismatic cohomology from <katex>q</katex>-de Rham cohomology, e.g. Proposition 4.8.8 of <cite><a href=\"https://arxiv.org/pdf/2201.06120.pdf#page=109\">Absolute prismatic cohomology</a></cite>)</p>\n\n## Thursday, June 8, 2023\n\nThe thing I'm trying to prove is **_obviously false_**. Like, one of the most basic examples of a prism is a counterexample. Jesus I'm dumb.\n\n<p class=\"opacity-20 text-xs\">(Math ppl: I'm referring to the Hodge-Tate point of <katex>\\mathrm{WCart}</katex>, coming from <katex>V(1)</katex>, which is a counterexample since <katex>FV=p</katex>.)</p>\n\nNow, if the answer to \"what do crystalline prisms correspond to?\" isn't what I expected, then that question becomes much more interesting. It's interesting, but it's a lot more work, and I just want this \\*\\*\\*\\*ing paper to be done.\n\nWait—actually maybe this _isn't_ a counterexample. In this subject, there are **static** things and **animated** things. This counterexample is one of the standard examples of an _animated_ prism, but the question I'm working on is really only about _static_ things. So I did some googling, and yes, this counterexample will _never_ be static. So we're back in business!\n\n## Friday, June 9, 2023\n\n<p class=\"text-center font-bold text-2xl\">SUCCESS!!!</p>\n\nI proved what I wanted. It was a little bit subtle: it seemed like you should be able to do the proof in either of two ways, but actually one way was slightly better, and that was exactly what I needed.\n\nI excitedly messaged Noah on Discord, and said \"you do this and this and this, and after sufficiently many shenanigans, you get what you want.\" And Noah said, \"hmm, I'm not seeing the shenanigans\", and I told him, \"it's a bit sneaky, I'll write something up tonight\".\n\nBut it was time to celebrate, so I biked over to the Brooklyn Society for Ethical Culture for board game night. My team won at Secret Hitler (go Fascists!), and then at midnight we went to Union Hall for karaoke. I got home around 3:30am, so I didn't get back to Noah.\n\n## Saturday, June 10, 2023\n\nWoke up sometime after noon, started writing up the proof to send to Noah. That thing where it seemed like the proof should work in either of two ways, but actually it only worked in one? Yeah it actually just doesn't work. I'd gotten my head so tangled up in this problem that I ended up making a circular argument.\n\nThere's no happy ending to this story. I put out [the paper](https://arxiv.org/abs/2309.03181) in September, and I just left this as a conjecture.\n",
    "description": "",
    "duration": null,
    "meta": {
      "math": {
        "macros": ""
      }
    },
    "ownerId": "41786b7c-b873-4373-8ede-477bf85070a1",
    "publicationDate": "2024-06-15 23:40:16.340316 UTC",
    "slug": "crystalline",
    "title": "Crystalline prisms",
    "type": "article"
  },
  {
    "id": "fddcc78f-af38-4cb2-8fcf-e6a53825faa3",
    "content": "",
    "description": "",
    "duration": null,
    "meta": {},
    "ownerId": "41786b7c-b873-4373-8ede-477bf85070a1",
    "publicationDate": "2024-09-15 00:18:15.572 UTC",
    "slug": "",
    "title": "Popup demo",
    "type": "recording"
  },
  {
    "id": "1d6c0831-ae3d-47fa-a971-53aec8232fb2",
    "content": "",
    "description": "",
    "duration": null,
    "meta": {},
    "ownerId": "41786b7c-b873-4373-8ede-477bf85070a1",
    "publicationDate": "2024-10-15 08:18:46.365 UTC",
    "slug": "",
    "title": "Popup demo w/ video",
    "type": "recording"
  },
  {
    "id": "e7513c4e-b266-47aa-9b62-7102402ddfc9",
    "content": "",
    "description": "",
    "duration": null,
    "meta": {},
    "ownerId": "41786b7c-b873-4373-8ede-477bf85070a1",
    "publicationDate": "2024-06-15 23:40:16.340 UTC",
    "slug": "",
    "title": "broken",
    "type": "recording"
  },
  {
    "id": "7867ba76-ea6f-4d28-831b-f1ca7e6b6f8b",
    "content": "",
    "description": "",
    "duration": 365366,
    "meta": {
      "thumbs": "single",
      "origins": [
        "https://canvasconnect.its.virginia.edu"
      ],
      "tracks": [
        {
          "kind": "captions",
          "srclang": "en"
        }
      ]
    },
    "ownerId": "41786b7c-b873-4373-8ede-477bf85070a1",
    "publicationDate": "2025-01-17 23:37:36.338 UTC",
    "slug": "",
    "title": "SIR Python",
    "type": "recording"
  },
  {
    "id": "5781afb2-2877-4a4c-bc8b-ddbb8b0f3cbc",
    "content": "",
    "description": "",
    "duration": 41816,
    "meta": {},
    "ownerId": "4a4d8990-1de7-481e-be21-17d46c119e88",
    "publicationDate": "2025-02-07 20:29:41.288683 UTC",
    "slug": "",
    "title": "",
    "type": "recording"
  },
  {
    "id": "772469c8-3e46-4382-becf-d640e04bb4e9",
    "content": "So far we've been setting up a lot of abstract language to talk about geometry. Let's do something more concrete: how do we animate a character moving from point $\\a$ to point $\\b$?\n\n<!-- insert demo -->\n\nIn the language we set up in the last post, $\\a$ and $\\b$ are points in **affine** space. Their difference $\\b-\\a$ is a **vector**. If we add $\\b-\\a$ to $\\a$, we get $\\b$.\n\n\\[ \\b = \\a + (\\b-\\a) \\]\n\nSince $\\b-\\a$ is a vector, we can **scale** it. For example,\n\n\\[ \\a + \\tfrac12(\\b-\\a) \\]\n\nis the point $50\\%$ of the way between $\\a$ and $\\b$; similarly, $\\a+0.3(\\b-\\a)$ is $30\\%$ along the way from $\\a$ to $\\b$.\n\n:::definition\n  If $\\a$ and $\\b$ are points in an affine space, we write\n  \\[ \\lerp_\\t(\\a, \\b) \\Defeq \\a + \\t(\\b-\\a). \\]\n  This stands for :dfn[linear interpolation]. If we have to put a complicated expression for $\\t$, we might also use the notation $\\lerp(\\a,\\b;\\t)$.\n:::\n\nWe often restrict $\\t$ to $\\CIntvl 01$, although you could let it be bigger to \"overshoot\".\n\nIn terms of the abstract language we introduced [before](./params-coords), this is a **parametrization** of the line segment from $\\a$ to $\\b$.\n\nNote that this linear motion doesn't look very natural. A real object moving would accelerate when starting and decelerate towards the end. We'll address that in the next post.\n\nThere's two ways to remember the above formula. One is: start at $\\a$ and add some multiple of $\\b-\\a$ to move towards $\\b$. Another way is: let's rewrite this as\n\\[ \\a + \\t(\\b - \\a) = (1-\\t)\\a + \\t\\b \\]\nThen when $\\t=0$, this becomes\n\\[ (1-0)\\a + 0\\b = \\a \\]\nand when $\\t=1$, it becomes\n\\[ (1-1)\\a + 1\\b = 0\\a + 1\\b = \\b. \\]\n\nBut wait! We saw in [the last post](./affine) that it doesn't make sense to add or scale **points**, only vectors. However,\n\\[ \\a + \\t(\\b - \\a) \\]\n**does** make sense, so it turns out that\n\\[ (1-\\t)\\a + \\t\\b \\]\nmakes sense, even though $(1-\\t)\\a$ and $\\t\\b$ don't! In general, we can make sense of\n\\[ x\\a + y\\b \\]\nif and only if $x+y=1$. Basically, we can take **weighted averages** of points.\n\n## Code\n\nIn THREE.js, we have the methods [`Vector3.lerp()`](https://threejs.org/docs/?q=lerp#api/en/math/Vector3.lerp) and [`Vector3.lerpVectors()`](https://threejs.org/docs/?q=lerp#api/en/math/Vector3.lerpVectors) for lerping vectors.",
    "description": "",
    "duration": null,
    "meta": {
      "math": {
        "macros": "\\newcommand{\\a}{\\red a}\n\\newcommand{\\b}{\\blue b}\n\\newcommand{\\t}{{\\color{gold} t}}"
      }
    },
    "ownerId": "41786b7c-b873-4373-8ede-477bf85070a1",
    "publicationDate": "2024-06-15 23:40:16.340316 UTC",
    "slug": "lerp",
    "title": "Linear interpolation",
    "type": "article"
  },
  {
    "id": "ef51960f-fcc3-4dae-8241-537a5ac6135e",
    "content": "<!-- #tab notes -->\nIn the [previous post](./params-coords), we took a closer look at how we represent problems numerically. In this post, we'll intoduce some additional \"type safety\" into this prcess by distinguishing between two _types_ of quantities: **points** and **vectors**. You might also call these **absolute** and **relative** quantities, or **affine** and **vector** quantities. In the next post, we'll use this perspective to [build a draggable popup](./dragging).\n\n## Introduction\n\nLet's start with the example of **temperature**. Suppose the temperatures in a given week are as follows:\n\n<table>\n  <thead>\n    <tr>\n      <th></th>\n      <th>M</th>\n      <th>T</th>\n      <th>W</th>\n      <th>R</th>\n      <th>F</th>\n    </tr>\n  </thead>\n  <tbody>\n    <tr>\n      <th scope=\"row\">\n        <katex>{}^\\circ\\text{C}</katex>\n      </th>\n      <td>\n        <katex>0</katex>\n      </td>\n      <td>\n        <katex>5</katex>\n      </td>\n      <td>\n        <katex>10</katex>\n      </td>\n      <td>\n        <katex>20</katex>\n      </td>\n      <td>\n        <katex>15</katex>\n      </td>\n    </tr>\n    <tr>\n      <th scope=\"row\">\n        <katex>{}^\\circ\\text{F}</katex>\n      </th>\n      <td>\n        <katex>32</katex>\n      </td>\n      <td>\n        <katex>41</katex>\n      </td>\n      <td>\n        <katex>50</katex>\n      </td>\n      <td>\n        <katex>68</katex>\n      </td>\n      <td>\n        <katex>59</katex>\n      </td>\n    </tr>\n  </tbody>\n</table>\n\nLooking at the Celsius row, we might be tempted to say something like \"it was twice as hot on Wednesday as it was on Tuesday\", having the equation\n\\[ 2\\cdot 5 = 10 \\]\nin mind. But if we write the same equation in Fahrenheit, we'd get\n\\[ \\color{red} 2\\cdot 41 = 50  \\]\nwhich is wrong!\n\nOn the other hand, we could say \"it *got* twice as hot from Monday to Wednesday as it did from Monday to Tuesday\". In the Celsius case, we'd be thinking of the equation\n\\[ 2 \\cdot (5 - 0) = 10 - 0; \\]\nin the Fahrenheit case, we'd have the equation\n\\[ 2\\cdot(41 - 32) = 50 - 32, \\]\nand this equation is true.\n\nWhat's going on? \n\n## Operations\n\nThere are two distinct things we can mean by \"temperature\": an **absolute** temperature (how hot an object is, or the temperature outside), or a **relative** temperature, representing the **difference** between two absolute temperatures. The formulas for converting between these are different: for _relative_ temperatures, we just multiply or divide by $\\frac59$, whereas for _absolute_ temperatures we also have to offset by $32$.\n\nHere are some more examples of absolute vs relative quantities:\n\n- an _absolute_ time is a **datetime** like \"3:23pm April 19 1943\"; a _relative_ time is a **duration**, like \"4 minutes and 33 seconds\".\n\n- an _absolute_ position is a specific point in space, like the top of the Eiffel tower. A _relative_ position is something like \"2km north and 500m east\".\n\nWe will call relative quantities :dfn[vectors], and absolute quantities :dfn[points]. The \"allowed\" (or \"meaningful\") operations between these are\n\n- $\\ptxt{point} - \\ptxt{\\red point} = \\vtxt{\\green vector}$\n\n- $\\ptxt{point} + \\vtxt{vector} = \\ptxt{point}$\n\n- $\\vtxt{vector} + \\vtxt{vector} = \\vtxt{vector}$\n\n- $\\text{\\blue{number}} \\cdot \\vtxt{vector} = \\vtxt{vector}$\n\nHere are some demos of that in 2d and 3d space:\n\n::embed[{epiplexis-content}/gng/01-coordinates/06-points-vectors/operations]{appDir inline source width=150%}\n\nWhen you're working with numbers (i.e. once you've picked a [coordinate system](./params-coords)), you can't really tell the difference between points and vectors: you can add and multiply points willy-nilly. You'll run into problems, though, when you try to _change_ coordinate systems: if you do an \"illegal\" operation, you'll get different answers in different coordinate systems.\n\nLet's make a definition.\n\n:::definition\n  We write $\\AffR n$ for :dfn[$n$-dimensional affine space], consisting of $n$-tuples of real numbers:\n  \\[ \\AffR n \\Defeq \\{\\ipt{x_1,\\dotsc,x_n} \\mid x_i \\in \\R \\}. \\]\n  This is the same _set_ as $\\VecR n$; the only difference is what we're allowed to do with them. When we write $\\ipt{x_1,\\dotsc,x_n}$ instead of $\\ivec{x_1,\\dotsc,x_n}$, we're emphasizing that this represents an _absolute_ quantity rather than a relative one. In particular, we're not allowed to add elements of $\\AffR n$ together, nor multiply them by numbers.\n\n  When writing them vertically, I'll write\n  \\[ \\begin{bmatrix}x\\\\y\\\\z\\end{bmatrix}\\text{ for vectors,} \\qquad \\begin{pmatrix}x\\\\y\\\\z\\end{pmatrix} \\text{ for points}. \\]\n  This is admittedly not very consistent/logical.\n:::\n\n:::warning\n  My notation for distinguishing between points and vectors is not standard. Also, I will probably get lax about the difference from time to time. The important thing is to distinguish the two concepts in your mind.\n\n  Also: this use of \"point\" is specific to the context of linear algebra. Pretty much every object in math can get called a \"point\".\n:::\n\nLet's try to give a slightly more precise definition (although I don't want to be fully rigorous in the main series).\n\nIf vectors represent differences between points, we might think to define points first, and then vectors. But look back at the operations we can do: all the operations involving points also involve vectors, but adding and scaling of vectors doesn't involve points. So we can talk about vectors without mentioning points, but not vice versa.\n\nSecond, if the distinguishing property of vectors is that they can be added together with other vectors, and scaled by numbers to produce other vectors, then it doesn't make sense to talk about individual vectors in isolation.\n\n:::definition\n  A :dfn[vector space] is a set $V$ whose elements can be added together to produce other elements of $V$, and which can be multiplied by real numbers. More precisely, the data of a vector space is the set $V$ _along with_:\n  - a \"zero vector\" $0_V\\in V$;\n  - an \"addition\" operation $V\\times V\\xrightarrow+ V$\n  - a \"scalar multiplication\" operation $\\R\\times V\\xrightarrow\\cdot V$\n:::\n\nThese operations are required to satisfy several [axioms](https://en.wikipedia.org/wiki/Vector_space#Definition_and_basic_properties), such as $v+0_V=v$ and $u+v=v+u$.\n\n:::example\n  Let $V$ be the set of continuous functions $f\\colon R\\to\\R$. The \"zero vector\" is the constant function\n  \\[ 0_V(x) = 0. \\]\n  Addition and scalar multiplication are defined by\n  \\[ (f+g)(x) \\Defeq f(x) + g(x) \\qquad (cf)(x) \\Defeq cf(x) \\]\n  for $f,g\\In V$ and $c\\In\\R$.\n\n  For example, if $f(x)=\\cos(x)-2x^2$, and $g(x)=x^2+2^x$, then $f+2g\\in V$ is the function\n  \\[ (f+2g)(x) = \\cos(x)+2^{x+1}. \\]\n:::\n\nIt might be startling to think of _functions_ as vectors—but this perspective turns out to be very useful, for example when solving systems of differential equations. One of the benefits of the abstract perspective is that it allows us to extend the tools of linear algebra to situations we wouldn't have originally thought of.\n\nIn most situations there will be an obvious choice for the \"zero vector\", \"addition\", and \"scalar multiplication\". However, it should be stressed that these are **additional data** that needs to be specified along with the set $V$.\n\n:::example\n  Here's a funny example of a vector space. I'll use $\\oplus$ and $\\odot$ for the addition and scalar multiplication operations, so you don't get them confused with the usual operations.\n  - the underlying set of our vector space is $V=\\R_{>0}$, the set of positive real numbers\n  - the \"zero vector\" is $0_V=1$\n  - the \"addition\" operation is given by multiplication, $x\\oplus y\\Defeq xy$\n  - the \"scalar multiplication\" operation is given by exponentiation, $c\\odot x=x^c$\n\n  Can you see how this unusual vector space is actually the usual vector space $(\\R,0,+,\\cdot)$ \"in disguise\"?\n:::\n\n:::definition\n  Let $V$ be a vector space. An :dfn[affine space over $V$] is a set $A$ along with operations\n  \\[\\begin{align*}\n    A \\times A & \\xrightarrow- V\\\\\n    A \\times V &\\xrightarrow+ A\n  \\end{align*}\\]\n  These operations are required to satisfy [axioms](https://en.wikipedia.org/wiki/Affine_space#Definition) like\n  \\[\\begin{align*}\n    a + 0_V &= a\\\\\n    (a-b) + v &= a-(b+v)\n  \\end{align*}\\]\n  for $a,b\\In A$ and $v\\In V$. Beware that in the second equation, there are two different $+$ operations! The $+$ on the left-hand side is adding two elements of $V$ together, while the one on the right-hand side is adding an element of $A$ with an element of $V$.\n:::\n\n:::example\n  Vector and affine spaces come up naturally when solving linear equations (which is my main motivation for introducing the distinction). Let\n  \\[\\begin{align*}\n    V &= \\{\\ivec{x,y} \\mid y=3x\\}\\\\\n    A &= \\{\\ipt{x,y} \\mid y=3x+1\\}\n  \\end{align*}\\]\n  <iframe class=\"w-full mx-auto my-2\" src=\"https://www.desmos.com/calculator/s23v22wcxp\" height=\"400\"></iframe>\n  \n  Let's first check that $V$ is a vector space under the usual coordinate-wise addition and scaling. We need to show that if $\\ivec{x,y},\\ivec{\\cl x{x'},\\cl y{y'}}\\In V$, and $r\\In\\R$, then\n  \\[\\begin{align*}\n    \\ivec{x+\\cl x{x'},y+\\cl y{y'}} &\\In V\\\\\n    \\ivec{rx, {r}y} &\\In V\n  \\end{align*}\\]\n  By definition of $V$, we have $y=3x$ and $\\cl y{y'}=3\\cl x{x'}$. So\n  \\[\\begin{align*}\n    y + \\cl y{y'}\n      &= 3x + 3\\cl x{x'}\\\\\n      &= 3(x + \\cl x{x'})\n  \\end{align*}\\]\n  which shows that $\\ivec{x+\\cl x{x'},y+\\cl y{y'}}\\In V$. Similarly,\n  \\[\\begin{align*}\n    {r}y\n      &= r(3x)\\\\\n      &= 3(rx)\n  \\end{align*}\\]\n  which shows that $\\ivec{rx,{r}y}\\In V$.\n\n  Next, let's show that $A$ is **NOT** a vector space (using the usual addition formula). Let's take the two points $P=\\ipt{0,1}$ and $Q=\\ipt{1,4}$, both of which are in $A$. Then\n  \\[ P+Q=\\ipt{1,5}\\notin A \\quad\\text{since}\\quad 3\\cdot1+1=4\\ne 5 \\]\n  However, $A$ is an affine space over $V$. First we'll show that when we add elements of $A$ with elements of $V$, the result is still in $A$. For this, let $\\ipt{a,b}\\In A$ and let $\\ivec{x,y}\\In V$. This means that $b=3a+1$ and $y=3x$. Thus,\n \\[\\begin{align*}\n   b + y\n     &= (3a+1) + (3x)\\\\\n     &= 3(a+x)+1\n \\end{align*}\\]\n which shows that $\\ipt{a+x,b+y}\\In A$. Next, let $\\ipt{a,b},\\ipt{\\cl a{a'},\\cl b{b'}}\\In A$. Then\n \\[\\begin{align*}\n   b - b'\n     &= (3a+1) - (3\\cl a{a'}+1)\\\\\n     &= 3a - 3\\cl a{a'}\\\\\n     &= 3(a-\\cl a{a'})\n \\end{align*}\\]\n which shows that $\\ivec{a-\\cl a{a'},b-\\cl b{b'}}\\In V$.\n:::\n\n## Code\n\n### Graphics\nEvery graphics library will have methods for dealing with vectors. For example, in THREE.js the relevant class is [`THREE.Vector3`](https://threejs.org/docs/#api/en/math/Vector3).\n\nFew (if any) graphics libraries explicitly make the distinction between points and vectors. Still, remembering the distinction is helpful for understanding how to convert between different coordinate systems.\n\nIn computer graphics, the ambient \"affine space\" is called :dfn[world space]. The vector space centered at a particular object is called :dfn[object space]. (See [below](#dictionary) for what I mean by \"centered at\".)\n\n### DOM\n\nAnother example of points vs vectors comes from my favorite DOM method, [`getBoundingClientRect()`](https://developer.mozilla.org/en-US/docs/Web/API/Element/getBoundingClientRect). The return type of this is a [`DOMRect`](https://developer.mozilla.org/en-US/docs/Web/API/DOMRect), which (ignoring `readonly`) is\n\n```ts\ninterface DOMRect {\n    height: number;\n    width: number;\n    x: number;\n    y: number;\n  \n    readonly bottom: number;\n    readonly left: number;\n    readonly right: number;\n    readonly top: number;\n}\n```\n\nTo distinguish between points and vectors, we could type this more precisely as\n\n```ts\ninterface DOMRect {\n    height: Vector1;\n    width: Vector1;\n    x: Point1;\n    y: Point1;\n  \n    readonly bottom: Point1;\n    readonly left: Point1;\n    readonly right: Point1;\n    readonly top: Point1;\n}\n```\nHere a `Vector1` and a `Point1` are both just `number`s, but we're not allowed to add two `Point1`s together.\n\n### TypeScript\n\nThe above discussion of axioms and operations might have been a little abstract or confusing. The following code is an approximate TypeScript equivalent of what I was saying above. In particular, note that the operations `add()`, `scale()`, `sub()` have to be **specified/implemented**. \n\n```ts\n// helpers\n// https://stackoverflow.com/a/43674389\n\ninterface Type<T> {\n  // eslint-disable-next-line @typescript-eslint/no-explicit-any\n  new (...args: any[]): T;\n}\n\nfunction staticImplements<T>() {\n  return <U extends T>(constructor: U, _context: ClassDecoratorContext) => {\n    constructor;\n  };\n}\n\n// vector types\ninterface Vector<V> {\n  /** Add two vectors together */\n  add(other: V): V;\n\n  /** Scale a vector by a number */\n  scale(factor: number): V;\n}\n\ninterface VectorStatic<V> extends Type<Vector<V>> {\n  zero: V;\n}\n\n// implementation\n@staticImplements<VectorStatic<Vector2>>()\nexport class Vector2 {\n  constructor(\n    public x: number,\n    public y: number,\n  ) {}\n\n  static zero = new Vector2(0, 0);\n\n  /** Add two vectors together */\n  add(other: Vector2) {\n    return new Vector2(this.x + other.x, this.y + other.y);\n  }\n  \n  /** Scale a vector by a number */\n  scale(factor: number) {\n    return new Vector2(this.x * factor, this.y * factor);\n  }\n\n  /** Whether two vectors are equal */\n  static eq(u: Vector2, v: Vector2) {\n    return u.x === v.x && u.y === v.y;\n  }\n}\n\n// affine types\ninterface Affine<V, A> {\n  /** Add a vector to a point to get another point */\n  add(other: V): A;\n\n  \n  /** Subtract two points to get a vector */\n  sub(other: A): V;\n}\n\n@staticImplements<Type<Affine<Vector2, Point2>>>()\nexport class Point2 {\n  constructor(\n    public x: number,\n    public y: number,\n  ) {}\n\n  /** Add a vector to a point to get another point */\n  add(other: Vector2) {\n    return new Point2(this.x + other.x, this.y + other.y);\n  }\n\n  /** Subtract two points to get a vector */\n  sub(other: Point2) {\n    return new Vector2(this.x - other.x, this.y * other.y);\n  }\n  \n  /** Whether this point is equal to another */\n  eq(other: Point2) {\n    return this.x === other.x && this.y === other.y;\n  }\n}\n```\n\nNote we have to do a little bit of decorator weirdness to express this in TypeScript. Also, TypeScript has no way of expressing the constraints (axioms) these operations need to specify, e.g.\n\\[ a+(u+v) = (a+u)+v\\quad a\\In A;\\ u,\\,v\\In V \\]\nThe closest code equivalent would be\n```ts\nfunction assertVectorSpaceAxioms(u: Vector2, v: Vector2, w: Vector2, r: number) {\n  // zero vector is identity element for addition\n  // u + 0 = u\n  assert(Vector2.eq(\n    u.add(Vector2.zero),\n    u,\n  );\n  // 0 + u = u\n  assert(Vector2.eq(\n    Vector2.zero.add(u), // 0 + v\n    u,\n  );\n\n  // associativity: (u + v) + w = u + (v + w)\n  assert(Vector2.eq(\n    u.add(v).add(w), // (u + v) + w\n    u.add(v.add(w)), // u + (v + w)\n  ));\n\n  // commutativity: u + v = v + u\n  assert(Vector2.eq(\n    u.add(v),\n    v.add(u)\n  ));\n\n  // ...and so on (see Exercises)\n}\n```\n\nThese limitations are deficiencies of TypeScript, not of mathematics.\n\n## Dictionary\n\nOne of the reasons the distinction between points and vectors is confusing is that it's possible to convert between the two. However, there are **many** different ways to do this—more precisely, every point gives a _different_ way to convert between points and vectors. It works as follows:\n\nLet $V$ be a vector space, let $A$ be an affine space over $V$, and let $\\O$ be a point of $A$. The choice of $\\O$ gives a way to go back and forth between $A$ and $V$:\n\\[\\begin{align*}\n  f_\\O\\colon & A\\to V & g_\\O\\colon & V\\to A\\\\\n  f_\\O(a) &= a-\\O & g_\\O(v) &= \\O+v\n\\end{align*}\\]\nWe include the subscript $\\O$ to emphasize that these functions depend on the choice of \"origin\" point $\\O$. These functions are [bijections](https://mutualed.test/gng/cg/maps#terminology):\n\\[\\begin{align*}\n  g_\\O(f_\\O(a)) &= g_\\O(a-\\O) &\n  f_\\O(g_\\O(v)) &= f_\\O(\\O+v)\\\\\n    &= \\O + (a-\\O) &&= (\\O+v)-\\O\\\\\n    &= a &&= v\n\\end{align*}\\]\nso no information is lost in this process.\n\nThe rub is that this dictionary **depends on the chosen point $\\O$**. In some situations there may be an obvious \"origin\" point, but in others there may be none, and in most there are several. For example, in computer graphics our \"default\" origin is the top-left corner of the screen. But if you want to animate a fireball circling around a character, you want to position the fireball _relative to_ that character, meaning the center of that character's bounding box will be your origin.\n\nNote that every vector space is an affine space _over itself_: we already know how to add vectors to vectors, and we can define subtraction of vectors by combining addition and scalar multiplication:\n\\[ u - v \\Defeq u + (-1\\cdot v). \\]\n\n<!-- #tab videos -->\n<iframe allow=\"fullscreen\" class=\"w-full\" src=\"https://epiplexis.xyz/a/w7s/lesson/\" style=\"aspect-ratio: 8/5;\"></iframe>\n\n<!-- #tab exercises  -->\n\n1. Compute the following expressions if they make sense, or answer \"meaningless\" if they do not make sense.  \n    1. $\\pt12 - \\pt21$\n    2. $\\pt{-1}{\\frac12} + \\vec1{\\frac32}$\n    3. $\\pt10 + \\pt01$\n    4. $\\vec{-3}1 + \\vec22$\n    5. $\\vecc111 + \\vec21$\n    6. $2\\vec1{\\frac12}$\n    7. $2\\pt1{\\frac12}$\n    8. $2\\vecc1{\\frac32}{-1} - \\vecc0{\\frac12}{-1}$\n    \n    :::popup{trigger=Answer}\n    1. $\\vec{-1}1$\n    \n    2. $\\pt02$\n    \n    3. meaningless: can't add a point to a point\n    \n    4. $\\vec{-1}3$\n    \n    5. meaningless: can't add vectors of different sizes (more abstractly, can't add vectors belonging to different vector spaces)\n    \n    6. $\\vec21$\n    \n    7. meaningless: can't scale a point\n    \n    8. $\\vecc2{\\frac52}{-1}$\n    :::\n  \n2. \n    1. Write code equivalents (as in the `assert()` example) for the full list of [vector space axioms](https://en.wikipedia.org/wiki/Vector_space#Definition_and_basic_properties). For convenience, those axioms are:  \n       $$\n       \\begin{align*}  \n         0 + v &= v &&\\text{(identity for +)}\\\\  \n         (u+v)+w &= u+(v+w) &&\\text{(associativity of +)}\\\\  \n         u + v &= v + u &&\\text{(commutativity of +)}\\\\  \n         v+(-1\\cdot v) &= 0 &&\\text{(inverses for +)}\\\\  \n          1\\cdot v&=v &&\\text{(identity for multiplication)}\\\\  \n          (rs)v&=r(sv) &&\\text{(associativity for multiplication)}\\\\  \n          r(u+v) &= ru+rv &&\\text{(distributivity)}  \n       \\end{align*}\n       $$\n       Here $u,v,w\\In V$ and $r,s\\In\\R$, where $V$ is a vector space. Write code equivalents for these, as in the `assert()` example.\n       \n       :::popup{trigger=Answer}\n       ```ts\n       function assertVectorSpaceAxioms(\n         u: Vector2, v: Vector2, w: Vector2,\n         r: number, s: number,\n       ) {\n         // 1. identity for addition\n         assert(Vector2.eq(\n           v.add(Vector2.zero),\n           v,\n         );\n       \n         // 2. associativity\n         assert(Vector2.eq(\n           u.add(v).add(w), // (u + v) + w\n           u.add(v.add(w)), // u + (v + w)\n         ));\n       \n         // 3. commutativity\n         assert(Vector2.eq(\n           u.add(v),\n           v.add(u)\n         ));\n       \n         // 4. inverses\n         assert(Vector2.eq(\n           v.add(v.scale(-1)),\n           Vector2.zero\n         ));\n    \n         // 5. identity for multiplication\n         assert(Vector2.eq(\n           v.scale(1),\n           v\n         ));\n    \n         // 6. associativity for multiplication\n         assert(Vector2.eq(\n           v.scale(r*s), // (rs)v\n           v.scale(s).scale(r), // r(sv)\n         ));\n    \n         // 7. distributivity\n         assert(Vector2.eq(\n           (u+v).scale(r), // r(u+v)\n           u.scale(r).add(v.scale(r)), // ru + rv\n         ));\n       }\n       ```\n       :::\n   2. The full list of affine space axioms is:\n      $$\n       \\begin{align*}  \n         a + 0 &= a &&\\text{(identity for +)}\\\\  \n         (a+u)+v &= a+(u+v) &&\\text{(associativity of +)}\\\\  \n         a + (b-a) &= b &&\\text{(transitivity)}\\\\  \n         a + v = a &\\implies v=0 &&\\text{(freeness)}\n       \\end{align*}\n      $$  \n      Here $a,b\\In A$ and $u,v\\in V$, where $A$ is an affine space over $V$. Write code equivalents for these, as in the `assert()` example.\n     \n      :::popup{trigger=Answer}\n      ```ts\n      function assertAffineSpaceAxioms(\n        u: Vector2, v: Vector2,\n        a: Point2, b: Point2,\n      ) {\n        // 1. identity\n        assert(Point2.eq(\n          a.add(Vector2.zero),\n          a,\n        );\n      \n        // 2. associativity\n        assert(Point2.eq(\n          a.add(u).add(v), // (a + u) + v\n          a.add(u.add(v)), // a + (u + v)\n        ));\n      \n        // 3. transitivity\n        assert(Point2.eq(\n          a.add(b.sub(a)), // a + (b - a)\n          b,\n        ));\n\n        // 4. freeness\n        assert(\n          Point2.eq(a.add(v), a)\n          ===\n          Vector2.eq(v, Vector2.zero)\n        );\n      }\n      ```\n      :::\n      There are many equivalent ways of defining affine spaces, so you might see these stated a little differently in other places.\n      \n3. Verify the vector space axioms for the vector space $(\\R_{>0}, 1, \\oplus, \\odot)$ where $x\\oplus y=xy$ and $r\\odot x=x^r$ for $x,y\\In \\R_{>0}$ and $r\\in\\R$. Can you see how this vector space is secretly the usual vector space $(\\R,0,+,\\cdot)$ \"in disguise\"?  \n\n     :::popup{trigger=Solution}\n     The easiest way to do this is to use the [bijection](/gng/cg/maps#terminology)\n     $$\n       2^\\bullet\\colon \\R \\to \\R_{>0}\n     $$\n     (Any other base would do just as well, $2$ isn't special here.) This takes the vector space structure on $\\R$ into the vector space structure on $\\R_{>0}$, in the sense that\n     $$\n     \\begin{align*}\n       2^0 &= 1\\\\\n       2^{x+y} &= 2^x 2^y \\\\&= 2^x\\oplus 2^y\\\\\n       2^{rx} &= (2^x)^r \\\\&= r\\odot 2^x\n     \\end{align*}\n     $$\n     :::\n",
    "description": "",
    "duration": null,
    "meta": {
      "math": {
        "macros": "\\newcommand{\\vecc}[3]{\\begin{bmatrix}#1\\\\#2\\\\#3\\end{bmatrix}}\n\\newcommand{\\ptxt}[1]{\\text{\\red{#1}}}\n\\newcommand{\\vtxt}[1]{\\text{\\green{#1}}}\n"
      }
    },
    "ownerId": "41786b7c-b873-4373-8ede-477bf85070a1",
    "publicationDate": "2024-06-15 23:40:16.340316 UTC",
    "slug": "points-vectors",
    "title": "Points and vectors",
    "type": "article"
  },
  {
    "id": "90223085-936e-4026-a9d5-274685666450",
    "content": "Over the years, friends, family, and strangers have asked me if I can explain the math that I do. This is tricky; because math is so cumulative, even professional mathematicians usually can't understand each other's work very well unless they work in the same field. (This has the advantage of making it difficult to talk about work at parties.) This series is my attempt to share the stuff I think about and why I think it's so fun.\n\nMy area of math is called **homotopy theory**. Historically, this grew out of **topology**, which is a form of **geometry**. Nowadays, it's increasingly viewed as foundational to math itself, so it interacts with a lot of other fields. In particular, I'm very interested in how it interacts with a subject called **arithmetic geometry**, which tries to incorporate things like prime numbers into geometry. The field is in a bit of a golden age right now: major papers are being posted nearly every month, and decades-old problems are falling one after another. \n\n What I mainly do is study **prismatic cohomology** (a hot new thing in arithmetic geometry) from the perspective of **equivariant** homotopy theory. *Equivariant* means having to do with symmetry—in this case the rotational symmetry of a circle.\n\nI'll explain all these fancy words over the course of many posts! A hyper-condensed overview is at the end of this post.\n\nHomotopy theory has a very theoretical side and a heavily computational side; I started out more on the theory side, but now lean more towards calculations. I often make interactive widgets and pretty pictures to help myself understand what I'm doing; pictures are maybe a good thing to organize this series around. My first goal is to explain what's going on in the following diagram:\n\n<figure class=\"rounded-md bg-gray-200 shadow-md border-stone-900 p-2 mx-auto\">\n  <object\n    title=\"Numbers 1 through 27 with colored bars stacked on top. Every number has a red bar; multiples of 3 (additionally) have an orange bar; multiples of 9 have a yellow bar; and 27 has a green bar.\"\n    data=\"https://ysulyma.github.io/assets/q-legendre-3.svg\" width=\"100%\"></object>\n</figure>\n\nLater, I'll talk about this one:\n\n\n<figure class=\"rounded-md bg-gray-200 shadow-md border-stone-900 p-2 mx-auto max-w-xl\">\n  <img\n    class=\"w-full\"\n    alt=\"\"\n    src=\"https://ysulyma.github.io/assets/grid.svg\" />\n</figure>\n\nand maybe eventually these guys (zoom in or open in new tab):\n\n<div class=\"flex justify-between gap-4 my-4 mx-auto\">\n  <figure class=\"bg-gray-100 rounded-md p-2\">\n    <img\n      alt=\"64x64 checkerboard, light squares filled with colored shapes\"\n      src=\"https://ysulyma.github.io/assets/slice-2-perfd.svg\" />\n  </figure>\n    \n  <figure class=\"bg-gray-100 rounded-md p-2\">\n    <img\n      alt=\"64x64 checkerboard, light squares filled with colored shapes\"\n      src=\"https://ysulyma.github.io/assets/slice-good-2.svg\" />\n  </figure>\n</div>\n\n:::think\nWhat patterns can you find in the above charts? For the last two, the specific shapes used don't mean anything; all that matters is the distribution of colors and shape families.\n:::\n\n## Topology\n\nLet's start by thinking about how we represent points on a shape:\n\n<iframe class=\"aspect-video w-full\" src=\"https://ysulyma.github.io/epiplexis/what-study/topology-demo/dist/\"></iframe>\n\n[Source](https://github.com/ysulyma/epiplexis/tree/main/what-study/topology-demo)\n\nWe can represent a point on the blue curve by a number between 0 and 1 (between 0% and 100% along the curve, starting from the left). This is the same way we'd represent points on a straight line segment. We can _almost_ do the same thing on the purple star, but now 0% and 100% represent the same point. This is similar to how $0^\\circ,$ $360^\\circ,$ $720^\\circ,$ etc. all correspond to the same point on the circle.\n\n:dfn[Topology] is the study of \"how data gets represented\". The blue curve is topologically equivalent to a straight line, and the purple curve is topologically equivalent to a circle. Topology is also often described as \"rubber-band geometry\": topology considers two shapes to be the same if each can be transformed into the other by twisting or bending, _but no cutting or tearing_.\n\nHowever, the difference between _the straight line and the circle_ is very important. To some extent, \"every problem that can be described using numbers, we can solve, and there's a unique solution\". (This is extremely vague, but I have precise statements in mind.) But suppose the solution involves dividing by $3$. Well, $0/3$ is just $0,$ but $0^\\circ/3$ is $\\\\{0^\\circ,120^\\circ,240^\\circ\\\\}.$ When the basic operations we do on numbers are unavailable, or behave differently than usual, we're no longer able to \"solve every problem\".\n\n:dfn[Homotopy theory] goes a step further than topology and adds \"inflating and deflating\" to the list of operations that \"don't change a shape\". We can shrink a straight line down to a single point (the most trivial shape there is), so these are _homotopically_ equivalent (but not topologically). We can build a circle by taking a straight line and gluing the ends together. When we pass from topology to homotopy, we \"delete\" the straight line, so the gluing is the only information that's left. I like to think about this as: we understand numbers pretty well, so we want to ignore those and just focus on the \"redundancies\" or \"wrinkles\" in the representation of data.\n\n## Cohomology\n:dfn[Cohomology] is a quantitative way to describe these \"wrinkles\" or \"redundancies\". In its crudest form, cohomology associates a sequence of numbers (called :dfn[Betti numbers]) to every shape. Here are some examples:\n\n<object\n  class=\"magic-svg\"\n  data=\"/assets/betti-numbers.svg\" type=\"image/svg+xml\"\n  aria-label=\"Numbers of various shapes. A string with no crossings: 1; a string with one loop: 1, 1; one string with three loops and another with one loop: 2, 4; a sphere: 1, 0, 1; a torus: 1, 2, 1\"></object>\n\n(The two shapes above the $2,\\,4$ are considered a single shape; the $2$ means there are two pieces, or :dfn[connected components]. Also, $2,\\,4$ is really short for $2,\\,4,\\,0,\\,0,\\,0,\\,\\dotsc$)\n\nThere are many different :dfn[cohomology theories] that offer different interpretations of what these numbers mean, and also provide richer information beyond these numbers.\n\n- from the perspective of :dfn[singular cohomology], these numbers are counting the number of (higher-dimensional) \"holes\" or \"loops\" in a shape.\n\n- :dfn[de Rham cohomology] is based on *calculus*[^calculus]. Calculus is about *change*: e.g. *velocity* as the rate of change of *position*, or *acceleration* as the rate of change of velocity. Although $0^\\circ$ and $360^\\circ$ represent the same point on a circle, an angular **_velocity_** of $360^\\circ\\text{ / sec}$ is very different from an angular velocity of $0^\\circ\\text{ / sec}$. So de Rham cohomology sees a numeric quantity (angular velocity) that looks like the rate of change of some other quantity (angle), but the original quantity is \"missing\".\n\nIf you kind of already know what your shape looks like, you can calculate its cohomology using any cohomology theory. But what if someone just hands you some random equations? De Rham cohomology is fairly easy to calculate \"mechanically\"—we can program computers to do calculus. But singular cohomology is very abstract, and literally impossible to calculate directly for anything beyond discrete points.\n\nDespite this, singular cohomology has some advantages over de Rham cohomology. Think about the distinction between a **line** (through the origin) and a **direction**: you can travel in two directions on every line. This \"2:1 redundancy\" shows up in many places: it's responsible for the \"plate trick\" seen below, as well as the phenomenon of [gimbal lock](https://en.wikipedia.org/wiki/Gimbal_lock). Gimbal lock causes problems in aviation and 3d graphics, necessitating the use of [quaternions](https://en.wikipedia.org/wiki/Quaternions) for doing rotations. (Rotations in 3d space are (non-obviously) topologically equivalent to lines through the origin in 4d space; unit quaternions are directions in 4d space.)\n\n<figure class=\"mx-auto my-2 max-w-[400px] text-center\">\n  <img alt=\"Woman rotating a coffee mug in her hand. Once the cup is returned to its original position, her arm is still twisted. After another full rotation, her arm is in a normal position.\" src=\"https://ysulyma.github.io/assets/plate-trick.png\" />\n  <figcaption>Taken from Bredon, <cite>Topology and Geometry</cite>.</figcaption>\n</figure>\n\nHopefully this convinces you that understanding \"2:1\" redundancies is important. Unfortunately, de Rham cohomology can only detect \"∞:1\" redundancies; singular cohomology can detect \"finite:1\" redundancies, but is much harder to compute. **Prismatic cohomology** is a fancier version of de Rham cohomology, based on a fancier version of calculus, which is able to detect \"finite:1\" redundancies, while remaining fairly computable.\n\nThe circle (infinitely many angles corresponding to the same point) is the simplest example of cohomology. It is also the _universal_ example: if you think hard enough about the circle, you can deduce the entire theory of de Rham cohomology. (I don't know why this should be true, or if this is even a good way of thinking about it.) In particular, the **rotational symmetries** of the circle play a central role in prismatic cohomology.\n\nWhat I mainly do these days is think about prismatic cohomology from the perspective of these rotational symmetries. There are many other perspectives; this one is historically the first, but the subsequent ones that were discovered are much simpler for most purposes, so this one has been neglected. However, I've shown that it illuminates some of the more advanced aspects of the theory.\n\nMy main project right now is trying to generalize prismatic cohomology to accommodate other kinds of symmetry. Circles also have **reflectional** symmetry, in addition to rotational. It's slightly harder to get \"even:1\" information out of prismatic cohomology than \"odd:1\", and it's thought that incorporating the reflectional symmetries might explain this. There are several people working on this, from different perspectives than mine, and I'm trying to understand how my approach compares to theirs.\n\nI'm also interested in plugging in completely different kinds of symmetry, like that of a triangle or square. It's less clear what this would be useful for.\n\n[^calculus]: I mean *differential* calculus here, which is about instantaneous rates of change. There's also *integral* calculus which is about the reverse: accumulated change over time. In cohomology land, the connection between differential and integral calculus (the fundamental theorem of calculus) translates to the fact that singular and de Rham cohomology give the same Betti numbers.\n",
    "description": "",
    "duration": null,
    "meta": {
      "math": {
        "macros": ""
      }
    },
    "ownerId": "41786b7c-b873-4373-8ede-477bf85070a1",
    "publicationDate": "2024-06-15 23:40:16.340316 UTC",
    "slug": "intro",
    "title": "Introduction",
    "type": "article"
  },
  {
    "id": "eeb4e10a-9637-49e6-9af3-3e1440238f56",
    "content": "Now for a definition. Let $X$ and $Y$ be spaces. A map $f\\colon X\\to Y$ is called an :dfn[isomorphism] if there is a map $g\\colon Y\\to X$ such that\n\\[ g\\circ f = \\id_X \\quad\\text{and}\\quad f\\circ g = \\id_Y. \\]\nMore explicitly,\n\\[\\begin{align*}\n  g(f(x)) &= x \\quad\\text{for all }x\\in X\\\\\n  f(g(y)) &= y \\quad\\text{for all }y\\in Y\n\\end{align*}\\]\nBasically, $f$ is a way to transport problems in $X$ to problems in $Y$. The identity $g(f(x))=x$ says that you can still recover $x$ after running it through $f$, so \"no information is lost\" about your original equation.\n\n<!-- need xymatrix for commutative diagrams here -->\n\n## Uniqueness\n\nAbove, we asked for **some** $g$ to exist, such that $gf=\\id_X$ and $fg=\\id_Y$. Could there be multiple of them?\n\n:::proposition\n  Let $f\\colon X\\to Y$, and let $g,h\\colon Y\\to X$ be a left and right inverse of $f$ respectively (meaning that $g\\circ f=\\id_X$ and $f\\circ h=\\id_Y$). Then $g=h$.\n\n  :::proof\n    We want to show that $g(y)=h(y)$ for all $y\\in Y$. We know that\n    \\[\n      \\blue{f(h(y)) = y}\n      \\quad\\text{and}\\quad\n      \\red{g(f(x)) = x}\n    \\]\n    for all $x\\in X$ and all $y\\in Y$. We can write\n    \\[\\begin{align*}\n      g(y)\n        &= g(f(h(y))) &&\\text{since } \\blue{y = f(h(y))}\\\\\n        &= g(f(x)) &&\\text{with } x = h(y)\\\\\n        &= x &&\\text{since } \\red{g(f(x)) = x}\\\\\n        &= h(y) &&\\text{by definition of }x\n    \\end{align*}\\]\n:::\n\nWe also could have written the above proof in \"functional notation\"\n\\[\\begin{align*}\n  g &= g\\circ\\id_Y\\\\\n    &= g\\circ(f\\circ h)\\\\\n    &= (g\\circ f)\\circ h\\\\\n    &= \\id_X\\circ h\\\\\n    &= h\n\\end{align*}\\]\n\nSince inverses are unique if they exist, we'll write $f^{-1}$ for the inverse of a map $f$.\n\n<!-- insert warning about f^-1 applied to sets -->\n\n<!-- left vs right inverses (above) -->\n\n## Equality\n\n<!-- bill clinton quote -->\n\nWhen we talked about [products](./products), we noted that the spaces\n\\[ (X\\times Y)\\times Z \\quad\\text{and}\\quad X\\times(Y\\times Z) \\]\nor the types\n<div class=\"text-center\">\n <code>[[X, Y], Z]</code> and <code>[X, [Y, Z]]</code> \n</div>\nwere technically different, but \"equivalent for all purposes\", since there's an obvious way to convert between them:\n\\[ ((x, y), z) \\leftrightarrow (x, (y, z)) \\]\n\nAbove, we saw that an arbitrary interval $\\CIntvl ab$ is essentially interchangeable with the unit interval $\\CIntvl01$.\n\n",
    "description": "",
    "duration": null,
    "meta": {
      "math": {
        "macros": "\\newcommand{\\id}{\\mathrm{id}}\n"
      }
    },
    "ownerId": "41786b7c-b873-4373-8ede-477bf85070a1",
    "publicationDate": "2024-06-15 23:40:16.340316 UTC",
    "slug": "isos",
    "title": "Isomorphism",
    "type": "article"
  },
  {
    "id": "4a1291cc-75e5-4ad7-9af7-e8a3f1092cd8",
    "content": "::unit[gng]\n\n::unit[what-study]\n\n::unit[logs]\n\n[Old site](https://epiplexis.xyz)\n",
    "description": "",
    "duration": null,
    "meta": {
      "math": {
        "macros": "% misc\n\\newcommand{\\twopi}{\\varpi}\n\\newcommand{\\twopi}{\\varpi}\n\\newcommand{\\<}{\\left\\langle}\n\\newcommand{\\>}{\\right\\rangle}\n\\newcommand{\\In}{\\htmlData{annotation_text=in / element of}{\\in}}\n\n\n\\newcommand{\\<}{\\left\\langle}\n\\newcommand{\\>}{\\right\\rangle}\n\\newcommand{\\In}{\\htmlData{annotation_text=in / element of}{\\in}}\n\n% algebra\n\\newcommand{\\im}{\\operatorname{im}}\n\n% prisms and THH\n\\ktxnewcommand{\\prism}{\\htmlClass{prism}}{\\Delta}\n\n\\newcommand{\\THH}{\\operatorname{THH}}\n\\newcommand{\\TC}{\\operatorname{TC}}\n\\newcommand{\\TCmin}{\\TC^-}\n\\newcommand{\\TP}{\\operatorname{TP}}\n\\newcommand{\\TF}{\\operatorname{TF}}\n\\newcommand{\\TR}{\\operatorname{TR}}\n\n% equivariant\n\\newcommand{\\rog}{\\bigstar}\n\n\\newcommand{\\m}{\\underline}\n\\newcommand{\\mpi}{\\m\\pi}\n\n% sets\n\\newcommand{\\A}{\\mathbf A}\n\\newcommand{\\C}{\\mathbf C}\n\\newcommand{\\F}{\\mathbf F}\n\\newcommand{\\G}{\\mathbf G}\n\\newcommand{\\L}{\\mathrm L}\n\\newcommand{\\H}{\\mathbf H}\n\\newcommand{\\N}{\\mathbf N}\n\\newcommand{\\O}{\\mathcal O}\n\\newcommand{\\P}{\\mathbf P}\n\\newcommand{\\Q}{\\mathbf Q}\n\\newcommand{\\R}{\\mathbf R}\n\\newcommand{\\T}{\\mathbf T}\n\\newcommand{\\Z}{\\mathbf Z}\n\n\\newcommand{\\RP}{\\mathbf{RP}}\n\\newcommand{\\CP}{\\mathbf{CP}}\n\n\n% TODO move these to per-unit\n\\newcommand{\\green}[1]{\\htmlStyle{color: ##16a34a;}{#1}}\n\\newcommand{\\red}[1]{\\htmlStyle{color: ##dc2626;}{#1}}\n\\newcommand{\\blue}[1]{\\htmlStyle{color: ##2563eb;}{#1}}\n\\newcommand{\\indigo}[1]{\\htmlStyle{color: ##6366f1;}{#1}}\n\\newcommand{\\violet}[1]{\\htmlStyle{color: ##8b5cf6;}{#1}}\n\n\\newcommand{\\Twopi}{\\htmlData{annotation_text=ratio of a circle's circumference to its radius, $\\approx6.28\\dots$}{\\twopi}}\n\n\\newcommand{\\Defeq}{\\htmlData{annotation_text=defined to be equal to}{\\mathrel{:=}}}\n\n\\newcommand{\\Restrict}[2]{\\htmlData{annotation_text=$#1$ with domain restricted to $#2$}{{#1}|_{#2}}}\n\n\\newcommand{\\comma}{,}\n"
      }
    },
    "ownerId": "41786b7c-b873-4373-8ede-477bf85070a1",
    "publicationDate": "2024-06-15 23:40:16.340316 UTC",
    "slug": "#",
    "title": "Epiplexis",
    "type": "root"
  },
  {
    "id": "ed4972a8-cc94-4255-b5df-0aa56e69c0c5",
    "content": "This is a series of \"research diary\" entries. Here, rather than trying to deeply explain the math, I just want to give a window into the _process_ of math research—especially how winding and full of confusion it is, and how it intertwines with the rest of my life.\n\n::unit[crystalline]\n",
    "description": "",
    "duration": null,
    "meta": {
      "math": {
        "macros": ""
      }
    },
    "ownerId": "41786b7c-b873-4373-8ede-477bf85070a1",
    "publicationDate": "2024-06-15 23:40:16.340316 UTC",
    "slug": "logs",
    "title": "Research logs",
    "type": "collection"
  },
  {
    "id": "73320725-bb2d-479f-97d1-daa14a4d0874",
    "content": "In this post I'm going to talk about writing numbers in different bases.\n\nOur usual way of writing numbers is in _base 10_. This means we represent a number as a sum of multiples of powers of 10. For example,\n\n\\[\\begin{align*}\n  324 &= 300 + 20 + 4\\\\\n      &= 3\\cdot100 + 2\\cdot 10 + 4\\cdot1\\\\\n      &= \\mathbf 3\\cdot10^2 + \\mathbf 2\\cdot 10^1 + \\mathbf 4\\cdot10^0\n\\end{align*}\\]\n\nWriting numbers in another base means we replace 10 with some other number. For example, $13$ is written as $1101$ in binary (base 2), because\n\n\\[\\begin{align*}\n  13 &= 8 + 4 + 1\\\\\n     &= 1\\cdot8 + 1\\cdot4 + 0\\cdot2 + 1\\cdot1\\\\\n     &= \\mathbf 1\\cdot2^3 + \\mathbf 1\\cdot2^2 + \\mathbf 0\\cdot2^1 + \\mathbf 1\\cdot2^0\n\\end{align*}\\]\n\nWe can indicate the base with a subscript: $13_{10} = 1101_{2}$. Note we're still using base 10 to write the subscript.\n\nIf the base is bigger than 10, we need symbols to go beyond the existing digits $0,1,2,3,4,5,6,7,8,9$. Traditionally, this is done using letters. So for instance, A represents 10, B represents 11, and so on, and F represents 15. For example, $173$ in \"hexadecimal\" (base 16) is $\\mathrm{AD}_{16}$, because\n\n\\[\\begin{align*}\n  173_{10} &= 10\\cdot 16 + 13\\cdot 1\\\\\n           &= \\mathbf A\\cdot16^1 + \\mathbf D\\cdot16^0\n\\end{align*}\\]\n\n:::think\n  How many words can you spell in hexadecimal? What are their decimal values? For example, $\\mathrm{BEEF}_{16}=48,879$.\n:::\n\nHere's a demo so you can see how this works with different numbers:\n\n::embed[{epiplexis-content}/what-study/01-legendre/02-digits/table]{inline source}\n\nThere's no _mathematical_ reason to choose 10 as our base, it's just a _cultural_ convention (probably due to us having ten fingers). For example, the Babylonians used base 60 (\"sexagesimal\"), and the Mayans used base 20 (\"vigesimal\"). Hexadecimal is used fairly often in computing.\n\nThe same idea works to the right of the \"decimal point\". For instance, $0.75_{10} = 0.11_{2}$, because\n\n\\[\\begin{align*}\n  0.75_{10} &= 0.5 + 0.25\\\\\n             &= \\mathbf 1\\cdot 2^{-1} + \\mathbf1 \\cdot{2^{-2}}\n\\end{align*}\\]\n\n## Converting\n:::example\n  Let's see how to convert bases by hand. We'll write $\\red{420}$ in base $\\blue{16}$. The remainder when $\\red{420}$ is divided by $\\blue{16}$ is $\\green4$, which we write as $\\red{420}\\equiv\\green4\\bmod\\blue{16}$. This tells us that the last hexadecimal digit of $\\blue{16}$ is $\\green4$.\n\n  Next, $\\red{420}-\\green4=\\red{416}$ is divisible by $\\blue{16}$. We divide $\\red{416}$ by $\\blue{16}$ to get $\\frac{\\red{416}}{\\blue{16}}=\\red{26}$. Now we have $\\red{26}\\equiv\\green{10}\\bmod\\blue{16}$, so the second-last (\"tens\") hexadecimal digit of $\\red{420}$ is $\\green{\\mathrm A}$ (which we use for the number $\\green{10}$).\n\n  Again we subtract $\\red{26}-\\green{10}=\\red{16}$, which divided by $\\blue{16}$ is $\\green1$. So $\\red{420}$ in hexadecimal is\n \\[ \\red{420}_{10} = \\green{\\mathrm{1A4}}_{\\blue{16}}. \\] \n Again, remember that this means\n \\[ \\red{420} = \\green4\\cdot\\blue{16}^0 + \\green{10}\\cdot\\blue{16}^1 + \\green1\\cdot\\blue{16}^2 \\fade{{}+\\green0\\cdot\\blue{16}^3+\\dotsb} \\]\n The algorithm we used above basically works by writing this as\n \\[ \\red{420} = \\green4\\cdot\\blue{16}^0 + \\blue{16}\\cdot(\\green{10} + \\blue{16}\\cdot(\\green1\\fade{{} + \\blue{16}\\cdot(\\green0 + \\dotsb)})). \\]\n:::\n\nHere's an implementation of that in code. We can check our work against the built-in [`Number.prototype.toString()`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number/toString) method.\n\n```ts\n// !interactive\nconst num = 420;\nconst base = 16;\n\n// built-in function\nconsole.log(`built-in: ${num.toString(base)}`);\n// implementing it ourselves\nconsole.log(`    ours: ${writeInBase(num, base)}`)\n\n/** Write a number in another base. */\nfunction writeInBase(\n  num,\n  base,\n  alphabet = \"0123456789abcdefghijklmnopqrstuvwxyz\"\n) {\n  if (base > alphabet.length) {\n    throw new RangeError(`Maximum base is ${alphabet.length}`);\n  }\n  \n  const digits = [];\n\n  // handle 0\n  if (num === 0) return \"0\";\n\n  // handle negative numbers\n  if (num < 0) return \"-\" + writeInBase(num, base);\n  \n  while (num > 0) {\n    const remainder = num % base;\n    digits.push(alphabet[remainder]);\n\n    num = (num - remainder) / base;\n  }\n\n  return digits.reverse().join(\"\");\n}\n```\n\n:::think\n  Can you modify the above algorithm to handle decimals, e.g. $420.1137$?\n:::\n\n## Uses\n\nAlthough the vast majority of what we do is in base 10, there are a handful of places where we make use of other bases. Here are a few:\n\n### Colors\nIf you grew up in the 90s, you may remember `[color=#FF0000]` or `<FONT COLOR=\"#ffffff\">` from forums and GeoCities. What do these mean?\n\nOn a computer, colors are represented by red, blue, and green (RGB) components, each between $0$ and $255$. Since $255 = 256 - 1 = 2^8 - 1 = 100_{16}-1$, this is between $0$ and $\\mathrm{FF}_{16}$ when written in hexadecimal. For example, <span style=\"color:#FF0060;\">#FF0060</span> is $255$ red, $0$ green, and ${60}_{16}=96$ blue. Here's a demo where you can experiment with this in general: \n\n::embed[{epiplexis-content}/what-study/01-legendre/02-digits/colors]{class=mt-2 inline source}\n\n### URLs\nVery high bases are sometimes used to make short URLs, e.g. [https://old.reddit.com/11jznte/](https://old.reddit.com/11jznte/) or [https://youtu.be/dQw4w9WgXcQ](https://youtu.be/dQw4w9WgXcQ). In their database, this thread has some numeric ID like `1298482891`, and `11jznte` is that number written in some base. I'm not sure exactly which base they chose: if we use capital and lower letters, the digits 0–9, and hyphens and underscores, then we get\n\\[ 2\\cdot26 + 10 + 2 = 64 \\]\nas a base. But it's best to omit e.g. capital O and lowercase l, so we don't get confused between `0O1l`, so in practice it's more likely to be base 62 or smaller.\n\n<!-- ::embed[{epiplexis-content}/what-study/01-legendre/02-digits/switches]{aspect-ratio=2.5} -->\n\n## What does it mean?\n\nSo, a given number can be represented many different ways. What can we learn about a given number by writing in various different bases? Let's look at a few different examples of this, and then a conceptual way of organizing it.\n\n### Rationality\n\nWe have names for different kinds of numbers.\n\n- the :dfn[natural numbers] are $0,1,2,\\dots$\n- the :dfn[integers] are $\\dots,-2,-1,0,1,2,\\dots$\n- a :dfn[rational] number is one that can be expressed as a _ratio_ of integers. For example, $\\frac12$, $\\frac53$, $-\\frac{12}7$, and so on.\n- numbers which aren't rational are called :dfn[irrational]. For example, $\\pi$ and $\\sqrt2$ are irrational.\n\nRationality can be seen in the digit representation of a number: a _rational_ number will always have a repeating pattern of digits. For example,\n\n\\[\\begin{align*}\n  \\frac{4}{11} &= 0.36363636\\dots\\\\\n\\end{align*}\\]\nwhich we write as\n\\[\\begin{align*}\n  \\phantom{\\frac{4}{11}} &= 0.\\overline{36}\\phantom{363636\\cdots}\n\\end{align*}\\]\n\nThis includes the case of a _terminating_ expression, which we can think of as a repeating $0$. In fact, every rational number has a _terminating_ expression in _some_ base. For example, we have\n\\[ 11/9 = 1.\\overline2_{10} = 1.12_6 = 1.02_3. \\]\nwhich terminates in bases 3 and 6 but repeats infinitely in base 10.\n\nIrrational numbers, on the other hand, never fall into a repeating pattern. (This doesn't mean there's \"no pattern\" to their digits, just that it can't be expressed so simply.)\n\n### Last digits\n\nLet's start by thinking about what the _last_ digit of an integer written in binary means. The numbers $0$ through $7$ written in binary are\n\\[ \\blue0,\\, \\red1,\\, 1\\blue0,\\, 1\\red1,\\, 10\\blue0,\\, 10\\red1,\\, 11\\blue0,\\, 11\\red1 \\]\nNotice that: **the last binary digit of a number tells us whether it's odd or even!**\n\nIn many situations, this is all we need to know about the number. For example, suppose you leave a room with the lights on, and come back later and the lights are off. You know that the light switch must have been flipped an **odd** number of times, but the exact number of times isn't relevant.\n\nIn general: the last digit of a number in base $b$ is its **remainder** when divided by $b$.\n\nWhat about, say, the first digit? It turns out that this is harder to interpret. To see why, let's consider two addition problems, where some of the numbers are covered up.\n\n\\[\n  \\begin{align*}\n        ?7\\\\\n    {}+{?4}\\\\\\hline\n    ??1\n  \\end{align*}\n  \\qquad\n  \\begin{align*}\n        7?\\\\\n    {}+{2?}\\\\\\hline\n    ???\n  \\end{align*}\n\\]\n\nFor example, the first of these could be either of the concrete problems\n\n\\[\n  \\begin{align*}\n       37\\\\\n    {}+64\\\\\\hline\n    101\n  \\end{align*}\n  \\qquad\n  \\begin{align*}\n       17\\\\\n    {}+24\\\\\\hline\n    41\n  \\end{align*}\n\\]\n\nAlthough these give different answers, the _last digit_ is the same between the two answers.  But in the second case, we can't pin down any of the digits for sure, not even the tens. For example, we could have either of\n\\[\n  \\begin{align*}\n       73\\\\\n    {}+25\\\\\\hline\n       98\n  \\end{align*}\n  \\qquad\n  \\begin{align*}\n       75\\\\\n    {}+29\\\\\\hline\n      104\n  \\end{align*}\n\\]\nAt most we can say that the middle $?$ is either $9$ or $0$.\n\nIn other words: to figure out the last digit of $a+b$, you just need to know the last digit of $a$ and of $b$. But to know the _second-last_ digit of $a+b$, you need to know the _last two_ digits of $a$ and $b$, since there could be _carries_ from the last digit.\n\n:::yell\n  Knowing the last $k$ digits of a number written in base $b$ is the same as knowing its remainder when divided by $b^k$.\n:::\n\nHow do different bases relate? Let's write the last digits of the numbers $0$ through $9$ in bases $2$, $5,$ and $10$.\n\n::embed[{epiplexis-content}/what-study/01-legendre/02-digits/endings]{inline}\n\nNotice that: **knowing the last digit of $n$ in base $10$ is the same as knowing its last digit in base $2$ and in base $5$!**\n\nLet's try this for $2$ and $4$:\n\n::embed[{epiplexis-content}/what-study/01-legendre/02-digits/endings-24]{inline}\n\nHere we don't have quite the same pattern as above: knowing the last digit in base $4$ isn't the same as \"knowing the last digit in base $2$ and also in base $2$.\" Instead, **knowing the last digit of $n$ in base $4$ is the same as knowing its last _two_ digits in base $2$**.\n\n:::yell\n  If $b$ and $c$ have no factors in common, then knowing the last however many digits in base $bc$ is the same as knowing the last that many digits in bases $b$ and $c$.\n\n  At the opposite end, knowing the last $k$ digits in base $b^r$ is the same as knowing the last $rk$ digits in base $b$.\n:::\n\n:::example\n  Let's take $b=360$. The prime factorization of this is $360=2^3 \\cdot 3^2 \\cdot 5$. Thus, to know the last $2$ digits of a number in base $360$ is the same as knowing\n  - its last $6$ digits in base $2$, i.e. its remainder when divided by $2^6=64$; \n  \n  - its last $4$ digits in base $3$, i.e. its remainder when divided by $3^4=81$;\n  \n  - its last $2$ digits in base $5$, i.e. its remainder when divided by $5^2=25$.\n:::\n\n### The function analogy\n\nWriting a number in base $b$,\n\\[ n = n_0 b^0 + n_1 b^1 + n_2 b^2 + \\dotsb \\]\nlooks very similar to writing a polynomial in one variable $x$:\n\\[ f(x) = a_0 x^0 + a_1 x^1 + a_2 x^2 + \\dotsb \\]\n\nFor example, the number\n\\[ 4,321 = 1 + 2\\cdot 10 + 3\\cdot10^2 + 4\\cdot10^3 \\]\nlooks very similar to the polynomial\n\\[ f(x) = 1 + 2x + 3x^2 + 4x^3. \\]\nIn particular, $4,321=f(10)$.\n\nSo, is it possible to either view\n- polynomials as \"numbers in base $x$\", or alternatively\n- integers as \"functions in the variable $b$\"?\n\nThe main difference between the two situations is that to add two polynomials, you just add the coefficients together:\n\\[\\begin{align*}\n    &{}\\phantom= (1+2x+3x^2+4x^3) + (5+9x+6x^2+x^3)\\\\\n    &= (1+5) + (2+9)x + (3+6)x^2 + (4+1)x^3\\\\\n    &= 6 + 11x + 9x^2 + 5x^3\n\\end{align*}\\]\nbut when adding two numbers, we have to **carry**:\n\\[\\begin{align*}\n  4,321 + 1,695\n    &= (1+5) + (2+9)\\cdot10 + (3+6)\\cdot10^2 + (4+1)\\cdot10^3\\\\\n    &= 6 + \\red11\\cdot10 + 9\\cdot10^2 + 5\\cdot10^3\\\\\n    &= 6 + 1\\cdot10 + \\red10\\cdot10^2 + 5\\cdot10^3\\\\\n    &= 6 + 1\\cdot10 + 0\\cdot10^2 + 6\\cdot10^3\\\\\n    &= 6,016\n\\end{align*}\\]\n\nSo in this analogy, polynomials are actually easier to work with than numbers! So we should take the _second_ of the above suggestions: that is, try to understand integers as ``functions in the variable $b$''.\n\nThere's a ton of math research around trying to flesh out this analogy; it broadly goes under the name of the \"function analogy\" or the \"philosophy of the [field with one element](https://en.wikipedia.org/wiki/Field_with_one_element)\" (but it will take quite a while to explain that name). The stuff I think about is part of or adjacent to one of the main approaches to doing so (but there are several others). Basically, we understand polynomials very very well, so we could try to take the tools we have for working with polynomials and translate them through this analogy to get very powerful tools for understanding integers and prime numbers and so on.\n\nCarrying is just one way that base expansions are harder to work with than polynomials. Another major one is that we can contemplate polynomials in _multiple variables_, e.g.\n\\[\n  x^2 + 2xy + y^2\n  \\quad\\text{or}\\quad\n  z^2-xy\n\\]\nWe really don't know what the analogue of this would be for numbers, i.e. how to \"mix bases\". In the past 10 years, there's been an explosion of activity in this area, and we now have very precise _glimpses_ of _parts_ of what this ought to be. These are very exciting, but we definitely don't have the full picture yet.\n\nWhat would be a satisfactory answer to \"fleshing this out\"? And relatedly, what would such a thing be good for?\n\nThe [Riemann hypothesis](https://en.wikipedia.org/wiki/Riemann_hypothesis) is widely considered the most important unsolved problem in math. It's a technical statement about complex numbers, but basically it gives an extremely precise description of the distribution of prime numbers, i.e. what is the probability that a randomly chosen number will be prime? There's a \"polynomial\" version of the Riemann hypothesis, which is still extremely difficult, but was proven in 1974. So one proposed strategy for proving the original Riemann hypothesis is to take that proof and translate it through this analogy—but that gets stuck due to not being able to talk about \"multi-base numbers\".\n\nConversely, this provides a way of assessing claims of \"making sense of the function analogy\". There's lots and lots of ideas about how to do this—but until we can prove the Riemann hypothesis, we haven't found the \"one true way\" (if there is one).\n\nI'll devote a future chapter to explaning the function analogy in more detail.",
    "description": "",
    "duration": null,
    "meta": {
      "math": {
        "macros": "\\newcommand{\\fade}[1]{\\htmlStyle{opacity:0.2;}{#1}}}"
      }
    },
    "ownerId": "41786b7c-b873-4373-8ede-477bf85070a1",
    "publicationDate": "2024-06-15 23:40:16.340316 UTC",
    "slug": "bases",
    "title": "Different bases",
    "type": "article"
  },
  {
    "id": "83831908-8ad2-4a60-b457-36c3b0752c14",
    "content": "Last time we saw that we could animate a point moving from $a$ to $b$ via\n\n\\[ \\lerp_\\t(\\a, \\b) = \\a + \\t(\\b - \\a) \\]\n\nWhile this formula is simple, the resulting motion doesn't look very realistic. Real objects don't move at a constant speed: they **accelerate** from rest, and **decelerate** before coming to a stop.\n\nWe can make this more realistic by using what's called an :dfn[easing function]. An easing function is essentially a function\n\\[ f\\colon \\CIntvl01 \\to \\CIntvl 01 \\quad \\text{ with $f(0)=0$ and $f(1)=1$}\\]\nthat tells you how fast you should be moving. Some examples are\n\\[ f(t) = t^3, \\qquad g(t)=\\sin\\frac{\\pi t}2 \\]\n(Again, we'll cover trig functions in the next chapter.)\n\nOur formulas become\n\\[\\begin{align*}\n  \\a + \\t^3(\\b - \\a) \n  &\\quad\\text{or}\\quad\n  (1-\\t^3)\\a + \\t^3\\b\\\\\n  \\a + \\sin\\frac{\\pi\\t}2(\\b-\\a)\n  &\\quad\\text{or}\\quad\n  \\left(1-\\sin\\frac{\\pi\\t}2\\right)\\a + \\sin\\frac{\\pi\\t}2\\b\n\\end{align*}\\]\n\nBut these formulas are very complicated. We don't actually need to expand the formula like this: we already understand $\\lerp_\\t(\\a,\\b)$, so we can just focus on the easing function.\n\n## Easing functions\n\nBefore launching into the theoretical discussion, let's cover practical resources on using easing functions.\n\n(easings.net, CSS functions)\n\n## Composition\n\nLet's take a more formal look at this.\n\n:::definition\n  Given two functions\n  \\[\\begin{align*}\n    f \\colon X &\\to Y\\\\\n    g \\colon Y &\\to Z,\n  \\end{align*}\\]\n  their :dfn[composite] $g\\circ f$ is the function\n  \\[ g\\circ f\\colon X\\to Z \\]\n  given by\n  \\[ (g\\circ f)(x) = g(\\underbrace{f(x)}_{{}\\in Y}) \\]\n  We sometimes write the composite as simply $gf$, omitting the $\\circ$.\n:::\n\nNote the order of composition is backwards to how we might say it out loud: $g\\circ f$ means apply $f$ first, then feed the result of that into $g$. However, the order $g\\circ f$ lines up with how we apply the function to an input (either in math or in programming).\n\n```ts\n/** Compose two functions */\nfunction compose<X, Y, Z>(g: (y: Y) => Z, f: (x: X) => Y): (x: X) => Z {\n  return (x) => g(f(x));\n}\n```\n\n**Functional** programming emphasizes composition more than imperative style programming. For example, here are two ways to sum the list of the first $n$ squares:\n\n```ts\n/** Sum the first n integers, 0^2 + 1^2 + 2^2 + ... + n^2 */\nfunction imperativeStyle(n: number) {\n  let sum = 0;\n\n  for (let i = 1; i <= n; ++i) {\n    sum += i ** 2;\n  }\n  \n  return sum;\n}\n\n/** Sum an array of numbers */\nfunction sum(arr: number[]) {\n  return arr.reduce((a, b) => a + b, 0);\n}\n\n/** Get an array of the integers 0, 1, ..., n */\nfunction range(n: number) {\n  return Array.from({length: n + 1}).map((_, i) => i)\n}\n\n/** Sum the first n integers, 0^2 + 1^2 + 2^2 + ... + n^2 */\nconst functionalStyle = compose(\n  sum,\n  compose(\n    // square entries\n    (arr) => arr.map(i => i ** 2),\n    range\n  )\n);\n```\n\n## Isomorphism\n\nTime to learn a fancy new word!\n\nYou might wonder why easing functions are only defined as functions\n\\[ \\CIntvl01 \\to \\CIntvl01 \\]\nIf we're animating something that lasts $5$ seconds, we might instead want to use a function\n\\[ \\CIntvl05 \\to \\CIntvl01 \\]\nif measuring time in seconds, or $\\CIntvl0{5000}\\to\\CIntvl01$ if measuring time in milliseconds. Similarly, if the character we're animating is traveling from point $1$ to point $8$, it might make more sense to use a map\n\\[ \\CIntvl05 \\to \\CIntvl18. \\]\n\nHowever, there's an easy way to convert between these. For any $\\CIntvl ab$, we have a map\n\\[\\begin{align*}\n  \\gamma_{a,b}\\colon \\CIntvl01 &\\to \\CIntvl ab\\\\\n  \\gamma_{a,b}(t) &= a+t(b-a)\n\\end{align*}\\]\nWe can also convert back: to do this, let's write $y=\\gamma_{a,b}(t)$, and then solve for $t$ in terms of $y$:\n\\[\\begin{align*}\n  y &= a+t(b-a)\\\\\n  y - a &= t(b-a)\\\\\n  t &= \\frac{y-a}{b-a}\n\\end{align*}\\]\nWe'll call this $\\gamma_{a,b}^{-1}\\colon\\CIntvl ab\\to\\CIntvl01$.\n\nWe can turn our function\n\\[ f\\colon \\CIntvl05 \\to \\CIntvl{75}{100} \\]\ninto a function $g\\colon \\CIntvl01\\to\\CIntvl01$ via\n\\[\\begin{CD}\n  \\CIntvl01 @>g>> \\CIntvl01\\\\\n  @V{\\gamma_{0,5}}VV @AA{\\gamma_{75,100}^{-1}}A\\\\\n  \\CIntvl05  @>>f> \\CIntvl{75}{100} \n\\end{CD}\\]\nThat is, $g=\\gamma_{75,100}^{-1}\\circ f\\circ\\gamma_{0,5}$.\n\nSo, in complete generality we might want to consider functions\n\\[ \\CIntvl ab \\to \\CIntvl cd \\]\nBut we can \"normalize\" these down to only considering functions\n\\[ \\CIntvl01 \\to \\CIntvl 01. \\]\nNote that we needed **both** $\\gamma$ and $\\gamma^{-1}$ to do this.\n\n",
    "description": "",
    "duration": null,
    "meta": {
      "math": {
        "macros": "\\newcommand{\\a}{\\red a}\n\\newcommand{\\b}{\\blue b}\n\\newcommand{\\t}{{\\color{gold} t}\n\\newcommand{\\id}{\\mathrm{id}}"
      }
    },
    "ownerId": "41786b7c-b873-4373-8ede-477bf85070a1",
    "publicationDate": "2024-06-15 23:40:16.340316 UTC",
    "slug": "easings",
    "title": "Composition / Easings",
    "type": "article"
  },
  {
    "id": "f173d254-8dbe-4425-8c65-454b16e4c95f",
    "content": "::unit[cg]\n\n::unit[trig]\n",
    "description": "",
    "duration": null,
    "meta": {
      "math": {
        "macros": "\\newcommand{\\I}{\\htmlData{annotation_text=unit interval}{I}}\n\n\\newcommand{\\cl}[2]{\\htmlClass{__ktx-content-#1}{#2}}\n\n% linear algebra\n\n\\newcommand{\\vec}[2]{\\begin{bmatrix}#1\\\\#2\\end{bmatrix}}\n\\newcommand{\\pt}[2]{\\begin{pmatrix}#1\\\\#2\\end{pmatrix}}\n\n\\newcommand{\\ivec}[1]{\\left(#1\\right)}\n\\newcommand{\\ipt}[1]{\\<#1\\>}\n\n\\newcommand{\\matr}[4]{\\begin{bmatrix}#1&#2\\\\#3&#4\\end{bmatrix}}\n\\newcommand{\\Matr}[1]{\\htmlData{annotation_text=matrix of linear transformation $#1$}{[#1]}}\n\n\\newcommand{\\dist}[2]{d(#1, #2)}\n\\newcommand{\\Dist}[2]{\\htmlData{annotation_text=distance from $#1$ to $#2$}{\\dist{#1}{#2}}}\n\n\\newcommand{\\norm}[1]{\\|#1\\|}\n\\newcommand{\\Norm}[1]{\\htmlData{annotation_text=length of vector $#1$}{\\norm{#1}}}\n\n\\newcommand{\\Dir}[1]{\\htmlData{annotation_text=normalization of $#1$}{\\widehat{#1}}}\n\n\\newcommand{\\Rot}[1]{\\htmlData{annotation_text=rotation by $#1$ ccw around the origin}{R_{#1}}}\n\\newcommand{\\ARot}[3]{\\htmlData{annotation_text=rotation of point $#2$ around point $#3$ by $#1$ (counter-clockwise)}{R_{#1}(#2;#3)}}\n\n\\newcommand{\\Refl}[1]{\\htmlData{annotation_text=reflection across the line through the origin at angle $#1$}{F_{#1}}}\n\n% graphics\n\\newcommand{\\lerp}{\\operatorname{lerp}}\n\n\\newcommand{\\ClsdIntvl}{\\CIntvl}\n\\newcommand{\\CIntvl}[2]{\\htmlData{annotation_text=$\\{x\\mid{#1}\\le{x}\\le {#2}\\}$}{[#1,#2]}}\n\\newcommand{\\OIntvl}[2]{\\htmlData{annotation_text=$\\{x\\mid{#1}<{x}<{#2}\\}$}{[#1,#2]}}\n\\newcommand{\\LIntvl}[2]{\\htmlData{annotation_text=$\\{x\\mid{#1}\\le{x}<{#2}\\}$}{[#1,#2]}}\n\\newcommand{\\RIntvl}[2]{\\htmlData{annotation_text=$\\{x\\mid{#1}<{x}\\le{#2}\\}$}{[#1,#2]}}\n\n% spaces\n\\newcommand{\\AffR}[1]{\\htmlData{annotation_text=$#1$-dimensional real affine space}{\\cl{A}{\\A^{#1}}}}\n\\newcommand{\\VecR}[1]{\\htmlData{annotation_text=$#1$-dimensional real vector space}{\\cl{R}{\\R^{#1}}}}\n\\newcommand{\\S}[1]{\\htmlData{annotation_text=$#1$-dimensional unit sphere}{S^{#1}}}\n\n"
      }
    },
    "ownerId": "41786b7c-b873-4373-8ede-477bf85070a1",
    "publicationDate": "2024-06-15 23:40:16.340316 UTC",
    "slug": "gng",
    "title": "Geometry & Graphics",
    "type": "collection"
  },
  {
    "id": "567e4f9b-ea31-4eb0-9bd2-0d6e0784f9f8",
    "content": "<!-- #tab notes -->\nThe content so far has been rather abstract and philosophical. In this post, we're going to get our hands dirty and implement drag functionality on a popup. We'll apply ideas from the previous post on [points and vectors](./points-vectors) to figure out the math.\n\n\nHere's the basic code we'll be starting with.\n\n## Initial code\n\n```tsx\n// !interactive\nimport {useId} from \"react\";\n\nexport default function Demo() {\n  return (\n    <Popup title=\"Demo\">\n      Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod\n      tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim\n      veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea\n      commodo consequat. Duis aute irure dolor in reprehenderit in voluptate\n      velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat\n      cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id\n      est laborum.\n    </Popup>\n  );\n}\n\n/** Draggable popup */\nfunction Popup({\n  children,\n  title,\n}: {\n  children: React.ReactNode;\n  title: React.ReactNode;\n}) {\n  const headerId = useId();\n\n  return (\n    <aside\n      aria-labelledby={headerId}\n      className=\"w-[600px] max-w-[100vw] rounded-md border border-solid border-gray-200 shadow dark:border-gray-700\"\n      role=\"dialog\"\n    >\n      <header\n        className=\"select-none rounded-t-md bg-purple-600 px-2 py-1 text-white\"\n        id={headerId}\n      >\n        {title}\n      </header>\n      <div className=\"px-2 py-1\">{children}</div>\n    </aside>\n  );\n}\n```\n\nWe want to add the ability to drag this popup while holding onto the title bar.\n\nThis is a pretty simple component; the only interesting thing to point out is the use of the [dialog role](https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/Roles/dialog_role) and the [aria-labelledby](https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/Attributes/aria-labelledby) attribute, which are used for accessibility. These aren't relevant to the mathematical content of what we're doing, but I'm including them anyway because accessibility gets skipped over far too often.\n\n## A basic attempt\n\nBefore getting into the vector math, we'll start by wiring up the event listeners. I'm going to intentionally make several errors in order to point them out / warn you about them.\n\n### onPointerMove\n\nTo respond to mouse movement, we use the [`pointermove` event](https://developer.mozilla.org/en-US/docs/Web/API/Element/pointermove_event). Let's try adding that to the title bar:\n\n```tsx\n// !interactive\nimport {useId, useRef} from \"react\";\n\nexport default function Demo() {\n  return (\n    <Popup title=\"Demo\">\n      Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod\n      tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim\n      veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea\n      commodo consequat. Duis aute irure dolor in reprehenderit in voluptate\n      velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat\n      cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id\n      est laborum.\n    </Popup>\n  );\n}\n\n/** Draggable popup */\nfunction Popup({\n  children,\n  title,\n}: {\n  children: React.ReactNode;\n  title: React.ReactNode;\n}) {\n  const headerId = useId();\n\n  const onPointerMove: React.PointerEventHandler = (e) => {\n    console.log(e.clientX, e.clientY);\n  };\n\n  return (\n    <aside\n      aria-labelledby={headerId}\n      className=\"absolute w-[600px] max-w-[100vw] rounded-md border border-solid border-gray-200 shadow dark:border-gray-700\"\n      role=\"dialog\"\n    >\n      <header\n        className=\"select-none rounded-t-md bg-purple-600 px-2 py-1 text-white\"\n        id={headerId}\n        onPointerMove={onPointerMove}\n      >\n        {title}\n      </header>\n      <div className=\"px-2 py-1\">{children}</div>\n    </aside>\n  );\n}\n```\n\nOpen up your browser console to see the results. We're getting the $(x,y)$ coordinates of the pointer (cursor/finger/stylus), but only when we're over the title bar. When we try to drag the dialog into a new position, the pointer will come off of the title bar.\n\n### Body event handlers\n\nTo fix this, we'll add the `pointermove` event on `document.body`. This needs to be done imperatively, not through a React prop. We'll add a [`pointerdown`](https://developer.mozilla.org/en-US/docs/Web/API/Element/pointerdown_event) event to the title bar, and that will set up the necessary subscriptions. We can also get it to transate the dialog now.\n\n```tsx\n// !interactive\nimport {useId, useRef} from \"react\";\n\nexport default function Demo() {\n  return (\n    <Popup title=\"Demo\">\n      Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod\n      tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim\n      veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea\n      commodo consequat. Duis aute irure dolor in reprehenderit in voluptate\n      velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat\n      cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id\n      est laborum.\n    </Popup>\n  );\n}\n\n/** Draggable popup */\nfunction Popup({\n  children,\n  title,\n}: {\n  children: React.ReactNode;\n  title: React.ReactNode;\n}) {\n  const headerId = useId();\n\n  const ref = useRef<HTMLElement>(null);\n\n  const onPointerMove = (e: PointerEvent) => {\n    if (!ref.current) return;\n    ref.current.style.translate = `${e.clientX}px ${e.clientY}px`;\n  };\n\n  const onPointerDown: React.PointerEventHandler = (e) => {\n    document.body.addEventListener(\"pointermove\", onPointerMove);\n    document.body.addEventListener(\"pointerup\", onPointerUp);\n  };\n\n  const onPointerUp: React.PointerEventHandler = (e) => {\n    document.body.removeEventListener(\"pointermove\", onPointerMove);\n    document.body.removeEventListener(\"pointerup\", onPointerUp);\n  };\n\n  return (\n    <aside\n      aria-labelledby={headerId}\n      className=\"absolute w-[600px] max-w-[100vw] rounded-md border border-solid border-gray-200 shadow dark:border-gray-700\"\n      ref={ref}\n      role=\"dialog\"\n    >\n      <header\n        className=\"select-none rounded-t-md bg-purple-600 px-2 py-1 text-white\"\n        id={headerId}\n        onPointerDown={onPointerDown}\n        onPointerUp={onPointerUp}\n      >\n        {title}\n      </header>\n      <div className=\"px-2 py-1\">{children}</div>\n    </aside>\n  );\n}\n```\n\nIf you try this, you'll notice several issues. Take a minute to try diagnosing (and fixing) them yourself before looking at the solution.\n\n- the top-left corner of the dialog is following the pointer position, rather than the pointer staying in the same place as when you pressed down initially. We'll fix this in [the next section](#figuring-out-the-math).\n- the `onPointerUp` event doesn't seem to be working, and the dialog can only be \"pushed\" down and right.  \n  Hint 1: use the Inspector.  \n  Hint 2: this is unlikely to occur in a real-world application.  \n  \n   :::popup{trigger=Solution}\n     The issue is that the `<body>` tag doesn't have a width, since its only child is the absolutely positioned popup. We can fix this by wrapping the content in a tag with `min-h-screen` and `min-w-screen` applied. (Probably you should use the [new viewport units](https://dev.to/frehner/css-vh-dvh-lvh-svh-and-vw-units-27k4) here.)\n   :::\n\n- after fixing the above issue, notice that when you drag your pointer outside of the preview window and release it, you're still dragging when you move your pointer back into the preview window.\n   :::popup{trigger=Solution}\n     Lifting outside of the preview window means that `pointerup` never fires on `document.body`. This happens because the preview is in an iframe, but could also happen if the user drags their pointer out of the browser window or onto the browser chrome. We can fix it by adding a `pointerleave` event handler to `document.body`.\n   :::\n\nHere's the code with fixes for the latter two issues. Don't peek until you've tried diagnosing+fixing them yourself!\n\n```tsx\n// !interactive\nimport {useId, useRef} from \"react\";\n\nexport default function Demo() {\n  return (\n    <main className=\"min-w-screen min-h-screen\">\n      <Popup title=\"Demo\">\n        Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod\n        tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim\n        veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea\n        commodo consequat. Duis aute irure dolor in reprehenderit in voluptate\n        velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint\n        occaecat cupidatat non proident, sunt in culpa qui officia deserunt\n        mollit anim id est laborum.\n      </Popup>\n    </main>\n  );\n}\n\n/** Draggable popup */\nfunction Popup({\n  children,\n  title,\n}: {\n  children: React.ReactNode;\n  title: React.ReactNode;\n}) {\n  const headerId = useId();\n\n  const ref = useRef<HTMLElement>(null);\n\n  const onPointerMove = (e: PointerEvent) => {\n    if (!ref.current) return;\n    ref.current.style.translate = `${e.clientX}px ${e.clientY}px`;\n  };\n\n  const endDrag = () => {\n    document.body.removeEventListener(\"pointerleave\", endDrag);\n    document.body.removeEventListener(\"pointermove\", onPointerMove);\n    document.body.removeEventListener(\"pointerup\", endDrag);\n  };\n\n  const onPointerDown = () => {\n    document.body.addEventListener(\"pointerleave\", endDrag);\n    document.body.addEventListener(\"pointermove\", onPointerMove);\n    document.body.addEventListener(\"pointerup\", endDrag);\n  };\n\n  return (\n    <aside\n      aria-labelledby={headerId}\n      className=\"absolute w-[600px] max-w-[100vw] rounded-md border border-solid border-gray-200 shadow dark:border-gray-700\"\n      ref={ref}\n      role=\"dialog\"\n    >\n      <header\n        className=\"select-none rounded-t-md bg-purple-600 px-2 py-1 text-white\"\n        id={headerId}\n        onPointerDown={onPointerDown}\n      >\n        {title}\n      </header>\n      <div className=\"px-2 py-1\">{children}</div>\n    </aside>\n  );\n}\n```\n\n## Figuring out the math\n\nTo figure out how to position the popup correctly, let's introduce some notation. Let\n\n- $t\\in\\R$ denote the time since the `pointerdown` event\n- $p(t)\\in \\AffR 2$ denote the coordinates of the pointer at time $t$\n- $c(t)\\in\\AffR 2$ denote the desired coordinates of the top-left corner of the popup at time $t$\n\nTo keep the pointer \"in the same place\" on the title bar, the relationship we want is\n\\[ p(0) - c(0) = p(t) - c(t) \\quad\\text{for all }t \\]\nNote that $c(t)$ and $p(t)$ are **points**, but the common difference here is a **vector**.\n\nWhich of these do we know?\n\n- we get $p(t)$ from `e.clientX` and `e.clientY`. For $t=0$, `e` is the `pointerdown` event, for $t>0$ it's the `pointermove` event.\n\n- we can get $c(0)$ from [`getBoundingClientRect()`](https://developer.mozilla.org/en-US/docs/Web/API/Element/getBoundingClientRect) on the popup `ref`\n\n- what we need to calculate is $c(t)$ for $t>0$\n\nWe can rearrange the above formula to isolate what we want to calculate:\n\n\\[ c(t) = p(t) + \\underbrace{(c(0) - p(0))}_{\\mathtt{offset}} \\]\n\nHere's the final code:\n\n```tsx\n// !interactive\nimport {useId, useRef} from \"react\";\n\nexport default function Demo() {\n  return (\n    <main className=\"min-w-screen min-h-screen\">\n      <Popup title=\"Demo\">\n        Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod\n        tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim\n        veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea\n        commodo consequat. Duis aute irure dolor in reprehenderit in voluptate\n        velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint\n        occaecat cupidatat non proident, sunt in culpa qui officia deserunt\n        mollit anim id est laborum.\n      </Popup>\n    </main>\n  );\n}\n\n/** Draggable popup */\nfunction Popup({\n  children,\n  title,\n}: {\n  children: React.ReactNode;\n  title: React.ReactNode;\n}) {\n  const headerId = useId();\n\n  const ref = useRef<HTMLElement>(null);\n\n  const offset = useRef({x: 0, y: 0});\n\n  const onPointerMove = (e: PointerEvent) => {\n    if (!ref.current) return;\n    ref.current.style.translate = `${e.clientX + offset.current.x}px ${e.clientY + offset.current.y}px`;\n  };\n\n  const endDrag = () => {\n    document.body.removeEventListener(\"pointerleave\", endDrag);\n    document.body.removeEventListener(\"pointermove\", onPointerMove);\n    document.body.removeEventListener(\"pointerup\", endDrag);\n  };\n\n  const onPointerDown: React.PointerEventHandler = (e) => {\n    if (!ref.current) return;\n\n    // record offset\n    // [rect.x, rect.y] is what we called c(0) in the formulas\n    // [e.clientX, e.clientY] is what we called p(0) in the formulas\n    const rect = ref.current.getBoundingClientRect();\n    offset.current = {x: rect.x - e.clientX, y: rect.y - e.clientY};\n\n    // attach event handlers\n    document.body.addEventListener(\"pointerleave\", endDrag);\n    document.body.addEventListener(\"pointermove\", onPointerMove);\n    document.body.addEventListener(\"pointerup\", endDrag);\n  };\n\n  return (\n    <aside\n      aria-labelledby={headerId}\n      className=\"absolute w-[600px] max-w-[100vw] rounded-md border border-solid border-gray-200 shadow dark:border-gray-700\"\n      ref={ref}\n      role=\"dialog\"\n    >\n      <header\n        className=\"select-none rounded-t-md bg-purple-600 px-2 py-1 text-white\"\n        id={headerId}\n        onPointerDown={onPointerDown}\n      >\n        {title}\n      </header>\n      <div className=\"px-2 py-1\">{children}</div>\n    </aside>\n  );\n}\n```\n\n## Extracting Hooks\n\nNow that we have the functionality in place, let's refactor things a little bit to split out logic that's not specific to our app.\n\nFirst let's extract the logic of starting a drag operation on `pointerdown`, and ending it on `pointerup` or `pointerleave`. It's conceivable that a consumer will want to distinguish between the latter two events, so we'll make them separate.\n\n```ts\nimport {useCallback} from \"react\";\n\n/**\n * Provides generic drag functionality\n * @returns An object of event handlers to spread onto the target\n */\nfunction useDrag<T = Element>(opts: {\n  down?: React.PointerEventHandler<T>;\n  leave?: (e: PointerEvent) => unknown;\n  move: (e: PointerEvent) => unknown;\n  up?: (e: PointerEvent) => unknown;\n}) {\n  // pointer event handlers\n  const onPointerUp = useCallback(\n    (e: PointerEvent) => {\n      opts.up?.(e);\n      unsubscribe();\n    },\n    [opts.up],\n  );\n\n  const onPointerLeave = useCallback(\n    (e: PointerEvent) => {\n      opts.leave?.(e);\n      unsubscribe();\n    },\n    [opts.leave],\n  );\n\n  /** Remove event handlers from document.body */\n  const unsubscribe = useCallback(() => {\n    document.body.removeEventListener(\"pointerleave\", onPointerLeave);\n    document.body.removeEventListener(\"pointermove\", opts.move);\n    document.body.removeEventListener(\"pointerup\", onPointerUp);\n  }, [opts.move, onPointerLeave, onPointerUp]);\n\n  const onPointerDown: React.PointerEventHandler<T> = useCallback(\n    (e) => {\n      opts.down?.(e);\n\n      // attach event handlers\n      document.body.addEventListener(\"pointerleave\", onPointerLeave);\n      document.body.addEventListener(\"pointermove\", opts.move);\n      document.body.addEventListener(\"pointerup\", onPointerUp);\n    },\n    [opts.move, onPointerUp, onPointerLeave],\n  );\n\n  return {onPointerDown};\n}\n```\n\nNext, let's address the specific case of dragging an element. We can build on what we did above:\n\n```ts\n/** Provides functionality to drag an element */\nfunction useDragElement<TRoot extends HTMLElement, TAnchor extends Element>(): {\n  /** Events to spread onto the dragging \"anchor\" */\n  anchorEvents: {\n    onPointerDown: React.PointerEventHandler<TAnchor>;\n  };\n\n  /** Ref to attach to the object you wish to make draggable. */\n  ref: React.RefObject<TRoot>;\n} {\n  const ref = useRef<TRoot>(null);\n\n  const offset = useRef({x: 0, y: 0});\n\n  const anchorEvents = useDrag(\n    useMemo(\n      () => ({\n        down: (e: React.PointerEvent<TAnchor>) => {\n          if (!ref.current) return;\n\n          // set offset\n          const rect = ref.current.getBoundingClientRect();\n          offset.current = {x: rect.x - e.clientX, y: rect.y - e.clientY};\n        },\n        move: (e: PointerEvent) => {\n          if (!ref.current) return;\n          const x = e.clientX + offset.current.x;\n          const y = e.clientY + offset.current.y;\n          ref.current.style.translate = `${x}px ${y}px`;\n        },\n      }),\n      [],\n    ),\n  );\n\n  return {\n    anchorEvents,\n    ref,\n  };\n}\n```\n\nThe complete refactored version is at the GitHub link below.\n\n::embed[{epiplexis-content}/gng/01-coordinates/07-dragging/demo]{source aspect-ratio=1.5}\n\n## Remarks\n\nTo get a full-featured dialog component (accessibility, focus guard, etc.), I recommend the [Radix Dialog](https://www.radix-ui.com/primitives/docs/components/dialog) component. You can attach this behavior onto one of those.\n\nDid we really need the abstract math perspective to figure the formula for the translation? Not really, we'd have eventually gotten there by trial and error + drawing some pictures. But getting comfortable with manipulating these makes it easier to just sit down and derive the formula and feel confident in it. The \"type safety\" of the points-vs-vectors distinction can also rule out faulty guesses.\n\n<!-- #tab exercises -->\n\n1. Modify the code to prevent the user from dragging the popup offscreen. You will need [`window.innerWidth`](https://developer.mozilla.org/en-US/docs/Web/API/Window/innerWidth) and [`window.innerHeight`](https://developer.mozilla.org/en-US/docs/Web/API/Window/innerHeight).\n\n2. Add functionality to resize the popup. You can make drag handles like so:  \n   ```tsx\n   // !interactive\n    import {useId} from \"react\";\n   \n   export default function Demo() {\n     return (\n       <Popup title=\"Demo\">\n         Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod\n         tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim\n         veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea\n         commodo consequat. Duis aute irure dolor in reprehenderit in voluptate\n         velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat\n         cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id\n         est laborum.\n       </Popup>\n     );\n   }\n   \n   /** Draggable popup */\n   function Popup({\n     children,\n     title,\n   }: {\n     children: React.ReactNode;\n     title: React.ReactNode;\n   }) {\n     const headerId = useId();\n   \n     return (\n       <aside\n         aria-labelledby={headerId}\n         className=\"max-w-[100vw] w-[600px] absolute rounded-md border border-solid border-gray-200 shadow dark:border-gray-700\"\n         role=\"dialog\"\n       >\n         <header\n           className=\"select-none rounded-t-md bg-purple-600 px-2 py-1 text-white\"\n           id={headerId}\n         >\n           {title}\n         </header>\n         <div className=\"px-2 py-1\">{children}</div>\n         {/* drag handles */}\n         <div className=\"absolute bottom-0 left-0 h-2 w-full cursor-ns-resize\" />\n         <div className=\"absolute right-0 top-0 h-full w-2 cursor-ew-resize\" />\n       </aside>\n     );\n   }\n   ```\n",
    "description": "",
    "duration": null,
    "meta": {
      "math": {
        "macros": ""
      }
    },
    "ownerId": "41786b7c-b873-4373-8ede-477bf85070a1",
    "publicationDate": "2024-08-19 05:26:12.146533 UTC",
    "slug": "dragging",
    "title": "Drag functionality",
    "type": "article"
  },
  {
    "id": "3871a07c-a634-45b5-b564-aba7ae31d656",
    "content": "",
    "description": "",
    "duration": 280962,
    "meta": {},
    "ownerId": "41786b7c-b873-4373-8ede-477bf85070a1",
    "publicationDate": "2025-01-12 08:19:04.766 UTC",
    "slug": "",
    "title": "SIR test",
    "type": "recording"
  },
  {
    "id": "b66bfba4-9b5e-4092-914d-d149b280f9f0",
    "content": "",
    "description": "",
    "duration": 368674,
    "meta": {},
    "ownerId": "41786b7c-b873-4373-8ede-477bf85070a1",
    "publicationDate": "2025-01-16 19:04:33.163 UTC",
    "slug": "",
    "title": "SIR Python (no audio)",
    "type": "recording"
  },
  {
    "id": "8d49cb26-4c86-4667-944a-d9b18c1fd886",
    "content": "",
    "description": "",
    "duration": 589960,
    "meta": {
      "tracks": [
        {
          "kind": "captions",
          "srclang": "en"
        }
      ]
    },
    "ownerId": "41786b7c-b873-4373-8ede-477bf85070a1",
    "publicationDate": "2025-02-07 19:12:04.049 UTC",
    "slug": "",
    "title": "SIRPLOT",
    "type": "recording"
  },
  {
    "id": "bbf997e7-df65-4d03-8eb5-304fabff55a5",
    "content": "",
    "description": "",
    "duration": 460130,
    "meta": {},
    "ownerId": "41786b7c-b873-4373-8ede-477bf85070a1",
    "publicationDate": "2025-02-08 08:56:09.323 UTC",
    "slug": "",
    "title": "SEQUENCE",
    "type": "recording"
  },
  {
    "id": "94560ee1-a7b5-432f-9de0-3a137c500e5e",
    "content": "",
    "description": "",
    "duration": 6940,
    "meta": {},
    "ownerId": "4a4d8990-1de7-481e-be21-17d46c119e88",
    "publicationDate": "2025-02-08 12:49:50.536499 UTC",
    "slug": "",
    "title": "",
    "type": "recording"
  },
  {
    "id": "2d047bf3-7134-4f29-8dde-022274b43e13",
    "content": "",
    "description": "",
    "duration": 1256463,
    "meta": {},
    "ownerId": "41786b7c-b873-4373-8ede-477bf85070a1",
    "publicationDate": "2025-02-09 02:45:48.565 UTC",
    "slug": "",
    "title": "LENGTH (too long)",
    "type": "recording"
  },
  {
    "id": "a0ff0333-817a-4258-aeb3-97059b823fe8",
    "content": "",
    "description": "",
    "duration": 614006,
    "meta": {},
    "ownerId": "41786b7c-b873-4373-8ede-477bf85070a1",
    "publicationDate": "2025-02-09 05:44:52.733 UTC",
    "slug": "",
    "title": "LENGTH",
    "type": "recording"
  }
]

Ambiguous slug:

logs
[
  {
    "id": "9877232c-d6e3-46c1-a140-3be13685ae82",
    "content": "",
    "description": "",
    "duration": null,
    "meta": {},
    "ownerId": "41786b7c-b873-4373-8ede-477bf85070a1",
    "publicationDate": "2024-06-15 23:40:16.340316 UTC",
    "slug": "",
    "title": "Triangle inequality",
    "type": "article"
  },
  {
    "id": "22a7b232-f4d0-492f-8249-5f2f7bf0d9f7",
    "content": "\\[ f(t) = \\cos t + i\\sin t \\]\n\n\\[\\begin{align*}\n  \\frac d{dt}\\cos t &= -\\sin t\\\\[.5em]\n  \\frac d{dt}\\sin t &=  \\cos t\n\\end{align*}\\]\n\n\\[ f'(t) = ci f(t) \\]\nfor some constant $c>0$. In fact, we have $c=1$ since blah. Thus, $f(t)$ satisfies the **initial value problem**\n\\[\\begin{aligned}\n  f'(t) &= i f(t)\\\\\n   f(0) &= 1. \\]\n\\end{aligned}\\]\n\nWe know that the unique solution to the equation\n\\[\\begin{aligned}\n  f'(t) &= k f(t)\\\\\n   f(0) &= a. \\]\n\\end{aligned}\\]\nis\n\\[ f(t) = ae^{kt} \\]\n\n\\[ e^{it} = \\cos t + i \\sin t \\]\n\nThis is known as **Euler's formula**.\n\n### A note on definitions\nDepending on your definition of $e^x$, the above equation may or may not be meaningful. There's no problem with the right-hand side: we already know what $\\cos(t)$ and $\\sin(t)$ mean for $t\\in\\R$.\n\\[ \\exp(z) = \\sum_{n=0}^\\infty \\frac{z^n}{n!} \\]\n\nIt might be better to write\n\\[ \\exp(it) = \\cos t + i\\sin t \\]\n\n## The kernel\n\n\\[ e^{\\Twopi i} = 1 \\]\n\nMore specifically,\n\n\\[ e^{i\\theta_1} = e^{i\\theta_2} \\iff \\theta_1 - \\theta_2 \\in \\Twopi\\Z \\]\n\n(rant about abelian groups?)\n\n## Trigonometric identities\n\\[\\begin{align*}\n  \\cos(\\alpha+\\beta) + i\\sin(\\alpha+\\beta)\n    &= e^{i(\\alpha+\\beta)}\\\\\n    &= e^{i\\alpha} e^{i\\beta}\\\\\n    &= (\\cos\\alpha+i\\sin\\alpha)(\\cos\\beta+i\\sin\\beta)\\\\\n    &= (\\cos\\alpha\\cos\\beta - \\sin\\alpha\\sin\\beta)+i(\\sin\\alpha\\cos\\beta+\\cos\\alpha\\sin\\beta)\n\\end{align*}\\]\n\nSetting real and imaginary parts equal to each other, we get\n\n\\[\\begin{align*}\n  \\cos(\\alpha+\\beta) &= \\cos\\alpha\\cos\\beta - \\sin\\alpha\\sin\\beta\\\\\n  \\sin(\\alpha+\\beta) &= \\sin\\alpha\\cos\\beta + \\cos\\alpha\\sin\\beta\n\\end{align*}\\]\n\n<iframe src=\"https://www.desmos.com/calculator/vtoks21fah\"></iframe>",
    "description": "",
    "duration": null,
    "meta": {},
    "ownerId": "41786b7c-b873-4373-8ede-477bf85070a1",
    "publicationDate": "2024-06-15 23:40:16.340316 UTC",
    "slug": "euler",
    "title": "Euler's formula",
    "type": "article"
  },
  {
    "id": "e3772289-b7b0-4b9c-997f-0c1e448525da",
    "content": "",
    "description": "",
    "duration": null,
    "meta": {},
    "ownerId": "41786b7c-b873-4373-8ede-477bf85070a1",
    "publicationDate": "2024-06-15 23:40:16.340316 UTC",
    "slug": "trinequality",
    "title": "Triangle inequality",
    "type": "article"
  },
  {
    "id": "3a48eda2-c609-415b-abde-76be30a97ba3",
    "content": "Define oh no\n\nis it broken",
    "description": "",
    "duration": null,
    "meta": {},
    "ownerId": "41786b7c-b873-4373-8ede-477bf85070a1",
    "publicationDate": "2024-06-15 23:40:16.340316 UTC",
    "slug": "tan",
    "title": "tan and atan2",
    "type": "article"
  },
  {
    "id": "c486f03e-b8c0-44bd-b461-f6da8656e14c",
    "content": "",
    "description": "",
    "duration": null,
    "meta": {},
    "ownerId": "41786b7c-b873-4373-8ede-477bf85070a1",
    "publicationDate": "2024-06-15 23:40:16.340316 UTC",
    "slug": "complex",
    "title": "Complex numbers",
    "type": "article"
  },
  {
    "id": "04686363-c824-4cc8-a90c-8342bac06dd5",
    "content": "",
    "description": "",
    "duration": null,
    "meta": {},
    "ownerId": "41786b7c-b873-4373-8ede-477bf85070a1",
    "publicationDate": "2024-06-15 23:40:16.340316 UTC",
    "slug": "mandelbrot",
    "title": "Mandelbrot set",
    "type": "article"
  },
  {
    "id": "bced6fd2-30fd-4fa1-8db4-1b89d8bac593",
    "content": "",
    "description": "",
    "duration": null,
    "meta": {},
    "ownerId": "41786b7c-b873-4373-8ede-477bf85070a1",
    "publicationDate": "2024-06-15 23:40:16.340316 UTC",
    "slug": "reflections",
    "title": "Reflections",
    "type": "article"
  },
  {
    "id": "04e1b41e-8fdd-4fd3-a7b5-49433e5b6b02",
    "content": "In this post and [the next](./maps) we'll introduce the idea of *functions* or *maps* between spaces. This is where things start to get more interesting and dynamic. The sequel will dive into the theoretical ideas around functions; in this post, we'll focus more concretely on how to *graph* or *plot* them.\n\n## 2d graphing\n\nIf $f\\colon\\R\\to\\R$ is a function, its :dfn[graph] is the set\n\n\\[ \\{(x, f(x)) \\mid x \\in \\R \\} \\subset \\R^2. \\]\n\nThat is, we plot the input on the horizontal axis and the output on the vertical axis.\n\nA parametric plot involves _two_ functions $g,h\\colon\\R\\to\\R;$ in this case, we visualize these using the set\n\n\\[ \\{(g(t), h(t)) \\mid t\\in \\R\\} \\subset \\R^2. \\]\n\nNote that the graph of a function is a special case of parametric plotting via\n\n\\[ g(t) = t, \\quad h(t) = f(t). \\]\n\nHowever, on a general parametric plot, it's not possible to read off the input value $t$ which produced a given output value $(x,y).$\n\n### Desmos\n\n[Desmos](https://www.desmos.com/calculator) is the best 2d graphing calculator on the internet. Here's an example of explicit and parametric plotting in Desmos:\n\n<iframe class=\"w-full\" src=\"https://www.desmos.com/calculator/gshejpaijs\" height=\"500\"></iframe>\n\nIt's also possible to use Desmos programmatically. They provide an API that will embed the calculator directly into your webpage (not an iframe!)\n\n- [Desmos API docs](https://www.desmos.com/api/v1.7/docs/index.html#self-hosting)\n\n- in a TypeScript project, you can install [`@types/desmos`](https://www.npmjs.com/package/@types/desmos)\n\n- [`desmos-react`](https://github.com/ysulyma/desmos-react) provides a React wrapper around the Desmos APIs\n\nHere's an example of using `desmos-react` to embeds Desmos in a video:\n\n<iframe class=\"w-full\" src=\"https://liqvidjs.org/r/ex-desmos/\" allowfullscreen=\"\" style=\"aspect-ratio: 16 / 10;\"></iframe>\n\n[Source](https://github.com/ysulyma/ex-desmos)\n\n### SVG and Canvas\n\nSince this is a series about programming, we want to be able to plot things programmatically, without relying on GUI tools. There are two options for doing so: [SVG](https://developer.mozilla.org/en-US/docs/Web/SVG/Tutorial) and [`<canvas>`](https://developer.mozilla.org/en-US/docs/Web/API/Canvas_API). However, plotting functions directly using the APIs (rather than a library) is a bit manual, so I'll show how to do it after we cover linear interpolation (a few posts from now).\n\nAlso, for experimenting, using a GUI tool like Desmos is usually faster.\n\n## 3d graphing\n\nThere are two kinds of plotting we can do in 3d: curves and surfaces. Curves involve _three_ functions of _one_ variable:\n\n\\[\\begin{align*}\n  x &= f(t)\\\\\n  y &= g(t)\\\\\n  z &= h(t)\n\\end{align*}\\]\n\nSurfaces involve _three_ functions of _two_ variables:\n\n\\[\\begin{align*}\n  x &= f(u, v)\\\\\n  y &= g(u, v)\\\\\n  z &= h(u, v)\n\\end{align*}\\]\n\nIn 2d, a special kind of parametric curve was the graph of a single function. Similarly, if we have a _single_ function of _two_ variables $f(x, y),$ then we can visualize it using the parametric surface\n\n\\[\\begin{align*}\n  x &= u\\\\\n  y &= v\\\\\n  z &= f(u, v)\n\\end{align*}\\]\n\n### THREE.js\n\nIn this series, we'll use [THREE.js](https://threejs.org/docs/) for all our 3d examples. I'll also (usually) use it in conjunction with [React Three Fiber](https://docs.pmnd.rs/react-three-fiber/), which provides a nice declarative way to use THREE inside React.\n\nWe use [`TubeGeometry`](https://threejs.org/docs/#api/en/geometries/TubeGeometry) to plot curves, and [`ParametricGeometry`](https://threejs.org/docs/?q=parametric#examples/en/geometries/ParametricGeometry) to plot surfaces. Here's a demonstration of using THREE.js to plot the parametric curve\n\n\\[\n  \\vcenter{\n    \\begin{align*}\n      x &= 5\\cos(4\\pi t)\\\\\n      y &= 5\\sin(4\\pi t)\\\\\n      z &= -3 + 6t\n    \\end{align*}\n  }\\qquad 0 \\le t \\le 1\n\\]\n\nand the graph of the function\n\n\\[\n  z = \\cos(x)\\sin(y),\\qquad -2\\pi \\le x,\\, y\\le 2\\pi\n\\]\n\n::embed[{epiplexis-content}/gng/01-coordinates/03-plotting/three-plotting]{aspect-ratio=2.5 inline source appDir}\n\n(I'll explain in the next chapter how I came up with these formulas.)\n\n### WebGL / WebGPU\n\nTHREE.js is a friendly API over [WebGL](https://developer.mozilla.org/en-US/docs/Web/API/WebGL_API). There's also a fancy new thing called [WebGPU](https://developer.mozilla.org/en-US/docs/Web/API/WebGPU_API). It's probably worth getting familiar with using these technologies directly. If I ever get around to doing so, I'll talk about it in this series.\n\n### Grapher\n\nIf you're on OS X, it comes with a great piece of software called Grapher. It can do 2d and 3d graphing, as well as animations; it was hugely important for me when I was learning math growing up. Here's a tutorial video I recorded on how to use it:\n\n<iframe class=\"w-full\" src=\"https://www.youtube.com/embed/2zFUeiynYqc\" style=\"aspect-ratio: 16 / 10\" allowfullscreen></iframe>\n",
    "description": "",
    "duration": null,
    "meta": {
      "math": {
        "macros": ""
      }
    },
    "ownerId": "41786b7c-b873-4373-8ede-477bf85070a1",
    "publicationDate": "2024-06-15 23:40:16.340316 UTC",
    "slug": "plotting",
    "title": "Plotting",
    "type": "article"
  },
  {
    "id": "938e7233-5626-4ba3-9f29-4f322119d471",
    "content": "So far we've talked about representing data using ($n$-tuples of) numbers. In this post I want to take a closer look at how we do this, and distinguish between two different ways of describing spaces.\n\n## Example: the unit circle\n\nLet's start with the example of the unit circle (which we are calling $S^1$). This is defined to be the set of points in the plane which are at distance 1 from the origin $(0, 0).$ Using the Pythagorean theorem (to be discussed in [the next chapter](/gng/trig/pythagoras)), this translates to\n\n\\[ \\{(x, y)\\In\\R^2 \\mid \\red{x^2 + y^2 = 1}\\}. \\]\n\n\n<iframe class=\"w-full\" src=\"https://www.desmos.com/calculator/k9frdjmhuc\" height=\"450\"></iframe>\n\nFor example, $(1,0),\\,(0, -1)$, and $\\left(\\frac{\\sqrt2}2,\\frac{\\sqrt2}2\\right)$ are in the unit circle since\n\n\\[\\begin{align*}\n  1^2 + 0^2 &= 1\\\\\n  0^2 + (-1)^2 &= 1\\\\\n  \\left(\\tfrac{\\sqrt2}2\\right)^2 + \\left(\\tfrac{\\sqrt2}2\\right)^2\n    &= \\tfrac12 + \\tfrac12\\\\\n    &= 1\n\\end{align*}\\]\nand $(0.3, 0.7)$ is not since\n\\[\\begin{align*}\n  0.3^2 + 0.7^2 &= 0.09 + 0.49\\\\\n  &= 0.58\\\\\n  &\\ne 1.\n\\end{align*}\\]\n\nSo this description of the unit circle makes it easy to _check_ whether a given point $(x, y)$ is in $S^1$ or not. But it's not easy to _come up_ with examples of points on the circle. Let's start by picking a value for $x$, e.g. $x=0.3$. We can rearrange the equation for the circle as follows:\n\n\\[\\begin{align*}\n  x^2 + y^2 &= 1\\\\\n  y^2 &= 1 - x^2\\\\\n  y &= \\pm\\sqrt{1 - x^2}\n\\end{align*}\\]\n\nIn our case $x=0.3$, the possibilities for $y$ are $\\pm0.7$. In general, once we fix a value of $x$, we get either one or two options for $y$ (one option if $1-x^2=0$, i.e. when $x=\\pm1$.\n\nHowever, not every value of $x$ is possible, since we can't take the square root of a negative number. Let's solve for the constraint on $x:$\n\n\\[\\begin{align*}\n  1 - x^2 &\\ge 0\\\\\n  1 &\\ge x^2\\\\\n  1 &\\ge |x|\n\\end{align*}\\]\nwhich is equivalent to\n\\[ -1 \\le x \\le 1 .\\]\n\nIn other words, $x\\In[-1, 1].$\n\nWe now have two maps\n\n\\[ \\fplus ,\\, \\fminus \\colon [-1, 1] \\to S^1 \\subset \\R^2 \\]\n\ngiven by\n\n\\[\\begin{align*}\n  \\fplus(x) &\\blue{{}= \\left(x, \\phantom-\\sqrt{1 - x^2}\\right)}\\\\\n  \\fminus(x) &\\purple{{}= \\left(x, -\\sqrt{1 - x^2}\\right)}\n\\end{align*}\\]\n\nWith this description, it's easy to _produce_ examples of points on the unit circle: we just plug in any value of $x$ between $-1$ and $1.$ On the other hand, it's difficult to _check_ whether a given point, say $(0.71, 0.73),$ is on the unit circle: we'd need to reverse the above derivation.\n\n<iframe class=\"w-full\" src=\"https://www.desmos.com/calculator/eu5pxeb3yb\" height=\"500\"></iframe>\n\n## Implicit, parametric, and explicit descriptions\n\nLet's generalize what we saw in the above example. \n\n:::definition\nLet $X$ be a subspace of $\\R^n;$ in the example above, $n=2$ and $X=S^1.$\n\n- an :dfn[implicit] description of $X$ is a system of equations and inequalities whose solutions are exactly $X.$  \n\n  In the above example, this was $\\red{x^2 + y^2 = 1}.$\n\n- a :dfn[local parametrization] of $X$ is a subset $U\\subset\\R^d$ along with a map $f\\colon U\\to X.$  \n\n  In the above example, $d=1,$ $U=[-1, 1],$ and both $\\fplus$ and $\\fminus$ are local parametrizations.\n\n  The _local_ is there because a local parametrization may not see all of $X,$ e.g. $\\fplus$ only sees the top half of the circle, and $\\fminus$ only sees the bottom half.\n\n- a :dfn[parametric] description of $X$ is a collection of local parametrizations of $X$ which are \"_jointly_ surjective\" in the sense that every $x\\In X$ is in the image of _at least one_ local parametrization.\n\n  In the example above, $(0, -1)$ is not in the image of $\\fplus,$ but it is in the image of $\\fminus.$\n\n- an :dfn[explicit] description is when we can isolate one variable as a (single-valued) function of the others, such as  \n  \\[ z = -y + x \\]   \n  This is both a parametric equation _and_ an implicit equation: viewing $x$ and $y$ as parameters, we can plug in any value for them and then find the necessary value of $z;$ and we can easily check whether any given $(x,y,z)$ satisfies the equation.\n:::\n\n  Being able to find an explicit description of a space is rare, since it implies that if you fix all but one coordinate, there is at most one possibility for the last coordinate. This is not true for the circle, since e.g. there are two possibilities for $(0, \\mathord ?),$ namely $(0,1)$ and $(0,-1).$ However, it's always possible to find explicit descriptions _locally_:\n  \\[ y = \\sqrt{1-x^2} \\]\n  is an explicit description of the _top half_ of the circle, even though an explicit description can't exist for the _entire_ circle.\n\nWe can think about \"solving equations\" very generally as trying to convert between implicit and parametric descriptions of a space.\n\n<table>\n  <thead>\n    <tr>\n      <th></th>\n      <th>Check membership</th>\n      <th>Produce examples</th>\n    </tr>\n  </thead>\n  <tbody>\n    <tr>\n      <th>Parametric</th>\n      <td class=\"text-red-600\">✗</td>\n      <td class=\"text-green-600\">✓</td>\n    </tr>\n    <tr>\n      <th>Implicit</th>\n      <td class=\"text-green-600\">✓</td>\n      <td class=\"text-red-600\">✗</td>\n    </tr>\n    <tr>\n      <th>Explicit</th>\n      <td class=\"text-green-600\">✓</td>\n      <td class=\"text-green-600\">✓</td>\n    </tr>\n  </tbody>\n</table>\n\n:::remark\n  A given space will admit many different parametrizations, and we often need to convert between two different parametrizations. The more common way of parametrizing the unit circle, which we will discuss in the next chapter, is by **angles**. For _nearly_ all purposes, this is a more convenient parametrization than the one we found above.\n:::\n\n:::remark\n  There are typically some other assumptions that we impose on parametrizations.\n\n  - $f$ is supposed to be \"injective away from the boundary of $U$\". I don't want to give a precise definition of this; in the case of $U=[-1, 1],$ it means we'd allow $f(-1)=f(1),$ but we'd require that $f$ be [injective](./maps#terminology) when restricted to $(-1, 1).$\n  - $U$ is supposed to be \"full-dimensional\", i.e. \"$d$-dimensional\". Again, I don't want to make this precise here, but for example a finite set of points $\\{0,0.5,1\\}$ would not be an allowed subset of $\\R^1$.\n  \n  The first condition puts an upper bound on the value of $d\\colon$ for example, there are no injective maps $\\R^2 \\to S^1$ (this is maybe intuitively true, but very hard to prove). The maximum value of $d$ is called the :dfn[dimension] of $X.$ For example, the unit circle is considered 1-dimensional (even though it lives in 2-dimensional space).\n:::\n\n## Coordinates\n\nLet me give a slightly different perspective on implicit descriptions which is more symmetric with parametric descriptions.\n\nLet's think an object in motion, e.g. a cow hurtling through the air, and freeze at a particular moment in time. Let $S$ be the space of all possible situations like this. Given such a situation $s\\In S,$ there are various quantities we can measure:\n\n- the kinetic energy $E(s)$ of the object;\n- the mass $m(s)$ of the object;\n- the speed $v(s)$ of the object.\n\nIf we pick units of measurement, (say joules for energy, kilograms for mass, and meters per second for speed), then we can view these as three maps\n\\[ E,m,v\\colon S \\to \\R. \\]\n[Recall](./maps#maps-into-a-product) that three maps $S\\to\\R$ can equivalently be viewed as a _single_ map\n\\[ (E,m,v)\\colon S\\to\\R^3. \\]\nNot every point $(x,y,z)\\In\\R^3$ can be hit by this map: physics tells us that these quantities must satisfy the constraint\n\\[ E = \\frac12 mv^2 \\]\nso we will only hit points in\n\\[ \\{ (x,y,z) \\In \\R^3 \\mid x = \\tfrac12 yz^2 \\}. \\]\n\n:::definition\n  A :dfn[coordinate] on a space $S$ is a map $S\\to\\R.$\n  \n  A :dfn[coordinate system] is a collection of coordinates $x_1,\\dotsc,x_n\\colon S\\to \\R$ such that the induced map\n  \\[ (x_1,\\dotsc,x_n)\\colon S\\to \\R^n \\]\n  is injective.\n:::\n\nIn many cases, it is difficult to find a \"global\" coordinate system, but we may be able to find a _local_ coordinate system\n\\[ (x_1, \\dotsc, x_n) \\colon U \\to \\R^n \\]\nwhere $U\\subset S$ is a subset of $S$ (similar to local parametrizations, above).\n\nThe upshot of this discussion is that we can view parametrizations of $X$ as maps $\\R^n\\to X,$ and coordinate systems on $X$ as maps $X\\to\\R^n.$ This also applies to local parametrizations/coordinate systems if we allow a subspace $U\\subset X$ in place of the entire $X.$\n\n## Marching squares / cubes\n\nWe won't be able to solve every system of equations algebraically---in fact, it's extremely rare that we can. So how can we visualize spaces that are given to us implicitly?\n\nWe take advantage of the fact that it's easy to _test_ whether a given point belongs to an implicitly defined subspace. Let's take the example\n\\[ 2y(y^{2}-3x^{2})(1-z^{2})+(x^{2}+y^{2})^{2}-(9z^{2}-1)(1-z^{2})=0 \\]\n(I just took this example from Wikipedia). If we plug in the point $(0.5,0.9,0.9),$ the left-hand side works out to $\\approx-0.051.$ That means this point is _not_ in $S$. But $-0.051$ is _close_ to $0$, so there's probably a point _near_ $(0.5,0.9,0.9)$ which _is_ in $S.$\n\nTherefore, we can try to graph an implicit equation as follows. We'll restrict our attention to some box, like the cube $[-1,1]^3$; maybe we know ahead of time that our space is contained in this box, or maybe it's not and we'll only be graphing part of it. We can subdivide this box, take a bunch of sample points from it, and plug them into our equation. Our sample points will almost certainly not satisfy the equation, but we can use how close/far they are from satisfying the equation to get a good idea of what our shape must look like.\n\nThe :dfn[marching squares] / :dfn[marching cubes] algorithms are sophisticated implementations of this basic idea. They let us graph implicitly defined shapes _without_ finding a parametrization, and are used internally by tools like [Desmos and Grapher](./plotting). We need to cover a bit more math in order to fully understand how these algorithms work, but I can give you source code right now:\n\n::embed[{epiplexis-content}/gng/01-coordinates/05-params-coords/implicit]{appDir aspect-ratio=1.5 inline source}\n",
    "description": "",
    "duration": null,
    "meta": {
      "math": {
        "macros": "\\newcommand{\\fplus}{\\blue{f_+}}\n\\newcommand{\\fminus}{\\purple{f_-}}"
      }
    },
    "ownerId": "41786b7c-b873-4373-8ede-477bf85070a1",
    "publicationDate": "2024-06-15 23:40:16.340316 UTC",
    "slug": "params-coords",
    "title": "Parameters & Coordinates",
    "type": "article"
  },
  {
    "id": "6a4ab0e5-92e6-4921-9520-d00e20c2cb3d",
    "content": "<iframe allow=\"fullscreen\" class=\"w-full\" src=\"https://epiplexis.xyz/a/8xw/lesson/\" style=\"aspect-ratio: 8/5;\"></iframe>\n\nTODO input article",
    "description": "",
    "duration": null,
    "meta": {
      "math": {
        "macros": ""
      }
    },
    "ownerId": "41786b7c-b873-4373-8ede-477bf85070a1",
    "publicationDate": "2024-06-15 23:40:16.340316 UTC",
    "slug": "rotations",
    "title": "Rotations",
    "type": "article"
  },
  {
    "id": "9d312ac2-d367-49c2-be34-c931e1db8806",
    "content": "Previously, we learned to calculate the length of vectors in $\\VecR n$, and thus the distance between *points* in $\\AffR n$. It's often useful to express a vector in terms of its __length__ and its _direction_.\n\nLet's start by defining direction.\n\n:::definition\nA vector $u\\In\\VecR n$ is said to be a :dfn[unit vector] if $\\Norm u=1$. A unit vector is also called a :dfn[direction].\n:::\n\nIf $v\\In\\VecR n$ is any _nonzero_ vector, its _direction_ is\n\n\\[ \\Dir v \\Defeq \\frac v{\\Norm v} \\]\n\nThis is also called the :dfn[normalization] of $v$. By definition, we have\n\n\\[ v = \\Norm v \\Dir v, \\]\n\nwhich expresses $v$ as its direction times its length. The $0$ vector has no direction.\n\n:::example\n  \\[ v = \\begin{bmatrix*}[r]-1\\\\2\\\\2\\\\0\\end{bmatrix*} \\]\n  :::solution\n  The length of $v$ is\n  \\[\\begin{aligned}\n  \\Norm v &= \\sqrt{(-1)^2 + 2^2 + 2^2 + 0^2}\\\\\n  &= \\sqrt9\\\\\n  &= 3\n  \\end{aligned}\\]\n  Thus\n  \\[ \\Dir v = \\begin{bmatrix*}[r]-1/3\\\\2/3\\\\2/3\\\\0\\end{bmatrix*} \\]\n:::\n\n## Spheres\n\nWe can now give a formal definition of one of the most important spaces in geometry: the $n$-sphere. This is defined to be the set of unit vectors in $\\VecR{n+1}$:\n\n\\[\\begin{aligned}\n  \\S n\n    &\\Defeq \\{v\\In\\VecR{n+1} \\mid \\Norm v = 1\\}\\\\\n    &= \\left\\{\\ivec{x_0,\\dotsc,x_n}\\In\\VecR{n+1} \\mid \\sqrt{\\sum_{i=0}^n x_i^2} = 1\\right\\}\n\\end{aligned}\\]\n\nSince $1^2 = 1$, this is equivalent to\n\n\\[ \\S n = \\left\\{\\ivec{x_0,\\dotsc,x_n} \\In \\VecR{n+1} \\mid \\sum_{i=0}^n x_i^2 = 1\\right\\}\\]\n\nNote the shift in indexing: $\\S1\\subset\\VecR 2$ is the usual unit circle in 2d, while $\\S2\\subset\\VecR3$ is the usual unit sphere in 3d.\n\nIt's worth looking at the edge case\n\\[\\begin{aligned}\n  \\S 0 &= \\{v\\In\\VecR1 \\mid \\Norm v = 1\\}\\\\\n      &= \\{\\pm1\\} \\subset \\R\n\\end{aligned}\\]\n\nThat is, the $0$-sphere consists of exactly two points! While this may seem strange, it fits nicely into a pattern about spheres in general:\n\n- every \"slice\" or \"cross-section\" of $\\S2$ is a $1$-sphere, except for the \"north and south poles\" $\\ivec{0,0,\\pm1}$.\n\n  <iframe class=\"w-full mx-auto\" src=\"https://www.desmos.com/3d/24d3d54b26?embed\" height=\"500\"></iframe>\n\n- every \"slice\" or \"cross-section\" of $\\S1$ is a $0$-sphere, except for the \"north and south poles\" $\\ivec{0,\\pm1}$;\n\n  <iframe class=\"w-full mx-auto\" src=\"https://www.desmos.com/calculator/baghu7bqdv?embed\" height=\"500\"></iframe>\n\nLet's prove this in general! This is a nice example of how we can use mathematical formalism to prove statements in $n$ dimensions based on our intuition in $\\le 3$ dimensions.\n\n:::proposition\n  Consider the cross section\n  \\[ S^n_t \\Defeq \\{\\ivec{x_0,\\dotsc,x_n}\\In S^n \\mid x_n = t \\} \\]\n  Then $S^n_t$ consists of a single point when $t=\\pm1$, and is isomorphic to $S^{n-1}$ when $|t|<1$.\n  \n  :::proof\n  \n  By definition,\n  \\[ S^n_t = \\{\\ivec{x_0,\\dotsc,x_{n-1},t} \\In \\VecR{n+1} \\mid \\sum_{i=0}^{n-1} x_i^2 + t^2 = 1\\} \\]\n  Let $v=\\ivec{x_0,\\dotsc,x_{n-1}} \\In \\VecR n$. We can rearrange the above condition to\n  \\[\\begin{aligned}\n    \\sum_{i=0}^{n-1} x_i^2 &= 1-t^2\\\\\n    \\sqrt{\\sum_{i=0}^{n-1} x_i^2} &= \\sqrt{1-t^2}\\\\\n    \\Norm v &= \\sqrt{1-t^2}\n  \\end{aligned}\\]\n  When $t=\\pm1$, this becomes $\\Norm v=0$, which implies $v=0$. This means that $S^n_t$ consists of the single point\n  \\[ \\ivec{0,\\dotsc,0,t}. \\]\n  When $|t|<1$, we have that $S^n_t$ is isomorphic to the sphere of radius $\\sqrt{1-t^2}$ in $\\VecR n$.\n:::\n\n## Parametrization\n\nWe can use the defining equation of $\\S n$ to find a parametrization of it. Let's start with the case of $\\S1$. Its defining equation is\n\n\\[ x^2 + y^2 = 1 \\]\n\nLet's rearrange this to solve for $y$ in terms of $x$:\n\n\\[\\begin{aligned}\n  x^2 + y^2 &= 1\\\\\n  y^2 &= 1 - x^2\\\\\n  y^2 &= \\pm\\sqrt{1 - x^2}\n\\end{aligned}\\]\n\nSo we can take $x=t$ as our parameter variable. We also need to find the domain of $t$ (equivalently $x$). Remember that we can only take square roots of non-negative numbers. So we need to have\n\n\\[\\begin{aligned}\n  0 &\\le 1-x^2\\\\\n  x^2 &\\le 1\\\\\n  |x| &\\le 1\n\\end{aligned}\\]\nor equivalently\n\\[ -1 \\le x \\le 1. \\]\n\nLet's try this in Desmos:\n<iframe class=\"w-full mx-auto mt-2 mb-4\" src=\"https://www.desmos.com/calculator/km7gkuq0ra?embed\" height=\"500\"></iframe>\n\n<iframe class=\"w-full mx-auto my-2\" src=\"https://www.desmos.com/3d/687d619b00?embed\" height=\"500\"></iframe>\n",
    "description": "",
    "duration": null,
    "meta": {
      "math": {
        "macros": ""
      }
    },
    "ownerId": "41786b7c-b873-4373-8ede-477bf85070a1",
    "publicationDate": "2024-06-15 23:40:16.340316 UTC",
    "slug": "unit-vectors",
    "title": "Unit vectors",
    "type": "article"
  },
  {
    "id": "e644f2c2-617f-4bd0-87b2-98e16a467c6d",
    "content": "## Distance\n\n::unit[pythagoras]\n\n::unit[unit-vectors]\n\n::unit[arclength]\n\n## Trig functions\n::unit[cos-sin]\n\n::unit[rotations]\n\n::unit[2x2-matrices]",
    "description": "",
    "duration": null,
    "meta": {
      "math": {
        "macros": ""
      }
    },
    "ownerId": "41786b7c-b873-4373-8ede-477bf85070a1",
    "publicationDate": "2024-06-15 23:40:16.340316 UTC",
    "slug": "trig",
    "title": "Trigonometry",
    "type": "collection"
  },
  {
    "id": "3ff98f24-6b94-4fef-9cf4-1ce3be1993ba",
    "content": "The Pythagorean theorem allowed us to calculate the length of straight line segments. In this post, we'll see how to extend this to calculate the length of _curved_ paths.\n\nLet's consider this curved path:\n\n::embed[{epiplexis-content}/gng/02-trigonometry/03-arclength/curve]{class=my-4 inline width=80%}\n\nWe can sample points along this curve and connect them by line segments:\n\n::embed[{epiplexis-content}/gng/02-trigonometry/03-arclength/approx]{class=my-4 inline source}\n\nThe result is a \"piecewise linear\" curve, shown in red. Since each piece of this is a line segment, we can calculate its length by applying the Pythagorean theorem to each segment and summing the results.\n\nAs we increase the density of the sample points, the piecewise linear curve becomes a better and better approximation of the original curve, and is length becomes a better and better approximation of the length of the original curve.\n\nWe can do the same thing in three dimensions:\n\n::embed[{epiplexis-content}/gng/02-trigonometry/03-arclength/3d]{aspect-ratio=2 class=my-4 inline source}\n\nThere are several delicate questions raised by this procedure.\n\n- Are we calculating the \"true\" answer, or just approximations to it?\n\n- If we sample points differently, will we get a different answer?\n\n- If we use a different [parametrization](/gng/cg/params-coords) of the same curve, does the answer change?\n\nThe first point gets at the heart of what \"real numbers\" actually are. Think about how we use numbers in practice: we might only care about the value within $0.01$. If the values produced by the algorithm are guaranteed to stay within that error tolerance once the number of steps is big enough, we can use any of the values beyond that point as our answer.\n\nA thorough answer to these questions involves **limits**, which we'll discuss in Chapter 5.\n\n<!-- define this in earlier unit I guess -->\n\n## Arclength parametrization\n\nRecall that a _curve_ $C$ in $\\AffR n$ is the image of _some_ map\n\n\\[ f\\colon \\CIntvl ab \\to \\AffR n \\]\n\nA choice of such an $f$ is called a _parametrization_ of the curve $C$. For example, we can pre-compose $f$ with an easing function to get many other parametrizations.\n\nA curve has lots and lots of different parametrizations; which one is best depends on the situation at hand and the nature of the curve. However, every curve has a _canonical_ parametrization, called the :dfn[arclength] parametrization, and this is usually the best option. The definition is as follows:\n\n:::definition\n  Let $C$ be an oriented curve from $P$ to $Q$ in $\\AffR n$. Suppose the arclength of $C$ is $s$. The :dfn[arclength parametrization] of $C$ is the function\n  \\[ f\\colon \\CIntvl 0s \\to \\AffR n \\]\n  such that the image of $f$ is $C$, and the arclength of the restriction $\\Restrict{f}{[0;t]}$ is $t$.\n:::\n\n:::example\n  Find the arclength parametrization of the line segment from $\\ipt{1,1}$ to $\\ipt{2,3}$ in $\\AffR 2$.\n  \n  :::solution\n  Let's start by finding the arclength. Since this is a straight line segment, the length is\n  \\[\\begin{align*}\n    \\|\\ipt{2,3} - \\ipt{1,1}\\|\n      &= \\|\\ivec{1, 2}\\|\\\\\n      &= \\sqrt{1^2 + 2^2}\\\\\n      &= \\sqrt5\n  \\end{align*}\\]\n  So the arclength parametrization is going to be parametrized on $\\CIntvl 0{\\sqrt5}$. Let's start with the parametrization given by linear interpolation,\n  \\[\\begin{align*}\n    f(t)\n      &= \\ipt{1, 1} + t(1, 2) & t&\\in\\CIntvl01\\\\\n      &= \\ipt{1+t,1+2t}\n  \\end{align*}\\]\n  To reparametrize this to $\\CIntvl0{\\sqrt5}$, we pre-compose with the map\n  \\[\\begin{align*}\n    g\\colon\\CIntvl0{\\sqrt5} &\\xrightarrow\\sim \\CIntvl01\\\\\n    g(t) &= \\frac t{\\sqrt5}\n  \\end{align*}\\]\n  The final arclength parametrization is therefore\n  \\[\\begin{align*}\n    s(t)\n      &= \\ipt{1, 1} + \\frac t{\\sqrt5}\\ivec{1,2} &t&\\in\\CIntvl0{\\sqrt5}\\\\\n      &= \\ipt{1+\\frac t{\\sqrt5}, 1+\\frac{2t}{\\sqrt5}}\n  \\end{align*}\\]\n:::\n\nLater, we will learn to find the arclength parametrization of more complicated curves; however, it is usually not possible to find an exact formula. It is doable by computer, however. As the above example shows, even in cases when we can find an exact formula for the arclength parametrization, it is often ugly (when written out in full).\n\n## APIs\n\n- [`getTotalLength()`](https://developer.mozilla.org/en-US/docs/Web/API/SVGGeometryElement/getTotalLength)\n- [`getPointAtLength()`](https://developer.mozilla.org/en-US/docs/Web/API/SVGGeometryElement/getPointAtLength)\n\n## Exercises\n\n1. In [Parameters and coordinates](/gng/cg/params-coords#example-the-unit-circle), we found a parametrization of the unit circle given by\n\n\\[\n  f_+(x) = \\ivec{x,\\sqrt{1 - x^2}},\\qquad\n  f_-(x) = \\ivec{x,-\\sqrt{1 - x^2}}\n\\]\n\nUsing this parametrization, write code to calculate (approximate) the arclength of the unit circle.\n\n```js\n// !interactive\n/** Parametrization of the top half of the unit circle. */\nconst unitSemiCircle = (t) => [t, Math.sqrt(1 - t ** 2)];\n\n/**\n * Compute the arclength of a parametrized curve.\n * @param f Parametrization of the curve\n * @param a Starting point\n * @param b Ending point\n * @param samples Number of samples\n */\nfunction arclength(f, a, b, samples) {\n  let sum = 0;\n  const mesh = (b - a) / samples;\n  for (let i = 0; i < samples; ++i) {\n    const ti = a + i * mesh;\n    const tNext = ti + mesh;\n    const [x, y] = f(ti);\n    const [xNext, yNext] = f(tNext);\n    sum += Math.hypot(xNext - x, yNext - y);\n  }\n  return sum;\n}\n\n// since it is a bit messy to combine the parametrizations of the top\n// and bottom halves of the unit circle into a single parametrization,\n// we will calculate the arclength of just the top half and multiply\n// that by 2\nconsole.log(2 * arclength(unitSemiCircle, -1, 1, 10_000));\n```\n",
    "description": "",
    "duration": null,
    "meta": {
      "math": {
        "macros": ""
      }
    },
    "ownerId": "41786b7c-b873-4373-8ede-477bf85070a1",
    "publicationDate": "2024-06-15 23:40:16.340316 UTC",
    "slug": "arclength",
    "title": "Arclength",
    "type": "article"
  },
  {
    "id": "54d3cfd7-e370-43ba-a0c4-201922ec154b",
    "content": "::unit[spaces]\n\n::unit[products]\n\n::unit[plotting]\n\n::unit[maps]\n\n::unit[params-coords]\n\n::unit[points-vectors]\n\n::unit[dragging]",
    "description": "",
    "duration": null,
    "meta": {
      "math": {
        "macros": ""
      }
    },
    "ownerId": "41786b7c-b873-4373-8ede-477bf85070a1",
    "publicationDate": "2024-06-15 23:40:16.340316 UTC",
    "slug": "cg",
    "title": "Coordinate geometry",
    "type": "collection"
  },
  {
    "id": "4b5cebea-f831-4e18-92ab-b57bea11e359",
    "content": "<!-- #tab notes -->\n\n:::yell\n  $\\cos$ and $\\sin$ are what you use when you want to draw a circle, or animate something moving in a circle.\n:::\n\nIn the post on [unit vectors](./unit-vectors), we defined the unit $n$-sphere and found a parametrization of it. In the [previous post](./arclength), we encountered the **arclength parametrization**, which for most purposes is more convenient than other parametrizations. In this post, we discuss the arclength parametrization of the unit circle $\\cl{S}{S^1}$, which is given by the $\\cos$ and $\\sin$ functions. This will be useful for drawing things along a circle or animating something that's rotating.\n\n## Radians\n\nWe need to start by naming the length of the unit circle.\n\n:::definition\n  We write $\\Twopi$ (pronounced either \"circle\", \"var-pi\", or \"two-pi\") for the arclength, or :dfn[circumference], of the unit circle\n  \\[ \\cl{S}{S^1} \\Defeq \\{(x, y) \\in \\VecR2 \\mid x^2 + y^2 = 1 \\}. \\]\n  In the [exercises](./arclength#exercises) of the previous unit, you calculated that $\\Twopi\\approx6.28\\dotsc$\n:::\n\nBy scaling, it follows that the circumference of a circle of radius $r$ is given by $\\Twopi r$. For example, the circumference of a circle of radius $4$ is $4\\Twopi\\approx25.13\\dots$. Equivalently, we could define $\\Twopi$ as the ratio of _any_ circle's circumference to its radius.\n\n:::remark\n  You may be more used to the constant $\\pi=\\Twopi/2\\approx3.14\\dots$, which is the ratio of a circle's circumference to its **diameter** (twice the radius). It turns out the ancient Greeks made a mistake in defining $\\pi$: while diameter is relevant in real-life situations, mathematically it's much more convenient to index circles by their radius rather than their diameter.\n  \n  This is not something to get too worked up about, however: although $\\Twopi$ is an important number, numbers are not that important in mathematics.\n  \n  Many sources use the letter $\\tau$ instead of $\\varpi$. This is patently absurd: on top of having completely the wrong vibes to be a circle constant, $\\tau$ is a B-tier Greek letter while $\\Twopi$ is an S-tier constant.\n:::\n\n## cos and sin\n\n:::definition\n  We define the functions $\\cos$ and $\\sin$ such that\n  \\[ \\ivec{\\cos\\theta,\\, \\sin\\theta}, \\qquad \\theta\\in \\ClsdIntvl0{\\twopi} \\]\n  is the arclength parametrization of the unit circle $\\cl{S}{S^1}$, starting at the point $\\ivec{1,0}$ and traveling counterclockwise. Equivalently, $\\ivec{\\cos\\theta,\\sin\\theta}$ is the $\\ivec{x,y}$-coordinates of the point at angle $\\theta$ from the origin.\n:::\n\nHere's a graph to experiment with that.\n\n<iframe class=\"w-full my-4\" height=\"500\" src=\"https://www.desmos.com/calculator/9v62whmuxi\"></iframe>\n\nThis completely defines $\\cos$ and $\\sin$, but doesn't tell us how to compute them. However, in just a few posts we'll derive an algorithm to compute these.\n\nYou may be used to a definition of $\\cos$ and $\\sin$ in terms of ratios of right-angle triangles; I'll review that interpretation [below](#triangle-interpretation). That interpretation is often useful, but it doesn't work for angles larger than $90^\\circ$.\n\n## Animation\n\nLet's say more about animation. So far, $\\cos$ and $\\sin$ tell us how to parametrize the unit circle, i.e. the circle of radius $1$ centered at the origin $\\O=(0,0)$. What about other circles?\n\nLet's do this in steps. First, let\n\\[ \\cl S{S^1}(r) = \\{v\\in\\VecR2 \\mathrel: \\|v\\| = r \\} \\]\nbe the circle of radius $r$ centered at the origin. We have\n\\[\\begin{align*}\n  \\cl S{S^1}(r)\n    &\\phantom:= r \\cl S{S^1}\\\\\n    &\\Defeq \\{rv \\mid v\\in \\cl S{S^1}\\}\n\\end{align*}\\]\nso can parametrize this by\n\\[ r\\ivec{\\cos t,\\sin t} = \\ivec{r\\cos t,r\\sin t}, \\qquad t\\in\\CIntvl0\\twopi. \\]\n\nNext, let's consider circles centered at other points. For a point $P\\in\\AffR2$ and a radius $r>0$, let\n\\[ \\cl S{S^1}(P,r) \\Defeq \\{Q \\in \\AffR2 \\colon \\|P-Q\\| = r \\} \\]\nbe the circle of radius $r$ centered at $P$. Note that $\\cl S{S^1}(r)$ lives in the _vector_ space $\\VecR2$, while $\\cl S{S^1}(P,r)$ lives in the _affine_ space $\\AffR2$; recall that \"the origin\" is a feature of _vector_ space. We can get $\\cl S{S^1}(P, r)$ by **translating** $\\cl S{S^1}(r)$ to the point $P$: in other words,\n\\[\\begin{align*}\n  \\cl S{S^1}(P, r)\n    &\\phantom:= P + \\cl S{S^1}(r)\\\\\n    &\\Defeq \\{P + v \\mid v \\in \\cl S{S^1}(r) \\}\n\\end{align*}\\]\nTherefore, a parametrization of $\\cl S{S^1}(P, r)$ is given by\n\\[ P+r\\ivec{\\cos t,\\sin t} = \\ipt{\\cl{p}{p_1}+r\\cos t,\\cl{p}{p_2}+r\\sin t}, \\qquad t\\in\\CIntvl0\\twopi, \\]\nwhere $P=\\ipt{\\cl{p}{p_1},\\cl{p}{p_2}}$.\n\nThat does everything we need if we want to draw a circle (or a part of a circle). Often though, we want to **animate** something moving in a circle. This means we need to further take into account its **speed** (or **angular velocity**) and its **starting position**.\n\nBy default, $(\\cos t,\\sin t)$ starts at $(1,0)$ and goes around the circle one every $\\Twopi$ units of time, going counterclockwise. To have it start at a different angle $\\cl{θ}{\\theta_0}$, we just add that on to $t$:\n\n\\[ \\ivec{\\cos(\\cl{θ}{\\theta_0} + t), \\sin(\\cl{θ}{\\theta_0} + t)} \\]\n\nTo change the speed, we multiply $t$ by a constant. For example, if $t$ is measured in seconds and we want to go around the circle once every two seconds, we'd use\n\n\\[ \\ivec{\\cos\\left(\\cl{θ}{\\theta_0}+\\frac{\\Twopi t}2\\right), \\sin\\left(\\cl{θ}{\\theta_0}+\\frac{\\Twopi t}2\\right)} \\]\n\nsince going around the circle once every two seconds is the same as going halfway around the circle every second. We can also scale by a negative number to go clockwise instead of counter-clockwise.\n\nTo summarize:\n\n:::proposition\n  The parametrization of a particle travelling:\n  - on a circle of radius $r$\n  - centered at the point $P=\\ipt{\\cl{p}{p_1},\\cl{p}{p_2}}$\n  - starting from angle $\\cl{θ}{\\theta_0}$\n  - making $k$ (counter-clockwise) rotations per unit of time $t$\n  \n  is given by\n  \\[\n    P + r\\ivec{\\cos(\\cl{θ}{\\theta_0}+\\Twopi kt), \\sin(\\cl{θ}{\\theta_0}+{\\Twopi}kt)}\n  \\]\n  which is the same as\n  \\[\n    \\ipt{\\cl{p}{p_1}+r\\cos(\\cl{θ}{\\theta_0}+\\Twopi kt), \\cl{p}{p_2}+r\\sin(\\cl{θ}{\\theta_0}+\\Twopi kt)}.\n  \\]\n:::\n\nHere's some code to try that out:\n\n```tsx\n// !interactive\nimport { useEffect, useRef } from \"react\";\n\n/** Point in 2-dimensional (affine) space */\ntype Pt2 = [number, number];\n\ntype Circle = {\n  /** Measured in [0, 100] x [0, 100] and mapped onto the actual screen later */\n  center: Pt2;\n  radius: number;\n};\n\nconst SECONDS = 1000,\n  MINUTES = 60 * SECONDS;\n\nconst CIRCLE = 2 * Math.PI;\n\n// scene setup\nexport default function Graph() {\n  const items: MovingProps[] = [\n    {\n      children: \"👻\",\n      circle: {\n        center: [50, 50],\n        radius: 25,\n      },\n      rpm: 45,\n    },\n    {\n      children: \"😈\",\n      circle: {\n        center: [25, 25],\n        radius: 20,\n      },\n      // negative to go clockwise\n      rpm: -30,\n    },\n    {\n      children: \"😍\",\n      circle: {\n        center: [75, 40],\n        radius: 10,\n      },\n      rpm: 15,\n    },\n    {\n      children: \"😡\",\n      circle: {\n        center: [30, 60],\n        radius: 20,\n      },\n      rpm: -60,\n    },\n    {\n      children: \"😡\",\n      circle: {\n        center: [70, 60],\n        radius: 20,\n      },\n      // so it will collide with the other one\n      initialAngle: CIRCLE / 2,\n      rpm: 60,\n    },\n  ];\n\n  return (\n    <main>\n      {items.map((props) => (\n        <Moving key={JSON.stringify(props)} {...props} />\n      ))}\n    </main>\n  );\n}\n\n// moving divs\ninterface MovingProps {\n  children: React.ReactNode;\n  circle: Circle;\n\n  /**\n   * Initial angle.\n   * @default 0\n   */\n  initialAngle?: number;\n  \n  /** Revolutions per minute. */\n  rpm: number;\n}\n\nfunction Moving({ children, circle, initialAngle = 0, rpm }: MovingProp) {\n  const ref = useRef<HTMLDivElement>(null);\n\n  useEffect(() => {\n    const start = performance.now();\n\n    let cancelId: number;\n\n    // update handler\n    const update = (t: number) => {\n      if (!ref.current) return;\n\n      const angle = initialAngle + ((CIRCLE * (t - start)) / MINUTES) * rpm;\n      const [x, y] = toScreenCoords(getCoords(circle, angle));\n\n      // we want to position the center rather than the top-left corner\n      const rect = ref.current.getBoundingClientRect();\n      ref.current.style.transform = `translate(\n        ${x - rect.width / 2}px,\n        ${y - rect.height / 2}px\n      )`;\n\n      cancelId = requestAnimationFrame(update);\n    };\n\n    // start animation loop\n    cancelId = requestAnimationFrame(update);\n\n    // cancel animation loop on unmount\n    return () => cancelAnimationFrame(cancelId);\n  }, []);\n\n  return (\n    <div className=\"w-min text-3xl absolute\" ref={ref}>\n      {children}\n    </div>\n  );\n}\n\n/** Get the coordinates of a point on a circle. */\nfunction getCoords(circle: Circle, angle: number): Pt2 {\n  const {\n    center: [cx, cy],\n    radius: r,\n  } = circle;\n\n  // we subtract in the second coordinate because screen y-axis\n  // goes down while math y-axis goes up\n  return [cx + r * Math.cos(angle), cy - r * Math.sin(angle)];\n}\n\n/** Map [0, 100] x [0, 100] onto the actual screen dimensions */\nfunction toScreenCoords([x, y]: Pt2) {\n  return [(window.innerWidth * x) / 100, (window.innerHeight * y) / 100];\n}\n```\n\n## Triangle interpretation\n\nYou may be more used to a definition of $\\cos$ and $\\sin$ in terms of ratios of angles of right-angle triangles.\n\n<div className=\"flex items-center w-2/3 mx-auto\">\n  <svg class=\"mx-auto flex-1\" viewBox=\"0 0 250 100\">\n    <path\n      class=\"stroke-black dark:stroke-white fill-none\"\n      d=\"M 5 80 l 195 -75 v 75 z\"\n    />\n    <g class=\"dark:fill-white\">\n      <text\n        x=\"40\" y=\"80\" dx=\"3\" dy=\"-3\"\n        fill=\"mediumpurple\"\n        font-family=\"KaTeX_Math\"\n        font-size=\"12\"\n      >θ</text>\n      <text\n        text-anchor=\"start\"\n        font-family=\"KaTeX_Main\"\n        transform=\"translate(208, 6) rotate(90)\"\n      >opposite</text>\n      <text\n        x=\"100\" y=\"95\" dy=\"1\"\n        dominant-baseline=\"text-top\" text-anchor=\"middle\"\n        font-family=\"KaTeX_Main\"\n      >adjacent</text>\n      <text\n        font-family=\"KaTeX_Main\"\n        dominant-baseline=\"text-bottom\" text-anchor=\"middle\"\n        transform=\"translate(100, 38) rotate(${Math.atan2(-75, 195) * 180 / Math.PI})\">hypotenuse</text>\n    </g>\n  </svg>\n  <katex class=\"mx-auto text-xl\" display>\n    \\begin{aligned}\n      \\cos\\theta &= \\frac{\\text{adjacent}}{\\text{hypotenuse}}\\\\\n      \\sin\\theta &= \\frac{\\text{opposite}}{\\text{hypotenuse}}\n    \\end{aligned}\n    </katex>\n</div>\n\nThis perspective is often useful, but it doesn't work for angles larger than $90^\\circ$.\n\nHow does this relate to coordinates of points on the unit circle? First, note that for any point on a circle, we can form a right-angle triangle whose hypotenuse is the line segment from the center of the circle to that point (see below). In the case of the unit circle, \n\n\n<iframe class=\"w-full my-4\" height=\"500\" src=\"https://www.desmos.com/calculator/kzhc0ynx0k\"></iframe>\n\n## Special angles\n\nAlthough we don't yet have a general algorithm for computing $\\cos$ and $\\sin$, we can read off the values of the coordinates of East $(0)$, North $(90^\\circ=\\frac\\Twopi4)$, West $(180^\\circ=\\frac\\Twopi2)$, and South $(270^\\circ=\\frac{3\\Twopi}4$).\n\\[\\begin{align*}\n  \\ivec{\\cos0,\\,\\sin0} &= \\ivec{1,0} &\n  \\ivec{\\cos\\frac\\Twopi2,\\,\\sin\\frac\\Twopi2} &= \\ivec{-1,\\, 0}\\\\[.5em]\n  \\ivec{\\cos\\frac\\Twopi4,\\,\\sin\\frac\\Twopi4} &= \\ivec{0,\\, 1} &\n  \\ivec{\\cos\\frac{3\\Twopi}4,\\,\\sin\\frac{3\\Twopi}4} &= \\ivec{0,\\, -1}\n\\end{align*}\\]\n\nWith a bit more work, we can calculate the coordinates of the point at $45^\\circ$, using the triangle interpretation above.\n\n<svg class=\"mx-auto\" width=\"200\" viewBox=\"0 0 110 110\">\n  <g class=\"fill-none stroke-black dark:stroke-white\">\n    <path d=\"M 5 95 l 90 -90 v 90 z\" />\n    <path d=\"M 85 95 v -10 h 10\" />\n  </g>\n  <g class=\"dark:fill-white\">\n    <text\n      x=\"20\" y=\"90\" dx=\"3\" dy=\"-3\"\n      font-family=\"KaTeX_Math\"\n      font-size=\"11\"\n    >45°</text>\n    <text\n      x=\"50\" y=\"100\" dy=\"5\"\n      font-family=\"KaTeX_Math\"\n      font-size=\"11\"\n      dominant-baseline=\"text-top\"\n      text-anchor=\"middle\"\n    >x</text>\n    <text\n      x=\"100\" y=\"50\"\n      font-family=\"KaTeX_Math\"\n      font-size=\"11\"\n      dominant-baseline=\"middle\"\n      text-anchor=\"start\"\n    >x</text>\n    <text\n      x=\"50\" y=\"50\" dx=\"-10\" dy=\"-10\"\n      font-family=\"KaTeX_Math\"\n      font-size=\"12\"\n      dominant-baseline=\"middle\"\n      text-anchor=\"middle\"\n    >1</text>\n  </g>\n</svg>\n\nSince the angles of a triangle add up to $180^\\circ=\\Twopi/2$, the remaining angle is also $45^\\circ=\\Twopi/8$. This implies that the two side lengths $\\cos45^\\circ$ and $\\sin45^\\circ$ are equal; let's call that $x$. By the Pythagorean theorem,\n\\[\\begin{align*}\n  \\cos(45^\\circ)^2 + \\sin(45^\\circ)^2 &= 1\\\\\n  2x^2 &= 1\\\\\n  x^2 &= \\frac12\\\\\n  x &= \\sqrt{\\frac12}\\\\\n    &= \\frac1{\\sqrt2}\\\\\n    &= \\frac{\\sqrt2}2\n\\end{align*}\\]\nTherefore, we have\n\\[ \\cos45^\\circ = \\sin45^\\circ = \\frac{\\sqrt2}2. \\]\n\n<!-- #tab videos -->\n\nThese are some old videos on $\\cos$ and $\\sin$.\n\n<iframe allow=\"fullscreen\" class=\"w-full my-4\" src=\"https://epiplexis.xyz/a/9vg/lesson/?t=3:12\" style=\"aspect-ratio: 8/5;\"></iframe>\n\n<iframe allow=\"fullscreen\" class=\"w-full my-4\" src=\"https://epiplexis.xyz/a/9vb/lesson/\" style=\"aspect-ratio: 8/5;\"></iframe>\n\n<!-- #tab exercises -->\n\n1. Find $\\cos$ and $\\sin$ of $30^\\circ$ and $60^\\circ$.\n\n2. Consider the following diagram:  \n   ::embed[{epiplexis-content}/gng/02-trigonometry/04-cos-sin/exc-minus]{aspect-ratio=2.5 source inline}  \n   By calculating the length of the green line segment in two different ways, establish the identity\n   $$\n   \\begin{equation}\\htmlId{eq-sin-pyth}{}\n   2\\sin\\left(\\frac{\\alpha - \\beta}2\\right) =\n   \\pm\\sqrt{\n     (\\cos\\alpha - \\cos\\beta)^2 + (\\sin\\alpha - \\sin\\beta)^2\n   }\n   \\end{equation}\n   $$\n   :::popup{trigger=Solution}  \n   The horizontal distance between the two points is $(\\cos\\alpha-\\cos\\beta)$, while the vertical distance is $(\\sin\\alpha-\\sin\\beta)$. Applying the Pythagorean theorem, we see that the length of the green segment is\n   $$\n   (\\cos\\alpha-\\cos\\beta)^2 + (\\sin\\alpha-\\sin\\beta)^2.\n   $$\n   ::embed[{epiplexis-content}/gng/02-trigonometry/04-cos-sin/exc-minus?rightAngle]{aspect-ratio=2.5 inline}\n   On the other hand, we can get a right angle triangle by drawing a line from the center of the circle to the midpoint of the green line: \n   ::embed[{epiplexis-content}/gng/02-trigonometry/04-cos-sin/exc-minus?bisect]{aspect-ratio=2.5 inline}\n   Now the angle between the red line and the dashed green line is $\\frac{\\alpha-\\beta}2$, and so the side opposite to it has length $\\sin\\left(\\frac{\\alpha-\\beta}2\\right)$. But this side is exactly half of the length of the green line, so the green line has length\n   $$\n   2\\sin\\left(\\frac{\\alpha-\\beta}2\\right).\n   $$\n   Putting these together, we have \n   $$\n   2\\sin\\left(\\frac{\\alpha-\\beta}2\\right) = (\\cos\\alpha-\\cos\\beta)^2 + (\\sin\\alpha-\\sin\\beta)^2\n   $$\n   :::  \n3. Consider a regular $n$-gon inscribed in a circle of radius 1:  \n   ::embed[{epiplexis-content}/gng/02-trigonometry/04-cos-sin/exc-polygon]{aspect-ratio=2 source inline}  \n   1. Show that its perimeter is given by $2n\\sin\\frac\\Twopi{2n}$.  \n      \n      :::popup{trigger=Hint}\n      Use the angle-bisection trick from the previous exercise.\n      :::\n   2. Show that its area is given by $\\frac n2\\sin\\frac\\Twopi n$.\n\n4. Once we've established [$(1)$](#eq-sin-pyth), we can derive all the usual trigonometric identities using algebraic manipulations, with no further geometric insight required. \n   1. Use [$(1)$](#eq-sin-pyth) to derive the \"half-angle formulas\"\n      $$\n      \\begin{align}\n        \\htmlId{eq-cos-half}{}\\cos(\\theta/2) &= \\pm\\sqrt{\\frac{1+\\cos\\theta}2}\\\\[1em]\n        \\htmlId{eq-sin-half}{}\\sin(\\theta/2) &= \\pm\\sqrt{\\frac{1-\\cos\\theta}2}\n      \\end{align}\n      $$\n   2. Use [$(2)$](#eq-cos-half) and [$(3)$](#eq-sin-half) to derive the \"double-angle formulas\"\n      $$\n      \\begin{align*}\n        \\cos(2\\theta)\n          &= \\cos^2(\\theta)-\\sin^2(\\theta)\\\\\n          &= 2\\cos^2(\\theta) - 1\\\\\n          &= 1 - 2\\sin^2(\\theta)\\\\\n        \\sin(2\\theta) &= 2\\cos(\\theta)\\sin(\\theta)\n      \\end{align*}\n      $$\n   3. Derive the \"angle-difference\" formulas\n      $$\n      \\begin{align*}\n        \\cos(\\alpha-\\beta) &= \\cos(\\alpha)\\cos(\\beta) + \\sin(\\alpha)\\sin(\\beta)\\\\\n        \\sin(\\alpha-\\beta) &= \\sin(\\alpha)\\cos(\\beta) - \\cos(\\alpha)\\sin(\\beta)\n      \\end{align*}\n      $$\n      and the \"angle-sum\" formulas\n      $$\n      \\begin{align*}\n        \\cos(\\alpha+\\beta) &= \\cos(\\alpha)\\cos(\\beta) - \\sin(\\alpha)\\sin(\\beta)\\\\\n        \\sin(\\alpha+\\beta) &= \\sin(\\alpha)\\cos(\\beta) + \\cos(\\alpha)\\sin(\\beta)\n      \\end{align*}\n      $$\n      These are sometimes stated in combined form\n      $$\n      \\begin{align*}\n        \\cos(\\alpha\\pm\\beta) &= \\cos(\\alpha)\\cos(\\beta) \\mp \\sin(\\alpha)\\sin(\\beta)\\\\\n        \\sin(\\alpha\\pm\\beta) &= \\sin(\\alpha)\\cos(\\beta) \\pm \\cos(\\alpha)\\sin\\beta)\n      \\end{align*}\n      $$\n      This is not the best way to derive these formulas, but it works; the point is mainly that you can get them from each other using pure algebra. We'll see a more enlightening explanation of and in a future lesson, and then the rest will follow by algebra in a similar way (in the opposite order as you derived them here).\n",
    "description": "",
    "duration": null,
    "meta": {
      "math": {
        "macros": "\\newcommand{\\Twopi}{\\htmlClass{text-teal-600 dark:text-teal-500}{\\varpi}}\n"
      }
    },
    "ownerId": "41786b7c-b873-4373-8ede-477bf85070a1",
    "publicationDate": "2024-06-15 23:40:16.340316 UTC",
    "slug": "cos-sin",
    "title": "cos and sin",
    "type": "article"
  },
  {
    "id": "3a11bff6-c7cc-44c7-80cd-65d16f0a1642",
    "content": "## Introduction\n\n:::definition\nLet $X$ and $Y$ be sets. A :dfn[function] $f: X \\to Y$ is a rule which assigns to each element of $x$ an element $f(x)$ of $Y$.\n\nWhen $X$ and $Y$ are spaces, a :dfn[map] $f: X \\to Y$ is a function from $X$ to $Y$ which \"preserves the (geometric) structure of $X$\".\n:::\n\nSince I haven't said what \"space\" means, this is kind of meaningless. Once we encounter precise definitions of various types of spaces, they'll be accompanied by precise notions of \"map\". Still, I'm going to use the word \"map\" more than \"function\" because it's shorter and more evocative. Also, sets are one kind of space (with no additional structure), and in that case map does mean any function.\n\n## Terminology\n\n:::definition\nIn the above definition:\n\n- $X$ is called the :dfn[domain] of $f$\n- $Y$ is called the :dfn[codomain] of $f$\n- the :dfn[image] of $f$ is the set of all values taken by $f$,\n  \\[ \\im(f) \\Defeq \\{ f(x) \\mid x \\in Y \\} \\]\n- if $x \\in X$, we call the value $f(x)$ the _image of $x$ under $f$_. We also call $x$ a :dfn[preimage] of $y \\in Y$ if $f(x) = y$.\n:::\n\nThe difference between codomain and range can be hard to appreciate at first. The domain and codomain are part of the \"type\" of $f$, wheras the image might be something difficult to determine.\n\n:::example\nConsider the function\n  \\[\\begin{align*}\n    f\\colon & \\R\\to\\R\\\\\n    f(x) &= x^2\n  \\end{align*}\\]\n  The image of $2$ under $f$ is $f(2)=2^2=4$, so $2$ is a preimage of $4.$ Another preimage of $4$ is $-2.$ The image of $f$ is the set $\\R_{\\ge0}=[0,\\infty)$ of non-negative real numbers.\n:::\n\nIn terms of vibes, the notation $f: X \\to Y$ is approximately equivalent to\n\n```ts\nf: (x: X) => Y;\n```\n\nA more accurate (though still imperfect) translation would be\n\n```ts\nf: Map<X, Y>;\n```\n\nThis is because in math, two functions $f$ and $g$ are considered _equal_ if\n\n- they have the same domain and codomain\n- they map each input to the same output: $f(x) = g(x)$ for all $x \\in X$\n\nThe second point is an important difference between functions in math and functions in programming (which are really _algorithms_). For mathematical functions, there's no such thing as a \"function body\" or \"runtime\".\n\n:::warning\n  Many precalculus/calculus classes ask questions like: \"What is the domain of the function\n  \n  \\[ f(x) = \\frac1{x-1}? \\]\n  \n  This question doesn't make sense: the domain of the function is _part of the data of the function_. What it's really asking is \"what is the largest subspace of $\\R$ on which this expression makes sense?\" (The answer being $\\R - \\{1\\}$, since we can't divide by $0$.)\n:::\n\nSome more terminology.\n\n:::definition\n  A function is:\n- :dfn[injective] if it never sends two different inputs to the same output. This can be phrased as  \n  \\[ x \\ne y \\implies f(x) \\ne f(y) \\]  \n  or equivalently as  \n  \\[ f(x) = f(y) \\implies x = y. \\]  \n  The first form is maybe easier to think about, but the second is easier to work with.\n- :dfn[surjective] if every element of $Y$ is the image of some $x\\in X$.\n- :dfn[bijective] if it is both injective and surjective.\n:::\n\n:::example\n  Let $\\R_{\\ge0} = [0, \\infty)$ be the space of non-negative real numbers. Consider the functions:\n  \n  - $f\\colon \\R\\to\\R,\\quad f(x) = x^2$  \n    This is not injective since $f(2)=f(-2)=4$.\n    It is not surjective since there is no $x$ such that $f(x)=-1$.\n  - $g\\colon \\R\\to\\R_{\\ge0},\\quad g(x) = x^2$  \n    This is surjective but not injective.\n  - $h\\colon \\R_{\\ge0}\\to\\R,\\quad h(x) = x^2$  \n    This is injective but not surjective.\n  - $k\\colon \\R_{\\ge0}\\to\\R_{\\ge0},\\quad k(x) = x^2$  \n    This is bijective.\n:::\n\n## Exponential interpretation\n\nWhen we introduced products of spaces, we saw that that concept was related to multiplication of numbers. Functions are also related to a numeric concept: exponentiation.\n\nFor example, say we have two balls which can be painted any of three colors, red, green, blue. We can represent the possibilities as functions from $\\{B_1, B_2\\}$ to $\\{\\red r,\\green g,\\blue b\\}$, e.g.\n\\[\n  \\vcenter{\\LARGE{\\red\\bullet}{\\blue\\bullet}}\n  \\quad\\text{corresponds to}\\quad\n  f(B_1) = \\red r, \\quad f(B_2) = \\blue b.\n\\]\nThere are $9=3^2$ possibilities in total:\n\n\\[\n  \\Big\\{\n    f\\colon\n    \\{B_1,B_2\\}\n    \\to\n    \\{\\red r ,\\green g, \\blue b\\}\n  \\Big\\}\n  =\n  \\LARGE\n  \\left\\{\\begin{matrix}\n    \\red\\bullet\\red\\bullet & \\green\\bullet\\red\\bullet & \\blue\\bullet\\red\\bullet\\\\\n    \\red\\bullet\\green\\bullet & \\green\\bullet\\green\\bullet & \\blue\\bullet\\green\\bullet\\\\\n    \\red\\bullet\\blue\\bullet & \\green\\bullet\\blue\\bullet & \\blue\\bullet\\blue\\bullet\n  \\end{matrix}\\right\\}\n\\]\n\nIn general, if $X$ and $Y$ are finite sets with $|X|$ and $|Y|$ elements respectively, then the number of functions from $X$ to $Y$ is $|Y|^{|X|}$: there are $|Y|$ options where to send each $x \\in X$, and we can choose those values independently of one another.\n\nThis suggests defining $Y^X$ as the set of functions from $X$ to $Y$, so that\n\\[ |Y^X| = |Y|^{|X|}. \\]\nThis is called the **function set** or **mapping space** from $X$ to $Y$. Although this can be hard to think about, it's very powerful to go from thinking about\n\n- individual elements of $X$ and $Y$, to\n- individual functions $f: X \\to Y$, to\n- considering _all_ functions $X \\to Y$ as a single object.\n\nAnother notation for the mapping space (more common in CS than in math) is $X \\to Y$, in which case the notation $f: X \\to Y$ is literally a type declaration. In any case, the mapping space from $X$ to $Y$ is approximately equivalent to the type `(x: X) => Y` or `Map<X, Y>`.\n\nI'll try to avoid using the concept of mapping space except when we have precise definitions of \"space\" and \"map\", since\n\n- the precise definition of \"map\" will affect what the actual elements of $Y^X$ are. For example,\n  \\[\\begin{align*}\n    f&\\colon \\R \\to \\R\\\\\n    f(x) &= x+1\n  \\end{align*}\\]\n  is considered an _affine_ map but not a _linear_ map.\n- depending on the precise meaning of \"space\", it may be easy, difficult, or impossible to turn the _set_ of maps $X \\to Y$ into a \"space\".\n\n## Maps and products\n\nLet's see how this interacts with the other way we've seen of combining spaces, namely products.\n\n### Repeated multiplication\n\nWhen $x$ is a natural number ($0,1,2,...)$ and $y$ is any number, the exponential $y^x$ is defined as repreated multiplication:\n\n\\[ y^x = \\underbrace{yy\\dotsm y}_{x\\text{ times}} \\]\n\nSomething similar is true for function spaces. Recall that three-dimensional space $\\R^3$ can be understood as the threefold product of $\\R$ with itself,\n\n\\[ \\R^3 = \\R \\times \\R \\times \\R. \\]\n\nWe can also view $\\R^3$ as the function space $\\R^{\\{0,1,2\\}}$. In code, this is saying that the types\n\n```ts\n[number, number, number];\n```\n\nand\n\n```ts\n{\n  0: number;\n  1: number;\n  2: number;\n}\n```\n\nare \"equivalent\".\n\nDepending on your application, you might prefer to have types like\n\n```ts\n{\n  x: number;\n  y: number;\n  z: number;\n}\n```\n\nor\n\n```ts\n{\n  height: number;\n  width: number;\n}\n```\n\nThese can be encoded as the mapping spaces $\\R^{\\{\\r x,\\r y,\\r z\\}}$ and $\\R^{\\{\\r{height},\\r{width}\\}}$.\n\n### Maps into a product\n\nLet $X$, $Y$, and $Z$ be spaces. We can form the product $Y \\times Z$, and then ask what maps $f\\colon X \\to Y \\times Z$ look like.\n\nBy definition, $f$ needs to send each element $x$ of $X$ to an element of $Y \\times Z$. An element of $Y \\times Z$ is a pair $(y, z)$ with $y\\in Y$ and $z\\in Z$. So can define maps $g: X \\to Y$ and $h: X \\to Z$ as the first and second components of $f$:\n\n\\[ f(x) = (g(x), h(x)) \\]\n\nIn other words, _a function from $X$ to $Y \\times Z$ is equivalent to two separate functions $X \\to Y$ and $X \\to Z$_. In terms of mapping spaces, we can express this as\n\n\\[ (Y \\times Z)^X \\qeq Y^X \\times Z^X. \\]\n\n(I'll say more about $\\qeq$ in a future post.) This parallels the identity for numbers\n\n\\[ (yz)^x = y^x z^x. \\]\n\nHere's what this equivalence looks like in code:\n\n```ts\n/** Projection onto first factor */\nconst pr1 = <X, Y>([x, y]: [X, Y]): X => x;\n\n/** Projection onto second factor */\nconst pr2 = <X, Y>([x, y]: [X, Y]): Y => y;\n\n/** Convert a function into a product to a pair of functions **/\nconst split = <X, Y, Z>(f: (x: X) => [Y, Z]): [(x: X) => Y, (x: X) => Z] => [\n  (x) => pr1(f(x)),\n  (x) => pr2(f(x)),\n];\n\n/** Convert a pair of functions to a function into a product */\nconst combine =\n  <X, Y, Z>(g: (x: X) => Y, h: (x: X) => Z): ((x: X) => [Y, Z]) =>\n  (x) =>\n    [g(x), h(x)];\n```\n\n## Maps out of a product\n\nWhat about maps _out of_ a product? That is, for spaces $X$, $Y$, $Z$, let's think about what maps $X \\times Y \\to Z$ look like.\n\nThese correspond to \"functions of two variables\": for example, the function\n\n\\[ f(x, y) = x^2 + y^2 \\]\n\nis a map $\\R^2 \\to \\R$.\n\nThere is another way of encoding a function of two variables: for a fixed value of $x$, we can get a function $f_x: Y \\to Z$ by defining\n\n\\[ f_x(y) = f(x, y) \\]\n\nFor instance, if $f(x, y) = x^2 + y^2$ as above, then $f_2(y) = 4+y^2$. This is saying that a function of two variables can also be expressed as a function from $X$ to _the set of functions from $Y$ to $Z$_. Symbolically, this is\n\n\\[ Z^{X\\times Y} \\qeq (Z^Y)^X \\]\n\nor\n\n\\[ (X \\times Y) \\to Z \\qeq X \\to (Y \\to Z) \\]\n\nThis \"lifts\" the numeric identity\n\n\\[ z^{xy} = (z^y)^x. \\]\n\nIn programming, this equivalence is called \"currying\".\n\n```ts\n/** Convert a function of two variables into a function returning a function. */\nconst curry =\n  <X, Y, Z>(f: ([x, y]: [X, Y]) => Z): ((x: X) => (y: Y) => Z) =>\n  (x) =>\n  (y) =>\n    f([x, y]);\n\n/** Convert a function returning a function to a function of two variables. */\nconst uncurry =\n  <X, Y, Z>(f: (x: X) => (y: Y) => Z): (([x, y]: [X, Y]) => Z) =>\n  ([x, y]) =>\n    f(x)(y);\n```\n\n## Coproducts\n\nThere's one more exponential identity remaining,\n\n\\[ z^{x + y} = z^x z^y \\]\n\nTo get an analogue of this for mapping spaces, we need the concept of the _coproduct_ $X \\amalg Y$. I don't want to really get into this concept right now, but it corresponds to the union type `X | Y`. The relevant identity is\n\n\\[ Z^{X\\amalg Y} \\qeq Z^X \\times Z^Y \\]\n\nOr if you prefer, this is saying that the types `Map<X | Y, Z>` and `[Map<X, Z>, Map<Y, Z>]` are \"equivalent\".\n\n:::exercise\n  Convince yourself of the above, and implement the conversion in code.\n:::\n",
    "description": "",
    "duration": null,
    "meta": {
      "math": {
        "macros": "\\newcommand{\\r}{\\mathrm}\n\\newcommand{\\qeq}{\\cong}\n"
      }
    },
    "ownerId": "41786b7c-b873-4373-8ede-477bf85070a1",
    "publicationDate": "2024-06-15 23:40:16.340316 UTC",
    "slug": "maps",
    "title": "Maps",
    "type": "article"
  },
  {
    "id": "7e063b2d-2406-4557-a8ff-7e8a5a02b731",
    "content": "This will be a series on *geometry* (broadly speaking), applied to and demonstrated through *web graphics*. The code samples will be in TypeScript/React/THREE.js/react-three-fiber, but the concepts are completely general and applicable to many other areas (machine learning, modelling, optimization, …)\n\n## Geometry \nFor starters, what do I mean by *geometry*? Well, 2d and 3d geometry are particularly relevant to us because we live in 3d space. 2d shapes appear on screens and flat surfaces, while the objects around us have 3d shapes.\n\nBut geometry also comes from more abstract sources. Consider the following situations:\n\n- in physics, the kinetic energy $E$ of an object is related to its mass $m$ and its speed $v$ by the formula\n\n  \\[ E = \\frac12mv^2; \\]\n\n- again in physics: say an object starts from rest, and has constant acceleration $a$ (e.g. $a=9.8\\text{ m/s}^2$ for gravity). The distance $s$ it travels after time $t$ is given by\n\n  \\[ s = \\frac12at^2; \\]\n\n- in geometry: we consider the set of points $(x,y,z)$ in 3d space which satisfy the condition\n\n  \\[ z = \\frac12xy^2. \\]\n  \n  Here's what that looks like:\n  <iframe class=\"w-full mx-auto my-2\" src=\"https://www.desmos.com/3d/2875b3713c\" height=\"600\"></iframe>\n\n\nThese are all different physical situations. But mathematically, they're all equivalent: all that matters is the relations between the numbers, not what the numbers represent.\n:::yell\nUnderstanding the geometry of the above shape is equivalent to understanding any (and all) of the more concrete situations.\n:::\nFor instance, an object of mass $4\\text{ kg}$ and velocity $3\\text{ m/s}$ corresponds to the point $(4,3,18)$.\n\nComplex problems may involve more than three dimensions; search algorithms routinely calculate in thousands or millions of dimensions. It's harder to visualize these problems. But we can use our physical intuition from 2d and 3d space to develop formulas that make sense in any number of dimensions. For example, in just a few posts we'll see how to talk about *lines* in any-dimensional space.\n\nEven \"spatial\" geometry in 2d and 3d space naturally leads us to consider higher dimensions. As a simple example, a point in 6-dimensional space is equivalent to two points in 3d space, or three points in 2d space:\n\n\\[\n  \\begin{bmatrix*}[r]\n    1\\\\-3\\\\2\\\\4.1\\\\0\\\\1\n  \\end{bmatrix*}\n  \\leftrightarrow\n  \\begin{bmatrix*}[r]\n    1&4.1\\\\-3&0\\\\2&1\n  \\end{bmatrix*}\n  \\leftrightarrow\n  \\begin{bmatrix*}[r]\n     1 & 2 & 0\\\\\n    -3 & 4.1 & 1\\\\\n  \\end{bmatrix*}\n\\]\n\n## Spaces\n\nThis brings us to our first definition.\n\n:::definition\n  A **space** is any concept that can be described using numbers.\n:::\n\n### Subsets of $\\mathbf R^n$\n\nThe above \"definition\" is extremely vague. Let me be more precise:  \n\n:::definition\n  $\\R^n$ (\"arr-enn\") is the set of $n$-tuples of real numbers:  \n  \\[ \\R^n = \\{(x_1,\\dotsc,x_n)\\mid x_i\\in \\R\\text{ for } i = 1,\\dotsc,n\\} \\]\n:::\n\n($\\in$ means \"in\" or \"is an element of\"). For example, $(0,0)$ is a point in $\\R^2,$ and $(3,0,1)$ is a point in $\\R^3.$ I might also write these vertically, e.g.\n  \n\\[ \\vec00 \\quad\\text{or}\\quad \\vecc301. \\]\n\n$\\R^n$ is one of the most important examples of a space. Any subset of $\\R^n$ is a space, and you could well take that as the precise definition. For example, the blue shape above is a subset (I could also say subspace) of $\\R^3$.\n\nActually, the term *space* doesn't have a precise definition in math (neither does *number*). There are a lot of technical concepts that have *space* in their name, which do have precise definitions, depending on what aspect of geometry we're focusing on or what tools we're using:\n  - *affine/vector spaces* are used when studying *translation* and *scaling*;\n  - *metric spaces* are for studying the concept of *distance*;\n  - *inner product spaces* incorporate all of the above and also *angles*;\n  - …\n  \n(We'll learn about these in due time.) But \"space\" on its own is just a vibe.\n\n### Coordinates\nNotice the word *can* in the definition. There are many different ways to represent any given situation, and rarely is there a single best one. For example, $10\\text{ cm}$, $3.94\\text{ in}$, and $0.33\\text{ ft}$ are three different numbers corresponding to the same concept.\n\nSo, there's a space of physical distances. This space \"is\" the same as $\\R$, but it is \"equivalent to $\\R$ in many ways\". Moreover, notice that \"equations\" like\n\n\\[ \n\\begin{align*}\n  \\line{2em} + \\line{1em} &= \\line{3em}\\\\\n  3\\times\\line{1.5em} &= \\line{4.5em}\n\\end{align*}\n\\]\n\nare meaningful, without even needing to assign numbers to the lengths. (Although this may be useful in *verifying* that the equations are true.)\n\nIn this series, I'll try to take a *coordinate-free* approach where we focus on the *intrinsic* properties of things. How we describe those spaces numerically will then be a separate step. In particular, a big chunk of geometry is just converting between different coordinate systems.\n\nWhen we do calculations, they're always going to be with $n$-tuples of numbers, and you can write your programs thinking this way. The benefit of the more abstract perspective is similar to the benefit of having types in your code.\n\n### Intrinsic / Extrinsic\n*Space* in the mathematical sense means basically the same thing as *shape*. In everyday language, we tend to think of *space* as an ambient medium which is populated by *shapes*. It's very powerful to get rid of that distinction as every shape as a space in its own right, and then one space can *embed* in another in many different ways.\n\nFor instance, the following depicts two circles drawn on a torus in 3d space. We can think of the circles as living in 3d space, occupying some of the same space as the torus. But we can also *forget* about ambient 3d space and just think about the torus as the ambient space. Furthermore, we can think of both these circles as different embeddings of one \"platonic\" circle into the torus.\n\n::embed[{epiplexis-content}/gng/01-coordinates/01-spaces/torus]{aspect-ratio=2.5 inline source} \n\n## Important Examples\n\nFinally, let me introduce notation for some important examples.\n\n- as we have already seen, $\\R^n$ is \"$n$-dimensional space\". For many purposes we are especially interested in the cases $\\R^2$ and $\\R^3$.\n\n- Frequently, we want to put bounds on the numbers we use. An :dfn[interval] consists of all numbers between two numbers $a$ and $b;$ the numbers $a$ and $b$ are called the :dfn[endpoints] of the interval. There are different versions depending on whether we want to include the endpoints or not:\n  \\[\\begin{align*}\n    [a, b] \\Defeq \\{ x \\in \\R \\mid a\\le x\\le b \\}\\\\\n    (a, b) \\Defeq \\{ x \\in \\R \\mid a < x < b \\}\n  \\end{align*}\\]\n  We call $[a, b]$ a :dfn[closed interval] and $(a,b)$ an :dfn[open interval]. There are also variants where we want to include one endpoint but not the other:\n  \\[\\begin{align*}\n    [a, b) \\Defeq \\{ x \\in \\R \\mid a\\le x < b \\}\\\\\n    (a, b] \\Defeq \\{ x \\in \\R \\mid a < x\\le b \\}\n  \\end{align*}\\]\n  These are sometimes called :dfn[half-open intervals] but there aren't individual names for them. For example, when describing angles in degrees, we're interested in the interval $[0,360).$\n\n- In particular, the :dfn[unit interval]\n  \\[ \\I \\Defeq [0, 1] \\]\n  consists of all numbers between 0 and 1, inclusive of both. This space comes up a lot when dealing with paths and animation (= paths in time).\n\n- we write $\\Sone$ for a :dfn[circle]. This means the *edge* of a circle, not the points inside; a filled circle is called a :dfn[disk] and denoted by $\\Dtwo$. Below, I've drawn a *circle* on the left and a *disk* on the right:\n\n<iframe class=\"w-full\" src=\"https://www.desmos.com/calculator/m4kxsba4su?embed\" height=\"500\"></iframe>\n\n  The notation $S^1$ means a one-dimensional *sphere*. Even though it lives in _two_-dimensional space, the circle is itself considered _one_-dimensional since you can only move backwards/forwards along it. The disk, on the other hand, is considered two-dimensional.\n\n  The notations extend to higher dimensions: $\\Stwo$ refers to a (hollow) :dfn[sphere] in $\\R^3$, while $D^3$ refers to a filled-in :dfn[ball]. Once we learn how to make sense of \"distance\" in higher dimensions, we'll be able to define $\\S n$ and $D^n$ for all $n$.\n",
    "description": "",
    "duration": null,
    "meta": {
      "math": {
        "macros": "\\newcommand{\\vec}[2]{\\begin{bmatrix}#1\\\\#2\\end{bmatrix}}\n\\newcommand{\\vecc}[3]{\\begin{bmatrix}#1\\\\#2\\\\#3\\end{bmatrix}}\n\\newcommand{\\line}[1]{\n  \\mathord{\n    \\raisebox{.2em}{\n      $\\rule{#1}{2px}$\n    }\n  }\n}\n\n\\newcommand{\\Sone}{S^1}\n\\newcommand{\\Stwo}{S^2}\n\\newcommand{\\Dtwo}{D^2}"
      }
    },
    "ownerId": "41786b7c-b873-4373-8ede-477bf85070a1",
    "publicationDate": "2024-06-15 23:40:16.340316 UTC",
    "slug": "spaces",
    "title": "Spaces",
    "type": "article"
  },
  {
    "id": "a5f12e03-5616-499d-a349-5d82fcd00550",
    "content": "In the [last post](/gng/cg/spaces) we encountered the notion of _spaces_, which are a way of thinking about situations numerically and geometrically. We saw a few examples of spaces:\n\n- $\\R^n$ is the set of all $n$-tuples of real numbers, which we think of as $n$-dimensional space\n\n- $\\ClsdIntvl ab$ is the interval of numbers between $a$ and $b$ (inclusive on both sides).\n\n- in particular, $\\I\\Defeq\\ClsdIntvl01$ consists of all $x$ with $0\\le x\\le 1$\n\n- $S^1$ is the unit circle in $\\VecR 2$\n\nIn this post, we'll discuss a way to combine two (or more) spaces $X$ and $Y$ into a new space $X\\times Y$, called the :dfn[product] of $X$ and $Y$. There are two reasons to do this:\n\n- it gives us more interesting examples of spaces;\n\n- conversely, we understand complicated spaces by expressing them in terms of simpler \"building block\" spaces. Most questions about $X\\times Y$ can be answered by answering the same question for the spaces $X$ and $Y$, and combining the answers somehow.\n\n:::definition\n  Let $X$ and $Y$ be spaces. The **product** $X\\times Y$ consists of all pairs of elements from $X$ and $Y$:\n  \\[ X \\times Y \\Defeq \\{(x,y) \\mid x\\in X,\\, y\\in Y \\}. \\]\n:::\n\nThe space $X\\times Y$ is analogous to the tuple type `[X, Y]`.\n\n### Examples\n\n:::example\nSuppose a user's screen is $w$ pixels wide by $h$ pixels tall. The screen can be modelled by the space\n  \\[ \\ClsdIntvl 0w\\times \\ClsdIntvl0h. \\]\n  The usual convention is that $(0,0)$ corresponds to the top left corner, but this is arbitrary. The order of the coordinates is also arbitrary: $\\ClsdIntvl 0h\\times\\ClsdIntvl 0w$ would work just as well.\n:::\n\n:::example\nThe set of playing cards can be viewed as\n  \\[\n    \\{ \\spadesuit, \\heartsuit, \\clubsuit, \\diamondsuit \\}\n    \\times\n    \\{\\mathrm A,2,3,4,5,6,7,8,9,10,\\mathrm J,\\mathrm Q,\\mathrm K\\}\n  \\]\n:::\n\n:::example\n$\\VecR2=\\R\\times\\R,\\ \\VecR3=\\R\\times\\R\\times\\R$, and so on. (See below about products of more than two spaces.)\n:::\n\n:::example\n  - a cube is $I\\times I\\times I$,\n  \n  - $I\\times S^1$ is a (hollow) cylinder,\n\n  - $S^1\\times S^1$ is a (hollow) torus:\n\n  ::embed[{epiplexis-content}/gng/01-coordinates/02-products/examples]{aspect-ratio=2 source appDir}\n:::\n\n:::example\nThe $n$-dimensional unit cube is\n  \\[ I^n = \\underbrace{I\\times\\dotsb\\times I}_{n\\text{ times}} \\]\n  This is harder to visualize in the same way as the cube above. But we can visualize it as $n$ slider controls.\n:::\n\n## Multiplication\n\nLet's explain why this operation is called multiplication. If $X$ is a finite set, we write $|X|$ for the number of elements of $X$, also called the :dfn[cardinality] or :dfn[size] of $X.$ For example, $|\\{a,b,c\\}|=3.$\n\nWhen $X$ and $Y$ are finite sets, the size of $X\\times Y$ is the product of the sizes of $X$ and $Y:$\n\n\\[ |X\\times Y| = |X||Y|. \\]\n\nFor instance, say we have three possible colors and four shapes. The number of possible colored shapes is $3\\times4=12:$\n\n\\[\n  \\Large\n  \\{\\red{\\mathrm{red}},\\, \\green{\\mathrm{green}},\\, \\blue{\\mathrm{blue}}\\}\n  \\times\n  \\{\\blacktriangle,\\, \\blacksquare,\\, \\bigstar,\\, \\bullet\\}\n  =\n  \\left\\{\\begin{matrix}\n  \\red\\blacktriangle&\\red\\blacksquare&\\red\\bigstar&\\red\\bullet\\\\\n  \\green\\blacktriangle&\\green\\blacksquare&\\green\\bigstar&\\green\\bullet\\\\\n  \\blue\\blacktriangle&\\blue\\blacksquare&\\blue\\bigstar&\\blue\\bullet\n  \\end{matrix}\\right\\}\n\\]\n\n## Associativity\n\nOne of the most important properties of ordinary multiplication (of numbers) is _associativity_: this is the property\n\\[ (ab)c = a(bc). \\]\nwhich means that the expression $abc$ is unambiguous. For example, we could evaluate $2\\cdot3\\cdot4$ as\n\\[\\begin{align*}\n  (2\\cdot3)\\cdot4 &= 6\\cdot4 = 24\\\\\n  2\\cdot(3\\cdot4) &= 2\\cdot12 = 24\n\\end{align*}\\]\nand both give the same result.\n\nSomething similar is true for the product of spaces, but we have to be more careful. We can give a direct definition of $X\\times Y\\times Z$ a space of 3-tuples\n\\[ X\\times Y\\times Z \\Defeq \\{(x,y,z) \\mid x\\in X,\\, y\\in Y,\\, z\\in Z\\}, \\]\nor we can build it out of products of two spaces at a time:\n\\[\\begin{align*}\n  (X\\times Y)\\times Z &= \\{((x, y), z) \\mid x\\in X,\\, y\\in Y,\\, z\\in Z\\}\\\\[.5em]\n  X\\times (Y\\times Z) &= \\{(x, (y, z)) \\mid x\\in X,\\, y\\in Y,\\, z\\in Z\\}\n\\end{align*}\\]\n\nThese three options aren't \"literally\" equal. As an analogy, in TypeScript, `[X, Y, Z]`, `[[X, Y], Z]`, and `[X, [Y, Z]]` are all different types. But there is an obvious way to go between them:\n\\[ (x,y,z) \\longleftrightarrow ((x,y),z) \\longleftrightarrow (x,(y,z)). \\]\nIn math, we generally leave these conversions implicit, so we will write\n\\[ (X\\times Y)\\times Z = X\\times Y\\times Z = X\\times(Y\\times Z). \\]\n\nI'll say a bit more about this expanded view of equality a few posts from now.\n\nIn my area of math (homotopy theory), there's often a lot of work that needs to be done to keep track of all these implicit conversions. One of the difficulties is that when converting between $(X\\times X)\\times X$ and $X\\times(X\\times X)$, you don't want to accidentally use the \"wrong\" conversion\n\\[ ((x,y),z) \\longleftrightarrow (z,(y,x)) \\]\n(which wouldn't typecheck for $(X\\times Y)\\times Z$ versus $X\\times(Y\\times Z)$)\n",
    "description": "",
    "duration": null,
    "meta": {
      "math": {
        "macros": ""
      }
    },
    "ownerId": "41786b7c-b873-4373-8ede-477bf85070a1",
    "publicationDate": "2024-06-15 23:40:16.340316 UTC",
    "slug": "products",
    "title": "Products",
    "type": "article"
  },
  {
    "id": "8dd0419d-b2d7-4685-9cdb-575eed7a983c",
    "content": "<iframe class=\"w-full h-[1000px]\" src=\"https://epiplexis.xyz/a/fxh/2d/\"></iframe>\n\nTODO migrate article",
    "description": "",
    "duration": null,
    "meta": {
      "math": {
        "macros": ""
      }
    },
    "ownerId": "41786b7c-b873-4373-8ede-477bf85070a1",
    "publicationDate": "2024-06-15 23:40:16.340316 UTC",
    "slug": "2x2-matrices",
    "title": "$2\\times2$ matrices",
    "type": "article"
  },
  {
    "id": "ccbd70d8-9b8d-470c-95d9-77335d78e0a7",
    "content": "## Episode 1: The $q$-Legendre principle\n\n::unit[intro]\n\n::unit[bases]",
    "description": "",
    "duration": null,
    "meta": {
      "math": {
        "macros": ""
      }
    },
    "ownerId": "41786b7c-b873-4373-8ede-477bf85070a1",
    "publicationDate": "2024-06-15 23:40:16.340316 UTC",
    "slug": "what-study",
    "title": "What do I study?",
    "type": "collection"
  },
  {
    "id": "6a3c0838-f88e-4fdc-ace7-4ecbdf951a0c",
    "content": "Consider a right-angle triangle with side lengths as indicated:\n\n::embed[{epiplexis-content}/gng/02-trigonometry/01-pythagoras/setup]{class=my-4 inline width=50%}\n\nThe lengths $a$ and $b$ are called the _side lengths_, and $c$ is called the (length of the) _hypotenuse_. The Pythagorean theorem says that these are related by the equation\n\\[ a^2 + b^2 = c^2. \\]\n\nThis can be visualized in terms of the areas formed by squares drawn on the sides of the triangle:\n::embed[{epiplexis-content}/gng/02-trigonometry/01-pythagoras/statement]{class=my-4 inline width=75%}\n\n:::example\n  Find the length of the hypotenuse of a triangle with side lengths 3 and 4.\n  :::solution\n  The hypotenuse has length $\\sqrt{3^2 + 4^2} = \\sqrt{9 + 16} = \\sqrt{25} = 5$.\n:::\n\n:::example\n  If a right-angle triangle has a hypotenuse of length 6, and one side of length 3, find the remaining side length.\n  :::solution\n  Taking $a=3$, $c=6$, we have\n  \\[\\begin{aligned}\n    3^2 + b^2 &= 6^2\\\\\n    b^2 &= 36 - 9\\\\\n        &= 27\\\\\n    b &= \\sqrt{27}\\\\\n      &= 3\\sqrt 3.\n  \\end{aligned}\\]\n:::\n\n## Proof\n\nLet's see why the Pythagoream theorem is true. We'll draw two squares, both having side length $a+b$, and divide them in different ways:\n\n::embed[{epiplexis-content}/gng/02-trigonometry/01-pythagoras/proof]{inline}\n\nThe left square says that\n\\[ (\\red a + \\blue b)^2 = \\red{a^2} + \\violet{2ab} + \\blue{b^2} \\]\nThe right square says that\n\\[ (\\red a + \\blue b)^2 = \\green{c^2} + \\violet{2ab} \\]\n\nSetting these equal to each other, we get\n\\[\\begin{aligned}\n  \\red{a^2} + \\violet{2ab} + \\blue{b^2} &= \\green{c^2} + \\violet{2ab}\\\\\n  \\red{a^2} + \\xcancel{\\violet{2ab}} + \\blue{b^2} &= \\green{c^2} + \\xcancel{\\violet{2ab}}\\\\\n  \\red{a^2} + \\blue{b^2} &= \\green{c^2}.\n\\end{aligned}\\]\n\n## Three dimensions\n\nIf $v=\\ivec{x,y}$ is a vector in $\\VecR2$, the Pythagorean theorem implies that the _length_ of $v$ is\n\\[ \\sqrt{x^2+y^2}. \\]\nSimilarly, if $A=\\ipt{x_1,y_1}$ and $B=\\ipt{x_2,y_2}$ are points in $\\AffR 2$, the Pythagorean theorem tells us that the _distance_ between these is\n\\[\n  \\sqrt{(x_1-x_2)^2 + (y_1-y_2)^2}\n\\]\n\nHow can we extend this to higher dimensions? That is, if $A=\\ipt{x_1,y_1,z_2}$ and $B=\\ipt{x_2,y_2,z_2}$ are points in $\\AffR3$, what is $\\Dist AB$? Writing $A-B=v=\\ivec{x,y,z}$, this is the same as asking for the length of $v$.\n\nA naive guess is that the length of $v=\\ivec{x,y,z}$ might be\n\\[ \\sqrt[3]{x^3+y^3+z^3}. \\]\nBut this can't be true, since the length of $\\ivec{x,y,0}$ should be the same as the length of $\\ivec{x,y}$. That is, the appearance of the number $2$ in the Pythagorean theorem isn't related to the problem being in two dimensions.\n\nInstead, we can introduce the point \\[ C=\\ipt{x_2,y_2,z_1},\\] which has $1$ component in common with $A$ and $2$ components in common with $B$. The points $A$, $B$, and $C$ lie in a common plane, and we can apply the \"2d\" Pythagorean theorem within this plane to get $\\Dist AB$ in terms of $\\Dist AC$ and $\\dist BC$. The vertical distance $\\dist BC$ is just $|z_2-z_1|$, and we can compute $\\Dist AC$ by the \"2d\" Pythagorean theorem. This is illustrated in the animation below.\n\n::embed[{epiplexis-content}/gng/02-trigonometry/01-pythagoras/3d]{aspect-ratio=1.6 class=my-2 source}\n\n## Distance\n\n:::definition\n  The **length** of a vector $v=\\ivec{v_1,\\dotsc,v_n}\\in\\VecR n$ is defined to be\n  \\[\n    \\Norm v \\Defeq \\sqrt{v_1^2 + \\dotsc + v_n^2}.\n  \\]\n  This is also sometimes called the **norm** of $v$.\n:::\n\n:::definition\n  If $p,q\\in\\AffR n$ are two points in _affine_ space, then the distance between them is\n  \\[\\begin{align*}\n    \\Dist pq\n      &\\Defeq \\Norm{p-q}\\\\\n      &= \\sqrt{(p_1-q_1)^2 + \\dotsb + (p_n-q_n)^2}\n  \\end{align*}\\]\n:::\n\n:::remark\n  If $v=\\ivec{x}\\in\\VecR1$, then $\\Norm v=\\sqrt{x^2}=|x|$ is the absolute value of $x$. This explains the double-bars notation for length, and you may sometimes see $|v|$ instead of $\\|v\\|$.\n:::\n\n:::example\n  Find the length of the vector $v=\\ivec{-1,2,3,-4}\\in\\VecR 4$.\n  :::solution\n    \\[\\begin{aligned}\n      \\Norm v\n        &= \\sqrt{(-1)^2 + 2^2 + 3^2 + (-4^2)}\\\\\n        &= \\sqrt{1 + 4 + 9 + 16}\\\\\n        &= \\sqrt{30}.\n    \\end{aligned}\\]\n:::\n\n:::example\n  Find the distance between the points $p=\\ipt{1,4,2,5}$ and $q=\\ipt{-1, 3, 0, 1}$.\n  \n  :::solution\n    By definition, $\\Dist pq = \\Norm{p-q}$. We have\n    \\[\\begin{aligned}\n      p-q\\\\\n        &= \\begin{pmatrix}1\\\\4\\\\2\\\\5\\end{pmatrix} - \\begin{pmatrix}-1\\\\3\\\\0\\\\1\\end{pmatrix}\\\\\n        &= \\begin{bmatrix}2\\\\1\\\\2\\\\4\\end{bmatrix}\n    \\end{aligned}\\]\n    We thus get\n    \\[\\begin{aligned}\n      \\Dist pq\n        &= \\sqrt{2^2+1^2+2^2+4^2}\\\\\n        &= \\sqrt{4+1+4+16}\\\\\n        &= \\sqrt{25}\\\\\n        &= 5\n  \\end{aligned}\\]\n:::\n\n## APIs\n\nIn Javascript, we can compute the lengths of vectors using [`Math.hypot()`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/hypot).\n\n```js\n// !interactive\n// finding the length of a vector in R^4\nconsole.log(\"Finding the length of a vector in R^4\");\nconsole.log(Math.hypot(-1, 2, 3, -4));\n\n// finding the distance between two points in A^4\nconsole.log(\"Finding the distance between points in A^4\");\nvar p = [1, 4, 2, 5];\nvar q = [-1, 3, 0, 1];\nconsole.log(Math.hypot(...p.map((pi, i) => pi - q[i])));\n```\n\n\nIn THREE.js, we have the following APIs for calculating distances and lengths:\n- [`Vector3.prototype.distanceTo()`](https://threejs.org/docs/?q=vector3#api/en/math/Vector3.distanceTo)\n- [`Vector3.prototype.distanceToSquared()`](https://threejs.org/docs/?q=vector3#api/en/math/Vector3.distanceToSquared)\n- [`Vector3.prototype.length()`](https://threejs.org/docs/?q=vector3#api/en/math/Vector3.length)\n- [`Vector3.prototype.lengthSq()`](https://threejs.org/docs/?q=vector3#api/en/math/Vector3.lengthSq)\n\nFor the \"squared\" methods, note that when $x,y\\ge 0$ we have $x\\ge y$ if and only iff $x^2 \\ge y^2$.\n\n## Exercises\n\n1. Make an app to draw circles like below. (Don't look at the source until you've tried it yourself.)   \n   ::embed[{epiplexis-content}/gng/02-trigonometry/01-pythagoras/drawing]{aspect-ratio=2 class=mt-2 source}\n\n2. Extend the above app to disallow drawing circles which overlap.\n",
    "description": "",
    "duration": null,
    "meta": {
      "math": {
        "macros": ""
      }
    },
    "ownerId": "41786b7c-b873-4373-8ede-477bf85070a1",
    "publicationDate": "2024-06-15 23:40:16.340316 UTC",
    "slug": "pythagoras",
    "title": "Pythagorean theorem",
    "type": "article"
  },
  {
    "id": "ef4b41a0-e507-456c-840d-e420ffddd37a",
    "content": "<iframe class=\"mx-auto aspect-video w-3/4\" width=\"75%\" src=\"https://www.youtube.com/embed/rjmQ5tT1aso?si=Trs18laFx3V7_Gq3\" title=\"YouTube video player\" frameborder=\"0\" allow=\"accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share\" referrerpolicy=\"strict-origin-when-cross-origin\" allowfullscreen></iframe>\n\n## Week of Monday, June 5, 2023\nThis week I've been stuck trying to prove something that I left til the last stages of writing my paper, because I thought it would be very quick to prove, and it's turning out to be extremely difficult.\n\nRoughly speaking, I have these two axes, and I have this operation that pulls you towards the $x$-axis. If you're already on the $x$-axis, it does nothing. And I need to show that, although this operation pulls you _toward_ the $x$-axis, it can't pull you _in_ if you're not already there.\n\n<figure class=\"mx-auto my-4 text-center w-1/2\">\n  <me-embed inline aspect-ratio=\"1\" width=\"100%\" src=\"{epiplexis-content}/logs/crystalline/diagram\"></me-embed>\n  <figcaption class=\"mt-2 text-sm\">Adapted from Figure 11.1 of the <cite><a href=\"https://people.mpim-bonn.mpg.de/scholze/Berkeley.pdf#page=102\">Berkeley lectures on p-adic geometry</a></cite>\n</figure>\n\n<p class=\"opacity-20 text-xs\" style=\"opacity:0.2;\">(Math ppl: I want to show that a prism <katex>(A,I)</katex> is crystalline if and only if <katex>(A,\\phi(I)A)</katex> is crystalline)</p>\n\nThe reason I'm doing this is that there's these mathematical objects called **prisms** that were invented in 2019, and have been pretty revolutionary. Many problems that were considered untouchable for decades have been solved just in the past few years, largely coming out of this circle of ideas. I'm developing a different perspective on prisms, which is somehow based on the rotational symmetries of the circle.\n\nIn order to justify my perspective, I have to explain how to see various aspects of the theory of prisms in my language—actually, not just show that it's possible, but that it's _natural_ to do so. In the diagram above, I have a natural candidate for prisms which \"lie on the $x$-axis\" (called **crystalline** prisms), but it turns out to actually correspond to things whose _twist_ ends up on the $x$-axis. So I have to show that this is actually the same as already being on the $x$-axis.\n\nFor comparison, there _wasn't_ any existing concept in the \"symmetry world\" to correspond to prisms on the $y$-axis (called **transversal** prisms). But I invented (or discovered) something to correspond to these, and these turned out to be something extremely fundamental that no one had noticed before, and which _massively_ simplify a lot of things in \"symmetry world\".\n\n## Wednesday, June 7, 2023\n\nAnyway, I've been trying and failing to prove this for several days. I messaged Ben on Discord to explain my problem and ask if he had any ideas. Ben suggested I first try to prove this for transversal ($y$-axis) prisms, then extend from that case.\n\nThis is a standard technique: often you can use the transversal guys to control all the others. But it doesn't work in this case, basically because the only thing which is on both the $x$-axis and the $y$-axis is $(0,0)$, and that's boring. So I told Ben \"no, that will never work\", he said \"oh yeah, whoops, sorry that was silly\", and I said \"no worries, I totally tried the same thing before realizing it was nonsense\".\n\nNow, there's a prime number involved in all of this, and I _have_ managed to make this work for the prime number $2$. There's a bunch of stuff in this field that works for any prime number _except_ $2$, so maybe I could use that to deal with the remaining primes? But that stuff goes over my head, so I spent a few hours trying to understand it better.\n\n<p class=\"opacity-20 text-xs\">(Math ppl: I'm referring to obtaining prismatic cohomology from <katex>q</katex>-de Rham cohomology, e.g. Proposition 4.8.8 of <cite><a href=\"https://arxiv.org/pdf/2201.06120.pdf#page=109\">Absolute prismatic cohomology</a></cite>)</p>\n\n## Thursday, June 8, 2023\n\nThe thing I'm trying to prove is **_obviously false_**. Like, one of the most basic examples of a prism is a counterexample. Jesus I'm dumb.\n\n<p class=\"opacity-20 text-xs\">(Math ppl: I'm referring to the Hodge-Tate point of <katex>\\mathrm{WCart}</katex>, coming from <katex>V(1)</katex>, which is a counterexample since <katex>FV=p</katex>.)</p>\n\nNow, if the answer to \"what do crystalline prisms correspond to?\" isn't what I expected, then that question becomes much more interesting. It's interesting, but it's a lot more work, and I just want this \\*\\*\\*\\*ing paper to be done.\n\nWait—actually maybe this _isn't_ a counterexample. In this subject, there are **static** things and **animated** things. This counterexample is one of the standard examples of an _animated_ prism, but the question I'm working on is really only about _static_ things. So I did some googling, and yes, this counterexample will _never_ be static. So we're back in business!\n\n## Friday, June 9, 2023\n\n<p class=\"text-center font-bold text-2xl\">SUCCESS!!!</p>\n\nI proved what I wanted. It was a little bit subtle: it seemed like you should be able to do the proof in either of two ways, but actually one way was slightly better, and that was exactly what I needed.\n\nI excitedly messaged Noah on Discord, and said \"you do this and this and this, and after sufficiently many shenanigans, you get what you want.\" And Noah said, \"hmm, I'm not seeing the shenanigans\", and I told him, \"it's a bit sneaky, I'll write something up tonight\".\n\nBut it was time to celebrate, so I biked over to the Brooklyn Society for Ethical Culture for board game night. My team won at Secret Hitler (go Fascists!), and then at midnight we went to Union Hall for karaoke. I got home around 3:30am, so I didn't get back to Noah.\n\n## Saturday, June 10, 2023\n\nWoke up sometime after noon, started writing up the proof to send to Noah. That thing where it seemed like the proof should work in either of two ways, but actually it only worked in one? Yeah it actually just doesn't work. I'd gotten my head so tangled up in this problem that I ended up making a circular argument.\n\nThere's no happy ending to this story. I put out [the paper](https://arxiv.org/abs/2309.03181) in September, and I just left this as a conjecture.\n",
    "description": "",
    "duration": null,
    "meta": {
      "math": {
        "macros": ""
      }
    },
    "ownerId": "41786b7c-b873-4373-8ede-477bf85070a1",
    "publicationDate": "2024-06-15 23:40:16.340316 UTC",
    "slug": "crystalline",
    "title": "Crystalline prisms",
    "type": "article"
  },
  {
    "id": "fddcc78f-af38-4cb2-8fcf-e6a53825faa3",
    "content": "",
    "description": "",
    "duration": null,
    "meta": {},
    "ownerId": "41786b7c-b873-4373-8ede-477bf85070a1",
    "publicationDate": "2024-09-15 00:18:15.572 UTC",
    "slug": "",
    "title": "Popup demo",
    "type": "recording"
  },
  {
    "id": "1d6c0831-ae3d-47fa-a971-53aec8232fb2",
    "content": "",
    "description": "",
    "duration": null,
    "meta": {},
    "ownerId": "41786b7c-b873-4373-8ede-477bf85070a1",
    "publicationDate": "2024-10-15 08:18:46.365 UTC",
    "slug": "",
    "title": "Popup demo w/ video",
    "type": "recording"
  },
  {
    "id": "e7513c4e-b266-47aa-9b62-7102402ddfc9",
    "content": "",
    "description": "",
    "duration": null,
    "meta": {},
    "ownerId": "41786b7c-b873-4373-8ede-477bf85070a1",
    "publicationDate": "2024-06-15 23:40:16.340 UTC",
    "slug": "",
    "title": "broken",
    "type": "recording"
  },
  {
    "id": "7867ba76-ea6f-4d28-831b-f1ca7e6b6f8b",
    "content": "",
    "description": "",
    "duration": 365366,
    "meta": {
      "thumbs": "single",
      "origins": [
        "https://canvasconnect.its.virginia.edu"
      ],
      "tracks": [
        {
          "kind": "captions",
          "srclang": "en"
        }
      ]
    },
    "ownerId": "41786b7c-b873-4373-8ede-477bf85070a1",
    "publicationDate": "2025-01-17 23:37:36.338 UTC",
    "slug": "",
    "title": "SIR Python",
    "type": "recording"
  },
  {
    "id": "5781afb2-2877-4a4c-bc8b-ddbb8b0f3cbc",
    "content": "",
    "description": "",
    "duration": 41816,
    "meta": {},
    "ownerId": "4a4d8990-1de7-481e-be21-17d46c119e88",
    "publicationDate": "2025-02-07 20:29:41.288683 UTC",
    "slug": "",
    "title": "",
    "type": "recording"
  },
  {
    "id": "772469c8-3e46-4382-becf-d640e04bb4e9",
    "content": "So far we've been setting up a lot of abstract language to talk about geometry. Let's do something more concrete: how do we animate a character moving from point $\\a$ to point $\\b$?\n\n<!-- insert demo -->\n\nIn the language we set up in the last post, $\\a$ and $\\b$ are points in **affine** space. Their difference $\\b-\\a$ is a **vector**. If we add $\\b-\\a$ to $\\a$, we get $\\b$.\n\n\\[ \\b = \\a + (\\b-\\a) \\]\n\nSince $\\b-\\a$ is a vector, we can **scale** it. For example,\n\n\\[ \\a + \\tfrac12(\\b-\\a) \\]\n\nis the point $50\\%$ of the way between $\\a$ and $\\b$; similarly, $\\a+0.3(\\b-\\a)$ is $30\\%$ along the way from $\\a$ to $\\b$.\n\n:::definition\n  If $\\a$ and $\\b$ are points in an affine space, we write\n  \\[ \\lerp_\\t(\\a, \\b) \\Defeq \\a + \\t(\\b-\\a). \\]\n  This stands for :dfn[linear interpolation]. If we have to put a complicated expression for $\\t$, we might also use the notation $\\lerp(\\a,\\b;\\t)$.\n:::\n\nWe often restrict $\\t$ to $\\CIntvl 01$, although you could let it be bigger to \"overshoot\".\n\nIn terms of the abstract language we introduced [before](./params-coords), this is a **parametrization** of the line segment from $\\a$ to $\\b$.\n\nNote that this linear motion doesn't look very natural. A real object moving would accelerate when starting and decelerate towards the end. We'll address that in the next post.\n\nThere's two ways to remember the above formula. One is: start at $\\a$ and add some multiple of $\\b-\\a$ to move towards $\\b$. Another way is: let's rewrite this as\n\\[ \\a + \\t(\\b - \\a) = (1-\\t)\\a + \\t\\b \\]\nThen when $\\t=0$, this becomes\n\\[ (1-0)\\a + 0\\b = \\a \\]\nand when $\\t=1$, it becomes\n\\[ (1-1)\\a + 1\\b = 0\\a + 1\\b = \\b. \\]\n\nBut wait! We saw in [the last post](./affine) that it doesn't make sense to add or scale **points**, only vectors. However,\n\\[ \\a + \\t(\\b - \\a) \\]\n**does** make sense, so it turns out that\n\\[ (1-\\t)\\a + \\t\\b \\]\nmakes sense, even though $(1-\\t)\\a$ and $\\t\\b$ don't! In general, we can make sense of\n\\[ x\\a + y\\b \\]\nif and only if $x+y=1$. Basically, we can take **weighted averages** of points.\n\n## Code\n\nIn THREE.js, we have the methods [`Vector3.lerp()`](https://threejs.org/docs/?q=lerp#api/en/math/Vector3.lerp) and [`Vector3.lerpVectors()`](https://threejs.org/docs/?q=lerp#api/en/math/Vector3.lerpVectors) for lerping vectors.",
    "description": "",
    "duration": null,
    "meta": {
      "math": {
        "macros": "\\newcommand{\\a}{\\red a}\n\\newcommand{\\b}{\\blue b}\n\\newcommand{\\t}{{\\color{gold} t}}"
      }
    },
    "ownerId": "41786b7c-b873-4373-8ede-477bf85070a1",
    "publicationDate": "2024-06-15 23:40:16.340316 UTC",
    "slug": "lerp",
    "title": "Linear interpolation",
    "type": "article"
  },
  {
    "id": "ef51960f-fcc3-4dae-8241-537a5ac6135e",
    "content": "<!-- #tab notes -->\nIn the [previous post](./params-coords), we took a closer look at how we represent problems numerically. In this post, we'll intoduce some additional \"type safety\" into this prcess by distinguishing between two _types_ of quantities: **points** and **vectors**. You might also call these **absolute** and **relative** quantities, or **affine** and **vector** quantities. In the next post, we'll use this perspective to [build a draggable popup](./dragging).\n\n## Introduction\n\nLet's start with the example of **temperature**. Suppose the temperatures in a given week are as follows:\n\n<table>\n  <thead>\n    <tr>\n      <th></th>\n      <th>M</th>\n      <th>T</th>\n      <th>W</th>\n      <th>R</th>\n      <th>F</th>\n    </tr>\n  </thead>\n  <tbody>\n    <tr>\n      <th scope=\"row\">\n        <katex>{}^\\circ\\text{C}</katex>\n      </th>\n      <td>\n        <katex>0</katex>\n      </td>\n      <td>\n        <katex>5</katex>\n      </td>\n      <td>\n        <katex>10</katex>\n      </td>\n      <td>\n        <katex>20</katex>\n      </td>\n      <td>\n        <katex>15</katex>\n      </td>\n    </tr>\n    <tr>\n      <th scope=\"row\">\n        <katex>{}^\\circ\\text{F}</katex>\n      </th>\n      <td>\n        <katex>32</katex>\n      </td>\n      <td>\n        <katex>41</katex>\n      </td>\n      <td>\n        <katex>50</katex>\n      </td>\n      <td>\n        <katex>68</katex>\n      </td>\n      <td>\n        <katex>59</katex>\n      </td>\n    </tr>\n  </tbody>\n</table>\n\nLooking at the Celsius row, we might be tempted to say something like \"it was twice as hot on Wednesday as it was on Tuesday\", having the equation\n\\[ 2\\cdot 5 = 10 \\]\nin mind. But if we write the same equation in Fahrenheit, we'd get\n\\[ \\color{red} 2\\cdot 41 = 50  \\]\nwhich is wrong!\n\nOn the other hand, we could say \"it *got* twice as hot from Monday to Wednesday as it did from Monday to Tuesday\". In the Celsius case, we'd be thinking of the equation\n\\[ 2 \\cdot (5 - 0) = 10 - 0; \\]\nin the Fahrenheit case, we'd have the equation\n\\[ 2\\cdot(41 - 32) = 50 - 32, \\]\nand this equation is true.\n\nWhat's going on? \n\n## Operations\n\nThere are two distinct things we can mean by \"temperature\": an **absolute** temperature (how hot an object is, or the temperature outside), or a **relative** temperature, representing the **difference** between two absolute temperatures. The formulas for converting between these are different: for _relative_ temperatures, we just multiply or divide by $\\frac59$, whereas for _absolute_ temperatures we also have to offset by $32$.\n\nHere are some more examples of absolute vs relative quantities:\n\n- an _absolute_ time is a **datetime** like \"3:23pm April 19 1943\"; a _relative_ time is a **duration**, like \"4 minutes and 33 seconds\".\n\n- an _absolute_ position is a specific point in space, like the top of the Eiffel tower. A _relative_ position is something like \"2km north and 500m east\".\n\nWe will call relative quantities :dfn[vectors], and absolute quantities :dfn[points]. The \"allowed\" (or \"meaningful\") operations between these are\n\n- $\\ptxt{point} - \\ptxt{\\red point} = \\vtxt{\\green vector}$\n\n- $\\ptxt{point} + \\vtxt{vector} = \\ptxt{point}$\n\n- $\\vtxt{vector} + \\vtxt{vector} = \\vtxt{vector}$\n\n- $\\text{\\blue{number}} \\cdot \\vtxt{vector} = \\vtxt{vector}$\n\nHere are some demos of that in 2d and 3d space:\n\n::embed[{epiplexis-content}/gng/01-coordinates/06-points-vectors/operations]{appDir inline source width=150%}\n\nWhen you're working with numbers (i.e. once you've picked a [coordinate system](./params-coords)), you can't really tell the difference between points and vectors: you can add and multiply points willy-nilly. You'll run into problems, though, when you try to _change_ coordinate systems: if you do an \"illegal\" operation, you'll get different answers in different coordinate systems.\n\nLet's make a definition.\n\n:::definition\n  We write $\\AffR n$ for :dfn[$n$-dimensional affine space], consisting of $n$-tuples of real numbers:\n  \\[ \\AffR n \\Defeq \\{\\ipt{x_1,\\dotsc,x_n} \\mid x_i \\in \\R \\}. \\]\n  This is the same _set_ as $\\VecR n$; the only difference is what we're allowed to do with them. When we write $\\ipt{x_1,\\dotsc,x_n}$ instead of $\\ivec{x_1,\\dotsc,x_n}$, we're emphasizing that this represents an _absolute_ quantity rather than a relative one. In particular, we're not allowed to add elements of $\\AffR n$ together, nor multiply them by numbers.\n\n  When writing them vertically, I'll write\n  \\[ \\begin{bmatrix}x\\\\y\\\\z\\end{bmatrix}\\text{ for vectors,} \\qquad \\begin{pmatrix}x\\\\y\\\\z\\end{pmatrix} \\text{ for points}. \\]\n  This is admittedly not very consistent/logical.\n:::\n\n:::warning\n  My notation for distinguishing between points and vectors is not standard. Also, I will probably get lax about the difference from time to time. The important thing is to distinguish the two concepts in your mind.\n\n  Also: this use of \"point\" is specific to the context of linear algebra. Pretty much every object in math can get called a \"point\".\n:::\n\nLet's try to give a slightly more precise definition (although I don't want to be fully rigorous in the main series).\n\nIf vectors represent differences between points, we might think to define points first, and then vectors. But look back at the operations we can do: all the operations involving points also involve vectors, but adding and scaling of vectors doesn't involve points. So we can talk about vectors without mentioning points, but not vice versa.\n\nSecond, if the distinguishing property of vectors is that they can be added together with other vectors, and scaled by numbers to produce other vectors, then it doesn't make sense to talk about individual vectors in isolation.\n\n:::definition\n  A :dfn[vector space] is a set $V$ whose elements can be added together to produce other elements of $V$, and which can be multiplied by real numbers. More precisely, the data of a vector space is the set $V$ _along with_:\n  - a \"zero vector\" $0_V\\in V$;\n  - an \"addition\" operation $V\\times V\\xrightarrow+ V$\n  - a \"scalar multiplication\" operation $\\R\\times V\\xrightarrow\\cdot V$\n:::\n\nThese operations are required to satisfy several [axioms](https://en.wikipedia.org/wiki/Vector_space#Definition_and_basic_properties), such as $v+0_V=v$ and $u+v=v+u$.\n\n:::example\n  Let $V$ be the set of continuous functions $f\\colon R\\to\\R$. The \"zero vector\" is the constant function\n  \\[ 0_V(x) = 0. \\]\n  Addition and scalar multiplication are defined by\n  \\[ (f+g)(x) \\Defeq f(x) + g(x) \\qquad (cf)(x) \\Defeq cf(x) \\]\n  for $f,g\\In V$ and $c\\In\\R$.\n\n  For example, if $f(x)=\\cos(x)-2x^2$, and $g(x)=x^2+2^x$, then $f+2g\\in V$ is the function\n  \\[ (f+2g)(x) = \\cos(x)+2^{x+1}. \\]\n:::\n\nIt might be startling to think of _functions_ as vectors—but this perspective turns out to be very useful, for example when solving systems of differential equations. One of the benefits of the abstract perspective is that it allows us to extend the tools of linear algebra to situations we wouldn't have originally thought of.\n\nIn most situations there will be an obvious choice for the \"zero vector\", \"addition\", and \"scalar multiplication\". However, it should be stressed that these are **additional data** that needs to be specified along with the set $V$.\n\n:::example\n  Here's a funny example of a vector space. I'll use $\\oplus$ and $\\odot$ for the addition and scalar multiplication operations, so you don't get them confused with the usual operations.\n  - the underlying set of our vector space is $V=\\R_{>0}$, the set of positive real numbers\n  - the \"zero vector\" is $0_V=1$\n  - the \"addition\" operation is given by multiplication, $x\\oplus y\\Defeq xy$\n  - the \"scalar multiplication\" operation is given by exponentiation, $c\\odot x=x^c$\n\n  Can you see how this unusual vector space is actually the usual vector space $(\\R,0,+,\\cdot)$ \"in disguise\"?\n:::\n\n:::definition\n  Let $V$ be a vector space. An :dfn[affine space over $V$] is a set $A$ along with operations\n  \\[\\begin{align*}\n    A \\times A & \\xrightarrow- V\\\\\n    A \\times V &\\xrightarrow+ A\n  \\end{align*}\\]\n  These operations are required to satisfy [axioms](https://en.wikipedia.org/wiki/Affine_space#Definition) like\n  \\[\\begin{align*}\n    a + 0_V &= a\\\\\n    (a-b) + v &= a-(b+v)\n  \\end{align*}\\]\n  for $a,b\\In A$ and $v\\In V$. Beware that in the second equation, there are two different $+$ operations! The $+$ on the left-hand side is adding two elements of $V$ together, while the one on the right-hand side is adding an element of $A$ with an element of $V$.\n:::\n\n:::example\n  Vector and affine spaces come up naturally when solving linear equations (which is my main motivation for introducing the distinction). Let\n  \\[\\begin{align*}\n    V &= \\{\\ivec{x,y} \\mid y=3x\\}\\\\\n    A &= \\{\\ipt{x,y} \\mid y=3x+1\\}\n  \\end{align*}\\]\n  <iframe class=\"w-full mx-auto my-2\" src=\"https://www.desmos.com/calculator/s23v22wcxp\" height=\"400\"></iframe>\n  \n  Let's first check that $V$ is a vector space under the usual coordinate-wise addition and scaling. We need to show that if $\\ivec{x,y},\\ivec{\\cl x{x'},\\cl y{y'}}\\In V$, and $r\\In\\R$, then\n  \\[\\begin{align*}\n    \\ivec{x+\\cl x{x'},y+\\cl y{y'}} &\\In V\\\\\n    \\ivec{rx, {r}y} &\\In V\n  \\end{align*}\\]\n  By definition of $V$, we have $y=3x$ and $\\cl y{y'}=3\\cl x{x'}$. So\n  \\[\\begin{align*}\n    y + \\cl y{y'}\n      &= 3x + 3\\cl x{x'}\\\\\n      &= 3(x + \\cl x{x'})\n  \\end{align*}\\]\n  which shows that $\\ivec{x+\\cl x{x'},y+\\cl y{y'}}\\In V$. Similarly,\n  \\[\\begin{align*}\n    {r}y\n      &= r(3x)\\\\\n      &= 3(rx)\n  \\end{align*}\\]\n  which shows that $\\ivec{rx,{r}y}\\In V$.\n\n  Next, let's show that $A$ is **NOT** a vector space (using the usual addition formula). Let's take the two points $P=\\ipt{0,1}$ and $Q=\\ipt{1,4}$, both of which are in $A$. Then\n  \\[ P+Q=\\ipt{1,5}\\notin A \\quad\\text{since}\\quad 3\\cdot1+1=4\\ne 5 \\]\n  However, $A$ is an affine space over $V$. First we'll show that when we add elements of $A$ with elements of $V$, the result is still in $A$. For this, let $\\ipt{a,b}\\In A$ and let $\\ivec{x,y}\\In V$. This means that $b=3a+1$ and $y=3x$. Thus,\n \\[\\begin{align*}\n   b + y\n     &= (3a+1) + (3x)\\\\\n     &= 3(a+x)+1\n \\end{align*}\\]\n which shows that $\\ipt{a+x,b+y}\\In A$. Next, let $\\ipt{a,b},\\ipt{\\cl a{a'},\\cl b{b'}}\\In A$. Then\n \\[\\begin{align*}\n   b - b'\n     &= (3a+1) - (3\\cl a{a'}+1)\\\\\n     &= 3a - 3\\cl a{a'}\\\\\n     &= 3(a-\\cl a{a'})\n \\end{align*}\\]\n which shows that $\\ivec{a-\\cl a{a'},b-\\cl b{b'}}\\In V$.\n:::\n\n## Code\n\n### Graphics\nEvery graphics library will have methods for dealing with vectors. For example, in THREE.js the relevant class is [`THREE.Vector3`](https://threejs.org/docs/#api/en/math/Vector3).\n\nFew (if any) graphics libraries explicitly make the distinction between points and vectors. Still, remembering the distinction is helpful for understanding how to convert between different coordinate systems.\n\nIn computer graphics, the ambient \"affine space\" is called :dfn[world space]. The vector space centered at a particular object is called :dfn[object space]. (See [below](#dictionary) for what I mean by \"centered at\".)\n\n### DOM\n\nAnother example of points vs vectors comes from my favorite DOM method, [`getBoundingClientRect()`](https://developer.mozilla.org/en-US/docs/Web/API/Element/getBoundingClientRect). The return type of this is a [`DOMRect`](https://developer.mozilla.org/en-US/docs/Web/API/DOMRect), which (ignoring `readonly`) is\n\n```ts\ninterface DOMRect {\n    height: number;\n    width: number;\n    x: number;\n    y: number;\n  \n    readonly bottom: number;\n    readonly left: number;\n    readonly right: number;\n    readonly top: number;\n}\n```\n\nTo distinguish between points and vectors, we could type this more precisely as\n\n```ts\ninterface DOMRect {\n    height: Vector1;\n    width: Vector1;\n    x: Point1;\n    y: Point1;\n  \n    readonly bottom: Point1;\n    readonly left: Point1;\n    readonly right: Point1;\n    readonly top: Point1;\n}\n```\nHere a `Vector1` and a `Point1` are both just `number`s, but we're not allowed to add two `Point1`s together.\n\n### TypeScript\n\nThe above discussion of axioms and operations might have been a little abstract or confusing. The following code is an approximate TypeScript equivalent of what I was saying above. In particular, note that the operations `add()`, `scale()`, `sub()` have to be **specified/implemented**. \n\n```ts\n// helpers\n// https://stackoverflow.com/a/43674389\n\ninterface Type<T> {\n  // eslint-disable-next-line @typescript-eslint/no-explicit-any\n  new (...args: any[]): T;\n}\n\nfunction staticImplements<T>() {\n  return <U extends T>(constructor: U, _context: ClassDecoratorContext) => {\n    constructor;\n  };\n}\n\n// vector types\ninterface Vector<V> {\n  /** Add two vectors together */\n  add(other: V): V;\n\n  /** Scale a vector by a number */\n  scale(factor: number): V;\n}\n\ninterface VectorStatic<V> extends Type<Vector<V>> {\n  zero: V;\n}\n\n// implementation\n@staticImplements<VectorStatic<Vector2>>()\nexport class Vector2 {\n  constructor(\n    public x: number,\n    public y: number,\n  ) {}\n\n  static zero = new Vector2(0, 0);\n\n  /** Add two vectors together */\n  add(other: Vector2) {\n    return new Vector2(this.x + other.x, this.y + other.y);\n  }\n  \n  /** Scale a vector by a number */\n  scale(factor: number) {\n    return new Vector2(this.x * factor, this.y * factor);\n  }\n\n  /** Whether two vectors are equal */\n  static eq(u: Vector2, v: Vector2) {\n    return u.x === v.x && u.y === v.y;\n  }\n}\n\n// affine types\ninterface Affine<V, A> {\n  /** Add a vector to a point to get another point */\n  add(other: V): A;\n\n  \n  /** Subtract two points to get a vector */\n  sub(other: A): V;\n}\n\n@staticImplements<Type<Affine<Vector2, Point2>>>()\nexport class Point2 {\n  constructor(\n    public x: number,\n    public y: number,\n  ) {}\n\n  /** Add a vector to a point to get another point */\n  add(other: Vector2) {\n    return new Point2(this.x + other.x, this.y + other.y);\n  }\n\n  /** Subtract two points to get a vector */\n  sub(other: Point2) {\n    return new Vector2(this.x - other.x, this.y * other.y);\n  }\n  \n  /** Whether this point is equal to another */\n  eq(other: Point2) {\n    return this.x === other.x && this.y === other.y;\n  }\n}\n```\n\nNote we have to do a little bit of decorator weirdness to express this in TypeScript. Also, TypeScript has no way of expressing the constraints (axioms) these operations need to specify, e.g.\n\\[ a+(u+v) = (a+u)+v\\quad a\\In A;\\ u,\\,v\\In V \\]\nThe closest code equivalent would be\n```ts\nfunction assertVectorSpaceAxioms(u: Vector2, v: Vector2, w: Vector2, r: number) {\n  // zero vector is identity element for addition\n  // u + 0 = u\n  assert(Vector2.eq(\n    u.add(Vector2.zero),\n    u,\n  );\n  // 0 + u = u\n  assert(Vector2.eq(\n    Vector2.zero.add(u), // 0 + v\n    u,\n  );\n\n  // associativity: (u + v) + w = u + (v + w)\n  assert(Vector2.eq(\n    u.add(v).add(w), // (u + v) + w\n    u.add(v.add(w)), // u + (v + w)\n  ));\n\n  // commutativity: u + v = v + u\n  assert(Vector2.eq(\n    u.add(v),\n    v.add(u)\n  ));\n\n  // ...and so on (see Exercises)\n}\n```\n\nThese limitations are deficiencies of TypeScript, not of mathematics.\n\n## Dictionary\n\nOne of the reasons the distinction between points and vectors is confusing is that it's possible to convert between the two. However, there are **many** different ways to do this—more precisely, every point gives a _different_ way to convert between points and vectors. It works as follows:\n\nLet $V$ be a vector space, let $A$ be an affine space over $V$, and let $\\O$ be a point of $A$. The choice of $\\O$ gives a way to go back and forth between $A$ and $V$:\n\\[\\begin{align*}\n  f_\\O\\colon & A\\to V & g_\\O\\colon & V\\to A\\\\\n  f_\\O(a) &= a-\\O & g_\\O(v) &= \\O+v\n\\end{align*}\\]\nWe include the subscript $\\O$ to emphasize that these functions depend on the choice of \"origin\" point $\\O$. These functions are [bijections](https://mutualed.test/gng/cg/maps#terminology):\n\\[\\begin{align*}\n  g_\\O(f_\\O(a)) &= g_\\O(a-\\O) &\n  f_\\O(g_\\O(v)) &= f_\\O(\\O+v)\\\\\n    &= \\O + (a-\\O) &&= (\\O+v)-\\O\\\\\n    &= a &&= v\n\\end{align*}\\]\nso no information is lost in this process.\n\nThe rub is that this dictionary **depends on the chosen point $\\O$**. In some situations there may be an obvious \"origin\" point, but in others there may be none, and in most there are several. For example, in computer graphics our \"default\" origin is the top-left corner of the screen. But if you want to animate a fireball circling around a character, you want to position the fireball _relative to_ that character, meaning the center of that character's bounding box will be your origin.\n\nNote that every vector space is an affine space _over itself_: we already know how to add vectors to vectors, and we can define subtraction of vectors by combining addition and scalar multiplication:\n\\[ u - v \\Defeq u + (-1\\cdot v). \\]\n\n<!-- #tab videos -->\n<iframe allow=\"fullscreen\" class=\"w-full\" src=\"https://epiplexis.xyz/a/w7s/lesson/\" style=\"aspect-ratio: 8/5;\"></iframe>\n\n<!-- #tab exercises  -->\n\n1. Compute the following expressions if they make sense, or answer \"meaningless\" if they do not make sense.  \n    1. $\\pt12 - \\pt21$\n    2. $\\pt{-1}{\\frac12} + \\vec1{\\frac32}$\n    3. $\\pt10 + \\pt01$\n    4. $\\vec{-3}1 + \\vec22$\n    5. $\\vecc111 + \\vec21$\n    6. $2\\vec1{\\frac12}$\n    7. $2\\pt1{\\frac12}$\n    8. $2\\vecc1{\\frac32}{-1} - \\vecc0{\\frac12}{-1}$\n    \n    :::popup{trigger=Answer}\n    1. $\\vec{-1}1$\n    \n    2. $\\pt02$\n    \n    3. meaningless: can't add a point to a point\n    \n    4. $\\vec{-1}3$\n    \n    5. meaningless: can't add vectors of different sizes (more abstractly, can't add vectors belonging to different vector spaces)\n    \n    6. $\\vec21$\n    \n    7. meaningless: can't scale a point\n    \n    8. $\\vecc2{\\frac52}{-1}$\n    :::\n  \n2. \n    1. Write code equivalents (as in the `assert()` example) for the full list of [vector space axioms](https://en.wikipedia.org/wiki/Vector_space#Definition_and_basic_properties). For convenience, those axioms are:  \n       $$\n       \\begin{align*}  \n         0 + v &= v &&\\text{(identity for +)}\\\\  \n         (u+v)+w &= u+(v+w) &&\\text{(associativity of +)}\\\\  \n         u + v &= v + u &&\\text{(commutativity of +)}\\\\  \n         v+(-1\\cdot v) &= 0 &&\\text{(inverses for +)}\\\\  \n          1\\cdot v&=v &&\\text{(identity for multiplication)}\\\\  \n          (rs)v&=r(sv) &&\\text{(associativity for multiplication)}\\\\  \n          r(u+v) &= ru+rv &&\\text{(distributivity)}  \n       \\end{align*}\n       $$\n       Here $u,v,w\\In V$ and $r,s\\In\\R$, where $V$ is a vector space. Write code equivalents for these, as in the `assert()` example.\n       \n       :::popup{trigger=Answer}\n       ```ts\n       function assertVectorSpaceAxioms(\n         u: Vector2, v: Vector2, w: Vector2,\n         r: number, s: number,\n       ) {\n         // 1. identity for addition\n         assert(Vector2.eq(\n           v.add(Vector2.zero),\n           v,\n         );\n       \n         // 2. associativity\n         assert(Vector2.eq(\n           u.add(v).add(w), // (u + v) + w\n           u.add(v.add(w)), // u + (v + w)\n         ));\n       \n         // 3. commutativity\n         assert(Vector2.eq(\n           u.add(v),\n           v.add(u)\n         ));\n       \n         // 4. inverses\n         assert(Vector2.eq(\n           v.add(v.scale(-1)),\n           Vector2.zero\n         ));\n    \n         // 5. identity for multiplication\n         assert(Vector2.eq(\n           v.scale(1),\n           v\n         ));\n    \n         // 6. associativity for multiplication\n         assert(Vector2.eq(\n           v.scale(r*s), // (rs)v\n           v.scale(s).scale(r), // r(sv)\n         ));\n    \n         // 7. distributivity\n         assert(Vector2.eq(\n           (u+v).scale(r), // r(u+v)\n           u.scale(r).add(v.scale(r)), // ru + rv\n         ));\n       }\n       ```\n       :::\n   2. The full list of affine space axioms is:\n      $$\n       \\begin{align*}  \n         a + 0 &= a &&\\text{(identity for +)}\\\\  \n         (a+u)+v &= a+(u+v) &&\\text{(associativity of +)}\\\\  \n         a + (b-a) &= b &&\\text{(transitivity)}\\\\  \n         a + v = a &\\implies v=0 &&\\text{(freeness)}\n       \\end{align*}\n      $$  \n      Here $a,b\\In A$ and $u,v\\in V$, where $A$ is an affine space over $V$. Write code equivalents for these, as in the `assert()` example.\n     \n      :::popup{trigger=Answer}\n      ```ts\n      function assertAffineSpaceAxioms(\n        u: Vector2, v: Vector2,\n        a: Point2, b: Point2,\n      ) {\n        // 1. identity\n        assert(Point2.eq(\n          a.add(Vector2.zero),\n          a,\n        );\n      \n        // 2. associativity\n        assert(Point2.eq(\n          a.add(u).add(v), // (a + u) + v\n          a.add(u.add(v)), // a + (u + v)\n        ));\n      \n        // 3. transitivity\n        assert(Point2.eq(\n          a.add(b.sub(a)), // a + (b - a)\n          b,\n        ));\n\n        // 4. freeness\n        assert(\n          Point2.eq(a.add(v), a)\n          ===\n          Vector2.eq(v, Vector2.zero)\n        );\n      }\n      ```\n      :::\n      There are many equivalent ways of defining affine spaces, so you might see these stated a little differently in other places.\n      \n3. Verify the vector space axioms for the vector space $(\\R_{>0}, 1, \\oplus, \\odot)$ where $x\\oplus y=xy$ and $r\\odot x=x^r$ for $x,y\\In \\R_{>0}$ and $r\\in\\R$. Can you see how this vector space is secretly the usual vector space $(\\R,0,+,\\cdot)$ \"in disguise\"?  \n\n     :::popup{trigger=Solution}\n     The easiest way to do this is to use the [bijection](/gng/cg/maps#terminology)\n     $$\n       2^\\bullet\\colon \\R \\to \\R_{>0}\n     $$\n     (Any other base would do just as well, $2$ isn't special here.) This takes the vector space structure on $\\R$ into the vector space structure on $\\R_{>0}$, in the sense that\n     $$\n     \\begin{align*}\n       2^0 &= 1\\\\\n       2^{x+y} &= 2^x 2^y \\\\&= 2^x\\oplus 2^y\\\\\n       2^{rx} &= (2^x)^r \\\\&= r\\odot 2^x\n     \\end{align*}\n     $$\n     :::\n",
    "description": "",
    "duration": null,
    "meta": {
      "math": {
        "macros": "\\newcommand{\\vecc}[3]{\\begin{bmatrix}#1\\\\#2\\\\#3\\end{bmatrix}}\n\\newcommand{\\ptxt}[1]{\\text{\\red{#1}}}\n\\newcommand{\\vtxt}[1]{\\text{\\green{#1}}}\n"
      }
    },
    "ownerId": "41786b7c-b873-4373-8ede-477bf85070a1",
    "publicationDate": "2024-06-15 23:40:16.340316 UTC",
    "slug": "points-vectors",
    "title": "Points and vectors",
    "type": "article"
  },
  {
    "id": "90223085-936e-4026-a9d5-274685666450",
    "content": "Over the years, friends, family, and strangers have asked me if I can explain the math that I do. This is tricky; because math is so cumulative, even professional mathematicians usually can't understand each other's work very well unless they work in the same field. (This has the advantage of making it difficult to talk about work at parties.) This series is my attempt to share the stuff I think about and why I think it's so fun.\n\nMy area of math is called **homotopy theory**. Historically, this grew out of **topology**, which is a form of **geometry**. Nowadays, it's increasingly viewed as foundational to math itself, so it interacts with a lot of other fields. In particular, I'm very interested in how it interacts with a subject called **arithmetic geometry**, which tries to incorporate things like prime numbers into geometry. The field is in a bit of a golden age right now: major papers are being posted nearly every month, and decades-old problems are falling one after another. \n\n What I mainly do is study **prismatic cohomology** (a hot new thing in arithmetic geometry) from the perspective of **equivariant** homotopy theory. *Equivariant* means having to do with symmetry—in this case the rotational symmetry of a circle.\n\nI'll explain all these fancy words over the course of many posts! A hyper-condensed overview is at the end of this post.\n\nHomotopy theory has a very theoretical side and a heavily computational side; I started out more on the theory side, but now lean more towards calculations. I often make interactive widgets and pretty pictures to help myself understand what I'm doing; pictures are maybe a good thing to organize this series around. My first goal is to explain what's going on in the following diagram:\n\n<figure class=\"rounded-md bg-gray-200 shadow-md border-stone-900 p-2 mx-auto\">\n  <object\n    title=\"Numbers 1 through 27 with colored bars stacked on top. Every number has a red bar; multiples of 3 (additionally) have an orange bar; multiples of 9 have a yellow bar; and 27 has a green bar.\"\n    data=\"https://ysulyma.github.io/assets/q-legendre-3.svg\" width=\"100%\"></object>\n</figure>\n\nLater, I'll talk about this one:\n\n\n<figure class=\"rounded-md bg-gray-200 shadow-md border-stone-900 p-2 mx-auto max-w-xl\">\n  <img\n    class=\"w-full\"\n    alt=\"\"\n    src=\"https://ysulyma.github.io/assets/grid.svg\" />\n</figure>\n\nand maybe eventually these guys (zoom in or open in new tab):\n\n<div class=\"flex justify-between gap-4 my-4 mx-auto\">\n  <figure class=\"bg-gray-100 rounded-md p-2\">\n    <img\n      alt=\"64x64 checkerboard, light squares filled with colored shapes\"\n      src=\"https://ysulyma.github.io/assets/slice-2-perfd.svg\" />\n  </figure>\n    \n  <figure class=\"bg-gray-100 rounded-md p-2\">\n    <img\n      alt=\"64x64 checkerboard, light squares filled with colored shapes\"\n      src=\"https://ysulyma.github.io/assets/slice-good-2.svg\" />\n  </figure>\n</div>\n\n:::think\nWhat patterns can you find in the above charts? For the last two, the specific shapes used don't mean anything; all that matters is the distribution of colors and shape families.\n:::\n\n## Topology\n\nLet's start by thinking about how we represent points on a shape:\n\n<iframe class=\"aspect-video w-full\" src=\"https://ysulyma.github.io/epiplexis/what-study/topology-demo/dist/\"></iframe>\n\n[Source](https://github.com/ysulyma/epiplexis/tree/main/what-study/topology-demo)\n\nWe can represent a point on the blue curve by a number between 0 and 1 (between 0% and 100% along the curve, starting from the left). This is the same way we'd represent points on a straight line segment. We can _almost_ do the same thing on the purple star, but now 0% and 100% represent the same point. This is similar to how $0^\\circ,$ $360^\\circ,$ $720^\\circ,$ etc. all correspond to the same point on the circle.\n\n:dfn[Topology] is the study of \"how data gets represented\". The blue curve is topologically equivalent to a straight line, and the purple curve is topologically equivalent to a circle. Topology is also often described as \"rubber-band geometry\": topology considers two shapes to be the same if each can be transformed into the other by twisting or bending, _but no cutting or tearing_.\n\nHowever, the difference between _the straight line and the circle_ is very important. To some extent, \"every problem that can be described using numbers, we can solve, and there's a unique solution\". (This is extremely vague, but I have precise statements in mind.) But suppose the solution involves dividing by $3$. Well, $0/3$ is just $0,$ but $0^\\circ/3$ is $\\\\{0^\\circ,120^\\circ,240^\\circ\\\\}.$ When the basic operations we do on numbers are unavailable, or behave differently than usual, we're no longer able to \"solve every problem\".\n\n:dfn[Homotopy theory] goes a step further than topology and adds \"inflating and deflating\" to the list of operations that \"don't change a shape\". We can shrink a straight line down to a single point (the most trivial shape there is), so these are _homotopically_ equivalent (but not topologically). We can build a circle by taking a straight line and gluing the ends together. When we pass from topology to homotopy, we \"delete\" the straight line, so the gluing is the only information that's left. I like to think about this as: we understand numbers pretty well, so we want to ignore those and just focus on the \"redundancies\" or \"wrinkles\" in the representation of data.\n\n## Cohomology\n:dfn[Cohomology] is a quantitative way to describe these \"wrinkles\" or \"redundancies\". In its crudest form, cohomology associates a sequence of numbers (called :dfn[Betti numbers]) to every shape. Here are some examples:\n\n<object\n  class=\"magic-svg\"\n  data=\"/assets/betti-numbers.svg\" type=\"image/svg+xml\"\n  aria-label=\"Numbers of various shapes. A string with no crossings: 1; a string with one loop: 1, 1; one string with three loops and another with one loop: 2, 4; a sphere: 1, 0, 1; a torus: 1, 2, 1\"></object>\n\n(The two shapes above the $2,\\,4$ are considered a single shape; the $2$ means there are two pieces, or :dfn[connected components]. Also, $2,\\,4$ is really short for $2,\\,4,\\,0,\\,0,\\,0,\\,\\dotsc$)\n\nThere are many different :dfn[cohomology theories] that offer different interpretations of what these numbers mean, and also provide richer information beyond these numbers.\n\n- from the perspective of :dfn[singular cohomology], these numbers are counting the number of (higher-dimensional) \"holes\" or \"loops\" in a shape.\n\n- :dfn[de Rham cohomology] is based on *calculus*[^calculus]. Calculus is about *change*: e.g. *velocity* as the rate of change of *position*, or *acceleration* as the rate of change of velocity. Although $0^\\circ$ and $360^\\circ$ represent the same point on a circle, an angular **_velocity_** of $360^\\circ\\text{ / sec}$ is very different from an angular velocity of $0^\\circ\\text{ / sec}$. So de Rham cohomology sees a numeric quantity (angular velocity) that looks like the rate of change of some other quantity (angle), but the original quantity is \"missing\".\n\nIf you kind of already know what your shape looks like, you can calculate its cohomology using any cohomology theory. But what if someone just hands you some random equations? De Rham cohomology is fairly easy to calculate \"mechanically\"—we can program computers to do calculus. But singular cohomology is very abstract, and literally impossible to calculate directly for anything beyond discrete points.\n\nDespite this, singular cohomology has some advantages over de Rham cohomology. Think about the distinction between a **line** (through the origin) and a **direction**: you can travel in two directions on every line. This \"2:1 redundancy\" shows up in many places: it's responsible for the \"plate trick\" seen below, as well as the phenomenon of [gimbal lock](https://en.wikipedia.org/wiki/Gimbal_lock). Gimbal lock causes problems in aviation and 3d graphics, necessitating the use of [quaternions](https://en.wikipedia.org/wiki/Quaternions) for doing rotations. (Rotations in 3d space are (non-obviously) topologically equivalent to lines through the origin in 4d space; unit quaternions are directions in 4d space.)\n\n<figure class=\"mx-auto my-2 max-w-[400px] text-center\">\n  <img alt=\"Woman rotating a coffee mug in her hand. Once the cup is returned to its original position, her arm is still twisted. After another full rotation, her arm is in a normal position.\" src=\"https://ysulyma.github.io/assets/plate-trick.png\" />\n  <figcaption>Taken from Bredon, <cite>Topology and Geometry</cite>.</figcaption>\n</figure>\n\nHopefully this convinces you that understanding \"2:1\" redundancies is important. Unfortunately, de Rham cohomology can only detect \"∞:1\" redundancies; singular cohomology can detect \"finite:1\" redundancies, but is much harder to compute. **Prismatic cohomology** is a fancier version of de Rham cohomology, based on a fancier version of calculus, which is able to detect \"finite:1\" redundancies, while remaining fairly computable.\n\nThe circle (infinitely many angles corresponding to the same point) is the simplest example of cohomology. It is also the _universal_ example: if you think hard enough about the circle, you can deduce the entire theory of de Rham cohomology. (I don't know why this should be true, or if this is even a good way of thinking about it.) In particular, the **rotational symmetries** of the circle play a central role in prismatic cohomology.\n\nWhat I mainly do these days is think about prismatic cohomology from the perspective of these rotational symmetries. There are many other perspectives; this one is historically the first, but the subsequent ones that were discovered are much simpler for most purposes, so this one has been neglected. However, I've shown that it illuminates some of the more advanced aspects of the theory.\n\nMy main project right now is trying to generalize prismatic cohomology to accommodate other kinds of symmetry. Circles also have **reflectional** symmetry, in addition to rotational. It's slightly harder to get \"even:1\" information out of prismatic cohomology than \"odd:1\", and it's thought that incorporating the reflectional symmetries might explain this. There are several people working on this, from different perspectives than mine, and I'm trying to understand how my approach compares to theirs.\n\nI'm also interested in plugging in completely different kinds of symmetry, like that of a triangle or square. It's less clear what this would be useful for.\n\n[^calculus]: I mean *differential* calculus here, which is about instantaneous rates of change. There's also *integral* calculus which is about the reverse: accumulated change over time. In cohomology land, the connection between differential and integral calculus (the fundamental theorem of calculus) translates to the fact that singular and de Rham cohomology give the same Betti numbers.\n",
    "description": "",
    "duration": null,
    "meta": {
      "math": {
        "macros": ""
      }
    },
    "ownerId": "41786b7c-b873-4373-8ede-477bf85070a1",
    "publicationDate": "2024-06-15 23:40:16.340316 UTC",
    "slug": "intro",
    "title": "Introduction",
    "type": "article"
  },
  {
    "id": "eeb4e10a-9637-49e6-9af3-3e1440238f56",
    "content": "Now for a definition. Let $X$ and $Y$ be spaces. A map $f\\colon X\\to Y$ is called an :dfn[isomorphism] if there is a map $g\\colon Y\\to X$ such that\n\\[ g\\circ f = \\id_X \\quad\\text{and}\\quad f\\circ g = \\id_Y. \\]\nMore explicitly,\n\\[\\begin{align*}\n  g(f(x)) &= x \\quad\\text{for all }x\\in X\\\\\n  f(g(y)) &= y \\quad\\text{for all }y\\in Y\n\\end{align*}\\]\nBasically, $f$ is a way to transport problems in $X$ to problems in $Y$. The identity $g(f(x))=x$ says that you can still recover $x$ after running it through $f$, so \"no information is lost\" about your original equation.\n\n<!-- need xymatrix for commutative diagrams here -->\n\n## Uniqueness\n\nAbove, we asked for **some** $g$ to exist, such that $gf=\\id_X$ and $fg=\\id_Y$. Could there be multiple of them?\n\n:::proposition\n  Let $f\\colon X\\to Y$, and let $g,h\\colon Y\\to X$ be a left and right inverse of $f$ respectively (meaning that $g\\circ f=\\id_X$ and $f\\circ h=\\id_Y$). Then $g=h$.\n\n  :::proof\n    We want to show that $g(y)=h(y)$ for all $y\\in Y$. We know that\n    \\[\n      \\blue{f(h(y)) = y}\n      \\quad\\text{and}\\quad\n      \\red{g(f(x)) = x}\n    \\]\n    for all $x\\in X$ and all $y\\in Y$. We can write\n    \\[\\begin{align*}\n      g(y)\n        &= g(f(h(y))) &&\\text{since } \\blue{y = f(h(y))}\\\\\n        &= g(f(x)) &&\\text{with } x = h(y)\\\\\n        &= x &&\\text{since } \\red{g(f(x)) = x}\\\\\n        &= h(y) &&\\text{by definition of }x\n    \\end{align*}\\]\n:::\n\nWe also could have written the above proof in \"functional notation\"\n\\[\\begin{align*}\n  g &= g\\circ\\id_Y\\\\\n    &= g\\circ(f\\circ h)\\\\\n    &= (g\\circ f)\\circ h\\\\\n    &= \\id_X\\circ h\\\\\n    &= h\n\\end{align*}\\]\n\nSince inverses are unique if they exist, we'll write $f^{-1}$ for the inverse of a map $f$.\n\n<!-- insert warning about f^-1 applied to sets -->\n\n<!-- left vs right inverses (above) -->\n\n## Equality\n\n<!-- bill clinton quote -->\n\nWhen we talked about [products](./products), we noted that the spaces\n\\[ (X\\times Y)\\times Z \\quad\\text{and}\\quad X\\times(Y\\times Z) \\]\nor the types\n<div class=\"text-center\">\n <code>[[X, Y], Z]</code> and <code>[X, [Y, Z]]</code> \n</div>\nwere technically different, but \"equivalent for all purposes\", since there's an obvious way to convert between them:\n\\[ ((x, y), z) \\leftrightarrow (x, (y, z)) \\]\n\nAbove, we saw that an arbitrary interval $\\CIntvl ab$ is essentially interchangeable with the unit interval $\\CIntvl01$.\n\n",
    "description": "",
    "duration": null,
    "meta": {
      "math": {
        "macros": "\\newcommand{\\id}{\\mathrm{id}}\n"
      }
    },
    "ownerId": "41786b7c-b873-4373-8ede-477bf85070a1",
    "publicationDate": "2024-06-15 23:40:16.340316 UTC",
    "slug": "isos",
    "title": "Isomorphism",
    "type": "article"
  },
  {
    "id": "4a1291cc-75e5-4ad7-9af7-e8a3f1092cd8",
    "content": "::unit[gng]\n\n::unit[what-study]\n\n::unit[logs]\n\n[Old site](https://epiplexis.xyz)\n",
    "description": "",
    "duration": null,
    "meta": {
      "math": {
        "macros": "% misc\n\\newcommand{\\twopi}{\\varpi}\n\\newcommand{\\twopi}{\\varpi}\n\\newcommand{\\<}{\\left\\langle}\n\\newcommand{\\>}{\\right\\rangle}\n\\newcommand{\\In}{\\htmlData{annotation_text=in / element of}{\\in}}\n\n\n\\newcommand{\\<}{\\left\\langle}\n\\newcommand{\\>}{\\right\\rangle}\n\\newcommand{\\In}{\\htmlData{annotation_text=in / element of}{\\in}}\n\n% algebra\n\\newcommand{\\im}{\\operatorname{im}}\n\n% prisms and THH\n\\ktxnewcommand{\\prism}{\\htmlClass{prism}}{\\Delta}\n\n\\newcommand{\\THH}{\\operatorname{THH}}\n\\newcommand{\\TC}{\\operatorname{TC}}\n\\newcommand{\\TCmin}{\\TC^-}\n\\newcommand{\\TP}{\\operatorname{TP}}\n\\newcommand{\\TF}{\\operatorname{TF}}\n\\newcommand{\\TR}{\\operatorname{TR}}\n\n% equivariant\n\\newcommand{\\rog}{\\bigstar}\n\n\\newcommand{\\m}{\\underline}\n\\newcommand{\\mpi}{\\m\\pi}\n\n% sets\n\\newcommand{\\A}{\\mathbf A}\n\\newcommand{\\C}{\\mathbf C}\n\\newcommand{\\F}{\\mathbf F}\n\\newcommand{\\G}{\\mathbf G}\n\\newcommand{\\L}{\\mathrm L}\n\\newcommand{\\H}{\\mathbf H}\n\\newcommand{\\N}{\\mathbf N}\n\\newcommand{\\O}{\\mathcal O}\n\\newcommand{\\P}{\\mathbf P}\n\\newcommand{\\Q}{\\mathbf Q}\n\\newcommand{\\R}{\\mathbf R}\n\\newcommand{\\T}{\\mathbf T}\n\\newcommand{\\Z}{\\mathbf Z}\n\n\\newcommand{\\RP}{\\mathbf{RP}}\n\\newcommand{\\CP}{\\mathbf{CP}}\n\n\n% TODO move these to per-unit\n\\newcommand{\\green}[1]{\\htmlStyle{color: ##16a34a;}{#1}}\n\\newcommand{\\red}[1]{\\htmlStyle{color: ##dc2626;}{#1}}\n\\newcommand{\\blue}[1]{\\htmlStyle{color: ##2563eb;}{#1}}\n\\newcommand{\\indigo}[1]{\\htmlStyle{color: ##6366f1;}{#1}}\n\\newcommand{\\violet}[1]{\\htmlStyle{color: ##8b5cf6;}{#1}}\n\n\\newcommand{\\Twopi}{\\htmlData{annotation_text=ratio of a circle's circumference to its radius, $\\approx6.28\\dots$}{\\twopi}}\n\n\\newcommand{\\Defeq}{\\htmlData{annotation_text=defined to be equal to}{\\mathrel{:=}}}\n\n\\newcommand{\\Restrict}[2]{\\htmlData{annotation_text=$#1$ with domain restricted to $#2$}{{#1}|_{#2}}}\n\n\\newcommand{\\comma}{,}\n"
      }
    },
    "ownerId": "41786b7c-b873-4373-8ede-477bf85070a1",
    "publicationDate": "2024-06-15 23:40:16.340316 UTC",
    "slug": "#",
    "title": "Epiplexis",
    "type": "root"
  },
  {
    "id": "ed4972a8-cc94-4255-b5df-0aa56e69c0c5",
    "content": "This is a series of \"research diary\" entries. Here, rather than trying to deeply explain the math, I just want to give a window into the _process_ of math research—especially how winding and full of confusion it is, and how it intertwines with the rest of my life.\n\n::unit[crystalline]\n",
    "description": "",
    "duration": null,
    "meta": {
      "math": {
        "macros": ""
      }
    },
    "ownerId": "41786b7c-b873-4373-8ede-477bf85070a1",
    "publicationDate": "2024-06-15 23:40:16.340316 UTC",
    "slug": "logs",
    "title": "Research logs",
    "type": "collection"
  },
  {
    "id": "73320725-bb2d-479f-97d1-daa14a4d0874",
    "content": "In this post I'm going to talk about writing numbers in different bases.\n\nOur usual way of writing numbers is in _base 10_. This means we represent a number as a sum of multiples of powers of 10. For example,\n\n\\[\\begin{align*}\n  324 &= 300 + 20 + 4\\\\\n      &= 3\\cdot100 + 2\\cdot 10 + 4\\cdot1\\\\\n      &= \\mathbf 3\\cdot10^2 + \\mathbf 2\\cdot 10^1 + \\mathbf 4\\cdot10^0\n\\end{align*}\\]\n\nWriting numbers in another base means we replace 10 with some other number. For example, $13$ is written as $1101$ in binary (base 2), because\n\n\\[\\begin{align*}\n  13 &= 8 + 4 + 1\\\\\n     &= 1\\cdot8 + 1\\cdot4 + 0\\cdot2 + 1\\cdot1\\\\\n     &= \\mathbf 1\\cdot2^3 + \\mathbf 1\\cdot2^2 + \\mathbf 0\\cdot2^1 + \\mathbf 1\\cdot2^0\n\\end{align*}\\]\n\nWe can indicate the base with a subscript: $13_{10} = 1101_{2}$. Note we're still using base 10 to write the subscript.\n\nIf the base is bigger than 10, we need symbols to go beyond the existing digits $0,1,2,3,4,5,6,7,8,9$. Traditionally, this is done using letters. So for instance, A represents 10, B represents 11, and so on, and F represents 15. For example, $173$ in \"hexadecimal\" (base 16) is $\\mathrm{AD}_{16}$, because\n\n\\[\\begin{align*}\n  173_{10} &= 10\\cdot 16 + 13\\cdot 1\\\\\n           &= \\mathbf A\\cdot16^1 + \\mathbf D\\cdot16^0\n\\end{align*}\\]\n\n:::think\n  How many words can you spell in hexadecimal? What are their decimal values? For example, $\\mathrm{BEEF}_{16}=48,879$.\n:::\n\nHere's a demo so you can see how this works with different numbers:\n\n::embed[{epiplexis-content}/what-study/01-legendre/02-digits/table]{inline source}\n\nThere's no _mathematical_ reason to choose 10 as our base, it's just a _cultural_ convention (probably due to us having ten fingers). For example, the Babylonians used base 60 (\"sexagesimal\"), and the Mayans used base 20 (\"vigesimal\"). Hexadecimal is used fairly often in computing.\n\nThe same idea works to the right of the \"decimal point\". For instance, $0.75_{10} = 0.11_{2}$, because\n\n\\[\\begin{align*}\n  0.75_{10} &= 0.5 + 0.25\\\\\n             &= \\mathbf 1\\cdot 2^{-1} + \\mathbf1 \\cdot{2^{-2}}\n\\end{align*}\\]\n\n## Converting\n:::example\n  Let's see how to convert bases by hand. We'll write $\\red{420}$ in base $\\blue{16}$. The remainder when $\\red{420}$ is divided by $\\blue{16}$ is $\\green4$, which we write as $\\red{420}\\equiv\\green4\\bmod\\blue{16}$. This tells us that the last hexadecimal digit of $\\blue{16}$ is $\\green4$.\n\n  Next, $\\red{420}-\\green4=\\red{416}$ is divisible by $\\blue{16}$. We divide $\\red{416}$ by $\\blue{16}$ to get $\\frac{\\red{416}}{\\blue{16}}=\\red{26}$. Now we have $\\red{26}\\equiv\\green{10}\\bmod\\blue{16}$, so the second-last (\"tens\") hexadecimal digit of $\\red{420}$ is $\\green{\\mathrm A}$ (which we use for the number $\\green{10}$).\n\n  Again we subtract $\\red{26}-\\green{10}=\\red{16}$, which divided by $\\blue{16}$ is $\\green1$. So $\\red{420}$ in hexadecimal is\n \\[ \\red{420}_{10} = \\green{\\mathrm{1A4}}_{\\blue{16}}. \\] \n Again, remember that this means\n \\[ \\red{420} = \\green4\\cdot\\blue{16}^0 + \\green{10}\\cdot\\blue{16}^1 + \\green1\\cdot\\blue{16}^2 \\fade{{}+\\green0\\cdot\\blue{16}^3+\\dotsb} \\]\n The algorithm we used above basically works by writing this as\n \\[ \\red{420} = \\green4\\cdot\\blue{16}^0 + \\blue{16}\\cdot(\\green{10} + \\blue{16}\\cdot(\\green1\\fade{{} + \\blue{16}\\cdot(\\green0 + \\dotsb)})). \\]\n:::\n\nHere's an implementation of that in code. We can check our work against the built-in [`Number.prototype.toString()`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number/toString) method.\n\n```ts\n// !interactive\nconst num = 420;\nconst base = 16;\n\n// built-in function\nconsole.log(`built-in: ${num.toString(base)}`);\n// implementing it ourselves\nconsole.log(`    ours: ${writeInBase(num, base)}`)\n\n/** Write a number in another base. */\nfunction writeInBase(\n  num,\n  base,\n  alphabet = \"0123456789abcdefghijklmnopqrstuvwxyz\"\n) {\n  if (base > alphabet.length) {\n    throw new RangeError(`Maximum base is ${alphabet.length}`);\n  }\n  \n  const digits = [];\n\n  // handle 0\n  if (num === 0) return \"0\";\n\n  // handle negative numbers\n  if (num < 0) return \"-\" + writeInBase(num, base);\n  \n  while (num > 0) {\n    const remainder = num % base;\n    digits.push(alphabet[remainder]);\n\n    num = (num - remainder) / base;\n  }\n\n  return digits.reverse().join(\"\");\n}\n```\n\n:::think\n  Can you modify the above algorithm to handle decimals, e.g. $420.1137$?\n:::\n\n## Uses\n\nAlthough the vast majority of what we do is in base 10, there are a handful of places where we make use of other bases. Here are a few:\n\n### Colors\nIf you grew up in the 90s, you may remember `[color=#FF0000]` or `<FONT COLOR=\"#ffffff\">` from forums and GeoCities. What do these mean?\n\nOn a computer, colors are represented by red, blue, and green (RGB) components, each between $0$ and $255$. Since $255 = 256 - 1 = 2^8 - 1 = 100_{16}-1$, this is between $0$ and $\\mathrm{FF}_{16}$ when written in hexadecimal. For example, <span style=\"color:#FF0060;\">#FF0060</span> is $255$ red, $0$ green, and ${60}_{16}=96$ blue. Here's a demo where you can experiment with this in general: \n\n::embed[{epiplexis-content}/what-study/01-legendre/02-digits/colors]{class=mt-2 inline source}\n\n### URLs\nVery high bases are sometimes used to make short URLs, e.g. [https://old.reddit.com/11jznte/](https://old.reddit.com/11jznte/) or [https://youtu.be/dQw4w9WgXcQ](https://youtu.be/dQw4w9WgXcQ). In their database, this thread has some numeric ID like `1298482891`, and `11jznte` is that number written in some base. I'm not sure exactly which base they chose: if we use capital and lower letters, the digits 0–9, and hyphens and underscores, then we get\n\\[ 2\\cdot26 + 10 + 2 = 64 \\]\nas a base. But it's best to omit e.g. capital O and lowercase l, so we don't get confused between `0O1l`, so in practice it's more likely to be base 62 or smaller.\n\n<!-- ::embed[{epiplexis-content}/what-study/01-legendre/02-digits/switches]{aspect-ratio=2.5} -->\n\n## What does it mean?\n\nSo, a given number can be represented many different ways. What can we learn about a given number by writing in various different bases? Let's look at a few different examples of this, and then a conceptual way of organizing it.\n\n### Rationality\n\nWe have names for different kinds of numbers.\n\n- the :dfn[natural numbers] are $0,1,2,\\dots$\n- the :dfn[integers] are $\\dots,-2,-1,0,1,2,\\dots$\n- a :dfn[rational] number is one that can be expressed as a _ratio_ of integers. For example, $\\frac12$, $\\frac53$, $-\\frac{12}7$, and so on.\n- numbers which aren't rational are called :dfn[irrational]. For example, $\\pi$ and $\\sqrt2$ are irrational.\n\nRationality can be seen in the digit representation of a number: a _rational_ number will always have a repeating pattern of digits. For example,\n\n\\[\\begin{align*}\n  \\frac{4}{11} &= 0.36363636\\dots\\\\\n\\end{align*}\\]\nwhich we write as\n\\[\\begin{align*}\n  \\phantom{\\frac{4}{11}} &= 0.\\overline{36}\\phantom{363636\\cdots}\n\\end{align*}\\]\n\nThis includes the case of a _terminating_ expression, which we can think of as a repeating $0$. In fact, every rational number has a _terminating_ expression in _some_ base. For example, we have\n\\[ 11/9 = 1.\\overline2_{10} = 1.12_6 = 1.02_3. \\]\nwhich terminates in bases 3 and 6 but repeats infinitely in base 10.\n\nIrrational numbers, on the other hand, never fall into a repeating pattern. (This doesn't mean there's \"no pattern\" to their digits, just that it can't be expressed so simply.)\n\n### Last digits\n\nLet's start by thinking about what the _last_ digit of an integer written in binary means. The numbers $0$ through $7$ written in binary are\n\\[ \\blue0,\\, \\red1,\\, 1\\blue0,\\, 1\\red1,\\, 10\\blue0,\\, 10\\red1,\\, 11\\blue0,\\, 11\\red1 \\]\nNotice that: **the last binary digit of a number tells us whether it's odd or even!**\n\nIn many situations, this is all we need to know about the number. For example, suppose you leave a room with the lights on, and come back later and the lights are off. You know that the light switch must have been flipped an **odd** number of times, but the exact number of times isn't relevant.\n\nIn general: the last digit of a number in base $b$ is its **remainder** when divided by $b$.\n\nWhat about, say, the first digit? It turns out that this is harder to interpret. To see why, let's consider two addition problems, where some of the numbers are covered up.\n\n\\[\n  \\begin{align*}\n        ?7\\\\\n    {}+{?4}\\\\\\hline\n    ??1\n  \\end{align*}\n  \\qquad\n  \\begin{align*}\n        7?\\\\\n    {}+{2?}\\\\\\hline\n    ???\n  \\end{align*}\n\\]\n\nFor example, the first of these could be either of the concrete problems\n\n\\[\n  \\begin{align*}\n       37\\\\\n    {}+64\\\\\\hline\n    101\n  \\end{align*}\n  \\qquad\n  \\begin{align*}\n       17\\\\\n    {}+24\\\\\\hline\n    41\n  \\end{align*}\n\\]\n\nAlthough these give different answers, the _last digit_ is the same between the two answers.  But in the second case, we can't pin down any of the digits for sure, not even the tens. For example, we could have either of\n\\[\n  \\begin{align*}\n       73\\\\\n    {}+25\\\\\\hline\n       98\n  \\end{align*}\n  \\qquad\n  \\begin{align*}\n       75\\\\\n    {}+29\\\\\\hline\n      104\n  \\end{align*}\n\\]\nAt most we can say that the middle $?$ is either $9$ or $0$.\n\nIn other words: to figure out the last digit of $a+b$, you just need to know the last digit of $a$ and of $b$. But to know the _second-last_ digit of $a+b$, you need to know the _last two_ digits of $a$ and $b$, since there could be _carries_ from the last digit.\n\n:::yell\n  Knowing the last $k$ digits of a number written in base $b$ is the same as knowing its remainder when divided by $b^k$.\n:::\n\nHow do different bases relate? Let's write the last digits of the numbers $0$ through $9$ in bases $2$, $5,$ and $10$.\n\n::embed[{epiplexis-content}/what-study/01-legendre/02-digits/endings]{inline}\n\nNotice that: **knowing the last digit of $n$ in base $10$ is the same as knowing its last digit in base $2$ and in base $5$!**\n\nLet's try this for $2$ and $4$:\n\n::embed[{epiplexis-content}/what-study/01-legendre/02-digits/endings-24]{inline}\n\nHere we don't have quite the same pattern as above: knowing the last digit in base $4$ isn't the same as \"knowing the last digit in base $2$ and also in base $2$.\" Instead, **knowing the last digit of $n$ in base $4$ is the same as knowing its last _two_ digits in base $2$**.\n\n:::yell\n  If $b$ and $c$ have no factors in common, then knowing the last however many digits in base $bc$ is the same as knowing the last that many digits in bases $b$ and $c$.\n\n  At the opposite end, knowing the last $k$ digits in base $b^r$ is the same as knowing the last $rk$ digits in base $b$.\n:::\n\n:::example\n  Let's take $b=360$. The prime factorization of this is $360=2^3 \\cdot 3^2 \\cdot 5$. Thus, to know the last $2$ digits of a number in base $360$ is the same as knowing\n  - its last $6$ digits in base $2$, i.e. its remainder when divided by $2^6=64$; \n  \n  - its last $4$ digits in base $3$, i.e. its remainder when divided by $3^4=81$;\n  \n  - its last $2$ digits in base $5$, i.e. its remainder when divided by $5^2=25$.\n:::\n\n### The function analogy\n\nWriting a number in base $b$,\n\\[ n = n_0 b^0 + n_1 b^1 + n_2 b^2 + \\dotsb \\]\nlooks very similar to writing a polynomial in one variable $x$:\n\\[ f(x) = a_0 x^0 + a_1 x^1 + a_2 x^2 + \\dotsb \\]\n\nFor example, the number\n\\[ 4,321 = 1 + 2\\cdot 10 + 3\\cdot10^2 + 4\\cdot10^3 \\]\nlooks very similar to the polynomial\n\\[ f(x) = 1 + 2x + 3x^2 + 4x^3. \\]\nIn particular, $4,321=f(10)$.\n\nSo, is it possible to either view\n- polynomials as \"numbers in base $x$\", or alternatively\n- integers as \"functions in the variable $b$\"?\n\nThe main difference between the two situations is that to add two polynomials, you just add the coefficients together:\n\\[\\begin{align*}\n    &{}\\phantom= (1+2x+3x^2+4x^3) + (5+9x+6x^2+x^3)\\\\\n    &= (1+5) + (2+9)x + (3+6)x^2 + (4+1)x^3\\\\\n    &= 6 + 11x + 9x^2 + 5x^3\n\\end{align*}\\]\nbut when adding two numbers, we have to **carry**:\n\\[\\begin{align*}\n  4,321 + 1,695\n    &= (1+5) + (2+9)\\cdot10 + (3+6)\\cdot10^2 + (4+1)\\cdot10^3\\\\\n    &= 6 + \\red11\\cdot10 + 9\\cdot10^2 + 5\\cdot10^3\\\\\n    &= 6 + 1\\cdot10 + \\red10\\cdot10^2 + 5\\cdot10^3\\\\\n    &= 6 + 1\\cdot10 + 0\\cdot10^2 + 6\\cdot10^3\\\\\n    &= 6,016\n\\end{align*}\\]\n\nSo in this analogy, polynomials are actually easier to work with than numbers! So we should take the _second_ of the above suggestions: that is, try to understand integers as ``functions in the variable $b$''.\n\nThere's a ton of math research around trying to flesh out this analogy; it broadly goes under the name of the \"function analogy\" or the \"philosophy of the [field with one element](https://en.wikipedia.org/wiki/Field_with_one_element)\" (but it will take quite a while to explain that name). The stuff I think about is part of or adjacent to one of the main approaches to doing so (but there are several others). Basically, we understand polynomials very very well, so we could try to take the tools we have for working with polynomials and translate them through this analogy to get very powerful tools for understanding integers and prime numbers and so on.\n\nCarrying is just one way that base expansions are harder to work with than polynomials. Another major one is that we can contemplate polynomials in _multiple variables_, e.g.\n\\[\n  x^2 + 2xy + y^2\n  \\quad\\text{or}\\quad\n  z^2-xy\n\\]\nWe really don't know what the analogue of this would be for numbers, i.e. how to \"mix bases\". In the past 10 years, there's been an explosion of activity in this area, and we now have very precise _glimpses_ of _parts_ of what this ought to be. These are very exciting, but we definitely don't have the full picture yet.\n\nWhat would be a satisfactory answer to \"fleshing this out\"? And relatedly, what would such a thing be good for?\n\nThe [Riemann hypothesis](https://en.wikipedia.org/wiki/Riemann_hypothesis) is widely considered the most important unsolved problem in math. It's a technical statement about complex numbers, but basically it gives an extremely precise description of the distribution of prime numbers, i.e. what is the probability that a randomly chosen number will be prime? There's a \"polynomial\" version of the Riemann hypothesis, which is still extremely difficult, but was proven in 1974. So one proposed strategy for proving the original Riemann hypothesis is to take that proof and translate it through this analogy—but that gets stuck due to not being able to talk about \"multi-base numbers\".\n\nConversely, this provides a way of assessing claims of \"making sense of the function analogy\". There's lots and lots of ideas about how to do this—but until we can prove the Riemann hypothesis, we haven't found the \"one true way\" (if there is one).\n\nI'll devote a future chapter to explaning the function analogy in more detail.",
    "description": "",
    "duration": null,
    "meta": {
      "math": {
        "macros": "\\newcommand{\\fade}[1]{\\htmlStyle{opacity:0.2;}{#1}}}"
      }
    },
    "ownerId": "41786b7c-b873-4373-8ede-477bf85070a1",
    "publicationDate": "2024-06-15 23:40:16.340316 UTC",
    "slug": "bases",
    "title": "Different bases",
    "type": "article"
  },
  {
    "id": "83831908-8ad2-4a60-b457-36c3b0752c14",
    "content": "Last time we saw that we could animate a point moving from $a$ to $b$ via\n\n\\[ \\lerp_\\t(\\a, \\b) = \\a + \\t(\\b - \\a) \\]\n\nWhile this formula is simple, the resulting motion doesn't look very realistic. Real objects don't move at a constant speed: they **accelerate** from rest, and **decelerate** before coming to a stop.\n\nWe can make this more realistic by using what's called an :dfn[easing function]. An easing function is essentially a function\n\\[ f\\colon \\CIntvl01 \\to \\CIntvl 01 \\quad \\text{ with $f(0)=0$ and $f(1)=1$}\\]\nthat tells you how fast you should be moving. Some examples are\n\\[ f(t) = t^3, \\qquad g(t)=\\sin\\frac{\\pi t}2 \\]\n(Again, we'll cover trig functions in the next chapter.)\n\nOur formulas become\n\\[\\begin{align*}\n  \\a + \\t^3(\\b - \\a) \n  &\\quad\\text{or}\\quad\n  (1-\\t^3)\\a + \\t^3\\b\\\\\n  \\a + \\sin\\frac{\\pi\\t}2(\\b-\\a)\n  &\\quad\\text{or}\\quad\n  \\left(1-\\sin\\frac{\\pi\\t}2\\right)\\a + \\sin\\frac{\\pi\\t}2\\b\n\\end{align*}\\]\n\nBut these formulas are very complicated. We don't actually need to expand the formula like this: we already understand $\\lerp_\\t(\\a,\\b)$, so we can just focus on the easing function.\n\n## Easing functions\n\nBefore launching into the theoretical discussion, let's cover practical resources on using easing functions.\n\n(easings.net, CSS functions)\n\n## Composition\n\nLet's take a more formal look at this.\n\n:::definition\n  Given two functions\n  \\[\\begin{align*}\n    f \\colon X &\\to Y\\\\\n    g \\colon Y &\\to Z,\n  \\end{align*}\\]\n  their :dfn[composite] $g\\circ f$ is the function\n  \\[ g\\circ f\\colon X\\to Z \\]\n  given by\n  \\[ (g\\circ f)(x) = g(\\underbrace{f(x)}_{{}\\in Y}) \\]\n  We sometimes write the composite as simply $gf$, omitting the $\\circ$.\n:::\n\nNote the order of composition is backwards to how we might say it out loud: $g\\circ f$ means apply $f$ first, then feed the result of that into $g$. However, the order $g\\circ f$ lines up with how we apply the function to an input (either in math or in programming).\n\n```ts\n/** Compose two functions */\nfunction compose<X, Y, Z>(g: (y: Y) => Z, f: (x: X) => Y): (x: X) => Z {\n  return (x) => g(f(x));\n}\n```\n\n**Functional** programming emphasizes composition more than imperative style programming. For example, here are two ways to sum the list of the first $n$ squares:\n\n```ts\n/** Sum the first n integers, 0^2 + 1^2 + 2^2 + ... + n^2 */\nfunction imperativeStyle(n: number) {\n  let sum = 0;\n\n  for (let i = 1; i <= n; ++i) {\n    sum += i ** 2;\n  }\n  \n  return sum;\n}\n\n/** Sum an array of numbers */\nfunction sum(arr: number[]) {\n  return arr.reduce((a, b) => a + b, 0);\n}\n\n/** Get an array of the integers 0, 1, ..., n */\nfunction range(n: number) {\n  return Array.from({length: n + 1}).map((_, i) => i)\n}\n\n/** Sum the first n integers, 0^2 + 1^2 + 2^2 + ... + n^2 */\nconst functionalStyle = compose(\n  sum,\n  compose(\n    // square entries\n    (arr) => arr.map(i => i ** 2),\n    range\n  )\n);\n```\n\n## Isomorphism\n\nTime to learn a fancy new word!\n\nYou might wonder why easing functions are only defined as functions\n\\[ \\CIntvl01 \\to \\CIntvl01 \\]\nIf we're animating something that lasts $5$ seconds, we might instead want to use a function\n\\[ \\CIntvl05 \\to \\CIntvl01 \\]\nif measuring time in seconds, or $\\CIntvl0{5000}\\to\\CIntvl01$ if measuring time in milliseconds. Similarly, if the character we're animating is traveling from point $1$ to point $8$, it might make more sense to use a map\n\\[ \\CIntvl05 \\to \\CIntvl18. \\]\n\nHowever, there's an easy way to convert between these. For any $\\CIntvl ab$, we have a map\n\\[\\begin{align*}\n  \\gamma_{a,b}\\colon \\CIntvl01 &\\to \\CIntvl ab\\\\\n  \\gamma_{a,b}(t) &= a+t(b-a)\n\\end{align*}\\]\nWe can also convert back: to do this, let's write $y=\\gamma_{a,b}(t)$, and then solve for $t$ in terms of $y$:\n\\[\\begin{align*}\n  y &= a+t(b-a)\\\\\n  y - a &= t(b-a)\\\\\n  t &= \\frac{y-a}{b-a}\n\\end{align*}\\]\nWe'll call this $\\gamma_{a,b}^{-1}\\colon\\CIntvl ab\\to\\CIntvl01$.\n\nWe can turn our function\n\\[ f\\colon \\CIntvl05 \\to \\CIntvl{75}{100} \\]\ninto a function $g\\colon \\CIntvl01\\to\\CIntvl01$ via\n\\[\\begin{CD}\n  \\CIntvl01 @>g>> \\CIntvl01\\\\\n  @V{\\gamma_{0,5}}VV @AA{\\gamma_{75,100}^{-1}}A\\\\\n  \\CIntvl05  @>>f> \\CIntvl{75}{100} \n\\end{CD}\\]\nThat is, $g=\\gamma_{75,100}^{-1}\\circ f\\circ\\gamma_{0,5}$.\n\nSo, in complete generality we might want to consider functions\n\\[ \\CIntvl ab \\to \\CIntvl cd \\]\nBut we can \"normalize\" these down to only considering functions\n\\[ \\CIntvl01 \\to \\CIntvl 01. \\]\nNote that we needed **both** $\\gamma$ and $\\gamma^{-1}$ to do this.\n\n",
    "description": "",
    "duration": null,
    "meta": {
      "math": {
        "macros": "\\newcommand{\\a}{\\red a}\n\\newcommand{\\b}{\\blue b}\n\\newcommand{\\t}{{\\color{gold} t}\n\\newcommand{\\id}{\\mathrm{id}}"
      }
    },
    "ownerId": "41786b7c-b873-4373-8ede-477bf85070a1",
    "publicationDate": "2024-06-15 23:40:16.340316 UTC",
    "slug": "easings",
    "title": "Composition / Easings",
    "type": "article"
  },
  {
    "id": "f173d254-8dbe-4425-8c65-454b16e4c95f",
    "content": "::unit[cg]\n\n::unit[trig]\n",
    "description": "",
    "duration": null,
    "meta": {
      "math": {
        "macros": "\\newcommand{\\I}{\\htmlData{annotation_text=unit interval}{I}}\n\n\\newcommand{\\cl}[2]{\\htmlClass{__ktx-content-#1}{#2}}\n\n% linear algebra\n\n\\newcommand{\\vec}[2]{\\begin{bmatrix}#1\\\\#2\\end{bmatrix}}\n\\newcommand{\\pt}[2]{\\begin{pmatrix}#1\\\\#2\\end{pmatrix}}\n\n\\newcommand{\\ivec}[1]{\\left(#1\\right)}\n\\newcommand{\\ipt}[1]{\\<#1\\>}\n\n\\newcommand{\\matr}[4]{\\begin{bmatrix}#1&#2\\\\#3&#4\\end{bmatrix}}\n\\newcommand{\\Matr}[1]{\\htmlData{annotation_text=matrix of linear transformation $#1$}{[#1]}}\n\n\\newcommand{\\dist}[2]{d(#1, #2)}\n\\newcommand{\\Dist}[2]{\\htmlData{annotation_text=distance from $#1$ to $#2$}{\\dist{#1}{#2}}}\n\n\\newcommand{\\norm}[1]{\\|#1\\|}\n\\newcommand{\\Norm}[1]{\\htmlData{annotation_text=length of vector $#1$}{\\norm{#1}}}\n\n\\newcommand{\\Dir}[1]{\\htmlData{annotation_text=normalization of $#1$}{\\widehat{#1}}}\n\n\\newcommand{\\Rot}[1]{\\htmlData{annotation_text=rotation by $#1$ ccw around the origin}{R_{#1}}}\n\\newcommand{\\ARot}[3]{\\htmlData{annotation_text=rotation of point $#2$ around point $#3$ by $#1$ (counter-clockwise)}{R_{#1}(#2;#3)}}\n\n\\newcommand{\\Refl}[1]{\\htmlData{annotation_text=reflection across the line through the origin at angle $#1$}{F_{#1}}}\n\n% graphics\n\\newcommand{\\lerp}{\\operatorname{lerp}}\n\n\\newcommand{\\ClsdIntvl}{\\CIntvl}\n\\newcommand{\\CIntvl}[2]{\\htmlData{annotation_text=$\\{x\\mid{#1}\\le{x}\\le {#2}\\}$}{[#1,#2]}}\n\\newcommand{\\OIntvl}[2]{\\htmlData{annotation_text=$\\{x\\mid{#1}<{x}<{#2}\\}$}{[#1,#2]}}\n\\newcommand{\\LIntvl}[2]{\\htmlData{annotation_text=$\\{x\\mid{#1}\\le{x}<{#2}\\}$}{[#1,#2]}}\n\\newcommand{\\RIntvl}[2]{\\htmlData{annotation_text=$\\{x\\mid{#1}<{x}\\le{#2}\\}$}{[#1,#2]}}\n\n% spaces\n\\newcommand{\\AffR}[1]{\\htmlData{annotation_text=$#1$-dimensional real affine space}{\\cl{A}{\\A^{#1}}}}\n\\newcommand{\\VecR}[1]{\\htmlData{annotation_text=$#1$-dimensional real vector space}{\\cl{R}{\\R^{#1}}}}\n\\newcommand{\\S}[1]{\\htmlData{annotation_text=$#1$-dimensional unit sphere}{S^{#1}}}\n\n"
      }
    },
    "ownerId": "41786b7c-b873-4373-8ede-477bf85070a1",
    "publicationDate": "2024-06-15 23:40:16.340316 UTC",
    "slug": "gng",
    "title": "Geometry & Graphics",
    "type": "collection"
  },
  {
    "id": "567e4f9b-ea31-4eb0-9bd2-0d6e0784f9f8",
    "content": "<!-- #tab notes -->\nThe content so far has been rather abstract and philosophical. In this post, we're going to get our hands dirty and implement drag functionality on a popup. We'll apply ideas from the previous post on [points and vectors](./points-vectors) to figure out the math.\n\n\nHere's the basic code we'll be starting with.\n\n## Initial code\n\n```tsx\n// !interactive\nimport {useId} from \"react\";\n\nexport default function Demo() {\n  return (\n    <Popup title=\"Demo\">\n      Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod\n      tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim\n      veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea\n      commodo consequat. Duis aute irure dolor in reprehenderit in voluptate\n      velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat\n      cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id\n      est laborum.\n    </Popup>\n  );\n}\n\n/** Draggable popup */\nfunction Popup({\n  children,\n  title,\n}: {\n  children: React.ReactNode;\n  title: React.ReactNode;\n}) {\n  const headerId = useId();\n\n  return (\n    <aside\n      aria-labelledby={headerId}\n      className=\"w-[600px] max-w-[100vw] rounded-md border border-solid border-gray-200 shadow dark:border-gray-700\"\n      role=\"dialog\"\n    >\n      <header\n        className=\"select-none rounded-t-md bg-purple-600 px-2 py-1 text-white\"\n        id={headerId}\n      >\n        {title}\n      </header>\n      <div className=\"px-2 py-1\">{children}</div>\n    </aside>\n  );\n}\n```\n\nWe want to add the ability to drag this popup while holding onto the title bar.\n\nThis is a pretty simple component; the only interesting thing to point out is the use of the [dialog role](https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/Roles/dialog_role) and the [aria-labelledby](https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/Attributes/aria-labelledby) attribute, which are used for accessibility. These aren't relevant to the mathematical content of what we're doing, but I'm including them anyway because accessibility gets skipped over far too often.\n\n## A basic attempt\n\nBefore getting into the vector math, we'll start by wiring up the event listeners. I'm going to intentionally make several errors in order to point them out / warn you about them.\n\n### onPointerMove\n\nTo respond to mouse movement, we use the [`pointermove` event](https://developer.mozilla.org/en-US/docs/Web/API/Element/pointermove_event). Let's try adding that to the title bar:\n\n```tsx\n// !interactive\nimport {useId, useRef} from \"react\";\n\nexport default function Demo() {\n  return (\n    <Popup title=\"Demo\">\n      Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod\n      tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim\n      veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea\n      commodo consequat. Duis aute irure dolor in reprehenderit in voluptate\n      velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat\n      cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id\n      est laborum.\n    </Popup>\n  );\n}\n\n/** Draggable popup */\nfunction Popup({\n  children,\n  title,\n}: {\n  children: React.ReactNode;\n  title: React.ReactNode;\n}) {\n  const headerId = useId();\n\n  const onPointerMove: React.PointerEventHandler = (e) => {\n    console.log(e.clientX, e.clientY);\n  };\n\n  return (\n    <aside\n      aria-labelledby={headerId}\n      className=\"absolute w-[600px] max-w-[100vw] rounded-md border border-solid border-gray-200 shadow dark:border-gray-700\"\n      role=\"dialog\"\n    >\n      <header\n        className=\"select-none rounded-t-md bg-purple-600 px-2 py-1 text-white\"\n        id={headerId}\n        onPointerMove={onPointerMove}\n      >\n        {title}\n      </header>\n      <div className=\"px-2 py-1\">{children}</div>\n    </aside>\n  );\n}\n```\n\nOpen up your browser console to see the results. We're getting the $(x,y)$ coordinates of the pointer (cursor/finger/stylus), but only when we're over the title bar. When we try to drag the dialog into a new position, the pointer will come off of the title bar.\n\n### Body event handlers\n\nTo fix this, we'll add the `pointermove` event on `document.body`. This needs to be done imperatively, not through a React prop. We'll add a [`pointerdown`](https://developer.mozilla.org/en-US/docs/Web/API/Element/pointerdown_event) event to the title bar, and that will set up the necessary subscriptions. We can also get it to transate the dialog now.\n\n```tsx\n// !interactive\nimport {useId, useRef} from \"react\";\n\nexport default function Demo() {\n  return (\n    <Popup title=\"Demo\">\n      Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod\n      tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim\n      veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea\n      commodo consequat. Duis aute irure dolor in reprehenderit in voluptate\n      velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat\n      cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id\n      est laborum.\n    </Popup>\n  );\n}\n\n/** Draggable popup */\nfunction Popup({\n  children,\n  title,\n}: {\n  children: React.ReactNode;\n  title: React.ReactNode;\n}) {\n  const headerId = useId();\n\n  const ref = useRef<HTMLElement>(null);\n\n  const onPointerMove = (e: PointerEvent) => {\n    if (!ref.current) return;\n    ref.current.style.translate = `${e.clientX}px ${e.clientY}px`;\n  };\n\n  const onPointerDown: React.PointerEventHandler = (e) => {\n    document.body.addEventListener(\"pointermove\", onPointerMove);\n    document.body.addEventListener(\"pointerup\", onPointerUp);\n  };\n\n  const onPointerUp: React.PointerEventHandler = (e) => {\n    document.body.removeEventListener(\"pointermove\", onPointerMove);\n    document.body.removeEventListener(\"pointerup\", onPointerUp);\n  };\n\n  return (\n    <aside\n      aria-labelledby={headerId}\n      className=\"absolute w-[600px] max-w-[100vw] rounded-md border border-solid border-gray-200 shadow dark:border-gray-700\"\n      ref={ref}\n      role=\"dialog\"\n    >\n      <header\n        className=\"select-none rounded-t-md bg-purple-600 px-2 py-1 text-white\"\n        id={headerId}\n        onPointerDown={onPointerDown}\n        onPointerUp={onPointerUp}\n      >\n        {title}\n      </header>\n      <div className=\"px-2 py-1\">{children}</div>\n    </aside>\n  );\n}\n```\n\nIf you try this, you'll notice several issues. Take a minute to try diagnosing (and fixing) them yourself before looking at the solution.\n\n- the top-left corner of the dialog is following the pointer position, rather than the pointer staying in the same place as when you pressed down initially. We'll fix this in [the next section](#figuring-out-the-math).\n- the `onPointerUp` event doesn't seem to be working, and the dialog can only be \"pushed\" down and right.  \n  Hint 1: use the Inspector.  \n  Hint 2: this is unlikely to occur in a real-world application.  \n  \n   :::popup{trigger=Solution}\n     The issue is that the `<body>` tag doesn't have a width, since its only child is the absolutely positioned popup. We can fix this by wrapping the content in a tag with `min-h-screen` and `min-w-screen` applied. (Probably you should use the [new viewport units](https://dev.to/frehner/css-vh-dvh-lvh-svh-and-vw-units-27k4) here.)\n   :::\n\n- after fixing the above issue, notice that when you drag your pointer outside of the preview window and release it, you're still dragging when you move your pointer back into the preview window.\n   :::popup{trigger=Solution}\n     Lifting outside of the preview window means that `pointerup` never fires on `document.body`. This happens because the preview is in an iframe, but could also happen if the user drags their pointer out of the browser window or onto the browser chrome. We can fix it by adding a `pointerleave` event handler to `document.body`.\n   :::\n\nHere's the code with fixes for the latter two issues. Don't peek until you've tried diagnosing+fixing them yourself!\n\n```tsx\n// !interactive\nimport {useId, useRef} from \"react\";\n\nexport default function Demo() {\n  return (\n    <main className=\"min-w-screen min-h-screen\">\n      <Popup title=\"Demo\">\n        Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod\n        tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim\n        veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea\n        commodo consequat. Duis aute irure dolor in reprehenderit in voluptate\n        velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint\n        occaecat cupidatat non proident, sunt in culpa qui officia deserunt\n        mollit anim id est laborum.\n      </Popup>\n    </main>\n  );\n}\n\n/** Draggable popup */\nfunction Popup({\n  children,\n  title,\n}: {\n  children: React.ReactNode;\n  title: React.ReactNode;\n}) {\n  const headerId = useId();\n\n  const ref = useRef<HTMLElement>(null);\n\n  const onPointerMove = (e: PointerEvent) => {\n    if (!ref.current) return;\n    ref.current.style.translate = `${e.clientX}px ${e.clientY}px`;\n  };\n\n  const endDrag = () => {\n    document.body.removeEventListener(\"pointerleave\", endDrag);\n    document.body.removeEventListener(\"pointermove\", onPointerMove);\n    document.body.removeEventListener(\"pointerup\", endDrag);\n  };\n\n  const onPointerDown = () => {\n    document.body.addEventListener(\"pointerleave\", endDrag);\n    document.body.addEventListener(\"pointermove\", onPointerMove);\n    document.body.addEventListener(\"pointerup\", endDrag);\n  };\n\n  return (\n    <aside\n      aria-labelledby={headerId}\n      className=\"absolute w-[600px] max-w-[100vw] rounded-md border border-solid border-gray-200 shadow dark:border-gray-700\"\n      ref={ref}\n      role=\"dialog\"\n    >\n      <header\n        className=\"select-none rounded-t-md bg-purple-600 px-2 py-1 text-white\"\n        id={headerId}\n        onPointerDown={onPointerDown}\n      >\n        {title}\n      </header>\n      <div className=\"px-2 py-1\">{children}</div>\n    </aside>\n  );\n}\n```\n\n## Figuring out the math\n\nTo figure out how to position the popup correctly, let's introduce some notation. Let\n\n- $t\\in\\R$ denote the time since the `pointerdown` event\n- $p(t)\\in \\AffR 2$ denote the coordinates of the pointer at time $t$\n- $c(t)\\in\\AffR 2$ denote the desired coordinates of the top-left corner of the popup at time $t$\n\nTo keep the pointer \"in the same place\" on the title bar, the relationship we want is\n\\[ p(0) - c(0) = p(t) - c(t) \\quad\\text{for all }t \\]\nNote that $c(t)$ and $p(t)$ are **points**, but the common difference here is a **vector**.\n\nWhich of these do we know?\n\n- we get $p(t)$ from `e.clientX` and `e.clientY`. For $t=0$, `e` is the `pointerdown` event, for $t>0$ it's the `pointermove` event.\n\n- we can get $c(0)$ from [`getBoundingClientRect()`](https://developer.mozilla.org/en-US/docs/Web/API/Element/getBoundingClientRect) on the popup `ref`\n\n- what we need to calculate is $c(t)$ for $t>0$\n\nWe can rearrange the above formula to isolate what we want to calculate:\n\n\\[ c(t) = p(t) + \\underbrace{(c(0) - p(0))}_{\\mathtt{offset}} \\]\n\nHere's the final code:\n\n```tsx\n// !interactive\nimport {useId, useRef} from \"react\";\n\nexport default function Demo() {\n  return (\n    <main className=\"min-w-screen min-h-screen\">\n      <Popup title=\"Demo\">\n        Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod\n        tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim\n        veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea\n        commodo consequat. Duis aute irure dolor in reprehenderit in voluptate\n        velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint\n        occaecat cupidatat non proident, sunt in culpa qui officia deserunt\n        mollit anim id est laborum.\n      </Popup>\n    </main>\n  );\n}\n\n/** Draggable popup */\nfunction Popup({\n  children,\n  title,\n}: {\n  children: React.ReactNode;\n  title: React.ReactNode;\n}) {\n  const headerId = useId();\n\n  const ref = useRef<HTMLElement>(null);\n\n  const offset = useRef({x: 0, y: 0});\n\n  const onPointerMove = (e: PointerEvent) => {\n    if (!ref.current) return;\n    ref.current.style.translate = `${e.clientX + offset.current.x}px ${e.clientY + offset.current.y}px`;\n  };\n\n  const endDrag = () => {\n    document.body.removeEventListener(\"pointerleave\", endDrag);\n    document.body.removeEventListener(\"pointermove\", onPointerMove);\n    document.body.removeEventListener(\"pointerup\", endDrag);\n  };\n\n  const onPointerDown: React.PointerEventHandler = (e) => {\n    if (!ref.current) return;\n\n    // record offset\n    // [rect.x, rect.y] is what we called c(0) in the formulas\n    // [e.clientX, e.clientY] is what we called p(0) in the formulas\n    const rect = ref.current.getBoundingClientRect();\n    offset.current = {x: rect.x - e.clientX, y: rect.y - e.clientY};\n\n    // attach event handlers\n    document.body.addEventListener(\"pointerleave\", endDrag);\n    document.body.addEventListener(\"pointermove\", onPointerMove);\n    document.body.addEventListener(\"pointerup\", endDrag);\n  };\n\n  return (\n    <aside\n      aria-labelledby={headerId}\n      className=\"absolute w-[600px] max-w-[100vw] rounded-md border border-solid border-gray-200 shadow dark:border-gray-700\"\n      ref={ref}\n      role=\"dialog\"\n    >\n      <header\n        className=\"select-none rounded-t-md bg-purple-600 px-2 py-1 text-white\"\n        id={headerId}\n        onPointerDown={onPointerDown}\n      >\n        {title}\n      </header>\n      <div className=\"px-2 py-1\">{children}</div>\n    </aside>\n  );\n}\n```\n\n## Extracting Hooks\n\nNow that we have the functionality in place, let's refactor things a little bit to split out logic that's not specific to our app.\n\nFirst let's extract the logic of starting a drag operation on `pointerdown`, and ending it on `pointerup` or `pointerleave`. It's conceivable that a consumer will want to distinguish between the latter two events, so we'll make them separate.\n\n```ts\nimport {useCallback} from \"react\";\n\n/**\n * Provides generic drag functionality\n * @returns An object of event handlers to spread onto the target\n */\nfunction useDrag<T = Element>(opts: {\n  down?: React.PointerEventHandler<T>;\n  leave?: (e: PointerEvent) => unknown;\n  move: (e: PointerEvent) => unknown;\n  up?: (e: PointerEvent) => unknown;\n}) {\n  // pointer event handlers\n  const onPointerUp = useCallback(\n    (e: PointerEvent) => {\n      opts.up?.(e);\n      unsubscribe();\n    },\n    [opts.up],\n  );\n\n  const onPointerLeave = useCallback(\n    (e: PointerEvent) => {\n      opts.leave?.(e);\n      unsubscribe();\n    },\n    [opts.leave],\n  );\n\n  /** Remove event handlers from document.body */\n  const unsubscribe = useCallback(() => {\n    document.body.removeEventListener(\"pointerleave\", onPointerLeave);\n    document.body.removeEventListener(\"pointermove\", opts.move);\n    document.body.removeEventListener(\"pointerup\", onPointerUp);\n  }, [opts.move, onPointerLeave, onPointerUp]);\n\n  const onPointerDown: React.PointerEventHandler<T> = useCallback(\n    (e) => {\n      opts.down?.(e);\n\n      // attach event handlers\n      document.body.addEventListener(\"pointerleave\", onPointerLeave);\n      document.body.addEventListener(\"pointermove\", opts.move);\n      document.body.addEventListener(\"pointerup\", onPointerUp);\n    },\n    [opts.move, onPointerUp, onPointerLeave],\n  );\n\n  return {onPointerDown};\n}\n```\n\nNext, let's address the specific case of dragging an element. We can build on what we did above:\n\n```ts\n/** Provides functionality to drag an element */\nfunction useDragElement<TRoot extends HTMLElement, TAnchor extends Element>(): {\n  /** Events to spread onto the dragging \"anchor\" */\n  anchorEvents: {\n    onPointerDown: React.PointerEventHandler<TAnchor>;\n  };\n\n  /** Ref to attach to the object you wish to make draggable. */\n  ref: React.RefObject<TRoot>;\n} {\n  const ref = useRef<TRoot>(null);\n\n  const offset = useRef({x: 0, y: 0});\n\n  const anchorEvents = useDrag(\n    useMemo(\n      () => ({\n        down: (e: React.PointerEvent<TAnchor>) => {\n          if (!ref.current) return;\n\n          // set offset\n          const rect = ref.current.getBoundingClientRect();\n          offset.current = {x: rect.x - e.clientX, y: rect.y - e.clientY};\n        },\n        move: (e: PointerEvent) => {\n          if (!ref.current) return;\n          const x = e.clientX + offset.current.x;\n          const y = e.clientY + offset.current.y;\n          ref.current.style.translate = `${x}px ${y}px`;\n        },\n      }),\n      [],\n    ),\n  );\n\n  return {\n    anchorEvents,\n    ref,\n  };\n}\n```\n\nThe complete refactored version is at the GitHub link below.\n\n::embed[{epiplexis-content}/gng/01-coordinates/07-dragging/demo]{source aspect-ratio=1.5}\n\n## Remarks\n\nTo get a full-featured dialog component (accessibility, focus guard, etc.), I recommend the [Radix Dialog](https://www.radix-ui.com/primitives/docs/components/dialog) component. You can attach this behavior onto one of those.\n\nDid we really need the abstract math perspective to figure the formula for the translation? Not really, we'd have eventually gotten there by trial and error + drawing some pictures. But getting comfortable with manipulating these makes it easier to just sit down and derive the formula and feel confident in it. The \"type safety\" of the points-vs-vectors distinction can also rule out faulty guesses.\n\n<!-- #tab exercises -->\n\n1. Modify the code to prevent the user from dragging the popup offscreen. You will need [`window.innerWidth`](https://developer.mozilla.org/en-US/docs/Web/API/Window/innerWidth) and [`window.innerHeight`](https://developer.mozilla.org/en-US/docs/Web/API/Window/innerHeight).\n\n2. Add functionality to resize the popup. You can make drag handles like so:  \n   ```tsx\n   // !interactive\n    import {useId} from \"react\";\n   \n   export default function Demo() {\n     return (\n       <Popup title=\"Demo\">\n         Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod\n         tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim\n         veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea\n         commodo consequat. Duis aute irure dolor in reprehenderit in voluptate\n         velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat\n         cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id\n         est laborum.\n       </Popup>\n     );\n   }\n   \n   /** Draggable popup */\n   function Popup({\n     children,\n     title,\n   }: {\n     children: React.ReactNode;\n     title: React.ReactNode;\n   }) {\n     const headerId = useId();\n   \n     return (\n       <aside\n         aria-labelledby={headerId}\n         className=\"max-w-[100vw] w-[600px] absolute rounded-md border border-solid border-gray-200 shadow dark:border-gray-700\"\n         role=\"dialog\"\n       >\n         <header\n           className=\"select-none rounded-t-md bg-purple-600 px-2 py-1 text-white\"\n           id={headerId}\n         >\n           {title}\n         </header>\n         <div className=\"px-2 py-1\">{children}</div>\n         {/* drag handles */}\n         <div className=\"absolute bottom-0 left-0 h-2 w-full cursor-ns-resize\" />\n         <div className=\"absolute right-0 top-0 h-full w-2 cursor-ew-resize\" />\n       </aside>\n     );\n   }\n   ```\n",
    "description": "",
    "duration": null,
    "meta": {
      "math": {
        "macros": ""
      }
    },
    "ownerId": "41786b7c-b873-4373-8ede-477bf85070a1",
    "publicationDate": "2024-08-19 05:26:12.146533 UTC",
    "slug": "dragging",
    "title": "Drag functionality",
    "type": "article"
  },
  {
    "id": "3871a07c-a634-45b5-b564-aba7ae31d656",
    "content": "",
    "description": "",
    "duration": 280962,
    "meta": {},
    "ownerId": "41786b7c-b873-4373-8ede-477bf85070a1",
    "publicationDate": "2025-01-12 08:19:04.766 UTC",
    "slug": "",
    "title": "SIR test",
    "type": "recording"
  },
  {
    "id": "b66bfba4-9b5e-4092-914d-d149b280f9f0",
    "content": "",
    "description": "",
    "duration": 368674,
    "meta": {},
    "ownerId": "41786b7c-b873-4373-8ede-477bf85070a1",
    "publicationDate": "2025-01-16 19:04:33.163 UTC",
    "slug": "",
    "title": "SIR Python (no audio)",
    "type": "recording"
  },
  {
    "id": "8d49cb26-4c86-4667-944a-d9b18c1fd886",
    "content": "",
    "description": "",
    "duration": 589960,
    "meta": {
      "tracks": [
        {
          "kind": "captions",
          "srclang": "en"
        }
      ]
    },
    "ownerId": "41786b7c-b873-4373-8ede-477bf85070a1",
    "publicationDate": "2025-02-07 19:12:04.049 UTC",
    "slug": "",
    "title": "SIRPLOT",
    "type": "recording"
  },
  {
    "id": "bbf997e7-df65-4d03-8eb5-304fabff55a5",
    "content": "",
    "description": "",
    "duration": 460130,
    "meta": {},
    "ownerId": "41786b7c-b873-4373-8ede-477bf85070a1",
    "publicationDate": "2025-02-08 08:56:09.323 UTC",
    "slug": "",
    "title": "SEQUENCE",
    "type": "recording"
  },
  {
    "id": "94560ee1-a7b5-432f-9de0-3a137c500e5e",
    "content": "",
    "description": "",
    "duration": 6940,
    "meta": {},
    "ownerId": "4a4d8990-1de7-481e-be21-17d46c119e88",
    "publicationDate": "2025-02-08 12:49:50.536499 UTC",
    "slug": "",
    "title": "",
    "type": "recording"
  },
  {
    "id": "2d047bf3-7134-4f29-8dde-022274b43e13",
    "content": "",
    "description": "",
    "duration": 1256463,
    "meta": {},
    "ownerId": "41786b7c-b873-4373-8ede-477bf85070a1",
    "publicationDate": "2025-02-09 02:45:48.565 UTC",
    "slug": "",
    "title": "LENGTH (too long)",
    "type": "recording"
  },
  {
    "id": "a0ff0333-817a-4258-aeb3-97059b823fe8",
    "content": "",
    "description": "",
    "duration": 614006,
    "meta": {},
    "ownerId": "41786b7c-b873-4373-8ede-477bf85070a1",
    "publicationDate": "2025-02-09 05:44:52.733 UTC",
    "slug": "",
    "title": "LENGTH",
    "type": "recording"
  }
]

Old site