Analysis

In this part we perform a mathematical analysis of the family of curves we found previously.

Definitions

Let \(p \in \mathbb N, p > 0\) and \(q \in \mathbb N, q > 0\). Let \(d = \gcd(p, q)\), \(p' = \frac{p}{d}\) and \(q' = \frac{q}{d}\). Let \(r \in \mathbb R\) and \(\delta_r \in \mathbb R\) such that \(0 < \delta_r < r\). Let’s define the following family of functions:

\[r_k : \theta \mapsto r + \delta_r \cdot \cos\left(\frac{p \cdot \theta - 2 \cdot k \cdot \pi}{q}\right)\]\[k \in \mathbb Z\]

Let \(\Gamma_k\) be the graph of \(r_k\) in polar coordinates, that is the graph of \(\vec{r_k} : \theta \mapsto r_k(\theta) \cdot \vec u(\theta)\) where \(\vec u(\theta)\) is the unit vector at polar angle \(\theta\).

Intersections

For \((m, n) \in \mathbb Z^2\), \(\Gamma_m\) and \(\Gamma_n\) intersect if and only if \(\exists \theta_1, \theta_2 \in \mathbb R^2, \vec{r_m}(\theta_1) = \vec{r_n}(\theta_2)\).

\[\begin{split}\begin{array}{rcl} \vec{r_m}(\theta_1) = \vec{r_n}(\theta_2) & \iff & r_m(\theta_1) \cdot \vec u(\theta_1) = r_n(\theta_2) \cdot \vec u(\theta_2) \\ & \iff & \left| \begin{array}{l} \left\{ \begin{array}{l} \vec u(\theta_1) = \vec u(\theta_2) \\ r_m(\theta_1) = r_n(\theta_2) \end{array} \right. \\ \mbox{or} \\ \left\{ \begin{array}{l} \vec u(\theta_1) = -\vec u(\theta_2) \\ r_m(\theta_1) = -r_n(\theta_2) \end{array} \right. \end{array} \right. \end{array}\end{split}\]

\(0 < \delta_r < r\) and \(\cos\) is between \(-1\) and \(1\) so \(r_k(\theta) > 0\) and we can drop the second case.

\[\begin{split}\begin{array}{rcl} \vec{r_m}(\theta_1) = \vec{r_n}(\theta_2) & \iff & \left\{ \begin{array}{l} \vec u(\theta_1) = \vec u(\theta_2) \\ r_m(\theta_1) = r_n(\theta_2) \end{array} \right. \\ & \iff & \left\{ \begin{array}{l} \vec u(\theta_1) = \vec u(\theta_2) \\ \cos\left(\frac{p \cdot \theta_1 - 2 \cdot m \cdot \pi}{q}\right) = \cos\left(\frac{p \cdot \theta_2 - 2 \cdot n \cdot \pi}{q}\right) \end{array} \right. \end{array}\end{split}\]

\(\vec u\) is \(2 \pi \mbox{-periodic}\) and \(\cos\) is even and \(2 \pi \mbox{-periodic}\) so:

\[\begin{split}\begin{array}{rcl} \vec{r_m}(\theta_1) = \vec{r_n}(\theta_2) & \iff & \left\{ \begin{array}{l} \exists a \in \mathbb Z, \theta_2 = \theta_1 + 2 \cdot a \cdot \pi \\ \exists b \in \mathbb Z, \left| \begin{array}{l} \frac{p \cdot \theta_1 - 2 \cdot m \cdot \pi}{q} = 2 \cdot b \cdot \pi + \frac{p \cdot \theta_2 - 2 \cdot n \cdot \pi}{q} \\ \mbox{or} \\ \frac{p \cdot \theta_1 - 2 \cdot m \cdot \pi}{q} = 2 \cdot b \cdot \pi - \frac{p \cdot \theta_2 - 2 \cdot n \cdot \pi}{q} \end{array} \right. \end{array} \right. \\ & \iff & \left| \begin{array}{l} \exists (a, b) \in \mathbb Z^2, \left\{ \begin{array}{l} \theta_2 = \theta_1 + 2 \cdot a \cdot \pi \\ \frac{p \cdot \theta_1 - 2 \cdot m \cdot \pi}{q} = 2 \cdot b \cdot \pi + \frac{p \cdot \theta_2 - 2 \cdot n \cdot \pi}{q} \end{array}\right. \qquad \mbox{Case 1} \\ \mbox{or} \\ \exists (a, b) \in \mathbb Z^2, \left\{ \begin{array}{l} \theta_2 = \theta_1 + 2 \cdot a \cdot \pi \\ \frac{p \cdot \theta_1 - 2 \cdot m \cdot \pi}{q} = 2 \cdot b \cdot \pi - \frac{p \cdot \theta_2 - 2 \cdot n \cdot \pi}{q} \end{array}\right. \qquad \mbox{Case 2} \end{array} \right. \end{array}\end{split}\]

Case 1

\[\begin{split}\begin{array}{cl} & \exists (a, b) \in \mathbb Z^2, \left\{ \begin{array}{l} \theta_2 = \theta_1 + 2 \cdot a \cdot \pi \\ \frac{p \cdot \theta_1 - 2 \cdot m \cdot \pi}{q} = 2 \cdot b \cdot \pi + \frac{p \cdot \theta_2 - 2 \cdot n \cdot \pi}{q} \end{array}\right. \\ \iff & \exists (a, b) \in \mathbb Z^2, \left\{ \begin{array}{l} \theta_2 = \theta_1 + 2 \cdot a \cdot \pi \\ n - m = a \cdot p + b \cdot q \end{array}\right. \end{array}\end{split}\]

So if we can find \(a\) and \(b\) such that \(n - m = a \cdot p + b \cdot q\), then \(\Gamma_m\) and \(\Gamma_n\) have an infinite number of intersection points and are identical.

According to Bézout’s identity, \(\exists (a, b) \in \mathbb Z, n - m = a \cdot p + b \cdot q\) if and only if \(n - m\) is a multiple of \(d\).

Reduction of the family

Applying this to \(n = m + d\) proves that \(\Gamma_{n + d}\) is identical to \(\Gamma_n\). It’s sufficient to consider intersections between \(\Gamma_m\) and \(\Gamma_n\) for \((m, n) \in [0, d-1]^2\) and \(m \le n\). And it’s enough to draw \(\Gamma_k\) for \(k \in [0, d-1]\).

Periodicity of \(r_k\)

By construction, \(r_k\) is \(2 \cdot q \cdot \pi \mbox{-periodic}\).

For \(m = n\), we can use \(a = q'\) and \(b = -p'\). Then we have \(\theta_2 = \theta_1 + 2 \cdot q' \cdot \pi\). So \(r_k\) is \(2 \cdot q' \cdot \pi \mbox{-periodic}\). It’s sufficient to consider intersections where \((\theta_1, \theta_2) \in \left[0, 2 \cdot q' \cdot \pi\right[^2\). And it’s enough to draw each \(\Gamma_k\) on \(\theta \in \left[0, 2 \cdot q' \cdot \pi\right[\).

Case 2

\[\begin{split}\begin{array}{cl} & \exists (a, b) \in \mathbb Z^2, \left\{ \begin{array}{l} \theta_2 = \theta_1 + 2 \cdot a \cdot \pi \\ \frac{p \cdot \theta_1 - 2 \cdot m \cdot \pi}{q} = 2 \cdot b \cdot \pi - \frac{p \cdot \theta_2 - 2 \cdot n \cdot \pi}{q} \end{array}\right. \\ \iff & \exists (a, b) \in \mathbb Z^2, \left\{ \begin{array}{l} \theta_1 = \frac{b \cdot q - a \cdot p + m + n}{p} \cdot \pi \\ \theta_2 = \frac{b \cdot q + a \cdot p + m + n}{p} \cdot \pi \end{array}\right. \end{array}\end{split}\]

So this case correspond to “real”, individual intersection points.

Let’s reduce the domain we need to search for \(a\) and \(b\). So far, we have:

\[0 \le k \lt d\]\[0 \le \theta_1 \lt 2 \cdot q' \cdot \pi\]\[0 \le \theta_2 \lt 2 \cdot q' \cdot \pi\]\[\theta_1 = \frac{b \cdot q - a \cdot p + 2 \cdot k}{p} \cdot \pi\]\[\theta_2 = \frac{b \cdot q + a \cdot p + 2 \cdot k}{p} \cdot \pi\]

Replacing \(\theta_1\) and \(\theta_2\) in \(-2 \cdot q' \cdot \pi \lt \theta_2 - \theta_1 \lt 2 \cdot q' \cdot \pi\) and isolating \(a\), we obtain \(-q' + 1 \le a \lt q'\).

Then, replacing \(\theta_1\) and \(\theta_2\) in \(0 \le \theta_1 \lt 2 \cdot q' \cdot \pi\) and \(0 \le \theta_2 \lt 2 \cdot q' \cdot \pi\) and isolating b, we obtain:

\[\frac{a \cdot p - m - n}{q} \le b \lt 2 \cdot p' - \frac{-a \cdot p + m + n}{q}\]\[\frac{-a \cdot p - m - n}{q} \le b \lt 2 \cdot p' - \frac{a \cdot p + m + n}{q}\]

We can regroup those two conditions in:

\[\frac{|a| \cdot p - m - n}{q} \le b \lt 2 \cdot p' - \frac{|a| \cdot p + m + n}{q}\]

So to obtain all intersections, it’s enough to iterate on \(a\) and \(b\) in those ranges. Note that if \(m = n\), this will give us each intersection twice. We can consider only the cases where \(\theta_1 \lt \theta_2\), which reduces the range of \(a\) to \(1 \le a \lt q'\).

This is just a necessary condition on \(a\) and \(b\). We have proven that we obtain all intersections, but @todoc we might want to prove that we don’t get duplicates.

import fractions
import math
import matplotlib.pyplot as plt
import numpy as np

P = 7
Q = 8

plt.figure(figsize=(P, Q))

for p in range(1, P + 1):
  for q in range(1, Q + 1):
    d = fractions.gcd(p, q)
    p_prime = p / d
    q_prime = q / d

    r = []
    for k in range(d):
      r.append(
        lambda theta, k=k: 2 + np.cos((p * theta - 2 * k * np.pi) / q)
      )
    theta = np.arange(0, 2 * q_prime * np.pi, 0.01)

    intersections = []
    # Note that these 4 imbricated loops are only O(p*q)
    for m in range(d):
      for n in range(m, d):
        if m == n:
            min_a = 1
        else:
            min_a = -q_prime + 1
        max_a = q_prime
        for a in range(min_a, max_a):
          min_b = int(math.ceil(float(abs(a) * p - m - n) / q))
          max_b = 2 * p_prime - int(math.floor(float(abs(a) * p + m + n) / q))
          for b in range(min_b, max_b):
            theta_1 = (b * q - a * p + m + n) * np.pi / p
            theta_2 = (b * q + a * p + m + n) * np.pi / p
            assert 0 <= theta_1 < 2 * q_prime * np.pi
            assert 0 <= theta_2 < 2 * q_prime * np.pi
            assert m != n or theta_1 < theta_2
            intersections.append((theta_1, r[m](theta_1)))
    assert len(intersections) == p * (q - 1)  # @todoc Explain

    sp = plt.subplot(Q, P, (q - 1) * P + p, polar=True)
    for k in range(d):
      sp.plot(theta, r[k](theta))
    sp.plot(
      [theta for theta, r in intersections],
      [r for theta, r in intersections],
      "r."
    )
    sp.set_rmin(0)
    sp.set_rmax(3.1)
    sp.set_yticks([1, 2, 3])
    sp.set_yticklabels([])
    sp.set_xticklabels([])
    sp.spines['polar'].set_visible(False)

plt.tight_layout()
../_images/analysis-1.png