Ryan Doenges - Articles
http://ryandoeng.es
Sometimes the math is just gross<p>Programming is a little game. My opponent, past Ryan, introduces a problem into
my code and I, present Ryan, program a solution. When the dust settles and
I review my work I often find it inelegant. Ugly, even. <em>Would a mathematician
accept this approach? Surely I’ve made some grave error: I’ve overspecialized
too early, overlooked some obvious structure inherent in the problem…</em> It’s
a frustrating feeling, and I have been trying to avoid it by remembering that
good solutions don’t have to be elegant.</p>
<p>Some math must be taught via counterexample. The teacher makes a conjecture at
the board.</p>
<blockquote>
<p>Continuous functions are differentiable.</p>
</blockquote>
<p>Then, as the class watches in horror, the teacher constructs a concrete
counterexample.</p>
<blockquote>
<p>Define <script type="math/tex">f(x) = x\sin(1/x)</script> for nonzero <script type="math/tex">x</script> and set <script type="math/tex">f(0) = 0</script>.
Try to differentiate <script type="math/tex">f</script> at the origin.</p>
</blockquote>
<p>The presentation of the counterexample is at once an argument against the false
conjecture and an argument for a better one, a theorem which avoids such
“monsters.”</p>
<p>This post describes a concrete counterexample to an informal conjecture: to be
good, a solution has to be elegant. Sometimes, as I’m going to show, there’s
nothing pleasant about the right thing.</p>
<p>My example is the Stark-Heegner theorem. I’ve picked a theorem from math rather
than some kind of software artifact because I want to emphasize that math isn’t
naturally more beautiful than other lines of work. I keep the story of this
theorem in my pocket for when I’m dissatisfied with my work, and I hope it’s
useful to you too.</p>
<h3 id="quadratic-number-fields-and-their-rings-of-integers">Quadratic number fields and their rings of integers</h3>
<p>We need to make a whirlwind tour of abstract algebra before we can state the
theorem. It’s been about two years since I last took an algebra course and
I think I sold my textbook, so this is all cobbled together from Wikipedia and
some survey papers. If anything seems off, let me know and I can fix it. If you
taught me algebra, I apologize in advance.</p>
<p>Recall the rational numbers <script type="math/tex">\mathbb{Q}</script>. They’re nice enough, but they’re
missing lots of other things we like to call numbers, like <script type="math/tex">\sqrt{2}</script> or
<script type="math/tex">\pi</script>. We can tack all these missing <em>irrational numbers</em> onto <script type="math/tex">\mathbb{Q}</script>
in one fell swoop using Dedekind cuts or Cauchy sequences. This gets us the real
numbers <script type="math/tex">\mathbb{R}</script>, which have enough analytic structure to support things
like continuity and differentiation.</p>
<p>However, they have some algebraic gaps. If we’ve got a polynomial with numbers
for coefficients, won’t it have numbers for roots? For real numbers, the answer
is no: we can’t solve <script type="math/tex">x^2 + 1 = 0</script> in <script type="math/tex">\mathbb{R}</script>. To fill this gap, we
introduce the imaginary unit <script type="math/tex">i</script> as a solution to our equation and then make
sure all our algebraic operations still work. This gives us the complex numbers
<script type="math/tex">\mathbb{C}</script>, whose elements act like <script type="math/tex">x + iy</script> for some real numbers <script type="math/tex">x</script>
and <script type="math/tex">y</script>.</p>
<p>In algebra, we say that we’ve <em>adjoined</em> the element <script type="math/tex">i = \sqrt{-1}</script> to the
field <script type="math/tex">\mathbb{R}</script> to obtain the <em>field extension</em> <script type="math/tex">\mathbb{C}</script> of
<script type="math/tex">\mathbb{R}</script>. We write <script type="math/tex">\mathbb{C} = \mathbb{R}(i)</script>. This operation makes
sense on any field, that is, on any set supporting addition, multiplication, and
division operations obeying some reasonable axioms. The Stark-Heegner theorem
involves a particular class of field extensions, the <em>quadratic field
extensions</em> <script type="math/tex">\mathbb{Q}(\sqrt{d})</script>.</p>
<p>The first thing we ought to notice is that the only values of <script type="math/tex">d</script> that matter
are <em>square-free</em>. If <script type="math/tex">k^2</script> divides <script type="math/tex">d</script> for some integer <script type="math/tex">k</script>, then there’s
an <script type="math/tex">n</script> smaller than <script type="math/tex">d</script> such that <script type="math/tex">d = nk^2</script> and <script type="math/tex">\sqrt{d} = k\sqrt{n}</script>.
Since <script type="math/tex">k</script> is just an integer, this means <script type="math/tex">\mathbb{Q}(d) = \mathbb{Q}(n)</script>.</p>
<p>Let <script type="math/tex">K = \mathbb{Q}(\sqrt{d})</script> for <script type="math/tex">d</script> square-free. We call a polynomial
with a leading coefficient <script type="math/tex">1</script> a <em>monic polynomial</em>. In <script type="math/tex">\mathbb{Q}</script>, the
roots of monic polynomials with coefficients in <script type="math/tex">\mathbb{Z}</script> are the integers
and nothing else. However, if we look for roots in <script type="math/tex">K</script> we sometimes get more
than just the ordinary integers. That’s okay, because the roots still form
a <em>ring</em>: they’re closed under multiplication and addition (but not division).
We call this ring the <em>ring of integers in <script type="math/tex">K</script></em> and denote it by
<script type="math/tex">\mathcal{O}_K</script>.</p>
<p>Rings have <em>ideals</em>, which are the nonempty subsets closed under addition and
absorbing under multiplication. For example, the even numbers are an ideal in
<script type="math/tex">\mathbb{Z}</script>: adding even numbers gets you an even number, and multiplying an
even number by any integer gets you an even number. The even numbers are
<em>generated</em> by <script type="math/tex">2</script>: you can write an even number <script type="math/tex">e</script> as <script type="math/tex">2k</script> for some
integer <script type="math/tex">k</script>, and for all integers <script type="math/tex">k</script>, <script type="math/tex">2k</script> is even. In arbitrary rings
<script type="math/tex">R</script>, ideals do not always have unique generators: sometimes you need a few
generators, and you take linear combinations of them with coefficients in <script type="math/tex">R</script>
to generate the ideal.</p>
<p>A ring in which this never happens and all ideals can be generated by a single
element is called a <em>principal ideal domain</em>. These are particularly nice
objects: in particular, rings of integers that are principal ideal domains admit
unique factorization into prime elements, just like in the natural numbers. For
a long time, mathematicians have wanted to figure out which quadratic field
extensions <script type="math/tex">K</script> have rings of integers <script type="math/tex">\mathcal{O}_K</script> that are principal
ideal domains. It turns out that for imaginary quadratic extensions, those
extensions in which we adjoin the square root of a negative number, this
question has been settled.</p>
<h3 id="years-of-toil">160 years of toil</h3>
<p>The Stark-Heegner theorem goes like this.</p>
<blockquote>
<p><strong>Theorem.</strong> <em>There are finitely many square-free negative integers <script type="math/tex">d</script> for
which the ring of integers in <script type="math/tex">\mathbb{Q}(\sqrt{d})</script> is a principal ideal
domain.</em></p>
</blockquote>
<p>Well, that’s not really it. Here’s the real thing.</p>
<blockquote>
<p><strong>Theorem.</strong> <em>There are exactly nine square-free negative integers <script type="math/tex">d</script> for
which the ring of integers in <script type="math/tex">\mathbb{Q}(\sqrt{d})</script> is a principal ideal
domain, and they are <script type="math/tex">-1,</script> <script type="math/tex">-2,</script> <script type="math/tex">-3,</script> <script type="math/tex">-7,</script> <script type="math/tex">-11,</script> <script type="math/tex">-19,</script>
<script type="math/tex">-43,</script> <script type="math/tex">-67,</script> and <script type="math/tex">-163</script>.</em></p>
</blockquote>
<p>It’s not elegant. It’s ugly and it’s frustrating. Why stop at <script type="math/tex">-163</script>? Is this
some kind of joke? It took 160 years of collective toil to produce satisfactory
answers to these two questions: a long proof, and “No.”</p>
<p>Gauss came up with the list of what are now known as Heegner numbers by
computing the <em>class number</em> of many rings of integers by hand. The class number
is 1 if and only if the ring is a principal ideal domain. He came up with the
above list of values for <script type="math/tex">d</script> and conjectured that it was complete.</p>
<p>That was at the turn of the 19th century. Plenty of mathematicians looked at the
list and felt frustrated. It’s maddening. Why no others? Even more maddening,
some 130 years later, was a result of Heilbronn and Linfoot showing that there
are at most 10 valid values for <script type="math/tex">d</script>:</p>
<p>\[d = -1, -2, -3, -7, -11, -19, -43, -67, -163,\ ???\]</p>
<p>Now this was high drama. God created the integers, but did He create a tenth
<script type="math/tex">d</script>?</p>
<p>In 1952, a German high school teacher named Kurt Heegner published a proof
showing that there is no tenth value for <script type="math/tex">d</script>. But his proof took some leaps of
faith and, worse yet, was “written in an amateurish and rather mystical style”
that made heavy use of results proved in a poorly regarded algebra textbook. You
can see where this is going: no one accepted his proof. He died in 1965 an
anonymous Berliner.</p>
<p>It was left to Harold Stark, a young American mathematician, to cross the finish
line. He learned enough German to decipher Heegner’s work and in 1967 published
a proof similar to Heegner’s. This isn’t to say that he simply unearthed
Heegner’s work and dusted it off. His approach was different enough that it
could rightfully be called a distinct proof, and he later published a paper
specifically devoted to closing “the gap” in Heegner’s proof.</p>
<p>The theorem carries Stark and Heegner’s names, but results like these are not
proved alone. There were important contributions from Baker, Siegel, and Deuring
around the same time. For more historical and mathematical details, I recommend
<a href="https://projecteuclid.org/download/pdf_1/euclid.bams/1183552617">Dorian Goldfeld’s survey paper</a>.</p>
<h3 id="whats-the-point">What’s the point</h3>
<p>There are better measures of importance and quality than elegance. Exciting and
worthwhile work can be clunky. Even the objectives of the work can be clunky.
It’s fine.</p>
Sat, 07 Oct 2017 00:00:00 -0400
http://ryandoeng.es/2017/10/07/stark-heegner/
http://ryandoeng.es/2017/10/07/stark-heegner/tactic : tactical :: function : functional<p><em>I’m going to try using this blog as a lab notebook. As a first entry in that
style, here’s a note about names.</em></p>
<p>In Coq, tactics build proofs and tacticals build complex tactics from simpler
ones. These names, particularly “tactical”, have always seemed strange to me.
While the Coq reference manual does explain what tactics and tacticals are, it
rejects “tactical” as a vague “folklore notion” and never elaborates on how the
names came to be.</p>
<blockquote>
<p>Tactics are built from atomic tactics and tactic expressions (which extends
the folklore notion of tactical) to combine those atomic tactics.</p>
</blockquote>
<p>It turns out that the people who invented tactic-based interactive theorem
proving in the LCF project also invented the names “tactic” and “tactical”. In
their 1972 paper “A Metalanguage for Interactive Proof in LCF”, Gordon et al.
are nice enough to explain why they choose the names they do:</p>
<blockquote>
<p>A strategy—or recipe for proof—could be something like “induction on f and
g, followed by assuming antecedents and doing case analysis, all interleaved
with simplification”. This is imprecise—analysis of what cases?—what kind
of induction, etc, etc.—but these in turn may well be given by further
recipes still in the same style. The point is that such strategies appear to
be built from simpler ones (which we call <em>tactics</em> rather than strategies) by
a number of general operations in fairly regular ways; we call these
operations <em>tacticals</em> by analogy with functionals.</p>
</blockquote>
<p>A functional is a function that takes functions as arguments. For example,
integration on the unit interval is a functional which takes a function
integrable on [0, 1] and produces a real number.</p>
<p>The use of “tactic” has migrated a bit since 1972. In LCF a tactic is an atomic
action on proof state and a strategy is built from tactics or sub-strategies
structured by tacticals. In Coq an LCF tactic is called an atomic tactic and an
LCF strategy is called a tactic, while tacticals or tactic expressions are
still tacticals. These are fuzzy correspondences: for example, an LCF strategy
might better correspond to a full-on Coq proof, which (CPDT advice aside) is
almost always going to be at least several tactics long. Got it?</p>
Sun, 19 Feb 2017 00:00:00 -0500
http://ryandoeng.es/2017/02/19/tactical/
http://ryandoeng.es/2017/02/19/tactical/A dog truth<p>When my family lived in Pennsylvania, we had a large back yard with one giant
oak and one tall cedar. On hot summer days our big blonde dog would lope down
to the base of the cedar tree and clear a swath the size of his body out of the
loosely matted needles there, and till the dirt with his claws. When he had
cleared away the top layer he would bring his body into position and flop
dramatically onto the newly exposed earth.</p>
<p>He would lounge there for hours, panting and occasionally lifting his head to
sniff at the breeze. We liked to pretend at exasperation or surprise in
response, but the truth is that few things in life are more magnificent to
behold than a big dog beating the heat.</p>
Sat, 22 Aug 2015 00:00:00 -0400
http://ryandoeng.es/2015/08/22/dog/
http://ryandoeng.es/2015/08/22/dog/We go down to the river<p>to wash our arms and legs.</p>
Fri, 21 Aug 2015 12:38:39 -0400
http://ryandoeng.es/2015/08/21/river/
http://ryandoeng.es/2015/08/21/river/"Every one writes like that now."<p>From Constance Garnett’s translation of <em>The Brothers Karamazov</em>:</p>
<blockquote>
<p>“He talks a lot of sense, too. Writes well. He began reading me an article
last week. I copied out three lines of it. Wait a minute. Here it is.”</p>
<p>Mitya hurriedly pulled out a piece of paper from his pocket and read:</p>
<p>“‘In order to determine this question, it is above all essential to put one’s
personality in contradiction to one’s reality.’ Do you understand that?”</p>
<p>“No, I don’t,” said Alyosha. He looked at Mitya and listened to him with
curiosity.</p>
<p>“I don’t understand either. It’s dark and obscure, but intellectual.
‘Every one writes like that now,’ he says, ‘it’s the effect of their
environment.’ They are afraid of the environment.”</p>
</blockquote>
Sat, 08 Aug 2015 07:11:00 -0400
http://ryandoeng.es/2015/08/08/every-one-writes-like-that-now/
http://ryandoeng.es/2015/08/08/every-one-writes-like-that-now/Overhaul<p>In May, I found out about an unfailingly pleasant bookstore in Wallingford
which stocks only poetry. It’s called <a href="http://www.openpoetrybooks.com/">Open Books</a>. If you live in
Seattle and have the time and money to read books of poetry, you should pay
Open Books a visit.</p>
<p>I bought some translated poetry: a Nichita Stănescu collection and a Kim
Hyesoon book. I liked the poems so much that I wrote Javascript to put little
quotes from them onto the bottom of my website, at random.<sup id="fnref:1"><a href="#fn:1" class="footnote">1</a></sup> I eventually
added more quotes from other things I’ve read or remembered. I regret bringing
in Javascript for this, but it’s only three lines of actual code. Readers with
no Javascript in their browser will get the same quote every time (thanks,
<code class="highlighter-rouge"><noscript></code>). If you are interested in finding the source of a given quote,
look no further than the source that gave you the quote, which is to say: I put
some helpful comments in <a href="/js/taglines.js"><code class="highlighter-rouge">/js/taglines.js</code></a>.</p>
<p>That all happened back in mid-May. Yesterday (the 21st of July) I took this
site-editing impulse to its obvious and natural conclusion by ripping out all
the CSS on my site and adding back in just enough styling to make it readable
on my phone and my laptop. This only took 16 lines of styling, surprisingly,
and it looks fine in <code class="highlighter-rouge">lynx</code>.</p>
<p>How is this the “obvious and natural conclusion” to my earlier additions?
I don’t know. It seems obvious, and natural. I don’t make<sup id="fnref:2"><a href="#fn:2" class="footnote">2</a></sup> the rules.</p>
<div class="footnotes">
<ol>
<li id="fn:1">
<p>Does this count as net art? Am I a net artist? <a href="#fnref:1" class="reversefootnote">↩</a></p>
</li>
<li id="fn:2">
<p>I do, however, enforce them. <a href="#fnref:2" class="reversefootnote">↩</a></p>
</li>
</ol>
</div>
Wed, 22 Jul 2015 05:17:00 -0400
http://ryandoeng.es/2015/07/22/overhaul/
http://ryandoeng.es/2015/07/22/overhaul/Chromatophoria<p>A few weeks ago I participated in the inagural <a href="https://picoctf.com/">PicoCTF</a>, a high
school hacking competition run by Carnegie Mellon’s Plaid Parliament of Pwning.
I ended up placing a disappointing 30th–I spent way too much time that week
playing trumpet in pit orchestra for the school musical.</p>
<p>At the close of the competition the organizers asked for interested competitors
to do writeups of some problems, so here’s one from me.</p>
<p><a href="https://picoctf.com/compete#Chromatophoria">Chromatophoria</a> was my favorite forensics problem. It presents
you with a PNG of a magnifying glass and asks you to determine the key with
a generous hint:</p>
<blockquote>
<p>Their transmission is entirely visual; you suspect that they may be
communicating through the color values.</p>
</blockquote>
<p>So, I knew I was looking for color alterations in the (mostly white) image.
I opened it in GIMP and used the bucket tool to shade identical white pixels
black. Zooming in, I looked for any remaining white pixels, and sure enough:</p>
<p><img src="/img/bucketfill.png" /></p>
<p>So, the first row of the image was full of slightly altered color values.
Since I recently spent a lot of time working with PNG images in ruby with
ChunkyPNG to build <a href="http://glitchit.ryandoeng.es/">glitchit</a> (blog post forthcoming), I decided to
inspect the image with ChunkyPNG in IRB.</p>
<div class="highlighter-rouge"><pre class="highlight"><code>irb(main):001:0> require 'chunky_png'
=> true
irb(main):002:0> img = ChunkyPNG::Image.from_file('./steg.png')
=> <huge string representation>
</code></pre>
</div>
<p>I only need the first row, so I pulled it out into an array:</p>
<div class="highlighter-rouge"><pre class="highlight"><code>irb(main):003:0> arr = []
=> []
irb(main):004:0> (0...img.width).each { |i| arr << img[i, 0] }
=> 0...800
irb(main):005:0> arr
=> [4278189823, 4278189823, 4278124287, 4294967039, 4278189823, 4294901759,
4294967295, 4278124543, 4278124543, 4278124287, 4278124287, 4294901503,
<snip>
4278124287, 4278124287, 4278124287, 4278124287, 4278124287, 4278124287,
4278124287, 4278124287, 4278124287, 4278124287, 4278124287, 4278124287,
4278124287, 4278124287]
irb(main):006:0> arr.map { |x| x.to_s(16) }
=> ["fefffeff", "fefffeff", "fefefeff", "fffffeff", "fefffeff", "fffeffff",
<snip>
"fefefeff", "fefefeff", "fefefeff", "fefefeff", "fefefeff", "fefefeff"]
</code></pre>
</div>
<p>At this point I realized that all the bytes in the row were either <code class="highlighter-rouge">0xFF</code> or
<code class="highlighter-rouge">0xFE</code>, so I split the whole array into bytes and did the first thing that came
to mind–changed <code class="highlighter-rouge">0xFF</code> to a 1 bit and <code class="highlighter-rouge">0xFE</code> to a 0 bit and joined them into
an ASCII string. That didn’t actually work–the transparency channel in the
image was only <code class="highlighter-rouge">0xFF</code> bytes and messed up the text. After dropping the
transparency byte, I got the flag out. It was an entertaining exercise in ruby
string manipulation and reminded me of building up a long shell pipeline in
zsh.</p>
<p>Here’s what I ended up with, though I’m pretty sure my solution during the
competition was slightly different. I’ll be taking better notes next time
around.</p>
<div class="highlighter-rouge"><pre class="highlight"><code>irb(main):007:0> [arr.map { |x| x.to_s(16).scan(/../).slice(0,3) }.flatten.map { |x| x == "fe" ? 0 : 1 }.join('')].pack("B*")
=> "Hey I think we can write safely in this file without anyone seeing it. Anyway, the secret key is: XXXXXXXXXXXXXXX\0\0<more null bytes>"
</code></pre>
</div>
<p>So, I took a list of color integers, turned them into hex strings, split those
into bytes, took the first three of those bytes in an array, flattened the
arrays, changed the bytes to a 1 or 0 if they were <code class="highlighter-rouge">0xFF</code> or <code class="highlighter-rouge">0xFE</code>, joined
those 1s and 0s into a string, wrapped the whole thing in an array, and used
<code class="highlighter-rouge">#pack</code> to turn that string of binary digits into a string.</p>
<p>Pipelines! They’re so fun. I approached most of the problems in this same
way–trying to slowly build up a pipeline before spending time on
a single-purpose script. Sometimes the pipleine was shell, sometimes it was
ruby. Either way, I felt thoroughly UNIXy!</p>
Sat, 18 May 2013 09:55:34 -0400
http://ryandoeng.es/2013/05/18/chromatophoria-writeup/
http://ryandoeng.es/2013/05/18/chromatophoria-writeup/New blog<p>I’ve finally got somewhere to put my writing. Expect some <a href="https://picoctf.com/">PicoCTF</a>
writeups here relatively soon.</p>
Wed, 15 May 2013 18:37:00 -0400
http://ryandoeng.es/2013/05/15/new-blog/
http://ryandoeng.es/2013/05/15/new-blog/