diff --git a/content/blog/modulo_patterns/index.md b/content/blog/modulo_patterns/index.md index 9fd5add..a802d18 100644 --- a/content/blog/modulo_patterns/index.md +++ b/content/blog/modulo_patterns/index.md @@ -277,37 +277,136 @@ factor with 9; 3, 6, 9, 12, and so on. However, those can't all serve as cycle l cycles can't get longer than 9. This leaves us with 3, 6, and 9 as _possible_ cycle lengths, none of which are divisible by 4. We've eliminated the possibility of spirals! -{{< todo >}} -This doesn't get to the bottom of it all. -{{< /todo >}} - ### Generalizing to Arbitrary Divisors The trick was easily executable on paper because there's an easy way to compute the remainder of a number when dividing by 9 (adding up the digits). However, we have a computer, and we don't need to fall back on such cool-but-complicated techniques. To replicate our original behavior, we can just write: -``` +```Ruby def sum_digits(n) x = n % 9 x == 0 ? 9 : x end ``` -But now, we can change the `9` to something else. Any number we pick, so long as it isn't -{{< sidenote "right" "div-4-note" "divisible by 4," >}} -"Wait", you might be thinking, "I thought you said that 4 can't have a common factor with the divisor, -and that means any even numbers are out, too."
-
-Good observation. Although the path-not-divisible-by-four condition is certainly sufficient, it is not -necessary. There seems to be another, less restrictive, condition at play here: even numbers work fine. I haven't -figured out what it is, but we might as well make use of it. -{{< /sidenote >}} will work. I'll pick primes for good measure. Here are a few good ones from using 13 +But now, we can change the `9` to something else. There are some numbers we'd like to avoid - specifically, +we want to avoid those numbers that would allow for cycles of length 4 (or of a length divisible by 4). +If we didn't avoid them, we might run into infinite loops, where our pencil might end up moving +further and further from the center. + +Actually, let's revisit that. When we were playing with paths of length \\(k\\) while dividing by 9, +we noted that the only _possible_ values of \\(k\\) are those that share a common factor with 9, +specifically 3, 6 and 9. But that's not quite as strong as it could be: try as you might, but +you will not find a cycle of length 6 when dividing by 9. The same is true if we pick 6 instead of 9, +and try to find a cycle of length 4. Even though 4 _does_ have a common factor with 6, and thus +is not ruled out as a valid cycle by our previous condition, we don't find any cycles of length 4. + +So what is it that _really_ determines if there can be cycles or not? + +Let's do some more playing around. What _are_ the actual cycle lengths when we divide by 9? +For all but two numbers, the cycle lengths are 9. The two special numbers are 6 and 3, and they end up +with a cycle length of 3. From this, we can say that the cycle length seems to depend on whether or +nor our \\(n\\) has any common factors with the divisor. + +Let's explore this some more with a different divisor, say 12. We fill find that 8 has a cycle length +of 3, 7 has a cycle length of 12, 9 has a cycle length of 4. What's +happening here? To see, let's divide 12 __by these cycle lengths__. For 8, we get (12/3) = 4. +For 7, this works out to 1. For 9, it works out to 3. These new numbers, 4, 1, and 3, are actually +the __greatest common factors__ of 8, 3, and 7 with 12, respectively. The greatest common factor +of two numbers is the largest number that divides them both. We thus write down our guess +for the length of a cycle: + +{{< latex >}} +k = \frac{d}{\text{gcd}(d,n)} +{{< /latex >}} + +Where \\(d\\) is our divisor, which has been 9 until just recently. Indeed, this equation is in agreement +with our experiment for \\(d = 9\\), too. Why might this be? Let's start once again with +our equation for paths of length \\(k\\): + +{{< latex >}} +kn \equiv 0\ (\text{mod}\ d) +{{< /latex >}} + +Here we've replaced 9 with \\(d\\), since we're trying to make it work for _any_ divisor, not just 9. +Now, suppose the greatest common divisor of \\(n\\) and \\(d\\) is some number \\(f\\). Then, +since this number divides \\(n\\) and \\(d\\), we can write \\(n=fm\\) for some \\(m\\), and +\\(d=fg\\) for some \\(g\\). We can rewrite our equation as follows: + +{{< latex >}} +kfm \equiv 0\ (\text{mod}\ fg) +{{< /latex >}} + +We can simplify this a little bit. Recall that what this equation _really_ means is that the +difference of \\(kfm\\) and \\(0\\), which is just \\(kfm\\) is divisible by \\(fg\\): + +{{< latex >}} +fg|kfm +{{< /latex >}} + +But if \\(fg\\) divides \\(kfm\\), it must be that \\(g\\) divides \\(km\\)! This, in turn, means +we can write: + +{{< latex >}} +g|km +{{< /latex >}} + +We also know that \\(g\\) and \\(m\\) have no common factors -- they were all divided out from \\(d\\) +and \\(n\\) when we divided by \\(f\\)! We can thus further simplify our claim: + +{{< latex >}} +g|k +{{< /latex >}} + +This says that \\(k\\) must be divisible by \\(g\\). Recall that we got \\(g\\) by dividing +\\(d\\) by \\(f\\), which is our largest common factor -- aka \\(\\text{gcd}(d,n)\\). We can thus +write: + +{{< latex >}} +\frac{d}{\text{gcd}(d,n)}|k +{{< /latex >}} + +All that's left is to pick the smallest \\(k\\) that fits this description (that would be the first +point at which our sequence of multiples of \\(n\\) will loop). Zero is divisible by anything, but +alas, our sequence numbers start at 1 -- zero's out. The next best thing is \\(d/\\text{gcd}(d,n)\\). +And there we have it: the first point at which our sequence loops, just like we guessed. + +Lastly, recall that a cycle occurs whenever a \\(k\\) is a multiple of 4. Now that we know what +\\(k\\) is, we can restate this as "\\(d/\\text{gcd}(d,n)\\) is divisible by 4". But if we pick +\\(n=d-1\\), the +{{< sidenote "right" "coprime-note" "greatest common factor has to be \(1\)," >}} +Wait, why is this true? Well, suppose some number \(f\) divides both \(d\) and \(d-1\). +In that case, we can write \(d=af\), and \((d-1)=bf\). Subtracting one equation from the other: +{{< latex >}} +1 = (a-b)f +{{< /latex >}} +But this means that 1 is divisible by \(f\)! That's only possible if \(f=1\). Thus, the only +number that divides \(x\) and \(x-1\) is 1; that's our greatest common factor. +{{< /sidenote >}} which means that our condition further simplifies to +"\\(d\\) is divisible by 4". +Thus, we can state simply that any divisor divisible by 4 is off-limits, as it will induce loops. +For example, pick \\(d=4\\). Running our algorithm for \\(n=d-1=3\\), we indeed find an infinite +spiral: + +{{< figure src="pattern_3_4.svg" caption="Spiral generated by the number 3 with divisor 4." class="tiny" alt="Spiral generated by the number 3 by summing digits." >}} + +Let's try again. Pick \\(d=8\\); then, for \\(n=d-1=7\\), we also get a spiral: + +{{< figure src="pattern_7_8.svg" caption="Spiral generated by the number 7 with divisor 8." class="tiny" alt="Spiral generated by the number 7 by summing digits." >}} + +A poem comes to mind: +> Turning and turning in the wydening gyre +> +> The falcon cannot hear the falconner; + +Fortunately, there are plenty of numbers that are not divisible by four, and we can pick +any of them! I'll pick primes for good measure. Here are a few good ones from using 13 (which corresponds to summing digits of base-14 numbers): {{< figure src="pattern_8_13.svg" caption="Pattern generated by the number 8 in base 14." class="tiny" alt="Pattern generated by the number 8 by summing digits." >}} {{< figure src="pattern_4_13.svg" caption="Pattern generated by the number 4 in base 14." class="tiny" alt="Pattern generated by the number 4 by summing digits." >}} -Here are a few from dividing by 17 (base-18 numbers). +Here's one from dividing by 17 (base-18 numbers). {{< figure src="pattern_5_17.svg" caption="Pattern generated by the number 5 in base 18." class="tiny" alt="Pattern generated by the number 5 by summing digits." >}} @@ -316,3 +415,86 @@ Finally, base-30: {{< figure src="pattern_2_29.svg" caption="Pattern generated by the number 2 in base 30." class="tiny" alt="Pattern generated by the number 2 by summing digits." >}} {{< figure src="pattern_6_29.svg" caption="Pattern generated by the number 6 in base 30." class="tiny" alt="Pattern generated by the number 6 by summing digits." >}} + +### Generalizing to Arbitrary Numbers of Directions +What if we didn't turn 90 degrees each time? What, if, instead, we turned 120 degrees (so that +turning 3 times, not 4, would leave you facing the same direction you started)? We can pretty easily +do that, too. Let's call this number of turns \\(c\\). Up until now, we had \\(c=4\\). + +First, let's update our condition. Before, we had "\\(d\\) cannot be divisible by 4". Now, +we aren't constraining ourselves to only 4, but rather using a generic variable \\(c\\). +We then end up with "\\(d\\) cannot be divisible by \\(c\\)". For instance, suppose we kept +our divisor as 9 for the time being, but started turning 3 times instead of 4. This +violates are divisibility condtion, and we once again end up with a spiral: + +{{< figure src="pattern_8_9_t3.svg" caption="Pattern generated by the number 8 in base 10 while turning 3 times." class="tiny" alt="Pattern generated by the number 3 by summing digits and turning 120 degrees." >}} + +If, on the other hand, we pick \\(d=8\\) and \\(c=3\\), we get patterns for all numbers just like we hoped. +Here's one such pattern: + +{{< figure src="pattern_7_8_t3.svg" caption="Pattern generated by the number 7 in base 9 while turning 3 times." class="tiny" alt="Pattern generated by the number 7 by summing digits in base 9 and turning 120 degrees." >}} + +Hold on a moment; it's actully not so obvious why our condition _still_ works. When we just turned +on a grid, things were simple. As long as we didn't end up facing the same way we started, we will +eventually perform the exact same motions in reverse. The same is not true when turning 120 degrees, like +we suggested. Here's a circle with the turn angles labeled: + +{{< figure src="turn_3_1.png" caption="Orientations when turning 120 degrees" class="small" alt="Possible orientations when turning 120 degrees." >}} + +We never quite do the exact _opposite_ of any one of our movements. So then, will we come back to the +origin anyway? Well, let's start simple. Suppose we always turn by exactly one 120-degree increment +(we might end up turning more or less, just like we may end up turning left, right, or back in the +90 degree case). Now, + +1. Suppose that having performed one complete cycle, we end up away from the center +by \\(dx\\) on the \\(x\\)-axis, and \\(dy\\) on the \\(y\\)-axis (we do this without loss +of generality). +2. We are now turned around by 120 degrees, so once we perform the cycle again, we end up offset +by \\(dx(\\cos 120)-dy(\\sin 120)\\) on the \\(x\\)-axis, and \\(dx(\\sin 120)+dy(\\cos 120)\\) on +the \\(y\\)-axis (I got this from the [rotation matrx](https://en.wikipedia.org/wiki/Rotation_matrix) +page on Wikipedia). +3. After one more step, we end up with having rotated a total of 240 degrees. As we perform the cycle +again, we end up having moved by an additional \\(dx(\\cos 240)-dy(\\sin 240)\\) and \\(dx(\\sin 240)+dy(\\cos 240)\\). + +Summing up all of these changes, we get: + +{{< latex >}} + dx(\cos0+\cos120+\cos240) + dy(\sin0+\sin120+\sin240) +{{< /latex >}} + +Why don't we start trying to write this in terms of variables already? For some number of turns +\\(c\\), a single turn is \\(360/c\\) degrees. We start having turned 0 degrees, then progress +to having turned \\(360/c\\) degrees, then \\(2\times360/c\\), and so on until \\((c-1)360/c\\). +We can write this using _summation notation_ (and radians instead of degrees) as follows: + +{{< latex >}} + \begin{aligned} + x &= dx\left[\sum_{i=0}^{c-1} \cos\left(i\frac{2\pi}{c}\right)\right] - + dy\left[\sum_{i=0}^{c-1} \sin\left(i\frac{2\pi}{c}\right)\right] \\ + y &= dx\left[\sum_{i=0}^{c-1} \sin\left(i\frac{2\pi}{c}\right)\right] + + dy\left[\sum_{i=0}^{c-1} \cos\left(i\frac{2\pi}{c}\right)\right] \\ + \end{aligned} +{{< /latex >}} + +For reasons beyond the scope of this article, sums like those between the square brackets +in the above equations _always_ equal zero. This means that after all the turns have been made, +we get \\(x=0\\) and \\(y=0\\) -- back at the origin, where we started! + +{{< todo >}}Maybe we can prove the sin/cos thing? {{< /todo >}} + +What if we turn by 240 degrees at a time: 2 turns instead of 1? Even though we first turn +a whole 240 degrees, the second time we turn we "overshoot" our initial bearing, and end up at 120 degrees +compared to it. As soon as we turn 240 more degrees (turning the third time), we end up back at 0. +In short, even though we "visited" each bearing in a different order, we visited them all. + +{{< figure src="turn_3_2.png" caption="Orientations when turning 120 degrees, twice at a time" class="small" alt="Possible orientations when turning 120 degrees, twice at a time." >}} + +Let's try put some mathematical backing to this "visited them all" idea. + +{{< todo >}}Remainders, visited them all, etc.{{< /todo >}} + +But let's not be so boring. We can branch out some, of course. + +{{< figure src="pattern_1_7_t5.svg" caption="Pattern generated by the number 1 in base 8 while turning 5 times." class="tiny" alt="Pattern generated by the number 1 by summing digits in base 8 and turning 72 degrees." >}} + +{{< figure src="pattern_3_11_t6.svg" caption="Pattern generated by the number 3 in base 12 while turning 6 times." class="tiny" alt="Pattern generated by the number 3 by summing digits in base 12 and turning 60 degrees." >}} diff --git a/content/blog/modulo_patterns/pattern_1_7_t5.svg b/content/blog/modulo_patterns/pattern_1_7_t5.svg new file mode 100644 index 0000000..11189b4 --- /dev/null +++ b/content/blog/modulo_patterns/pattern_1_7_t5.svg @@ -0,0 +1,80 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/content/blog/modulo_patterns/pattern_3_11_t6.svg b/content/blog/modulo_patterns/pattern_3_11_t6.svg new file mode 100644 index 0000000..d23b179 --- /dev/null +++ b/content/blog/modulo_patterns/pattern_3_11_t6.svg @@ -0,0 +1,142 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/content/blog/modulo_patterns/pattern_3_4.svg b/content/blog/modulo_patterns/pattern_3_4.svg new file mode 100644 index 0000000..d2683a9 --- /dev/null +++ b/content/blog/modulo_patterns/pattern_3_4.svg @@ -0,0 +1,42 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/content/blog/modulo_patterns/pattern_7_8.svg b/content/blog/modulo_patterns/pattern_7_8.svg new file mode 100644 index 0000000..38bf8ac --- /dev/null +++ b/content/blog/modulo_patterns/pattern_7_8.svg @@ -0,0 +1,74 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/content/blog/modulo_patterns/pattern_7_8_t3.svg b/content/blog/modulo_patterns/pattern_7_8_t3.svg new file mode 100644 index 0000000..a055989 --- /dev/null +++ b/content/blog/modulo_patterns/pattern_7_8_t3.svg @@ -0,0 +1,58 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/content/blog/modulo_patterns/pattern_8_9_t3.svg b/content/blog/modulo_patterns/pattern_8_9_t3.svg new file mode 100644 index 0000000..727e876 --- /dev/null +++ b/content/blog/modulo_patterns/pattern_8_9_t3.svg @@ -0,0 +1,64 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/content/blog/modulo_patterns/turn_3_1.png b/content/blog/modulo_patterns/turn_3_1.png new file mode 100644 index 0000000..af17a27 Binary files /dev/null and b/content/blog/modulo_patterns/turn_3_1.png differ diff --git a/content/blog/modulo_patterns/turn_3_2.png b/content/blog/modulo_patterns/turn_3_2.png new file mode 100644 index 0000000..a00b66c Binary files /dev/null and b/content/blog/modulo_patterns/turn_3_2.png differ diff --git a/content/blog/modulo_patterns/turn_5_1.png b/content/blog/modulo_patterns/turn_5_1.png new file mode 100644 index 0000000..1784ea2 Binary files /dev/null and b/content/blog/modulo_patterns/turn_5_1.png differ