<?xml version="1.0" encoding="UTF-8"?><rss version="2.0"><channel><title>Dennis Chen's Writing</title><link>https://dennisc.net/writing</link><description>Content in the writing section of Dennis Chen's website</description><language>en</language>
<item>
	<title>All New Year's resolutions come to an end</title>
	<link>https://dennisc.net/writing/blog/ny-res.md</link>
	<description><![CDATA[<p>At the start of the year I set some
puzzle-writing goals. Well, I've technically met them all, and as usual
for a New Year's resolution, now is about time to call it quits.</p>
<p>I've figured out the niches of sudoku I like to set: arithmetic,
sets, and geometry. (Though I still don't want to touch anti-knight with
a 10-foot long pole.) Since the role of these goals was to find my
niche, in some sense, I've succeeded in my meta-goal, even if I'm
technically giving up on my resolution.</p>]]></description>
	<pubDate>11 Apr 2023</pubDate>
</item>
<item>
	<title>Gas Leak on an Airplane</title>
	<link>https://dennisc.net/writing/blog/gas-airplane.md</link>
	<description><![CDATA[<p>As I am writing this, I am sitting at gate A38
of Dallas Fort Worth International Airport, waiting for news of when our
next plane might take off. It is 1:30 AM in Dallas, and I am just about
ready to keel over and die.</p>
<p>How did we get here?</p>
<p>I boarded a plane from PIT to DFW which took off about 7:15 PM,
Pittsburgh time. (It's an hour ahead of Dallas.) Everything is all
hunky-dory, and we land at about 10 PM Dallas time. We bust our asses
off and get on a plane from DFW to SFO which took off about 11 PM. So
far so good.</p>
<p>But then a gas leak(!!) of all things occurs in the plane, and so we
have to turn around. Initially I was a bit annoyed that there was a
problem with our flight, but it quickly turns into a horrified sort of
gratitude that the plane didn't blow up in the sky instead. Anyway, we
hadn't been flying long, so we were able to land safely.</p>
<p>The plan originally was to get everyone out of the plane, including
the pilots, and then all hop onto a different plane. However, the pilots
reported feeling sick(?)<a href="#fn1" class="footnote-ref" id="fnref1"
role="doc-noteref"><sup>1</sup></a> because of the gas fumes and thus
were unable to fly. So we are now waiting for another set of pilots, and
who knows how long that'll take because (expectedly) pilots are
<em>sleeping</em> at 1:30 AM.</p>
<p>The next scheduled flight is at 5 AM, and if there is no replacement
flight, I fear the passengers may need to fight for the seats on the 5
AM flight. (The plane with the gas leak was a full flight.)</p>
<p>So yeah, this has been a great start to my fall break. But genuinely,
I am so glad to be alive right now.</p>
<p><strong>Update</strong>: They found a flight at 7 AM and gave us
meal/Uber/hotel vouchers. Unfortunately, the only hotels around were
about 20 minutes away, but at least the hotel room was very nice. I
slept for about 3 hours until I woke up at 5 to go to the airports and
got McDonald's.</p>
<p>The 7 AM flight got to San Francisco without a hitch. I am still
tired as hell, but all is alright, I suppose.</p>
<section id="footnotes" class="footnotes footnotes-end-of-document"
role="doc-endnotes">
<hr />
<ol>
<li id="fn1"><p>I'm not entirely sure about the details because I was in
the bathroom when this announcement was made. But I was later informed
that the pilots were in no condition to fly.<a href="#fnref1"
class="footnote-back" role="doc-backlink">↩︎</a></p></li>
</ol>
</section>]]></description>
	<pubDate>11 Oct 2025</pubDate>
</item>
<item>
	<title>Regarding financial aid in my math courses</title>
	<link>https://dennisc.net/writing/blog/finaid.md</link>
	<description><![CDATA[<p>On the subject of financial aid for math
classes: I used to say something along the lines of,</p>
<blockquote>
<p>"My parents don't want to pay" or "I ran out of allowance" is not
going to get your tuition waived. If you have genuine financial need,
then of course that is a different story.</p>
</blockquote>
<p>In some alternate universe I would've started charging for classes
while saying this. In that alternate universe, someone who needs
financial aid might not have applied for my class, or worse, they would
have paid for it. And this fall, I <em>am</em> charging for classes.<a
href="#fn1" class="footnote-ref" id="fnref1"
role="doc-noteref"><sup>1</sup></a> So let me clear this up for the
record.</p>
<p>You know, I don't like charging students extortionary fees.<a
href="#fn2" class="footnote-ref" id="fnref2"
role="doc-noteref"><sup>2</sup></a> In fact, I charge a nominal fee for
two reasons: so everyone takes the class seriously, and to raise funds
for Math Advance.</p>
<p>I have bad memories of debating whether to pay 1500 a semester for
some AIME classes and regretting it dearly, and I don't want to put
anyone else in a similar situation. Most of my students are upper-middle
class Americans who can see a price tag of $100 and say, "wow that's
pretty cheap let's go for it" without a second thought.</p>
<p>But I recognize this is not everyone.</p>
<p>There are countries where 100 dollars goes a lot further than it does
here. People have individual circumstances. The particulars are none of
my business.</p>
<p>In any case, the message I was inadvertently sending was that I was
concerned about abuse. And well-intentioned students might think, "wow
there is a problem, and I should avoid trying to be part of it".</p>
<p>But there is no such problem. I can think of only one instance where
someone acted in bad faith in my classes (a kid posted a handout on
CourseHero, hardly what I'd call a systematic pattern of abuse), and
zero from my work at Math Advance.</p>
<p>I don't mean to brag, but I will anyway: our program attracts good
students. Really good students. Many of them qualify for MOP. It
wouldn't surprise me too much if we start seeing IMO qualifications
soon. And all of them are hardworking, honest students who respect the
program and leave it better than they found it. If you are a prospective
student reading this, then this description probably applies to you too.
I will say it again: we attract good students, and you hopefully will be
among that number. Not a single one of our students has turned out to be
a bad actor, and if you are worrying that you might become the first,
you most probably are not.</p>
<p>I am rather more concerned that there will be a lack of <em>use</em>
than a pattern of abuse. So if you think you need financial aid, you
need financial aid. And you will get it, no questions asked. Very rarely
will a program accept "trust me bro" as a reason for financial aid, and
for good reason. But for better reason, we do.</p>
<p>To make a long story short: if you think you maybe might kinda
probably sort of need a little financial aid, then you should ask for
financial aid. We need to be more proactive in making sure not all our
students are upper middle class Americans, and this post is the first
step.</p>
<section id="footnotes" class="footnotes footnotes-end-of-document"
role="doc-endnotes">
<hr />
<ol>
<li id="fn1"><p>I almost wrote the same thing this year too, until I
realized it was a bad idea. In fact, that's why I'm writing this post.<a
href="#fnref1" class="footnote-back" role="doc-backlink">↩︎</a></p></li>
<li id="fn2"><p>Parents who try to get me to teach their kid are a
different story; if I'm feeling mean, I might just quote you for a
hundred an hour. Read the <a href="/faq">FAQ</a>, people!<a
href="#fnref2" class="footnote-back" role="doc-backlink">↩︎</a></p></li>
</ol>
</section>]]></description>
	<pubDate>17 Aug 2023</pubDate>
</item>
<item>
	<title>Puzzle goals, part 3</title>
	<link>https://dennisc.net/writing/blog/puzzle-goals-part-3.md</link>
	<description><![CDATA[<p>It's March 1st, and my February goal was either
a success or failure, depending on how you think about it.</p>
<p>It was a success in that I further developed my range with standard
variants, like killer, diagonal, thermo, etc. It also was a success in
that I wrote using 4 variants I never used before: diagonal, quad,
X-lines, and starry sums. Two of these are new variants invented by me:
X-Lines and Starry Sums, and I particularly think the second has a lot
of potential.</p>
<p>It was a failure in the sense that I didn't use four new standard
variants, so my range of setting does not even encompass many of the
common variants. There's a lot I'm missing: sandwiches, between lines,
etc, that just feel out of my alleyway right now (which I suppose is why
I never set them). I am not too concerned about this fact though.</p>
<p>So supposedly I'm slated to write a classic sudoku this month, but a
couple of reasons this might not happen:</p>
<ul>
<li>I'm interested in writing a Monster Cages puzzle, where the clue
indicates the product of the sum of shaded cells and unshaded cells. (Or
I can make it a Chaos Construction and make clues indicate the product
of the region sums... that would be kind of cool.)</li>
<li>Also my latest puzzle, "Intersections", has an obvious dual: "Mind
the Gap", where X-Sum clues in the same row/col add to less than 45. I
don't know if including diagonals would be very thematic so I won't use
them.</li>
<li>I also want to start learning more math/CS in preparation for
college next year.</li>
<li>I'd like to reignite some activity and come back to teaching in Math
Advance.</li>
</ul>
<p>So who knows if it'll happen in time. And as for the April goal,
probably I will not end up writing a crossword. I don't really get how
they work as a solver so my debut as a setter still seems pretty
far.</p>]]></description>
	<pubDate>1 Mar 2023</pubDate>
</item>
<item>
	<title>I have achieved the impossible --- anti-knight</title>
	<link>https://dennisc.net/writing/blog/ak.md</link>
	<description><![CDATA[<p>Well, ladies and gentlemen, I did it. The one
thing I never thought I'd do. I wrote an Anti-Knight puzzle, and with a
little help from <a
href="https://github.com/dclamage/SudokuSolver/wiki/fpuzzles-integration">Rangsk's
solver</a> to ensure that no cage I put broke the puzzle, I present you
<a href="/puzzles/6:13/ctc">6:13</a>.</p>
<p>Given the name for this puzzle, I think it'd be very easy to use
different cage totals and make this a recurring series. For example, if
I wanted to use 10 and 15 cages, I could call it 10:15, etc. Kind of
like a knock-off Killer Cages version of Florian Wortmann's Colorado
series.</p>
<p>And the best part is, it only took somewhere around 2 hours. Given
how long it's been since I set my last puzzle, I'm really proud of
that.</p>
<p>More life updates, including the recounting of a track meet, my
struggles in AP Chemistry, and roommate rizz, hopefully coming tomorrow
:)</p>]]></description>
	<pubDate>16 Apr 2023</pubDate>
</item>
<item>
	<title>Extension to Fall 2023 application deadline</title>
	<link>https://dennisc.net/writing/blog/fall-extension.md</link>
	<description><![CDATA[<p><a href="/writing/tech/domain-renewal">Because
my website was down for two days</a>, I'm extending the application
deadline for our <a href="/apply-2023.pdf">Fall 2023 course</a> until
Wednesday (Sep 6), 11:59 PM EST.</p>]]></description>
	<pubDate>4 Sep 2023</pubDate>
</item>
<item>
	<title>The difference between my essays and college apps</title>
	<link>https://dennisc.net/writing/blog/college-apps.md</link>
	<description><![CDATA[<p>Whenever I write an essay it's structured like
this: I've got a point and I'm bringing in anecdotes about myself to
back it up. The general point I'm trying to make is front and
center.</p>
<p>But for college apps I'm supposed to focus on myself, using anecdotes
about myself and making observations where I can.</p>
<p>So the difference is, rather than writing "this is my takeaway, here
are some stories" it has to be "this is my story, here are some
takeaways". It's a little difficult for me to write like that since I do
it so rarely.</p>]]></description>
	<pubDate>27 Aug 2022</pubDate>
</item>
<item>
	<title>Ten Things Effective Leaders Do</title>
	<link>https://dennisc.net/writing/blog/10-traits.md</link>
	<description><![CDATA[<p>Leading is hard. I have to lead myself to bed
each night without tripping over and falling on my face. Nobody is
perfect, but recently I've been able to find the bathroom in the dark
nine out of every ten times, so I thought I'd share my expertise with
you.</p>
<h2 id="blame-everything-on-consensus">1. Blame Everything on
Consensus</h2>
<p>Rejecting people is hard. So is doing things that aren't popular. But
even harder is explaining why. Fortunately, effective leaders never have
to explain anything.</p>
<p>"Why'd you ban me from the server?" Sorry, pal, it wasn't me --- it
was the <em>group</em> that banned you. You can ask me to explain and
I'll "consult the rest of the team" until you stop.</p>
<h2 id="ask-people-to-do-work-for-you">2. Ask People to Do Work For
You</h2>
<p>As a leader, doing work is beneath you. That's why you have to get
your subordinates to do it for you. But be careful, don't fall into the
trap that many others have fallen into before. Don't work to make other
people do work. This includes doing things like the dreadful
"communication". Your time is better spent writing angry blog posts
anyway.</p>
<h2 id="be-pissy-when-things-dont-go-your-way">3. Be Pissy When Things
Don't Go Your Way</h2>
<p>Sometimes, just asking people to do your work doesn't work.
Fortunately, there is a simple solution for this.</p>
<p>Decision theory states that all animals weigh the potential gains and
losses of an action before doing it. Humans fall into the animal
kingdom, last time I checked my National Geographic. If you can make the
potential losses (i.e. time and sanity) greater, maybe people will do
what you want next time. It's not like they can kick you out, you're the
<em>leader</em> for crying out loud.</p>
<h2 id="take-second-chances">4. Take Second Chances</h2>
<p>Your mama always told you everyone deserves a second chance. And as a
leader, a brave pioneer, a daring venturer whose risk of failure is
naturally higher, you deserve a lot more second chances than anyone
else. So be brave and take them, even when no one else is brave enough
to admit that you deserve it.</p>
<h2 id="take-breaks">5. Take Breaks</h2>
<p>Leading is hard work. So is writing this article, so I'll be taking a
break from explaining this point...</p>
<h2 id="waste-time">6. Waste Time</h2>
<p>Not yours, because it's too valuable to waste, but everyone else's.
Find people who would be willing to do anything for you even if you have
no clue what you need them to do. To prevent anyone else from figuring
out you have no clue what you're doing, waste their time to distract
them. They won't notice.</p>
<h2 id="hold-meetings">7. Hold Meetings</h2>
<p>Everyone knows that important people meet often, and you're
important, so meet often. As a bonus, you get to hear yourself talk. How
cool is that!</p>
<p>As a double-bonus, you also get to fulfill the sixth point at the
same time. Incredible!</p>
<h2 id="take-responsibility">8. Take Responsibility</h2>
<p>Make sure you take responsibility for all of your successes. Don't
worry about mistakes, those are what lesser leaders make.</p>
<h2 id="shift-the-goalposts">9. Shift the Goalposts</h2>
<p>After getting such good nuggets of wisdom it wouldn't be fair to
expect yet another one from me. After all, this post was so good it
might as well be worth ten of someone else's tips. Or even a hundred,
pick whatever arbitrarily large number you like.</p>]]></description>
	<pubDate>4 Dec 2021</pubDate>
</item>
<item>
	<title>Our Fall 2023 program has rejected 0 applicants</title>
	<link>https://dennisc.net/writing/blog/0-rejections.md</link>
	<description><![CDATA[<p>As you read the title, you might be thinking,
"then what's the point of the application? If it isn't to weed people
out, then what is it?"</p>
<p>Well, that is <em>kind of</em> the point. There's probably a
selection bias happening here: because there's an application process
and I'm very vocal about only accepting very self-motivated students who
take things into their own hands, the only kind of people who would
apply are the ones who would be accepted anyway.</p>
<p>But this selection bias, while a nice side effect of the application
process, is not the main point. The point is to get people used to
"shooting their shot", so to say. Instead of having your parents fill
out a class registration form for you, and getting driven there,
students now have to reach out to me, put in their own effort to get in
the class, etc. In fact, it's <em>because</em> enough people have taken
this initiative over the last year that I decided to teach a class again
to begin with.</p>]]></description>
	<pubDate>2 Sep 2023</pubDate>
</item>
<item>
	<title>Inductive Structures</title>
	<link>https://dennisc.net/writing/blog/inductive-structures.md</link>
	<description><![CDATA[<p>I sat in on a lecture mostly about inductive
structures today in CMU's 21-300 Basic Logic. I went with who we will
refer to as <em>cursed schedule guy</em> (from the last post) and we
talked with Professor Cummings afterwards; more on the contents at the
end.</p>
<p>Also, I will be a lot more expository than the lecture was. I feel
like you had to connect a lot of dots in your head in the lecture,
whereas the point here is to at least provide a reference for myself to
turn my brain off.</p>
<p>No guarantees that the details are entirely right since this is off
memory and Google is really, really bad when it comes to formal logic
stuff. Also I will be vague since this is a general overview.</p>
<p>Anyway, it's math time!</p>
<p>First we establish the following:</p>
<blockquote>
<p>(Finitary Function) A <strong>finitary function</strong> is just a
function with a finite number of inputs.</p>
</blockquote>
<p>An example of a finitary function is addition on the reals: it takes
<span class="math inline">ℝ × ℝ → ℝ</span>.</p>
<p>An example of an infinitary function (i.e. not finitary) is one that
takes an infinite number of reals as input and outputs their sum; e.g.
<span class="math inline">$f(1, \frac{1}{2}, \frac{1}{4}, \cdots) =
2$</span>.<a href="#fn1" class="footnote-ref" id="fnref1"
role="doc-noteref"><sup>1</sup></a> Now here is where things get real
tricky. Take the function <span class="math inline"><em>g</em></span>
that does much the same as <span class="math inline"><em>f</em></span>,
only it takes <em>one</em> (which you will note is a finite number)
infinite sequence of reals. For example, <span
class="math inline">$g([1, \frac{1}{2}, \frac{1}{4}, \cdots]) =
2$</span>, where the input of <span
class="math inline"><em>g</em></span> is <em>the sequence</em> <span
class="math inline">$[1, \frac{1}{2}, \frac{1}{4}, \cdots]$</span>
rather than each individual element.</p>
<p>This seems super cursed; <span class="math inline"><em>f</em></span>
and <span class="math inline"><em>g</em></span> are fundamentally the
same and yet they are classified entirely differently for a theorem who
we will see <em>only</em> cares about this one classification. The point
is about finiteness of the number of inputs though, we don't need the
members of the input to be finite or countable or whatever.</p>
<blockquote>
<p>(Inductive Structures) An <strong>inductive structure</strong> is an
ordered pair <span class="math inline">(<em>X</em>, <em>F</em>)</span>
where <span class="math inline"><em>X</em></span> is a set and <span
class="math inline"><em>F</em></span> is a set of finitary
functions.</p>
</blockquote>
<p>This definition is very general. There is no restriction besides that
every function is <span class="math inline"><em>F</em></span> is
finitary. <span class="math inline"><em>F</em></span> itself may be
infinite, uncountable, whatever. So may <span
class="math inline"><em>X</em></span> be. In fact, not every function in
<span class="math inline"><em>F</em></span> needs to even admit any
member of <span class="math inline"><em>X</em></span> or tuples of
members of <span class="math inline"><em>X</em></span> as inputs.</p>
<p>A standard inductive structure is <span
class="math inline">(ℝ, {+, ×})</span>. Note <span
class="math inline">+</span> and <span class="math inline">×</span> are
functions that take two inputs in <span class="math inline">ℝ</span> and
return an output in <span class="math inline">ℝ</span>. For instance,
<span class="math inline">+(2, 2) = 4</span>. Yes, this is cursed
notation, but you can think of the binary operator <span
class="math inline">+</span> as a function with two inputs. And in fact,
you have to when strictly considering inductive structures. Also, this
inductive structure feels <strong>closed</strong>. This is a word we
will define later, but <span class="math inline">+</span> takes two
members of <span class="math inline">ℝ</span> to a member of <span
class="math inline">ℝ</span>. So does <span
class="math inline">×</span>. You should intuitively feel that this
inductive structure feels closed-ish.</p>
<p>Here is a more cursed inductive structure. Let <span
class="math inline"><em>X</em></span> be the set of odd integers and
<span class="math inline"><em>Y</em></span> be the set of even integers.
Then let <span class="math inline"><em>f</em></span> be some function
from <span class="math inline"><em>Y</em></span> to <span
class="math inline"><em>Y</em></span>. Then <span
class="math inline">(<em>X</em>, {<em>f</em>})</span> is an inductive
structure, despite the fact that <span
class="math inline"><em>f</em></span>'s domain does not include any
member of <span class="math inline"><em>X</em></span>. Cursed, isn't it?
But it still falls under the definition, even if this inductive
structure does not actually do anything interesting.</p>
<p>Now for a bit of notation that will make it easier to refer to <span
class="math inline"><em>f</em></span>'s arguments for arbitrary <span
class="math inline"><em>f</em> ∈ <em>F</em></span>. The motivation for
this notation is vectors, because in some sense vectors are just
lists.</p>
<p>We denote the list <span
class="math inline"><em>a</em><sub>0</sub></span>, <span
class="math inline"><em>a</em><sub>1</sub></span>, <span
class="math inline">…</span>, <span
class="math inline"><em>a</em><sub><em>n</em> − 1</sub></span> as <span
class="math inline"><em>a⃗</em></span>. We will refer to an arbitrary
element in the list <span class="math inline"><em>a⃗</em></span> as <span
class="math inline"><em>a</em><sub><em>i</em></sub></span>.</p>
<p>Now for our final definition:</p>
<blockquote>
<p>(Closure) A <strong>closure under <span
class="math inline"><em>F</em></span></strong> is a set <span
class="math inline"><em>X</em></span> such that for every function <span
class="math inline"><em>f</em> ∈ <em>F</em></span> and every <span
class="math inline"><em>a⃗</em></span> in the domain of <span
class="math inline"><em>f</em></span> such that <span
class="math inline"><em>a</em><sub><em>i</em></sub> ∈ <em>X</em></span>,
<span
class="math inline"><em>f</em>(<em>a⃗</em>) ∈ <em>X</em></span>.</p>
</blockquote>
<p>Say <span class="math inline"><em>X</em></span> is a closure under
<span class="math inline"><em>F</em></span>. Then you can naturally
construct a closed inductive structure <span
class="math inline">(<em>X</em>, <em>F</em>)</span>. We won't worry
about that in this post.</p>
<h2 id="the-argument">The argument</h2>
<p>Now for the theorem.</p>
<blockquote>
<p>For any set <span class="math inline"><em>X</em></span> and any set
of finitary functions <span class="math inline"><em>F</em></span>, there
exists a set <span class="math inline"><em>Y</em></span> such that <span
class="math inline"><em>X</em> ⊂ <em>Y</em></span> and <span
class="math inline"><em>Y</em></span> is a closure under <span
class="math inline"><em>F</em></span>. Furthermore, we can find a least
upper bound <span class="math inline"><em>Y</em></span>, meaning that
there exists some <span class="math inline"><em>Y</em></span> such that
for all <span class="math inline"><em>Z</em></span> satisfying the same
property, <span class="math inline"><em>Y</em> ⊂ <em>Z</em></span>.</p>
</blockquote>
<p>The main difficulty is showing such a <span
class="math inline"><em>Y</em></span> exists. The least upper bound
property is pretty easy to see just from how <span
class="math inline"><em>Y</em></span> is explicitly constructed.</p>
<h3 id="y-exists">Y exists</h3>
<p>We will recursively generate a sequence <span
class="math inline"><em>X</em><sub><em>i</em></sub></span>. Let <span
class="math inline"><em>X</em><sub>0</sub> = <em>X</em></span>, and let
<span
class="math inline"><em>X</em><sub><em>n</em> + 1</sub> = <em>X</em> ∪ {<em>f</em>(<em>a⃗</em>) ∣ <em>f</em> ∈ <em>F</em>, <em>a</em><sub><em>i</em></sub> ∈ <em>X</em>}</span>.
In other words, we look at what we get from taking <span
class="math inline"><em>f</em>(<em>a⃗</em>)</span> with every input in
<span class="math inline"><em>X</em></span>, and join it to <span
class="math inline"><em>X</em></span> to find <span
class="math inline"><em>X</em><sub><em>n</em> + 1</sub></span>.</p>
<p>Now let <span
class="math inline"><em>Y</em> = <em>X</em><sub>0</sub> ∪ <em>X</em><sub>1</sub> ∪ <em>X</em><sub>2</sub> ∪ ⋯</span>.
We claim <span class="math inline"><em>Y</em></span> works, and we show
this by proving if each <span
class="math inline"><em>a</em><sub><em>i</em></sub></span> is in some
<span class="math inline"><em>X</em><sub><em>i</em></sub></span>, then
<span class="math inline"><em>f</em>(<em>a⃗</em>)</span> must be too.</p>
<p>Note each <span
class="math inline"><em>a</em><sub><em>i</em></sub></span> by definition
is in some <span
class="math inline"><em>X</em><sub><em>i</em></sub></span> if it is in
<span class="math inline"><em>Y</em></span>. Because <span
class="math inline"><em>X</em><sub><em>i</em></sub> ⊂ <em>X</em><sub><em>j</em></sub></span>
for <span class="math inline"><em>i</em> ≤ <em>j</em></span>, and there
is some maximum <span
class="math inline"><em>X</em><sub><em>m</em></sub></span> in the list
of <span class="math inline"><em>X</em><sub><em>i</em></sub></span> that
<span class="math inline"><em>a</em><sub><em>i</em></sub></span> are in,
<span
class="math inline"><em>a</em><sub><em>i</em></sub> ∈ <em>X</em><sub><em>m</em></sub></span>
for all <span
class="math inline"><em>a</em><sub><em>i</em></sub></span>. <strong>This
is where we use the finitary condition, because otherwise we have no
guarantee this maximal <span
class="math inline"><em>X</em><sub><em>m</em></sub></span> exists to
begin with.</strong> And by definition, <span
class="math inline"><em>f</em>(<em>a⃗</em>) ∈ <em>X</em><sub><em>m</em> + 1</sub> ∈ <em>Y</em></span>.</p>
<h3 id="y-is-a-least-upper-bound">Y is a least upper bound</h3>
<p>This is a standard set theory argument; we just want to show that
<span
class="math inline"><em>z</em> ∈ <em>Y</em> ⟹ <em>z</em> ∈ <em>Z</em></span>
for the <span class="math inline"><em>Y</em></span> we have just
constructed. (<span class="math inline"><em>Z</em></span> is an
arbitrary closure under <span class="math inline"><em>F</em></span> that
is a superset of <span class="math inline"><em>X</em></span>.)</p>
<p>We claim that if <span
class="math inline"><em>z</em> ∈ <em>X</em><sub><em>n</em></sub></span>
for any <span
class="math inline"><em>X</em><sub><em>n</em></sub></span>, we must have
<span class="math inline"><em>z</em> ∈ <em>Z</em></span>. We prove this
via induction on <span class="math inline"><em>n</em></span>.</p>
<p>The base case where <span class="math inline"><em>n</em> = 0</span>
holds true by definition (<span
class="math inline"><em>X</em> ⊂ <em>Z</em></span>).</p>
<p>If <span
class="math inline"><em>z</em> ∈ <em>X</em><sub><em>n</em> + 1</sub></span>,
then either <span
class="math inline"><em>z</em> ∈ <em>X</em><sub><em>n</em></sub></span>
or there is some <span class="math inline"><em>a⃗</em></span> with all
<span
class="math inline"><em>a</em><sub><em>i</em></sub> ∈ <em>X</em><sub><em>n</em></sub></span>
such that <span
class="math inline"><em>f</em>(<em>a⃗</em>) = <em>z</em></span>. This
follows straight from the definition of <span
class="math inline"><em>X</em></span>. If <span
class="math inline"><em>z</em> ∈ <em>X</em><sub><em>n</em></sub></span>
then we are done. Otherwise we are done by the definition of a
closure.</p>
<h2 id="finitary-is-a-lie">Finitary is a lie</h2>
<p><em>A subset of our discussion with Prof. Cummings after class. This
is where I don't really know what I'm saying, which is why it is quite
hand-wavy.</em></p>
<p>The finitary condition should make you feel like something is off;
like it isn't really necessary. And in fact, it isn't if you use the
right perspective. In the "<span class="math inline"><em>Y</em></span>
exists" section, we indexed the finite set <span
class="math inline"><em>X</em><sub><em>i</em></sub></span> with a
countable set, namely the natural numbers. The reason we cannot let
<span class="math inline"><em>X</em><sub><em>i</em></sub></span> be
infinite (more precisely, have the same cardinality as <span
class="math inline">ℕ</span> is because then we cannot find some maximum
in <span class="math inline">ℕ</span> of these elements in <span
class="math inline">ℕ</span>.</p>
<p>But what if we had a number that was guaranteed to be "bigger" than
anything in <span class="math inline">ℕ</span>? Another source of
motivation: don't you see how the size of the indexing set <span
class="math inline">ℕ</span> is "just an infinity bigger" than the
finite set <span
class="math inline"><em>X</em><sub><em>i</em></sub></span>? If we index
with the ordinal number <span
class="math inline"><em>ω</em><sub>1</sub></span>, then we can find some
"maximum" in <span class="math inline"><em>ω</em><sub>1</sub></span>
that is bigger than every element in the set of size <span
class="math inline"><em>ω</em></span> (you can treat this as <span
class="math inline">ℕ</span> here) of our finitary set. <strong>And
thus, if we commit to using ordinals for indexing, we can have the
number of inputs be ordinal too</strong>. And thus the finitary
condition can be dropped.</p>
<p>Apparently all of this is legal in set theory land. They just tighten
their argument up much more than I am right now.</p>
<section id="footnotes" class="footnotes footnotes-end-of-document"
role="doc-endnotes">
<hr />
<ol>
<li id="fn1"><p>We won't deal with the detail of convergence here since
it's just an example. Set <span
class="math inline"><em>f</em> = 0</span> if the sum diverges or
something to cover this hole, the function will still be infinitary. Or
you can exclude divergent sequences. It doesn't matter.<a href="#fnref1"
class="footnote-back" role="doc-backlink">↩︎</a></p></li>
</ol>
</section>]]></description>
	<pubDate>31 Aug 2023</pubDate>
</item>
<item>
	<title>Schedule for Fall 2023 course</title>
	<link>https://dennisc.net/writing/blog/fall-schedule.md</link>
	<description><![CDATA[<p>The schedule for the Fall 2023 AIME course has
been finalized: Sundays 5 - 6 PM Eastern. Class starts on September
17th.</p>
<p>Also, if you are a student reading this and have not received any
emails from me containing general advice or an invite to the class
Discord, please email me at <a
href="mailto:dchen@mathadvance.org">dchen@mathadvance.org</a>.</p>]]></description>
	<pubDate>10 Sep 2023</pubDate>
</item>
<item>
	<title>MAST Late Applications</title>
	<link>https://dennisc.net/writing/blog/mast-late-apps.md</link>
	<description><![CDATA[<p>I've decided to open MAST late apps for all
people who satisfy all of the conditions below:</p>
<ul>
<li>Qualified for AIME</li>
<li>They (NOT their parents) email me</li>
</ul>
<p>This is for a couple reasons:</p>
<ul>
<li>Only AIME qualifiers have even asked me to join MAST (obviously
there might be some selection bias since AIME qualifiers are far more
likely to be confident enough to ask). But I don't think MAST will be
particularly helpful for non-qualifiers anyway, and we will probably
hold summer classes for less experienced contestants anyway.</li>
<li>Emailing me demonstrates that you show some non-zero initiative of
your own. I think communication is a lot easier when you don't have to
play telephone through parents (so I typically do not bother).</li>
</ul>
<p>MAST late apps will be open throughout the entire year! You won't be
able to submit Season 4 late applications once Season 5 starts (you can
replace 4 and 5 with n and n+1 in general), but otherwise, there are no
deadlines.</p>
<p>Obviously this is not a blank check to ignore the regular application
period. But if you learn about MAST in May and have already made the
AIME, I see no reason to stop you from joining the
program.</p>]]></description>
	<pubDate>21 Apr 2022</pubDate>
</item>
<item>
	<title>Anime/Manga/TV Recs (2021)</title>
	<link>https://dennisc.net/writing/blog/2021-recs.md</link>
	<description><![CDATA[<p>This is a list of media I recommend, especially
for newcomers to the genres. My tastes change, so this is just the 2021
version. The list is in no particular order. Everything on this list is
finished in English in at least one medium.</p>
<p>Also, I really only like shows that are more serious, I do not watch
a ton of comedies. But if you liked Squid Game (or at least the first
six episodes) this list is probably for you.</p>
<ul>
<li><p>Alice in Borderland (manga, JDrama)</p>
<p>Note that Season 2 of the JDrama is coming out December 2022, the
manga is finished.</p></li>
<li><p>Yugami (manga)</p></li>
<li><p>Liar's Game (manga)</p></li>
<li><p>Psycho-Pass (anime)</p></li>
<li><p>Madoka (anime)</p></li>
<li><p>Kaguya (manga, anime)</p>
<p>OK, it's not finished and it also doesn't fit with the rest of this
list, but come on, I had to include it.</p></li>
<li><p>Anohana (anime)</p></li>
<li><p>Death Note (anime)</p></li>
<li><p>Stein's Gate (anime)</p></li>
<li><p>Tokyo Ghoul (manga)</p></li>
</ul>]]></description>
	<pubDate>25 Sep 2021</pubDate>
</item>
<item>
	<title>The beach by the cliffside</title>
	<link>https://dennisc.net/writing/blog/beach.md</link>
	<description><![CDATA[<p>It's the spring, and you're standing by the
California coast, feeling the gentle rays of the sun and the cool
breeze. Not too far to your right and circling behind you is a tall
cliff with lush grass and trees.</p>
<p>There is nothing to do but walk forward.</p>
<p>So you walk, feeling the soft sand beneath your feet, smooth from the
waves that slowly wore it down. You don't think about it in the moment,
but one day you'll realize that the cliff was here centuries ago, and
the ground was made of hard, jagged rocks.</p>
<p>Yet you keep walking, and to your surprise, you spot another person
in the distance. They are only a couple of inches taller, but it seems
as if they tower over you. Once you get a few steps closer, the pleasant
smell of the ocean is overpowered by a horrible cacophony of odors. In a
few seconds, you realize this putrid scent is coming from them.</p>
<p>They greet you, and you mumble back an awkward hello. You head on
your way as quickly as possible, but it seems like they want to tell you
something. For a moment you resign yourself, but then you remember that
horrible stench. So you run. You run as fast as you can, and they are
chasing after you, shouting something you can't make out, and you run
even faster, you are running for your life.</p>
<p>By the time you stop running, the skies have turned red and the sun
is about to set. You look back and they are nowhere in sight. Now that
the danger has passed, you are so, so tired. You think to yourself, no,
you can't quite rest, it isn't dark yet, as if you only deserve to rest
when it's properly nighttime. But your body, exhausted from all the
running, screams at you. So you acquiesce.</p>
<p>You lie down on the sand, and as you are about to fall asleep, you
notice your pockets feel a little lighter than before. You think back to
what you might have lost but nothing important comes to mind, and you
slowly drift back to sleep. ∎</p>]]></description>
	<pubDate>12 Dec 2025</pubDate>
</item>
<item>
	<title>How to remember your SCOTUS justices</title>
	<link>https://dennisc.net/writing/blog/scotus-justices.md</link>
	<description><![CDATA[<p>The Supreme Court plays a large role in the
government, yet most people (likely including you) don't know who the
justices are by heart. Here's an easy way to group them up:</p>
<ul>
<li><strong>Trump appointees</strong>: Neil Gorsuch, Brett Kavanaugh,
Amy Coney Barrett</li>
<li><strong>Original conservatives</strong> (i.e. not Trump appointees):
<em>Chief Justice</em> Roberts, Clarence Thomas, Samuel Alito</li>
<li><strong>Liberals</strong>: Elena Kagan, Sonya Sotomayor, Ketanji
Brown Jackson</li>
</ul>
<p>It's also worth knowing that Gorsuch, Kavanaugh, ACB, and Jackson
replaced Justices Antonin Scalia, Anthony Kennedy, Ruth Bader Ginsburg,
and Steven Breyer, respectively. Jackson was a Biden
nominee.</p>]]></description>
	<pubDate>16 Jul 2023</pubDate>
</item>
<item>
	<title>I have made a continuous lapse in my judgment</title>
	<link>https://dennisc.net/writing/blog/continuous-lapse-in-judgment.md</link>
	<description><![CDATA[<p>In Hooks and Swipes I forgot to add a 2-long
thermo (there should be a total of 3). It should be present
now.</p>]]></description>
	<pubDate>5 Jan 2023</pubDate>
</item>
<item>
	<title>Puzzle-writing goals, part 1</title>
	<link>https://dennisc.net/writing/blog/puzzle-goals-part-1.md</link>
	<description><![CDATA[<p>I've already written four puzzles and it hasn't
even been a week, so the January goal seems pretty easy. However, I'm
going to be participating in MIT Battlecode with Math Advance, so I
don't want to update this goal because keeping it easy is not bad. Also
I have to apply for scholarships :(</p>
<p>For the February goal, I obviously don't know every common variant
yet (I recently learned about non-disjoint, for example). So, I'll just
consider the common variants I listed as examples, and any (fun)
variants I haven't used in January will count. (Which means that if I
set one of the variants I list in January, it doesn't count in
February.)</p>
<p>The March goal is actually way too easy. I wrote two easy classic
sudoku puzzles already, but they don't use intermediate to advanced
techniques (partially because I do not recognize them quickly or
consistently enough). So, I want to set a classic with at least an
X-Wing.</p>
<p>As for what I plan to do for the remainder of January, I want to
explore the following two puzzle types I've invented: the close/distant
neighbors variant (more generally, positive global restrictions on the
difference of neighbors), and Equations (which I think had too few given
digits and too many given equations). Stay tuned for more
puzzles!</p>]]></description>
	<pubDate>6 Jan 2023</pubDate>
</item>
<item>
	<title>Congratulations, Aprameya</title>
	<link>https://dennisc.net/writing/blog/congratulations-apra.md</link>
	<description><![CDATA[<p>Today, Aprameya, one of my former students and
current colleagues<a href="#fn1" class="footnote-ref" id="fnref1"
role="doc-noteref"><sup>1</sup></a> in Math Advance was invited to
MOP.</p>
<p>Let me tell you a bit more about him. When he was in 7th grade he
applied to the MAST program, not having qualified for the AIME. But
through his solutions to the application problems, I could see that he
had a lot of depth and could solve really hard problems, and so I
invited him to the program.</p>
<p>I was more right than I ever could have imagined. A few months later,
he started writing geometry questions and sending them to me. At first I
could handle the number he was sending me --- for about a few weeks or
so (if my memory is correct). Then the output ballooned into something I
couldn't review alone, so I invited him to the contest-writing branch of
Math Advance in the hopes that the rest of the team could help review.
And even after the rest of the team was looking at his problems, we
still could barely testsolve <em>most</em> of his questions --- and our
team has a ton of MOPpers and USAMO qualifiers. That's how hard they
were, and that's how many he wrote. He's also helped out with MAST and
wrote a couple pieces of advanced number theory content.</p>
<p>Two years later he qualified for the USAJMO. This year he qualified
for the USAMO --- as a sophomore. He'd been grinding ISLs and not only
did his depth extend, he also became more accurate and more articulate
in communicating his mathematical ideas.</p>
<p>All this is to say: this is not particularly surprising news. Given
his work ethic and his contributions to our program, it was really just
a matter of time. Congratulations again, Aprameya, and thanks for all
your contributions to Math Advance. Let's continue making more cool
stuff like the geometry contest <del>that we've been planning for
literally two years</del>!</p>
<section id="footnotes" class="footnotes footnotes-end-of-document"
role="doc-endnotes">
<hr />
<ol>
<li id="fn1"><p>There's gotta be a better word for this, but I can't
think of it.<a href="#fnref1" class="footnote-back"
role="doc-backlink">↩︎</a></p></li>
</ol>
</section>]]></description>
	<pubDate>27 Apr 2023</pubDate>
</item>
<item>
	<title>Dan Gabor 2022</title>
	<link>https://dennisc.net/writing/blog/gabor-2022.md</link>
	<description><![CDATA[<p>Last Saturday I ran the 1600m and the 800m in
our home meet, the <a
href="https://diablotiming.com/results/2022-03-05/">Dan Gabor
Invitational</a>, and summarily proceeded to run absolutely terrible
(i.e. worse than median).</p>
<h2 id="m">1600m</h2>
<p><strong>5:44.80</strong>, PRed over my Freshman year Dan Gabor time
(by one second!)</p>
<p>The 1600m was the first event most of the distance runners were
racing. My heat started at 5 in the afternoon, but we came too early ---
we arrived at 3, when we only need 45 minutes for warmups. So we lounged
around and did nothing until 3:50, when we began warmups.</p>
<p>Warmups also began too early, we had literally 30 minutes between the
end of warmups and when our heat got <em>called</em> to race. So that
was 30 minutes we had to basically fill up with random strides. But I
think I was in pretty good condition before the race.</p>
<p>In the 1600 (and the 800) we started in a double waterfall formation.
The inner waterfall can merge immediately but the outer waterfall has to
merge after the first bend. I think it's better to be in the inner
waterfall so you can see everyone else, but then you might get
passed/blocked early on. I was in the outer waterfall.</p>
<p>I started out pretty strong during the first hundred meters, but got
flat tired as someone stepped on my shoe AND drove their spike into my
heel. The hole in my foot didn't hurt as much during the mile
(adrenaline!), but would really suck for cooldowns/warmup between the
1600m and 800m. The flat tire made it a lot harder to kick in the end
since I couldn't sprint effectively. Plus, some poor tactical moves in
the second half of the second lap and the third lap also contributed to
a slowish time.</p>
<p>Goal next time: <strong>5:35</strong>.</p>
<h2 id="m-1">800m</h2>
<p><strong>2:29.38</strong>, PR by a lot (did not get a good 800m race
before this)</p>
<p>After the race the pain in my foot started to kick in, to the point
where I had to hobble towards our team tent. I couldn't cool down
properly since I could barely walk, so I decided to sit down and eat
some food to replenish my energy.We did nothing for about an hour and in
the interim I got a bandaid on my foot.</p>
<p>Afterwards we did some more warmups (not as long as the usual
pre-race warmups) and this time we finished right before my heat got
called to the bullpen. (So we started a bit late then, especially since
we had to cut the warmup run short.) It was cold as hell when I was
waiting in the bullpen, and I honestly regret not bringing my jacket
there.</p>
<p>Again, I was in the outer waterfall, and I made sure to position
myself right at the front of lane 5 this time around. I relied on
adrenaline to make my pain "go away". Funnily enough this is the third
race I've relied on adrenaline before a race. Some part of me would
always hurt enough to make it hard to walk and right before the race I
just think "it will be fine the pain will go away".</p>
<p>I started the 800m near the front and was doing quite well for the
first 600m. A breakdown thereof: when I closed the first curve I was in
4th and right behind 3rd. The top 3 in each heat get a T-shirt and I was
thinking, "T-shirt T-shirt gotta go fast". So I kept running fast
without slowing down my pace from the beginning (I always start pretty
fast, probably too fast) and passed him at around the 300m mark. Then it
was open season for the next 200m, I passed 2nd place pretty quickly too
and was pretty far behind 1st but also pretty far ahead of everyone
else. Unfortunately between 500m-600m I could feel that I was slowing
down and started to go a bit more conservatively. Here 3rd place passed
me and I became 3rd place again, and in the final 200m I just ran out of
gas. Then I got passed by 2 more people and audibly screamed (not that
you can scream very loudly when you're running) "No!" because I knew I
wasn't passing them after that/getting the T-shirt.</p>
<p>I don't even think I went out too fast really, just that I didn't
have the endurance/mental strength to keep up for the last 200m. So I
should start taking tempos &amp; repeats more seriously and pushing
myself to the point of exhaustion there (not that I shouldn't have
before).</p>
<p>Goal next time: <strong>2:27</strong></p>]]></description>
	<pubDate>7 Mar 2022</pubDate>
</item>
<item>
	<title>I Made It</title>
	<link>https://dennisc.net/writing/blog/i-made-it.md</link>
	<description><![CDATA[<p>A deluge of emotions are rushing through me as
I type this post. The cutoffs are so low/I did not deserve to make it/ha
I made it even after missing #1 on the AIME. I've been pretty much below
average (or at least believed so) yet come close in pretty much
everything. Missing the F=ma cutoff by 1 point (14 vs 15, missed
questions 1 AND 4, which were both free). Gassing during the Dan Gabor
800m and not getting the T-shirt. I've been pretty objectively mediocre
at physics/CS/running/whatever else I tried my hand in and until now I
thought math was also on the list. I thought cutoffs would be &gt;225
for 12A + I (so effectively 230+ for me) and believed I missed USAMO
because I was stupid enough to miss question 1 on the AIME. (I forgot to
double on the test.) But apparently not. I made it.</p>
<p>I don't know how much this will, say, help with college apps (I
predict not much). I don't think much in my life will change, but one
important thing has happened: I feel like I've finally won something in
life. It's been a while since I really, truly felt like I've managed to
best a challenge which really mattered to me, and finally I did it.</p>
<p>By the way, next Friday I also (hopefully) have a track event
(representing our school at some fun run). So if that pans out, I am
skipping three straight days of school. I am definitely looking forward
to that.</p>]]></description>
	<pubDate>16 Mar 2022</pubDate>
</item>
<item>
	<title>In 2025, use Typst to typeset your slidedcks</title>
	<link>https://dennisc.net/writing/blog/typst-slides.md</link>
	<description><![CDATA[<p>Back before I knew Typst existed, I wrote <a
href="https://dennisc.net/code/beam">Beam</a>, a language which could
transpile to TeX and then generate LaTeX beamer slides. For some obvious
reasons this is quite a suboptimal idea, and really papers over the fact
that LaTeX syntax, <em>particularly for typesetting slides</em>, is very
cumbersome.</p>
<p>Well, it is the year 2025, and Typst is a very ergonomic typesetting
language. For almost any reason, it is probably wiser to use Typst to
typeset slideshows instead of beamer. I personally am using <a
href="https://typst.app/universe/package/slydst/">slydst</a> to typeset
the slides for my puzzle course next semester.</p>
<p>That's all from me today. Cheers, and happy new
year!</p>]]></description>
	<pubDate>31 Dec 2024</pubDate>
</item>
<item>
	<title>Wisdom Teeth</title>
	<link>https://dennisc.net/writing/blog/wisdom-teeth.md</link>
	<description><![CDATA[<p>So I got two of my wisdom teeth pulled today. I
have to come back in about a week to pull the other two.</p>
<p>I'm in China and they only do facial anesthesia. This seems
objectively better. The rest of the operation was a little sus though.
The person doing it stepped out of the room to do god knows what and was
panicking about missing something <em>after</em> I got anethesiaed. Also
the bottom right tooth seemed like an absolute struggle for them to pull
out considering the top was removed in like 30 seconds.</p>
<p>Afterwards since I couldn't talk, I had to pantomime to communicate.
It's like I was playing charades but five times worse.</p>
<p>I am typing this with only my left hand on my phone. My right hand is
holding an ice bag to my face. Obviously I will be publishing this when
I am home, at which point I will probably be fine.</p>
<p>I started writing a SCOTUS post before the op and my language was a
lot less wooden then. (You can compare the results when it comes out.)
Now it is stilted. I wonder why.</p>
<p>This must be what it feels like to suck at writing. And that, I feel,
is far more painful than removing wisdom teeth ever could
be.</p>]]></description>
	<pubDate>18 Jul 2023</pubDate>
</item>
<item>
	<title>Trying new things</title>
	<link>https://dennisc.net/writing/blog/new-things.md</link>
	<description><![CDATA[<p>I feel like it's harder now to get people to
try new things than it was when I was younger. Back then people would
make an honest effort even if they didn't follow through with it, but
now the answer is a non-committal "sure, I'll check it out" with zero
followup.</p>
<p>A caveat: this is based on a sample size of <span
class="math inline"><em>n</em> = 1</span> (i.e. me), and I was pretty
weird as a kid and "pushed" things on people (with varying degrees of
success), whereas now I kinda don't. (It's not like I'm exactly the
paragon of normality now, but at least now I can <em>pretend</em> to be
normal when I have to.)</p>
<p>And I'm noticing this mostly because <em>I'm</em> the one who does
this to people more often than I'd like. (In fact, I think being
non-committal has been a pretty big issue of mine.) I can think of a
couple of times where people asked me to join them in doing something or
whatever, and since I don't want to say no, I just say "yes" without
following up 90% of the time. So yeah, I want to work on that
myself.</p>]]></description>
	<pubDate>2 Jan 2023</pubDate>
</item>
<item>
	<title>Hidden Pages</title>
	<link>https://dennisc.net/writing/blog/hidden.md</link>
	<description><![CDATA[<p>Some of my favorite personal websites have lots
of hidden gems hidden throughout. Not explicitly hidden, mind you, but
just pages that don't particularly stand out or call to your attention.
These pages, however, tend to be the most interesting.</p>
<p>As two examples, take Evan Chen's Taiwan TST/IMO/USAMO reports and
Drew DeVault's Gemini-exclusive blogposts. (There are a couple on his
website that conspiciously jump out at you, by virtue of saying "this is
gemini exclusive use gemini to access", but some others are not.) If you
<em>know</em> how to find them, it will be very obvious how to get
there. But if you're new to a site it won't.</p>
<p>I don't think it is by design that these pages are out-of-the-way.
Typically it is the miscellaneous, for-fun, trivia, etc pages that are
in this position, and not the "main content". And interestingly enough,
because these pages are not as important or mainline, they tend to be
the most fun to read.</p>
<p>If you want people to stay on your site, have pages that are
non-essential for the user and don't get in their way. Think about all
the Wordle clones; the reason they got boring quick was because there is
no novelty, due to infinitely many words being generated; it's all the
same. You can't churn out unique and organic content quick enough so
there's something new every day, but just like a fibre does for
carbohydrates, hidden pages can make people digest your site for
longer.<a href="#fn1" class="footnote-ref" id="fnref1"
role="doc-noteref"><sup>1</sup></a></p>
<p>You don't have to try too hard to do this on purpose. Just by virtue
of having enough stuff to say, your website will necessarily have stuff
pushed to the side. But if your content is interesting enough, could you
use that to get people to make changes for the better?</p>
<p>What Drew DeVault did was putting some exclusive content on his
Gemini blog instead of his WWW blog. Another thing that I've been doing
is jotting down some notes in a small notepad. But because I haven't
been transferring my notes over to a more permanent medium (i.e. a
blog), I have subconsciously kept my notepad neat by not writing stuff
down when I think of it if it doesn't fit into a certain page's
structure. Which sort of defeats the purpose of a notepad where I can
write anything I want.</p>
<p>So I can put the two together. I'm going to make a Gemini mirror of
(some subset) of my website, and on it I will add exclusive status
updates. I'll probably put the first one on my WWW website, just to give
people a taste of what's on my Gemlog.</p>
<section id="footnotes" class="footnotes footnotes-end-of-document"
role="doc-endnotes">
<hr />
<ol>
<li id="fn1"><p>Your pages will be unique by virtue of being unimportant
trivia. Because there are only so many things to say about math contests
or whatever, you'll probably have seen anything I have to say before.
(That's why I don't write on preparing for math contests as often
anymore.)</p>
<p>But it frankly does not matter if you never see <a
href="/writing/glee-design">the design for a small-scale filesystem-like
Git service</a>, which is why very few people write about it, and the
people who write about it don't really push it that hard.<a
href="#fnref1" class="footnote-back" role="doc-backlink">↩︎</a></p></li>
</ol>
</section>]]></description>
	<pubDate>18 Mar 2022</pubDate>
</item>
<item>
	<title>Silent improvements to Glee's frontend</title>
	<link>https://dennisc.net/writing/tech/glee-frontend.md</link>
	<description><![CDATA[<p>Unless you pay really close attention, you
probably won't notice a difference between <a
href="https://git.dennisc.net">git.dennisc.net</a> today versus before.
That's because I've mostly made semantic improvements to the page plus
some CSS choices that work better for non-mainstream browsers like
NetSurf. Now the frontend should be tolerable on terminal browsers, and
though the navbar does not behave exactly like I want it to on NetSurf,
we're at the point where this is probably more because LibCSS doesn't
conform with standards (I don't see any way to replicate "stuff on the
left and the right" without a flexbox).</p>
<p>Currently links does not work well with redirects. It's not just my
site that faces this issue --- the logout link for <a
href="https://sr.ht">SourceHut</a> also does not work. links doesn't
handle redirects well, and at some point I just have to shrug and say
"not my problem".</p>]]></description>
	<pubDate>6 Nov 2022</pubDate>
</item>
<item>
	<title>Creativity is not methodical</title>
	<link>https://dennisc.net/writing/blog/creative-methodical.md</link>
	<description><![CDATA[<p>A couple of days ago I took the AP Chemistry
exam, and what struck me about preparing for it was how methodical it
was. You just recognize what type of problem it is, remember the steps
you take to solve it, and voila! you are done. Sure, it's not always
trivial because sometimes you just don't know what to do. Nowhere in the
process is there much anxiety about whether you can do the problem
though: you either know it or you don't. For the most part, you don't
try questions, actively struggle on them for along time, miss the
fundamental idea, and then go <em>damn it I could've gotten that if the
conditions were right or I was a bit luckier</em>.</p>
<p>Well, that's what creative processes are like. Take puzzle-writing
for instance: while much of the process is put a clue down, figure out
what it does, and repeat, you do have to use some ingenuity to figure
out what clues to place. But perhaps far more importantly, determining
what kind of puzzle you even want to write is really not methodical.
What ruleset do you want to use? How are you going to make the rules
interact with each other? That kind of thing.</p>
<p>For instance, take my puzzle <em>Monster Without A Name</em>.
Normally, you'd think that I wrote this puzzle and found a good name for
it afterwards. And that is true for most of my puzzles. But for this
one, I came up with the title before I had any clue what the puzzle
would be about, because I really wanted to force the song lyric.<a
href="#fn1" class="footnote-ref" id="fnref1"
role="doc-noteref"><sup>1</sup></a></p>
<p>So I first was thinking of just making a really hard puzzle. Problem
is, you can't just decide to make a really hard puzzle, and I did make a
couple of semi-hard puzzles but they all had obviously better titles,
e.g. X-Lines Sudoku. So I thought, "maybe the constraint should actually
have <em>Monster</em> in the name, at least".</p>
<p>When I thought of <em>Monsters</em>, I thought of the similar word
killers, since you have Killer Cages and Little Killers. And since
Killers do stuff with sums, Monsters should do the next simplest thing:
products.</p>
<p>Then the question is, how do I do products? Just doing the product of
every cell is really boring, since it removes a lot of nuance and
degrees of freedom. So somehow, I would want to do region sums.</p>
<p>Now I had to decide how to construct my regions. First I tried using
shading pencil puzzles like Yin-Yang or Caves to create a hybrid --- and
I still think that approach has a lot of viability --- but after doing a
few Chaos Construction puzzles, I realized: the most natural way to do
products of region sums, which requires region construction... is to do
the variant that uses region construction. The Monster Cages constraint
had finally crystallized.</p>
<p>The process I took was definitely not methodical: if the puzzles I
did or the thoughts I had changed a little bit along the way, I would've
gotten a completely different puzzle or no puzzle altogether. In other
words, the system is chaotic: small perturbations to initial conditions
create a vastly different result. But far more importantly, the process
wasn't even <em>logical</em>. There's absolutely no reason for me to
fixate on, "ah yes let's force <em>Monster Without A Name</em>" to work
as a title and then go to the lengths I did.</p>
<p>But that's the thing about finding inspiration. You're lost in a sea
of possibilities, and having something to anchor you can be really
helpful. Even if that thing makes no sense at all. And this, in ~600
words, is how and why I use song lyrics as the titles to my puzzles.</p>
<section id="footnotes" class="footnotes footnotes-end-of-document"
role="doc-endnotes">
<hr />
<ol>
<li id="fn1"><p>This is kind of becoming a trend: another puzzle title I
forced to work was First Burn. <em>Your enemies whisper, so you have to
scream...</em><a href="#fnref1" class="footnote-back"
role="doc-backlink">↩︎</a></p></li>
</ol>
</section>]]></description>
	<pubDate>5 May 2023</pubDate>
</item>
<item>
	<title>Math Advance got into MIT</title>
	<link>https://dennisc.net/writing/blog/mathadvance-mit.md</link>
	<description><![CDATA[<p>About two-thirds of Math Advance has applied to
MIT early action and as far as I've heard, everyone got in. (I was not
in said two-thirds. I EAed to Princeton and got
deferred.)</p>]]></description>
	<pubDate>17 Dec 2022</pubDate>
</item>
<item>
	<title>Setting up SSH with Git</title>
	<link>https://dennisc.net/writing/tech/ssh-git.md</link>
	<description><![CDATA[<p>So, a while back, GitHub finally disabled
authenticating with password (a very good decision!) In this post, I
want to cover a couple of things:</p>
<ul>
<li>What is the point of using SSH instead of password-based
authentication?</li>
<li>How does one set up SSH locally?</li>
<li>How/why you upload a public key to a Git provider (like GitHub)</li>
</ul>
<h2 id="whats-the-point">What's the point?</h2>
<p>Let's first discuss why GitHub decided to enforce SSH encryption. The
advantage of SSH is that it is more secure. When I send a password, as
long as the connection between myself and GitHub is insecure, the
password can be intercepted, whether it's on my end of sending or
GitHub's end of receiving the password. This means that for common
operations (like pushing to a repository), it is best if we avoid
sending passwords.</p>
<p>The advantage of SSH (and asymmetric keys in general) is that you do
not actually provide anything that can be intercepted; you only
<em>prove</em> that you have the private key that you claim you have
(i.e. the private key that corresponds to your public key). Also, SSH
keys are forced to be randomly generated, meaning that SSH private keys
are unguessable, unlike your crappy password of <code>P@ssw0rd</code>.<a
href="#fn1" class="footnote-ref" id="fnref1"
role="doc-noteref"><sup>1</sup></a></p>
<h2 id="how-to-set-up-ssh">How to set up SSH</h2>
<p>I don't use Windows, so I have no idea how the specifics work. What
goes will mainly apply for Unix operating systems, like Linux and BSDs.
(This will probably work for Mac OS work too.)</p>
<p>Using <code>ssh-keygen</code>, generate a public/private keypair:</p>
<pre><code>ssh-keygen -t ed25519</code></pre>
<p>(The <code>-t ed25519</code> option specifies the keytype as
<code>ed25519</code>, which is faster and more secure than RSA, mostly
due to implementation difficulties in RSA.)</p>
<p>Then, just copy the public key's contents (its file extension is
<code>.pub</code>) and add it to GitHub (or whatever).</p>
<p>Now, when you clone repositories, make sure to clone using the SSH
URL, not the HTTPS URL. So, run</p>
<pre><code>git clone ssh://git@github.com/git/git</code></pre>
<p>instead of</p>
<pre><code>git clone https://github.com/git/git</code></pre>
<section id="footnotes" class="footnotes footnotes-end-of-document"
role="doc-endnotes">
<hr />
<ol>
<li id="fn1"><p>Folks, use a password manager.<a href="#fnref1"
class="footnote-back" role="doc-backlink">↩︎</a></p></li>
</ol>
</section>]]></description>
	<pubDate>11 Jan 2023</pubDate>
</item>
<item>
	<title>The Best Colors</title>
	<link>https://dennisc.net/writing/blog/best-colors.md</link>
	<description><![CDATA[<p>For some reason, if you append the strings
"42", "69", and "1337" to make hex codes, you will get pretty good
colors.</p>
<ul>
<li><span style="color: #426942">#426942</span>: I use this color for my
Polybar (X11) and i3blocks (Sway + Wayland, though I hope migrate to
swaybar eventually). Out of all the colors listed, this is my
favorite.</li>
<li><span style="color: #421337">#421337</span>: I love this
purple.</li>
<li><span style="color: #691337">#691337</span>: I love this magenta
even more.</li>
<li><span style="color: #133742">#133742</span>: A nice dark turqouise
blue. It's not bad, but not my favorite.</li>
<li><span style="color: #133769">#133769</span>: A decent blue, but not
the best color. I personally prefer richer blues, like <span
style="color: #003366">#003366</span> (dark midnight blue).</li>
<li><span style="color: #694269">#694269</span>: Might not look great in
isolation, but it's similar to <a
href="https://mat.mathadvance.org">MAT</a>'s light purple. Don't hate on
it, it could be a good complement for a design!</li>
</ul>
<p>OK, these were the stupidest color reviews of all time. But these
colors are unironically pretty good. I know I'll be trying at least one
of these out in my next design.</p>]]></description>
	<pubDate>2 Jun 2022</pubDate>
</item>
<item>
	<title>Quality is the sole value of Math Advance</title>
	<link>https://dennisc.net/writing/blog/quality.md</link>
	<description><![CDATA[<p>A few days ago, I happened to see yet another
group of students who decided, "hey, let's try to write a math contest
in [absurdly short period of time]." This is so ridiculous that I
decided I finally had to say something about it. Too few organizations
care about quality. Too few organizations actually set
<em>standards</em> for themselves, and instead they just push out
whatever seems like a good idea at the time.</p>
<p>The <em>mission</em> of Math Advance is to, well, advance math
education. (It's in the name.) But it is not one of our <em>values</em>,
and the difference is important. Because our mission is something we can
compromise or change, something we can scale down on depending on
circumstances, etc, while when it comes to values, we refuse to
compromise.</p>
<p>If our unrelenting goal was to, say, introduce math contests to more
people, we would be writing even easier math contests. But almost as a
rule, those "super easy" math contests are almost entirely made of
filler. I have the same opinion of those math contests as I do for
computer-generated Sudoku puzzles: they can be mass produced, are
typically somewhat lacking in quality, and while they can be used for
learning, <em>I</em> am not touching it with a 10-foot pole.</p>
<p>That's the same opinion that Math Advance as an organization holds.
And our goal is not just to produce <em>good</em> math contests or
<em>good</em> teaching materials. It is not even to produce <em>the
best</em> of something, because that standard can sometimes be woefully
low. Our goal is to produce contests (for now, and maybe something else
later on) <em>as good as possible</em>. This is why for the first Summer
MAT, we spent almost a year constructing the test despite it only having
12 problems, and why we asked close to a dozen people, completely
independent of the test-setting group, to provide feedback. Sometimes we
will have to compromise other things to ensure quality: sometimes we
have to reduce scope, as we did by putting MAST on hiatus, and sometimes
we have to delay the release date of lots of good work (we have so many
backlogged problems that we could probably run for 3 or 4 more years if
no one proposed another problem from now).</p>
<p>When two values conflict, you are going to have to compromise on one
of them. That is why the only value we have is the only value we need:
<em>quality.</em> I believe there is a role for people who mass produce
math contests and math problems. But if you, just like us, are sick of
mass-producing problems for mass-produced contests that become
irrelevant after two weeks, we have a place at you for Math
Advance.</p>]]></description>
	<pubDate>1 Jan 2023</pubDate>
</item>
<item>
	<title>The upcoming Winter MAT</title>
	<link>https://dennisc.net/writing/blog/winter-mat.md</link>
	<description><![CDATA[<p>Nothing I am about to say is official or even
solidified internally, but Math Advance has plans to hold a Winter MAT
sometime after winter break this upcoming school year. I want to explain
what the Winter MAT is, what its goals are, and how it differs from the
Summer MAT.</p>
<p>In summary, the Winter MAT is an easier version of the MAT compared
to the Summer MAT. On average you could say it's similar to the Summer
MAT shifted one problem down, although the introductory problems don't
have that much room to get easier.</p>
<p>The Winter MAT is meant to be an introductory contest. It is intended
to fill a similar niche as the Mandelbrot before it was discontinued. As
thus, there will be a minimal focus on competitiveness, which means we
will not need to focus on breaking ties. Prizes (if any) and recognition
will be cutoff-based, not ranking based, though we will obviously use
contest statistics to determine said cutoffs. This removes the need for
tiebreakers entirely, so in the interest of logistics (shorter contests
are easier to run), we'll be dropping the tiebreaker set from the Winter
MAT. (It will still stay for the Summer.)</p>
<p>As part of our outreach efforts, some Math Advance members are
thinking about holding the Winter MAT at school or other local testing
centers. This is because taking contests online is a draining
experience, even if it isn't as long as other contests. One of my
favorite parts of math contests was discussing problems immediately
after tests were collected after each round. COVID has robbed this
experience from us for the last few years, and I'd like to try and get
it back.</p>
<p>This year we made the Summer MAT significantly easier, particularly
for the last problem in each set. While we don't ever intend to return
to 2021 levels of difficulty, you can expect a spike next year in the
final problems in each set, and a minor increase for 2/5/8 as well. This
is for mostly pragmatic reasons: we have a lot of really good hard
problems that we've been waiting to use. Part of the reason we're
hosting the Winter MAT is to make hosting harder MATs in the summer more
feasible: if we already have a dedicated beginner contest, then the
Summer MAT does not need to be as accessible anymore and can cater more
to stronger contestants.</p>]]></description>
	<pubDate>29 Jul 2022</pubDate>
</item>
<item>
	<title>Announcing Beam</title>
	<link>https://dennisc.net/writing/tech/beam.md</link>
	<description><![CDATA[<p>beam is a file format that makes it easier to
write LaTeX beamer. A beam <em>compiler</em> (synonymously
<em>implementation</em>) turns a <code>.beam</code> file into a
<code>.tex</code> file and invokes <code>latexmk</code>. As of writing
one exists in Rust and one for C is planned (partially for greater
portability, and partially as an exercise in learning C for my own
sake).</p>
<p>I'll just show you what an example beam document looks like, since
the spec is so simple.</p>
<pre><code>^ \documentclass[12pt]{beamer}
^ \title{beam}
^ \author{Dennis Chen}

\titlepage

# Introduction

~ What is beam?
- beam is a file format to write presentations with
- beam is a program that converts beam files into beamer

~ Why?
beam does for beamer what Markdown does for HTML
- beamer takes far too long to write.
- We only need a subset of beamer&#39;s features

# Features

~ Frametitles
Use the ``\textasciitilde&#39;&#39; character to set the frametitle.

~ Bullet points
- You&#39;ve already seen it in this presentation.
- Bullet points invoke the ``itemize&#39;&#39; environment.

~ Block
&gt; How to make a block
&gt; This symbol makes a block.

~ Exampleblock
&lt; How to make an exampleblock
&lt; This symbol makes an exampleblock.

~ Alertblock
! How to make an alertblock
! This symbol makes an alertblock.

~ Images
Use the ``@&#39;&#39; character to set a background image.

@beach.jpg

# Miscellaneous

~ Stylization
beam should be written in all lowercase, even at the start of a sentence.</code></pre>
<p>Interested in using beam? Read the <a href="/code/beam">beam page on
my website</a>.</p>]]></description>
	<pubDate>10 Apr 2022</pubDate>
</item>
<item>
	<title>Constructing &quot;5&quot;</title>
	<link>https://dennisc.net/writing/blog/constructing-5.md</link>
	<description><![CDATA[<style>
img {
    margin-left: 0;
    width: 40%;
    height: 40%;
}
</style>
<p><em>Spoilers ahead for <a href="/puzzles/5">5</a>, so please try it
yourself first! It is GAS level and is probably around 2.5 or 3 stars in
difficulty.</em></p>
<p>This post will be a little different from my last one. Instead of
listing the (ultimately useless) trial and error I did, which was not
much, I will instead show the order which I added the final clues in.
Since the solve process is fairly linear, it was easy to just layer
clues on top of each other this time around. (This is in contrast to
Alphabet Soup, which was much more intricate... a post on that coming
soon!)</p>
<p><img src="order.png" alt="Order that clues were added"></p>
<p>You will notice that two sets of clues were added at the same time: 5
and 6. This is because I was near the end and experimented with
brute-force to find the most aesthetically pleasing set of constraints
to finish the puzzle off.</p>
<p>So a couple of days ago, I decided I wanted to try writing a German
Whispers puzzle and playing around with the number 5 (German Whispers
also cannot have a 5 on them). I wanted to pay homage to this number 5,
so I just drew a fat 5. Originally it was not as tall (1 row less on
each side), but on paper it didn't look as good so I stretched it. I
also knew it would be more constraining and make writing the puzzle
easier.</p>
<p>Conveniently, XV pairs also cannot have a 5! I was going to use V's
at first, but if I needed an X, I knew I could use it later as well. So
I'm like, "Hmm let's force my first 5" and placed clue 2. Now 5 was
fairly constrained: it must appear in row 4 for region 5 and so must
appear in row 5 for region 6. Then I pushed the puzzle to its logical
limits and got the 6 at the bottom, and some other good stuff</p>
<p><img src="12.png" alt="The implications of clues 1 and 2"></p>
<p>There are some very constraining things to note: though 8 and 9
cannot resolve at this stage (there is no differentiator between the two
at the moment), the 6's and 7's on the German whisper only have one
degree of freedom. Also, a V in regions 1 and 6 would nicely
differentiate where 5 was, and the V in region 1 would also take care of
the 4 in region 4.</p>
<p>So hopefully it is quite clear why I added clues 3 and 4. I had to do
something to differentiate columns 1/2 and columns 8/9, because at the
moment those pairs are symmetric. Determining some 5's and the 4 seemed
fairly natural. (As to why I chose to place them on the outside, well, I
just thought it looked aesthetically better. I could've just as well
placed the V in columns 2 and 8 instead of 1 and 9.)<a href="#fn1"
class="footnote-ref" id="fnref1" role="doc-noteref"><sup>1</sup></a></p>
<p>After adding each of clues 3 and 4, I logicked out the puzzle to take
stock of where I was. After clue 4 I figured I was close enough to the
endgame. I decided to place clue 5 to forcefully differentiate the 14
pair in column 3 and the numbers in the V of clue 3. Then I realized I
really was close, started playing around with online sudoku solvers
(essentially it was just a faster way to fill in candidates for each
cell), and after trying a couple of potential XVs I settled on clue
6.</p>
<p>Then I decided to check that clue 6 actually made things satisfying
to solve and didn't cause any unnecessary cheese. It did: it gave
solvers a early 5 disambiguation in region 5 (the X clue), made the
middle and end of the puzzle less convoluted (the V clue), and the
combination of the two also somewhat quickly determines the location of
4 in region 5. (I mean, technically it determines everything, but you
know what I mean.)</p>
<h2 id="summary">Summary</h2>
<p>So yeah. This puzzle was almost entirely constructed on paper and
took about 3 hours. This was a much easier puzzle to construct than
Alphabet Soup. (Alphabet Soup took my soul out of me. I consider it a
miracle that I managed to finish it within a week, and that's a long
time for one puzzle, I think.)</p>
<p>My general thought process for constructing a puzzle, and what
happened for this one in particular, was</p>
<ul>
<li>I thought of a general theme (the 5, the German whisper, etc). From
my experience writing math contest problems you don't just decide "OK I
will write a problem", you have to stumble your way into the core idea.
(At least, I can't just decide to write a problem --- I'm sure there are
people who can.)</li>
<li>I put down a couple of probing clues to get started.</li>
<li>In the middle, I aggressively constrain things that are almost
constrained.</li>
<li>At the end, I use some computer assistance to determine which set of
final constraints is most viable.</li>
</ul>
<p>In particular, there was a lot less floundering than when I was
writing X Marks the Spot, and since the puzzle was not as intricately
connected as Alphabet Soup, it was not too hard to finish.</p>
<p>Hopefully this made my thought process behind the puzzle clear, and
helps you in writing your own puzzles! If you do write a puzzle, whether
it is because of my blog or for any other reason, please send them over
--- I'd love to solve some nice puzzles :)</p>
<p>By the way, if anyone knows how to make German Whispers and XV sums
in Penpa, please let me know :)</p>
<section id="footnotes" class="footnotes footnotes-end-of-document"
role="doc-endnotes">
<hr />
<ol>
<li id="fn1"><p>By the way, this is why you need humans to craft good
puzzles, especially variant puzzles. When I put these clues here, the
intent will eventually be communicated to the solver. Computers have no
intent, and especially for variant puzzles, intent is necessary to make
a good puzzle (or even a puzzle at all). Without intent it may not even
be possible to construct around some trickier variants, like German
Whispers, which force you to keep track of polarity, the natural
restriction on 5, etc...<a href="#fnref1" class="footnote-back"
role="doc-backlink">↩︎</a></p></li>
</ol>
</section>]]></description>
	<pubDate>5 Dec 2022</pubDate>
</item>
<item>
	<title>An Embarrassing Gaffe</title>
	<link>https://dennisc.net/writing/tech/domain-renewal.md</link>
	<description><![CDATA[<p>So I didn't renew my domain on time, and
apparently it expired. This is really bad, especially because there was
some advertiser-parker on my website for several hours <em>after</em>
renewal and because students were looking at my website for the
application PDF. Oops.</p>
<p>The reason this happened was because I didn't have auto-renew on for
God knows what reason, and I just let it get to today without paying any
attention. Maybe I should have Namecheap send emails to the addresses I
actually check (i.e. dennisc.net and mathadvance.org). Well, hopefully
that's never happening again.</p>]]></description>
	<pubDate>2 Sep 2023</pubDate>
</item>
<item>
	<title>Suguru</title>
	<link>https://dennisc.net/writing/blog/suguru.md</link>
	<description><![CDATA[<p>The last puzzle I set --- and likely the next
few I will set --- was a Chaos Deconstruction Suguru, a genre invented
by mathpesto. These puzzles are really hard to do wrong, you set one of
these and it's probably good just by virtue of existing. Granted, I've
always been a Chaos Construction fan, so the region-building aspect is
something that might not speak to everyone.</p>
<p>My impression is that these puzzles are in some ways easier to set
than sudokus of similar difficulty. When setting a puzzle, you have two
problems you need to simultaenously solve: you must make sure there
aren't no solutions and there aren't multiple solutions. With a sudoku,
you are not really guaranteed that solution at the start. But with a
suguru, you start with the solution: a blank board. You just need to
make it unique.</p>
<p>Also, since not every square has to be filled out, Suguru is a little
more forgiving, since while the <em>geometric</em> interactions are
plentiful, actual <em>numbers</em> do not interact that much unless you
specifically design them to.</p>
<p>At the same time, I wouldn't recommend a first-time setter to try a
Suguru in particular. It <em>is</em> much bigger, and there is less
solver support, meaning that verifying a puzzle must be done entirely by
hand. Also there's a lot of scanning when you check, and Sugurus feel
easier to break.</p>
<p>There are a couple of quirks of this genre too, especially when
solving. Since the solution is unique, say you have a cell completely
enclosed off, so it can only be a 1. By uniqueness you know it can't be
a degree of freedom so somewhere in that row there must be a 1. More
generally, you can be sure that only squares that interact in some way
with clues --- maybe not directly --- will have a digit. While using
uniqueness as a logical basis for solving is cringe, sometimes it is
useful to know what must be true and find the logic to confirm it. I got
lucky in that uniqueness didn't actually help with my puzzle, and it
doesn't really play a big role in any potential solve routes, but it is
a minor pain point that exists.</p>]]></description>
	<pubDate>27 Apr 2023</pubDate>
</item>
<item>
	<title>Setting up Gmail on aerc</title>
	<link>https://dennisc.net/writing/tech/gmail-aerc.md</link>
	<description><![CDATA[<p>A few days ago, I committed to CMU and got my
university email: dennisc2@andrew.cmu.edu. I made an alias,
reychen@cmu.edu, and if anyone wants to email my uni email I'd strongly
prefer if you emailed that alias because come on, dennisc2 is probably
the least sexy email address possible. I mean, why'd they have to put a
<em>number</em> in my email?</p>
<p>Anyway, the Gmail web client is a disaster, so I wanted to get my CMU
email on aerc. And since CMU uses Google Suites, the problem essentially
reduced to getting Gmail to work on aerc.</p>
<h2 id="tutorial">Tutorial</h2>
<p>TL;DR follow the <a
href="https://git.sr.ht/~sircmpwn/aerc/commit/b0eaf5191c9bc5b128e347625b7eef998ba63c41">commit
message</a> for the aerc patch that introduced aerc support. However,
note that the token endpoint --- when URL-escaped--- is now
<code>https%3A%2F%2Foauth2.googleapis.com%2Ftoken</code> instead.</p>
<p>Step-by-step:</p>
<ul>
<li>Go to <a
href="https://console.cloud.google.com">console.cloud.google.com</a> and
create a project.</li>
<li>Save the client id and client secret somewhere. (You can just copy
it into a temporary text file or something.)</li>
<li>Go to <a
href="https://developers.google.com/oauthplayground">developers.google.com/oauthplayground</a>.</li>
<li>Press the settings button and check "Use your own OAuth
Credentials". Then, copy the client id and client secret that you
saved.</li>
<li>Authorize the <code>mail.google.com</code> API under "Gmail API
v1".</li>
<li>Exchange your authorization code for tokens and save your refresh
token somewhere.</li>
</ul>
<p>Now that you have all the information you need, go to aerc's
<code>accounts.conf</code> and create a new entry with the following
source:</p>
<pre><code>source = imaps+oauthbearer://{username}:{refresh_token}@imap.gmail.com:993? \
client_id=XX&amp;\
client_secret=XX&amp;\
token_endpoint=https%3A%2F%2Foauth2.googleapis.com%2Ftoken</code></pre>
<p>The <code>outgoing</code> entry is identical: just replace
<code>imaps</code> with <code>smtps</code> and
<code>imap.gmail.com:993</code> with <code>smtp.gmail.com:465</code> and
you're good to go. Full example:</p>
<pre><code>outgoing = smtps+oauthbearer://{username}:{refresh_token}@smtp.gmail.com:465? \
client_id=XX&amp;\
client_secret=XX&amp;\
token_endpoint=https%3A%2F%2Foauth2.googleapis.com%2Ftoken</code></pre>]]></description>
	<pubDate>27 Apr 2023</pubDate>
</item>
<item>
	<title>The difference between my blog posts and essays</title>
	<link>https://dennisc.net/writing/blog/blog-vs-essay.md</link>
	<description><![CDATA[<p>I've already <a
href="/writing/blog/separation">written about this before</a>, so
forgive me for treading over old grounds. But this is more a reminder
for myself than a public explanation.</p>
<p>Blog posts are timely --- they largely rely on context from events
around that time. As of now, some of my posts reference <a
href="/writing/blog/2021-recs">my anime taste in 2021</a>, <a
href="/writing/blog/mat-remarks">the 2021 MAT</a>, <a
href="/writing/blogs/paragraphs">an English essay I was really upset
about having to write</a>, <a href="/writing/blog/gabor-2022">a track
meet</a>, <a href="/writing/blog/i-made-it">USAMO 2022</a>, and <a
href="/writing/blog/mast-hiatus">MAST's indefinite hiatus</a>.<a
href="#fn1" class="footnote-ref" id="fnref1"
role="doc-noteref"><sup>1</sup></a> This doesn't necessarily apply for
<a href="/writing/blog/best-colors">really stupid stuff</a>, but hey, a
man's got to shitpost.</p>
<p>Essays are more timeless and usually don't need the context of a
specific event to be understood. That's why <a
href="writing/essays/dont-email">To parents: stop emailing me</a>
ultimately became an essay even though it doesn't feel like one. In
retrospect, maybe these posts about the distinction between my blog and
essays should be in the essays section too.<a href="#fn2"
class="footnote-ref" id="fnref2" role="doc-noteref"><sup>2</sup></a></p>
<p>I don't make this distinction for tech posts because all tech posts
become obsolete over time, though the rate of obsolescence differs (for
instance, I along with the rest of the world stopped caring about <a
href="/writing/tech/gemini">Gemini</a>, but <a
href="/writing/tech/static-website">the morally correct way to make a
static website</a> will likely remain the same for the next decade at
least).</p>
<section id="footnotes" class="footnotes footnotes-end-of-document"
role="doc-endnotes">
<hr />
<ol>
<li id="fn1"><p>I could have included more but chose not to for space.<a
href="#fnref1" class="footnote-back" role="doc-backlink">↩︎</a></p></li>
<li id="fn2"><p>The reason I put them in blog posts is because I think
my mind is prone to changing about this distinction. At the very least,
I'm explicitly discovering criteria that I vaguely/subconsciously used
before.<a href="#fnref2" class="footnote-back"
role="doc-backlink">↩︎</a></p></li>
</ol>
</section>]]></description>
	<pubDate>31 Jul 2022</pubDate>
</item>
<item>
	<title>Plans for the MAT website</title>
	<link>https://dennisc.net/writing/tech/mat-web-plans.md</link>
	<description><![CDATA[<p>In <a href="mathadvance-rust">Math Advance is
looking for Rust developers</a>, I wrote</p>
<blockquote>
<p>We’ll unfortunately still be using Javascript, because I am not
rewriting the frontend.</p>
</blockquote>
<p>which implies that the marketing website and the contest portal would
still be intermingled. Now, I plan to separate the MAT website into the
marketing website and the contest portal.</p>
<p>I intend to use Rust to server-side generate the pages (just like
with Glee) and only use the bare minimum of Javascript required (timer
and autosubmit when time runs out). Then, I'll rewrite the marketing
website using just HTML and CSS, because we really don't need Javascript
for that. (Maybe I'll pawn the marketing rewriting off on someone
else.)</p>
<p>In semi-related news, I am developing multiple choice support for
mapm, and I will be integrating mapm with the contest portal (i.e. you
can upload mapm contests). So the portal will be able to hold mock AMCs,
and I'm considering opening up a community portal for anyone who wants
to host their mocks in addition to the official Math Advance portal. But
this is all pretty far off into the future.</p>]]></description>
	<pubDate>28 Dec 2022</pubDate>
</item>
<item>
	<title>Tentative plans for a puzzle book</title>
	<link>https://dennisc.net/writing/blog/puzzle-book.md</link>
	<description><![CDATA[<p>I've invented some homemade variants while
setting Sudoku puzzles that I think can be expanded on or further
explored, like Kakuro Sudoku, Equations, and Close Neighbors (which will
be renamed into Consecutive Neighbors).</p>
<p>These variants are worth further exploring, but at the same time,
it'd be silly to have a puzzle on this website titled "Close Neighbors
10" (whereas it might make more sense in a book). So I tentatively plan
to write a small book of puzzles with these custom variants.</p>
<p>I will try to make it suitable for beginner/intermediate solvers
while still providing fun for more experienced solvers. Some of the
things I'm planning to add are:</p>
<ul>
<li>brief explanations of the <em>implications</em> of the rules at the
beginning of each section (the reader can choose whether to read it and
"spoil themselves" or not)</li>
<li>possibly puzzle hints for harder puzzles</li>
<li>two challenge times (one for beginners, one for experienced solvers)
for anyone who wants to time their solves</li>
<li>answers to each puzzle, and a worked solution for each section.</li>
</ul>
<p>Anyway, here are the puzzles I'm planning to include:</p>
<ul>
<li>Classic sudoku, depending on how approachable I want to make this
book for absolute newbies (7)</li>
<li>Consecutive Neighbors, which is what I'm calling the "Close
Neighbors" genre (7)</li>
<li>Dutch Neighbors, which is what I'm calling the "Distant Neighbors"
genre (7)</li>
<li>Averaging circles, which is what I'm calling the "That's What I
Mean" genre (7)</li>
<li>Digit Neighbor Sums, which is what I'm calling 7-Eleven (and any
puzzles with a similar constraint, just with the digit and sum changed)
(7)</li>
<li>Thermo Sudoku, as an introduction for thermo placement puzzles
(5)</li>
<li>Thermo placement puzzles, like Alphabet Soup (2)</li>
</ul>
<p>This adds up to 28 or 35 puzzles, depending on whether I include
classic sudoku. These numbers are not strict, and is just a guideline
for about how many of each type I will include. I might write more of a
type depending on how I feel, and I will probably post final
specifications once the book is ready for purchase. I will probably
include the publicly available puzzles, because that way I can
reasonably generate a preview of the book without revealing any more
book-exclusive information.</p>
<p>In the off chance someone would like to submit puzzles for this book,
email me and we can discuss details.</p>]]></description>
	<pubDate>12 Jan 2023</pubDate>
</item>
<item>
	<title>Bedrock Linux</title>
	<link>https://dennisc.net/writing/tech/bedrock.md</link>
	<description><![CDATA[<blockquote>
<p>Can't set up Arch Linux? Maybe that's just because you're a
dumb-dumb. Maybe you just aren't smart enough, and deserve to use
Noobuntu for the rest of your life. You'll never get to use the AUR,
muwahahaha...</p>
</blockquote>
<p>Until you learn how to use <a
href="https://bedrocklinux.org/">Bedrock Linux</a>, that is...<a
href="#fn1" class="footnote-ref" id="fnref1"
role="doc-noteref"><sup>1</sup></a></p>
<h2 id="my-brl-setup">My brl setup</h2>
<p>A long, long time ago, I installed Arch manually on my laptop, so it
was the distro that I hijacked and it is the distro I boot into. For my
desktop, Ubuntu is the distro I boot into, because I accidentally nuked
my system by doing a <code>sudo rm -rf</code> in the wrong place at the
wrong time.</p>
<p>On my desktop, I use Ubuntu to work with my hardware (including,
amazingly enough, an XP-Pen Pro). I'm sure I could set it up with Arch
as well, but I do not know nor care how. On my laptop, which is a Lenovo
IdeaPad, the hardware has been very cooperative with me and easy to set
up, so after adding a couple of scripts to my i3 config it was up and
running.</p>
<p>For most of my software, I use the Arch package manager. It's
incredibly fast and between the official repos and the AUR, pretty much
everything is there. If I'm really particular about a particular program
(say, one I use often for work like Vim), then I will compile it myself
with Gentoo.<a href="#fn2" class="footnote-ref" id="fnref2"
role="doc-noteref"><sup>2</sup></a></p>
<p>If I'm feeling especially braindead one day and want to copy some
Ubuntu tutorial on the internet, or get something that's really annoying
in Arch (looking at you, printer drivers!) I have an Ubuntu stratum on
both my desktop and laptop.</p>
<h3 id="installation">Installation</h3>
<p>Because I liked the idea of Bedrock almost immediately, have some of
the biggest cajones on planet Earth, and have literally no important
files on my computer (my dotfiles and code are in Git repos AND synced
with Dropbox<a href="#fn3" class="footnote-ref" id="fnref3"
role="doc-noteref"><sup>3</sup></a>), I just went ahead and installed it
on bare metal. So I don't get flamed, I'm going to pretend that I
totally have a backup of my old system somewhere, even though I
literally have never used it in forever.</p>
<p>Maybe you don't want to commit to installing Bedrock just yet and
want to use it in a VM or something. You can do that and see how it
goes, but from my experience if you're using Ubuntu/Arch it really makes
no difference anyways, nothing breaks. Running recovery scripts, though,
does get a lot more annoying since you can't just <code>chroot</code> in
<code>/</code>, you gotta chroot into
<code>/bedrock/strata/&lt;some_strata&gt;</code>.</p>
<p>If you have an already existing machine, installing brl is so simple
that the official documentation is actually all you need for once. Since
you'd already have a desktop environment (and I'm counting the likes of
twms like dwm and i3) setup, there's not much to say on that front. I
think what's most interesting is how to set up a new computer.</p>
<p>What I do with new machines (and indeed, how I setup my desktop after
bricking my old partition and giving up) is install an Ubuntu variant
called <a href="https://regolith-linux.org/">Regolith</a>. It's like
Ubuntu but with <code>i3</code> on top of GNOME. It's a bit annoying if
you already have your own <code>i3</code> dotfiles and want to use them
instead, and you will have to Google where Regolith puts its own i3
config files so you can symlink yours there. Then I just clone my
dotfiles, run dotbot's install command, fetch Arch and Gentoo, and just
setup whatever apps I need.</p>
<p>Fortunately all my hardware cooperates with Linux more or less
(though pulseaudio volume scaling is annoying to deal with and is the
only thing that doesn't work out of the box), your experiences may
differ.</p>
<section id="footnotes" class="footnotes footnotes-end-of-document"
role="doc-endnotes">
<hr />
<ol>
<li id="fn1"><p>It would be a good idea to briefly read over the website
before returning to this post.<a href="#fnref1" class="footnote-back"
role="doc-backlink">↩︎</a></p></li>
<li id="fn2"><p>I bring up vim specifically because in Arch, it does not
come with X11 support (i.e. no <code>+</code> or <code>*</code>
registers). I've tried configuring my own custom vim build with pacman,
but because my brain is small and I latered switched to brl with Gentoo
as one of my strata, I gave up pretty quickly. Gentoo is better suited
to this sort of thing anyway.</p>
<p>And yes, I know neovim exists.<a href="#fnref2" class="footnote-back"
role="doc-backlink">↩︎</a></p></li>
<li id="fn3"><p>Well, just my code, actually. This is so I don't have to
make some nonsense commit, push it to a nonsense branch, and delete it
later.<a href="#fnref3" class="footnote-back"
role="doc-backlink">↩︎</a></p></li>
</ol>
</section>]]></description>
	<pubDate>21 Dec 2021</pubDate>
</item>
<item>
	<title>I've been receiving some interesting spam</title>
	<link>https://dennisc.net/writing/blog/spam.md</link>
	<description><![CDATA[<p><em>I wrote this a while ago but never got
around to publishing it, which is why the dates are from last
year.</em></p>
<p>I want to make my website accessible so I make it really easy for
anyone to go to the footer, find the mailto link, and send me an email.
That's why I haven't employed tricks such as "dchen at dennisc dot net".
Unfortunately, accessible to anyone includes spammers. Of the spam I've
received, the most interesting is stuff from web/app developers,
probably because a lot of keywords in my site suggest I'd be interested
in that.</p>
<p>Let's take a look at this gem from Priyankshu, sent in
2022-05-05:</p>
<blockquote>
<p>Hi there,</p>
<p>My name is Priyanshu, and we are a team of Professional IOS &amp;
Android Apps Developer with 7+ years' experience based in India. Do you
need a great App adjusted or built from scratch?</p>
<p>Reply me if you need any kinds of help in mobile Apps.</p>
<p>Let me know what you think.</p>
<p>Kind regards,</p>
<p>Priyanshu</p>
</blockquote>
<p>The very next day (2022-05-06), Ameli the Wordpress expert (ugh)
jumps in:</p>
<blockquote>
<p>Hi,</p>
<p>I'm a web developer who builds amazing looking websites for small
businesses. I'd like to have the chance to show you how I can improve
for your business.</p>
<p>I'm an expert in the Wordpress website platform and many other
platforms and shopping carts.</p>
<p>I can upgrade your existing website or build you a new one completely
that has all of the modern features and functionality. Would you be
available in the next few days for a quick consultation?</p>
<p>I'd like to share with you my ideas and some expert advice, share me
your Requirements and any direct contact number.</p>
<p>Thank You.</p>
<p>Ameli</p>
</blockquote>
<p>I'm sure these people are copy-pasting emails because there's no way
they have the technical skill to run a script to automatically spam
random people with emails. I'm pretty sure these emails aren't just spam
but also (attempted) scams: it is likely you'll never see the app or
website these guys promise you. (I mean, what kind of developer
cold-emails people without a portfolio?)</p>
<p>If I'm bored one day, I might scambait one of these poor chaps (or
figure out if they are, contrary to all appearances, legitimate). I'd
set up a burner email like notspam@dennisc.net to do it and then delete
it immediately after (unless I found more people to scambait).</p>
<p>Oh, and a ton of people are trying to tell me that my databases for
dennisc.net have been hacked. Yeah, sure...</p>]]></description>
	<pubDate>17 Feb 2023</pubDate>
</item>
<item>
	<title>Cracking the Cryptic, and New Year setting goals</title>
	<link>https://dennisc.net/writing/blog/ctc-2023.md</link>
	<description><![CDATA[<p>I'm writing this at midnight of New Year's Day,
and this year's "resolution" is going to be themed around
puzzle-writing. Yay!</p>
<p>For anyone who doesn't know yet, "5" was featured on Cracking the
Cryptic:</p>
<iframe src="https://www.youtube.com/embed/pvHAxxplxm4" frameborder="0" allowfullscreen>
</iframe>
<p>I left a comment on it, but because I linked back to my website for
my <a href="/writing/blog/constructing-5">construction notes</a>, it
probably got auto-deleted by YouTube's anti-spam bot. Sad.</p>
<p>Anyway, a couple of puzzle-constructy things &amp; my overall goals
for the next 4 months (let's be honest, I am going to give up on "New
Years resolutions" way before that, so let's not pretend for the next 8
months).</p>
<p>I really enjoy setting puzzles with my own homemade variants
(PARTICULARLY 7-Eleven and Close Neighbors), especially variants with
simple rules. But I also think there is some value in just exploring
more conventional variants, like thermos, anti-knight, etc. Also I
really want to set a renban and a between line someday.</p>
<h2 id="january-goal-volume">January goal: volume</h2>
<p>Release 8 puzzles, i.e. two a week (biweekly).</p>
<p>Nothing too much to be said about that, I think it's doable, but also
I will have to balance puzzle writing with USACO and updating my blog
and doing taxes for Math Advance and aaaagh</p>
<p>You will probably see a lot of ideas I've done before since I have
experience with them. For instance, rulesets like that of "Close
Neighbors" will probably appear a few times. ("Distant Neighbors",
anyone?)</p>
<h2 id="february-goal-coverage">February goal: coverage</h2>
<p>Use at least three of the following five common variants I haven't
used before:</p>
<ul>
<li>Renban lines</li>
<li>Between lines</li>
<li>Anti-knight/anti-king (for the purposes of this challenge I will
consider them the same)</li>
<li>Quads</li>
<li>Palindrome lines</li>
</ul>
<p>I can invent my own rules if I want or not. Either way is fine.</p>
<h2 id="march-goal-classic">March goal: classic</h2>
<p>Write a GOOD classic sudoku. I dunno, I feel like this is hard, but I
also should just do it. (For the purposes of this challenge, I will
count an anti-diagonal sudoku as pretty much meeting half of my goal.)
Also, I will better know wtf I am doing, since my classic sudoku
knowledge is... not exactly the greatest? I just have "intuition."</p>
<p>I should probably watch some CTC classic sudoku videos to get a feel
for them. Although I probably will not be using any difficult techniques
in mine.</p>
<h2 id="april-goal-non-sudoku-pen-puzzle">April goal: Non-sudoku pen
puzzle</h2>
<p>Probably a logic puzzle but crosswords are fair game too. (Although I
probably won't be doing a crossword quite yet? I dunno, four months is a
long time.)</p>]]></description>
	<pubDate>1 Jan 2023</pubDate>
</item>
<item>
	<title>I suck: a mapm bug</title>
	<link>https://dennisc.net/writing/tech/i-suck-mapm.md</link>
	<description><![CDATA[<p>With release 3.1.1 of the mapm library has come
a critical fix to how filtering works. Before, the command would fail
with <code>&gt;1</code> filter; it would only care about the first.
Here's the <a
href="https://gitlab.com/mathadvance/mapm/lib/-/commit/bfd6d58df4f0b8e390c7ab71ca4d5c9523206dbf">commit</a>
that fixes this: the bug was so stupid that I can't even begin to cringe
hard enough at it.</p>
<p>As a matter of analogy let's say you have an array of true/falses and
want to determine whether every value is <code>true</code>. What I did
was essentially (and this example code is written in <code>C</code>,
though it is so basic I would be shocked if it didn't work in C++ and
maybe even Rust) the following:</p>
<div class="sourceCode" id="cb1"><pre class="sourceCode c"><code class="sourceCode c"><span id="cb1-1"><a href="#cb1-1" aria-hidden="true" tabindex="-1"></a><span class="dt">void</span> allTrue<span class="op">(</span><span class="dt">bool</span> bools<span class="op">[],</span> <span class="dt">int</span> size<span class="op">)</span> <span class="op">{</span></span>
<span id="cb1-2"><a href="#cb1-2" aria-hidden="true" tabindex="-1"></a>  <span class="cf">for</span> <span class="op">(</span><span class="dt">int</span> i <span class="op">=</span> <span class="dv">0</span><span class="op">;</span> i <span class="op">&lt;</span> size<span class="op">;</span> i<span class="op">++)</span> <span class="op">{</span></span>
<span id="cb1-3"><a href="#cb1-3" aria-hidden="true" tabindex="-1"></a>    <span class="cf">return</span> <span class="dt">bool</span><span class="op">[</span>i<span class="op">];</span></span>
<span id="cb1-4"><a href="#cb1-4" aria-hidden="true" tabindex="-1"></a>  <span class="op">}</span></span>
<span id="cb1-5"><a href="#cb1-5" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code></pre></div>
<p>and obviously this isn't what you want to do, you want</p>
<div class="sourceCode" id="cb2"><pre class="sourceCode c"><code class="sourceCode c"><span id="cb2-1"><a href="#cb2-1" aria-hidden="true" tabindex="-1"></a><span class="dt">void</span> allTrue<span class="op">(</span><span class="dt">bool</span> bools<span class="op">[],</span> <span class="dt">int</span> size<span class="op">)</span> <span class="op">{</span></span>
<span id="cb2-2"><a href="#cb2-2" aria-hidden="true" tabindex="-1"></a>  <span class="cf">for</span> <span class="op">(</span><span class="dt">int</span> i <span class="op">=</span> <span class="dv">0</span><span class="op">;</span> i <span class="op">&lt;</span> size<span class="op">;</span> i<span class="op">++)</span> <span class="op">{</span></span>
<span id="cb2-3"><a href="#cb2-3" aria-hidden="true" tabindex="-1"></a>    <span class="cf">if</span> <span class="op">(!</span><span class="dt">bool</span><span class="op">[</span>i<span class="op">])</span> <span class="op">{</span></span>
<span id="cb2-4"><a href="#cb2-4" aria-hidden="true" tabindex="-1"></a>      <span class="cf">return</span> <span class="kw">false</span><span class="op">;</span></span>
<span id="cb2-5"><a href="#cb2-5" aria-hidden="true" tabindex="-1"></a>    <span class="op">}</span></span>
<span id="cb2-6"><a href="#cb2-6" aria-hidden="true" tabindex="-1"></a>  <span class="op">}</span></span>
<span id="cb2-7"><a href="#cb2-7" aria-hidden="true" tabindex="-1"></a>  <span class="cf">return</span> <span class="kw">true</span><span class="op">;</span></span>
<span id="cb2-8"><a href="#cb2-8" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code></pre></div>
<p>It's so obvious an error that there's no way this should've slipped
past me, but it did. And this is the price I pay for getting lax on
doctests. (So reminder to future self tomorrow, write the goddamn test
for this function. Ya?)</p>]]></description>
	<pubDate>18 Feb 2022</pubDate>
</item>
<item>
	<title>Puzzle-writing goals, part 2</title>
	<link>https://dennisc.net/writing/blog/puzzle-goals-part-2.md</link>
	<description><![CDATA[<p>I've been meaning to write this post for a long
time, but every time I sat down to work I instead just wrote another
puzzle. (Go figure.) But since it's about the end of January, I figured
I might as well do it now.</p>
<p>I've finished the January goal --- in fact, I've pretty much blown it
out of the water. With 8 puzzles posted to my website and 6 more kept
private for various reasons, I've been able to write at a pace of around
one puzzle every two days.</p>
<h2 id="puzzle-book">Puzzle-book</h2>
<p>For the <a href="puzzle-book">puzzle-book</a> I discussed earlier
this month, it might behoove me to reconsider which variants I include
more of. Equations is particularly easy to set, while Consecutive/Dutch
Neighbors is incredibly hard to set. Also, <em>if</em> I want to make
this book entirely approachable (rather than targeting both beginners
and experts), Clue Placement (i.e. Alphabet Soup + maybe other puzzles
I'll set later) might not be appropriate. Every other puzzle (so far)
seems like it'll be 2-3 stars of difficulty, so it'd be weird to force
in a 5 star puzzle.</p>
<p>Also, I don't know how milkable the 7-Eleven concept is. I tried
setting a puzzle entitled "24-7" where the orthogonal neighbors of each
7 summed up to 11, but no such grid exists. (Exercise for the reader:
why?) Instead, to preserve the theme and many of its ideas, I forced the
7 to have orthogonal neighbors of 2 and 4.<a href="#fn1"
class="footnote-ref" id="fnref1" role="doc-noteref"><sup>1</sup></a> The
Averaging Circles variant seems much more tractable, since we don't have
to deal with global constraints, so global digit neighbor constraints
will likely cover a broader range of puzzles in the book.</p>
<p>In general, I'm thinking that as long as my puzzles have unique,
semi-related constraints, it will be fine. It is probably going to be
difficult (and somewhat boring!) to literally write 7 puzzles with the
exact same constraint, so the sections of puzzles in the book will
likely be roughly grouped by theme, rather than strictly organized into
constraints.</p>
<h2 id="new-year-goals">New Year Goals</h2>
<p>As for the rest of my goals, I think for February I should probably
up it to four new variants. I originally was thinking five, but between
writing this post in my notebook and typing it up I managed to use
Renban lines, X-Sum, and Little Killers (speaking of the latter two, I
really ought to complete my sudoku rules intro). So the goal will
probably be a bit harder than initially anticipated, particularly since
some of the constraints I have left are annoying global constraints like
Anti-knight.<a href="#fn2" class="footnote-ref" id="fnref2"
role="doc-noteref"><sup>2</sup></a> But there are a ton of other
variants I didn't even mention, like Kropi, Sandwich, Odd/Even,
Diagonal, Anti-Diagonal, and Indexing.<a href="#fn3"
class="footnote-ref" id="fnref3" role="doc-noteref"><sup>3</sup></a></p>
<p>On the other and, my goals for March and April were grossly easy.
(Which is a good ting, because if I set low standards I am virtually
guaranteed to meet them and not get discouraged, etc.) As I've already
discussed, I've managed to set two Classic Sudokus, and a few days ago I
also set a Star Battle. So maybe I should up the ante a little bit and
change March/April goals to <em>themes</em>. Try to set 4-ish classic
sudokus in March and 4-ish pencil puzzles in April, and increase the
focus in those genres for those months.</p>
<h2 id="may-goal">May Goal</h2>
<p>I've only set one 5-star puzzle so far (Alphabet Soup), and I think
it's much easier for me to set 2-3 star puzzles than 4-5 star puzzles.
(1-star puzzles I can do, but I don't do it as often because the space
to explore is smaller with easier puzzles.) So a new goal for May:
<em>publish</em> puzzles on Logic Masters Germany such that I have at
least one of each rating (1-5 stars). I say publish because I'm a pretty
bad judge of difficulty (I originally thought Bird was a 2-star puzzle
at most). So depth/range is one of my goals now.</p>
<p>(Of note: I've never written a 4-star puzzle.)</p>
<h2 id="cracking-the-cryptic">Cracking the Cryptic</h2>
<p>I know it's been a while, but Close Neighbors has been featured on
Cracking the Cryptic too. I think the debut feature was a much bigger
deal for me (since, y'know, first time), and probably I will get less
surprised with each new puzzle featured.</p>
<p>Of course, it's always going to be a nice thing to see my puzzles
make it, but I think it does not make sense to make a post announcing
each new feature. So I will probably mention features when they happen
if I'm already writing a puzzle blog post, and otherwise, I'll probably
just silently update my puzzle page.</p>
<h2 id="taking-a-break">Taking a break?</h2>
<p>Maybe I should take a break from setting or reduce the pace to get my
life kind of together. (Right now I'm barely even a functional human
being since I spend so much time setting.) I say this, but I know with
pretty high probability I won't intentionally do this. A couple of tings
that will naturally make me slow down, though:</p>
<ul>
<li>Track and Field is about to officially start</li>
<li>In February I'll be spending 10 days grinding out my hardware
project for Hack Club</li>
<li>In March I will be attending <a href="https://warp.camp">WARP</a>
and milking as much as I can out of that experience (which means I
cannot spend hours setting --- in fact, I expect to set 0 puzzles in
that timeframe)</li>
</ul>
<p>There are other things I want to do, like finally finishing my Git
server<a href="#fn4" class="footnote-ref" id="fnref4"
role="doc-noteref"><sup>4</sup></a>, pivoting back towards teaching for
Math Advance, etc. So yeah, a steady pace of about 3-5 puzzles a month
(and not 14) is probably what I'll converge towards.</p>
<p>Thanks for reading, and thanks for trying my puzzles.</p>
<section id="footnotes" class="footnotes footnotes-end-of-document"
role="doc-endnotes">
<hr />
<ol>
<li id="fn1"><p>This is one of the puzzles I've kept private --- gotta
leave something for the book! Instead of using cages, this time I used
thermos, so if that interests you, keep an eye on the book!<a
href="#fnref1" class="footnote-back" role="doc-backlink">↩︎</a></p></li>
<li id="fn2"><p>Don't get me wrong, anti-knight is pretty fun to solve
when done right, but trying to write it is absolute misery. Particularly
because if I use the anti-knight constraint, I'll have to center the
puzzle around anti-knight deductions or at least base a large part of it
off that, and that seems kind of annoying.<a href="#fnref2"
class="footnote-back" role="doc-backlink">↩︎</a></p></li>
<li id="fn3"><p>My original draft of this post had Little Killers,
X-Sums, and Renban. But I just had to make it harder on myself :D<a
href="#fnref3" class="footnote-back" role="doc-backlink">↩︎</a></p></li>
<li id="fn4"><p>Fuck college apps. Seriously. They completely killed any
momentum I had going.<a href="#fnref4" class="footnote-back"
role="doc-backlink">↩︎</a></p></li>
</ol>
</section>]]></description>
	<pubDate>29 Jan 2023</pubDate>
</item>
<item>
	<title>What I want from a static site generator</title>
	<link>https://dennisc.net/writing/tech/ssg.md</link>
	<description><![CDATA[<p><a
href="https://jaspervdj.be/hakyll/">Hakyll</a> is the best static site
generator I've seen (though I haven't used it myself). Unsurprisingly it
uses Pandoc under the hood. Jekyll, Hugo, etc basically require you to
make another repository just for a <em>theme</em>, which is a WTF
moment.</p>
<p>What I want on top of Pandoc is</p>
<ul>
<li><p>no complex theming system (Hakyll CSS is good, my
<code>static/</code> directory is good, Jekyll is bad)</p></li>
<li><p>generate RSS and HTML themes (something like a Pandoc template is
probably best for the latter, the former could be made much better than
Pandoc + Bash)</p></li>
<li><p>Have LaTeX and Asymptote just <em>work</em>. Pandoc can do the
former (well, kind of, it can't statically compile KaTeX into HTML which
would be ideal) and cannot do the latter.</p>
<p>Note that under the hood, you'd want to replace an <code>asy</code>
environment with the generated SVG which can trivially be generated with
<code>asy -f svg file.asy</code>.</p></li>
</ul>
<p>Maybe this will be a future project sometime
later.</p>]]></description>
	<pubDate>9 Aug 2022</pubDate>
</item>
<item>
	<title>How I use conventional commits</title>
	<link>https://dennisc.net/writing/tech/conventional-commits.md</link>
	<description><![CDATA[<p>I like the general idea of <a
href="https://www.conventionalcommits.org/en/v1.0.0/">conventional
commits</a>: tag commits so that you can filter them through your pager.
However, especially coming from the context of Rust development, I think
conventional commits do not work well as stated.</p>
<p>I don't really care if commits are feats or breaking (and in early
development, many commits are breaking), so I omit these tags from my
commit messages. Later on, I do care if a line of changes is breaking. I
totally see the value in saying "this is a breaking change" in the
commit description, but when I'm scrolling through all I need are the
versions tagged. In practice breaking releases will typically not
include changes that are really compatible with the previous major
version, because otherwise why wouldn't you release those changes
separately first? Also, most commits are features, so I'm saving the
extra room in my commit header and not writing <code>feat</code>.</p>
<p>Instead, I use the absence of a tag to indicate "this is a normal
commit that adds some functionality". When I want to fix a logical error
up, <code>fixup</code>. For formatting errors (which shouldn't ever slip
by since I have a pre-commit hook that runs
<code>cargo fmt --check</code> among other things), I use the
<code>fmt</code> tag. Tags should be used sparingly and only for commits
that are "weird" in some way, i.e. commits you ideally never would have
needed to make to begin with.</p>
<p>Of course with Rust, you have to make commits where you just bump up
the version number. Here, a <code>release</code> tag would be
appropriate.</p>
<p>Tags are things that should be used sparingly for out of the ordinary
commits. The fact of the matter is that most commits add functionality
of some sort to your program, and indicating that with <code>feat</code>
dilutes the value of your actual tags. Conventional commits are a good
set of guidelines to consider for your repository's Git history, but for
me they hold little value as specifications: they are too intrusive on
the commit history. Especially since I haven't ever used any
conventional commit tooling and honestly don't see the point: I just
search for <code>fixup:</code> or whatever in my Git shortlog.</p>
<p>Overall I think <a href="https://git.sr.ht/~dennisc/glee/log">my
approach is working out for me</a>, and I find my history a little more
readable than a history where <em>everything</em> is tagged. However,
there are cases where tagging can present a more concise way to describe
the <em>scope</em> of your changes, which is one thing conventional
commits do well as is.</p>]]></description>
	<pubDate>29 Jul 2022</pubDate>
</item>
<item>
	<title>An Independent Judiciary</title>
	<link>https://dennisc.net/writing/blog/an-independent-judiciary.md</link>
	<description><![CDATA[<p>Liberal media outlets are crying foul after the
SFFA case, claiming the judiciary is an outdated, partisan institution
that solely exists as a policy instrument for the conservatives. They
call for the day when the judiciary can again be <em>their</em>
political instrument (and have been even during the 2020 election),
whether through more legitimate means such as repeated political
victories or less legitimate means such as court-packing. Never mind the
lessons of history --- apparently, some of them want to repeat the same
mistake as FDR.</p>
<p>In doing so, they reveal that they have little interest in an
independent judiciary. It's just a policy tool, one that happens to be
Theirs and not Ours at the moment. Of course, conservatives played
politics with the judiciary too: they blocked the appointment of Merrick
Garland and still reel over David Souter not ruling <em>exactly</em> as
they expected him to. But currently the judiciary's opinions please the
conservatives, so they do not cry foul.</p>
<p>An independent judiciary is vital. Who else is supposed to interpret
the law? The legislature, whose response to any Constitutional challenge
would be "trust us"? The executive, who would then shape the law
according to his whims? If we let those who make or execute the law
interpret its Constitutionality, then the Constitution merely becomes a
series of suggestions.</p>
<p>Living in a constitutional democracy has costs. It means a church of
homophobes can picket the funeral of a gay Marine (Snyder v. Phelps). It
means cakeshops and website creators can refuse to express support of a
gay wedding for religious reasons. (Masterpiece Cakeshop, 303 Creative
LLC). These results are detestable. Even most homophobes would side with
Snyder.</p>
<p>But the costs of not having a Constitution are far greater. If we do
not apply the Constitution impartially and abrogate the rights of those
we dislike, the minorities we seek to protect today could very well
become the targets of tomorrow. The Constitution admits no exceptions<a
href="#fn1" class="footnote-ref" id="fnref1"
role="doc-noteref"><sup>1</sup></a>, and for good reason. It is rights
for all or rights for none.</p>
<p>To be fair, the Supreme Court has not always held true to this
principle. Famously bad examples of judicial overreach are Dred Scott,
Plessy, and Korematsu. More recently, Bakke/Grutter and Roe<a
href="#fn2" class="footnote-ref" id="fnref2"
role="doc-noteref"><sup>2</sup></a> are examples too. (Given this, one
can hardly fault the current Supreme Court for overturning these last
two decisions.) These examples of judicial overreach do not show that
the SCOTUS is "broken". Rather, they show the dire consequences of the
judiciary being used in ways it was never meant to: as a partisan tool
to buttress policy outcomes.</p>
<p>Given this, what are we to make of those who claim the justices'
impartiality is a sham, and that the judiciary is just a political tool?
There are those who want the judiciary to become a political tool ---
just one that works for Us, not Them. They do not believe in an
impartial judiciary whatsoever and do not understand its importance.
These people lack an understanding of the law, and frankly, common
sense.</p>
<p>How about the rest, who wish the judiciary was "impartial" but think
it is not? Their concerns are entirely based on policy: they do not like
the outcome of SCOTUS cases, so they cry foul. Never mind that they only
pay attention to the "big cases" --- the ones they are personally
invested in --- and ignore the cases that get less press coverage, where
many "conservative" justices vote just as they would.</p>
<p>There are legitimate arguments that some of the judiciary's rulings
are incorrect. I certainly do not agree with every SCOTUS outcome.
However, any such argument would have be to based in constitutional law,
rather than naked policy preferences. And that is how conversations
about the Supreme Court <em>should be</em>. If you have a problem with a
Supreme Court ruling, find where your interpretation of constitutional
law disagrees with theirs. "But muh outcome" is no reason to disparage
the legitimacy of one of the most important institutions in America. It
is when they apply the Constitution inconsistently, rather, that the
alarms really ought to be sounded.</p>
<section id="footnotes" class="footnotes footnotes-end-of-document"
role="doc-endnotes">
<hr />
<ol>
<li id="fn1"><p>This is not strictly true. There are various standards
for exceptions, such as rational basis and strict scrutiny. However,
none of them are "we don't like bigots", because it could easily turn
around and become "we don't like minorities".<a href="#fnref1"
class="footnote-back" role="doc-backlink">↩︎</a></p></li>
<li id="fn2"><p>Yes, Roe. <a
href="https://rossonl.wordpress.com/2023/01/22/the-paradox-of-roe-v-wade-50th-anniversary-special/">Loren
Rosson's post</a> explains it very well.<a href="#fnref2"
class="footnote-back" role="doc-backlink">↩︎</a></p></li>
</ol>
</section>]]></description>
	<pubDate>18 Jul 2023</pubDate>
</item>
<item>
	<title>College Observations</title>
	<link>https://dennisc.net/writing/blog/college-observations.md</link>
	<description><![CDATA[<ul>
<li><p><strong>Internships</strong>: I think the hardest part of getting
an internship is getting to the point where you can talk to a person
(i.e. passing resume screens, OAs, etc). I also know way more people who
are getting roles in quant firms (even if it's a SWE role at Jane
Street, for example) than people who get into big tech, which is not
horribly surprising given recent hiring trends.</p>
<p>On another note, I think it is truly a soul-sucking process,
especially when the processes take so long. I am incredibly lucky to be
done early, but I was not having the greatest time last year. Quant
companies do tend to have shorter processes, which probably is a reason
they poach a lot of talent.</p></li>
<li><p><strong>Classes</strong>: In high school, my teachers would
always say stuff like "your college classes will be a lot harder", and a
lot of the messaging around intro-level classes/freshman year is "as you
get further into college, your experience will get more difficult (but
you will be more adjusted to college life to compensate)", etc. While
there is some level of truth to that, I found my experience has been the
opposite. The really advanced graduate classes have grading structures
like "submit writeups to a few problems by the end of the semester".
Unsurprisingly, they also were the classes where I learned the
most.</p></li>
<li><p><a
href="https://the-tartan.org/2025/10/06/cmu-undergraduate-womens-enrollment-declines-across-colleges/">The
gender ratio at CMU is quite concerning.</a> Especially in CS. I am sure
that the ratio for math majors is also similarly dire.</p></li>
<li><p>My sleep schedule is not actually functional. I usually go to
sleep around 1 - 2 AM, and wake up around 9 - 10 AM (I get out of bed
much later). My sleep schedule did fix itself somewhat when I was
working, but I will need it to be quite good for the summer.</p></li>
<li><p>There is so, so much to learn. I feel like my knowledge of every
field is quite shallow, and the number of fields I have any proficiency
in are quite small. Even if you restrict it to pure math, I don't have
much experience with differential equations, complex analysis,
probability,<a href="#fn1" class="footnote-ref" id="fnref1"
role="doc-noteref"><sup>1</sup></a> etc.</p></li>
<li><p>In a similar vein, there is so, so much to do. It is really quite
nice that even in a less interesting campus like Carnegie Mellon, I will
still run out of stuff to do.</p></li>
<li><p><strong>Gratitude</strong>: You know, in freshman year of college
I wasn't the happiest person. Forgive me if this is a little cliche, but
now I am genuinely so glad to be alive every day. I've met a lot of
people and made many friends, some of whom I have fallen out of touch
with. While it is a bit sad, I wake up every day glad to be seeing the
same sun as them every morning, and I hope that they are all doing
well.</p></li>
<li><p><strong>Ambition and overwork</strong>: I was really ambitious
going in freshman year. I skipped all the intro classes, sat in on tons
of classes, and took 66 units (for people not in CMU, that translates to
"a ridiculous amount") in freshman spring. I have mixed feelings about
taking so many classes. On one hand, it put me in a really good position
now, where I am just a hair away from fulfilling my graduation
requirements very early. But a lot of the classes I took so early on
were junk volume, and the junk prevented me from paying as much
attention to the classes I actually enjoyed. (Although I really did have
the ability to power through more earlier than I do now. But I think
that may have heavily contributed to my dissatisfaction with early
university life.)</p></li>
<li><p><strong>Geneds</strong>: I think geneds have been a horrible
waste of my time. This is not because I think writing, the arts, etc.
are worthless. But if I am in a room with people who are just here
because they have to be here, then I will not have a good time either,
regardless of how much I actually like the subject itself. <em>You
cannot beat creativity into a person.</em> Also, having depth in one or
two areas in the arts would have been so much more valuable to me than
the superficial breadth that gened requirements impose. (On my end, I
wish I learned more music theory/rhythm classes/etc...)</p></li>
<li><p><strong>Poker</strong>: Gambling is lowkey way too fun. But
seriously though, I think playing some poker teaches you quite a few
things about life, particularly risk management.</p></li>
</ul>
<section id="footnotes" class="footnotes footnotes-end-of-document"
role="doc-endnotes">
<hr />
<ol>
<li id="fn1"><p>I am referring to more measure-theoretic probability
concepts, such as the Borel Normal Number Theorem, etc. I do understand
"intuitive probability" decently well.<a href="#fnref1"
class="footnote-back" role="doc-backlink">↩︎</a></p></li>
</ol>
</section>]]></description>
	<pubDate>9 Oct 2025</pubDate>
</item>
<item>
	<title>Consider learning Typst instead of LaTeX</title>
	<link>https://dennisc.net/writing/tech/typst.md</link>
	<description><![CDATA[<p>If you do not already know LaTeX, you should
seriously consider learning Typst in lieu of learning LaTeX.</p>
<ul>
<li>Typst is trivial to set up on your machine. LaTeX is a pain in the
ass. Sure, you can install some partial distribution of LaTeX on your
machine, but you are in for a world of hurt the second you want to
install or upgrade a package. You can also install LaTeX as a user with
the install script, which can be quite daunting for a complete computer
newbie.</li>
<li>Typst compiles much faster.</li>
<li>And you don't have to use a single brain cell to get the compilation
pipeline working. This is in stark contrast with LaTeX, which requires
installing and configuring the external <code>latexmk</code> script just
to get things to work right.</li>
<li>No <code>\documentclass</code> or <code>\begin{document}</code>
needed. Just type some text and equations and it will compile.</li>
<li>Typst is <em>less</em> of a pain in the ass to write. Sure, I have
to write <code>$x y$</code> instead of <code>$xy$</code> because
otherwise Typst will think I am referring to a <em>variable</em>
<code>xy</code>, but the commands make a lot more sense (e.g.
<code>union</code> over <code>\cup</code>), I don't ever have to type a
backslash, and writing a fraction does not make me sad because I no
longer have to use <code>\frac</code>.</li>
<li>It is much easier to design a simple document. My LaTeX document
designs would take two days; my Typst design took me two hours.</li>
</ul>
<p>Now, life isn't all sunshine and rainbows with Typst. I admit there
are some pain points. <code>#show</code> rules behave somewhat
strangely, especially if you are used to LaTeX. I also do not think it
was trivial to do some more complex things, such as setting up footers
to reflect the current chapter/section and then not having my footnote
counter resets screw up the references. (By the way, the footer counter
doesn't reset at all, which is frankly ridiculous.)</p>
<p>But here's the thing. You can install Typst right now, import <a
href="https://gitlab.com/chennisden/dotfiles/typst/conversational">my
package</a><a href="#fn1" class="footnote-ref" id="fnref1"
role="doc-noteref"><sup>1</sup></a>, and compile a good-looking document
in under ten minutes. Good luck doing that with LaTeX.</p>
<section id="footnotes" class="footnotes footnotes-end-of-document"
role="doc-endnotes">
<hr />
<ol>
<li id="fn1"><p>I wish it were a lot easier to install packages from
third-party repositories than it is right now. Unfortunately <a
href="https://github.com/typst/typst/issues/1554#issuecomment-1604330130">this
is not planned</a>, although the reasoning is very understandable.<a
href="#fnref1" class="footnote-back" role="doc-backlink">↩︎</a></p></li>
</ol>
</section>]]></description>
	<pubDate>21 Jul 2024</pubDate>
</item>
<item>
	<title>More on WARP</title>
	<link>https://dennisc.net/writing/blog/more-on-warp.md</link>
	<description><![CDATA[<ul>
<li>On Day 0 my roommate used a sharpie to draw smiley faces on
everyone's hand.</li>
<li>WARP has a distinct lack of consequences for basically anything.
People leave their trash strewn around the commons (a lot more on this
later), nothing happens if you miss class, and generally no one gives a
shit what you do.</li>
<li>I'm more introverted than I expected to be. I skipped a lot of
afternoon/some evening activities to recharge my batteries, preferring
instead to interact with no one or do light interactions with a few
people (generally just "chilling").</li>
<li>I tend to find a group of people in the first few days and after
that, I'm mostly just with them. Fortunately this time the group I chose
was gym rats 💪</li>
<li>On the break day (which already had a ton of physical activity),
Max, Bryan, and I did two archery contests where the loser had to do 50
pushups (for each loss). Guess who ended up doing 100...</li>
</ul>
<h2 id="cleanliness">Cleanliness</h2>
<p><em>This will be much angrier than my usual post --- even my usual
angry post. If you don't want to deal with that, you've been
warned.</em></p>
<p>Jesus. Fucking. Christ.</p>
<p>How hard is it to just clean up after yourself?</p>
<figure>
<img
src="https://media.discordapp.net/attachments/1077038148112093304/1085101221964152832/3CCB1BC4-9FFA-4147-9BC8-8FA8F70740C4.jpg?width=513&amp;height=684"
alt="Trash at WARP. Yeah, it&#39;s really bad." />
<figcaption aria-hidden="true">Trash at WARP. Yeah, it's really
bad.</figcaption>
</figure>
<p>Yeah I get it, you're too rational to clean this shit up. You choose
to defect rather than cooperate and let some other poor chap clean up in
the mess, and in the same day, you manage to mess the entire commons up
again. I'm honestly impressed.</p>
<p>If you're reading this, and you <em>know</em> that you're one of the
people who regularly contributed to this, then know that I think you're
generally a very cool person --- everyone at WARP is --- but please,
make it a habit to clean up after yourself. Please make "leaving the
place better than I found it" an actual <em>value</em> of yours, even if
it's 2AM or whatever.<a href="#fn1" class="footnote-ref" id="fnref1"
role="doc-noteref"><sup>1</sup></a> I know no one is doing this out of
malice, but if you "just forgot" to clean up, it's because you just
don't care enough. I know, for a fact, that you learned a ton of skills
to train habits at this camp. Put the "Applied" in "Applied
Rationality": please make this a habit you decide to train because it is
really important.</p>
<p>Because how the fuck are you going to solve hard problems like AI
alignment if you can't even solve the mess in the commons?</p>
<section id="footnotes" class="footnotes footnotes-end-of-document"
role="doc-endnotes">
<hr />
<ol>
<li id="fn1"><p>And if you're too tired at 2AM to fix your mess,
consider sleeping earlier.<a href="#fnref1" class="footnote-back"
role="doc-backlink">↩︎</a></p></li>
</ol>
</section>]]></description>
	<pubDate>15 Mar 2023</pubDate>
</item>
<item>
	<title>Beam's C implementation is done</title>
	<link>https://dennisc.net/writing/tech/c-beam.md</link>
	<description><![CDATA[<p>After quite a bit of time, I've finally
finished the C implementation for Beam as well. This is more portable
for systems that do not have Rust, though I doubt that matters since
LaTeX is quite hefty as well.</p>
<p>In any case, it was mostly for my own learning experience. And learn
I did:</p>
<ul>
<li>File i/o</li>
<li>Used <code>malloc()</code> and <code>free()</code>. Also learned
about <code>realloc()</code>, though I intentionally did not fix
segfaulting for slides/presentations that were too long (since long
presentations are bad)- Learned about structs/enums/unions in C (and how
to make a tagged union), though I never ended up using them</li>
<li>The equivalent of <code>str.split()</code> in pretty much any other
language</li>
<li>Wrote a Makefile for the first time, learning about
<code>.PHONY</code> and the <code>all</code> convention, including files
like <code>config.mk</code>, and the <code>${DESTDIR}</code>
variable.</li>
</ul>
<p>And this is only a subset of what I applied in the code. Since it's
my first program in C, the code probably sucks ass. If you want to make
sure something works I'd use the Rust implementation because I don't
suck as badly at Rust, this was just an educational exercise for
me.</p>]]></description>
	<pubDate>30 Apr 2022</pubDate>
</item>
<item>
	<title>Commit discipline with git add -p</title>
	<link>https://dennisc.net/writing/tech/git-add-p.md</link>
	<description><![CDATA[<p>A lot of people have god-awful commit
discipline, like using <code>git commit -a</code> for every commit and
writing nonsense because a bunch of changes were jumbled up. One of the
biggest reasons for this is because they don't know there's a way to
only commit part of a file at a time, and no, it's not deleting the
excess and then adding it back. (At least, not directly and not always
--- you do have the option with the <code>e</code> option of
<code>git add -p</code>.)</p>
<p>Well, there is. And it's <code>git add -p</code>.</p>
<h2 id="commit-discipline">Commit Discipline</h2>
<p>The way you are supposed to write a commit is by staging what you
want to commit with <code>git add</code>, and then actually writing the
commit with <code>git commit</code>. In some sense, the fact that
<code>git commit</code> has any more arguments (like filenames, but
especially <code>-a</code> and <code>-m</code>) is really dangerous. But
dangerous in the sense that an idiot or a lazy person will use them
improperly --- they have reasons for existing.<a href="#fn1"
class="footnote-ref" id="fnref1" role="doc-noteref"><sup>1</sup></a></p>
<p>Sometimes you know that all you changed was refactoring some module
by renaming it, in which case <code>git commit -a</code> is justified.
Or you just changed one file, initialized your project, etc. But in
these cases you knew from the start exactly what you were going to
change.</p>
<p>More often, when you're writing the most important or complicated
features, you'll have a bunch of semi-related changes uncommitted. The
wrong thing to do is <code>git commit -a</code>. The right thing to do
is ask, "What's the smallest set of related changes I can commit?" And
then commit those.</p>
<p>So my workflow looks like</p>
<ul>
<li>Run the appropriate <code>git add</code> and <code>git commit</code>
operations to get, in some order, the changes I want to push to
upstream. Typically, I do the smallest/simplest commits first.</li>
<li><code>git rebase -i</code> and swap the order of commits if
necessary.</li>
</ul>
<h2 id="how-does-git-add--p-help">How does <code>git add -p</code>
help?</h2>
<p>What the workflow I described above requires is being able to
separate changes in one file into separate commits conveniently. Running
<code>git add -p FILENAME</code> lets you pick which edits you want to
stage. It gives you an interactive prompt, and you can choose options
like <code>y,n,q,e,s</code> (these tend to be the only ones that
matter). They stand for yes, no, quit (aka answering no for every
remaining prompt), edit (more on that in a second), and split, which
splits a hunk into multiple sub-hunks. Split only works if the current
hunk is not all in one chunk of consecutive lines.</p>
<p>Here's an example of what pops up when running
<code>git add -p</code>. Notice there is no <code>s</code> because you
can't split up these changes, since they're on consecutive lines.</p>
<pre><code>diff --git a/api/src/accounts/verify_email.rs b/api/src/accounts/verify_email.rs
index abf1a7d..d870c98 100644
--- a/api/src/accounts/verify_email.rs
+++ b/api/src/accounts/verify_email.rs
@@ -2,7 +2,7 @@

 use lib::{
     models::{
-        table::Table,
+        sql::Table,
         token::{RedisPool, RedisToken},
         user::User,
     },
(1/2) Stage this hunk [y,n,q,a,d,j,J,g,/,e,?]?</code></pre>
<p>Now let's talk about <code>e</code>, which is edit. Here you can
directly choose which lines in a hunk you want to stage and which you
want to ignore. When you open up the edit menu, you'll be met with all
the changes in the hunk, and what you want to do is remove the changes
you do not want to keep.</p>
<ul>
<li>In order to remove a deletion, simply remove the <code>-</code>
character. (You will have to insert a space in the line to compensate.)
<strong>Do not remove the rest of the line.</strong></li>
<li>To remove an addition, remove the entire line.</li>
</ul>
<p>That's pretty much for <code>git add -p</code>. It's a pretty simple
tool, but it is very powerful. It makes it that much easier to keep your
commit history clean, and that is why you should use it more often
:)</p>
<section id="footnotes" class="footnotes footnotes-end-of-document"
role="doc-endnotes">
<hr />
<ol>
<li id="fn1"><p>Particularly the <code>-m</code> flag of
<code>git commit</code>. It makes it much easier for a shell script
(like <a href="https://codeberg.org/dennisc/musiclist">musiclist</a> or
GNU pass) to automatically generate commits. But these are situations
where Git is not used as a development tool, and all changes are
predictable to the point of being machine-generatable: add, delete,
edit, or move a password.<a href="#fnref1" class="footnote-back"
role="doc-backlink">↩︎</a></p></li>
</ol>
</section>]]></description>
	<pubDate>28 May 2022</pubDate>
</item>
<item>
	<title>Separation</title>
	<link>https://dennisc.net/writing/blog/separation.md</link>
	<description><![CDATA[<p>To get good at any sport, there are two things
you have to do: train and compete. In training you extend your
capabilities, while in competition you display them.</p>
<p>Now, this isn't quite the same when it comes to academic endeavors.<a
href="#fn1" class="footnote-ref" id="fnref1"
role="doc-noteref"><sup>1</sup></a> Take programming, for instance:
except for some throwaway scripts --- which don't make you significantly
better at programming anyway --- there is no "practice code."
<em>All</em> of your code is supposed to be neat, organized, and checked
into Git. And you're not supposed to write bad on purpose.</p>
<p>But training isn't supposed to be bad. You're still trying your best,
whether it's with a piece of writing or a workout. Training is just
different --- different in the way it's performed and different in its
goals.</p>
<p>The reason I don't do daily writing prompts (and I always despised
them in English class) is because almost all of the prompts are stuff I
don't care about. Writing is actually quite similar to track and field:
on the surface the events all look the same. But dig a little deeper and
you'll see the intricacies behind them. Why a 100m runner cannot run the
mile. Why an essayist like me can't describe his first pet.<a
href="#fn2" class="footnote-ref" id="fnref2"
role="doc-noteref"><sup>2</sup></a></p>
<p>So why separate my writings in the first place, instead of just
throwing them all in the same place? To answer this, it's worth
identifying the consequences of neglecting to do this separation.</p>
<p>Around the spring of 2020 to the fall of 2021, the COVID pandemic was
in full force for us, and we had not reopened or returned to in person
school. Naturally, this meant that every athletic competition was
cancelled. This totally eroded any separation between training and
competing. Maybe my willpower isn't strong enough, but I totally stopped
caring about a month in.<a href="#fn3" class="footnote-ref" id="fnref3"
role="doc-noteref"><sup>3</sup></a></p>
<p>Another reason is because it encourages me to follow through with the
writings that are less likely to pan out.<a href="#fn4"
class="footnote-ref" id="fnref4" role="doc-noteref"><sup>4</sup></a>
There's a certain standard when it comes to my essays: there has to be a
point.</p>
<p>But even if there isn't a point, it can still be entertaining. I
still read other people's updates on the last however many days of their
lives. And hell, separating my blog from my essays gives me room to <a
href="/writing/blog/10-traits">mess around</a> from time to time. Even
though this isn't my serious writing, I like to think it makes my
serious writing better.</p>
<p>Was there a point in writing this post? Not really. It doesn't make
any salient points about the world, or even writing. But I wanted to
write this anyway, and that, to me, is enough to justify it. That's why
I have a blog.</p>
<section id="footnotes" class="footnotes footnotes-end-of-document"
role="doc-endnotes">
<hr />
<ol>
<li id="fn1"><p>Though there is a one-to-one correspondence in math
contests and the like.<a href="#fnref1" class="footnote-back"
role="doc-backlink">↩︎</a></p></li>
<li id="fn2"><p>I've never even had a pet.<a href="#fnref2"
class="footnote-back" role="doc-backlink">↩︎</a></p></li>
<li id="fn3"><p>And if it's that my willpower isn't strong enough, then
all the more reason to rely on these tools like separation as
substitutes.<a href="#fnref3" class="footnote-back"
role="doc-backlink">↩︎</a></p></li>
<li id="fn4"><p>Like this essay, for instance. Early visitors to my
website will know how long I referenced this (not yet existent) essay,
which goes to show that even with more relaxed standards, it had to go
through a lot of rewrites and rethinking.<a href="#fnref4"
class="footnote-back" role="doc-backlink">↩︎</a></p></li>
</ol>
</section>]]></description>
	<pubDate>6 Jan 2022</pubDate>
</item>
<item>
	<title>Why I Journal</title>
	<link>https://dennisc.net/writing/blog/why-i-journal.md</link>
	<description><![CDATA[<p>Recently I've picked up a habit of journaling.
It's not an everyday thing --- some days nothing worth reporting on
happens, and other days so much happens that I'm just really tired at
the end.</p>
<p>Back in the start of 2022, I said in <a
href="separation">Separation</a>:</p>
<blockquote>
<p>The reason I don’t do daily writing prompts (and I always despised
them in English class) is because almost all of the prompts are stuff I
don’t care about.</p>
</blockquote>
<p>And typically I don't really care about my daily life a lot, but as
college applications are coming up, I've begun to realize that maybe I
should. I've written about a lot on this website in the past two years:
about my teaching philosophy, the way I approach programming and
technology, how I like to write, and more. But I've never really written
about <em>myself</em>, sans <a
href="https://www.dennisc.net/writing/blog/i-made-it">qualifying for
USAMO 2022</a> and <a
href="https://www.dennisc.net/writing/blog/gabor-2022">a track meet</a>.
Looking at my writing in the last two months, almost all of it has been
focused on or related to the work I've been doing: it's either about
technology or Math Advance. Hell, even in the last four, the only
exceptions have been shitposts and a post complaining about an English
essay I really didn't want to do.</p>
<p>Before journaling I couldn't really write about myself. You know,
it's a little embarrassing: writing about yourself means to be
presumptuous enough to think anyone else cares about who you are. It
also means you think that to some extent the way you think is
<em>right</em>. I think we all secretly feel this way though, and it's
just that some of us are confident enough to admit it outright.</p>
<p>But the reason I journal is usually not that deep. Part of it is for
the generic reasons, like processing the day, decompressing, or
whatever. But I really do it to have a log of my thoughts (or at least a
subset of them) and what I did. This is part of why I wrote even before
journaling: sometimes I read my past writing and think "wow this guy was
onto something". But as cliche as it sounds, I think sometimes I can
find value in the everyday things I do years in the future. Knowing what
I did and how I thought will make it much easier to be introspective in
the future, which is a skill that would come in real handy right
now.</p>
<p>Talking about yourself is a rite of passage that everyone goes
through, and it's my turn now. So I'll lay all the cards down on the
table.</p>
<p>I'm an obstinate and stubborn person who really cares about doing
things the way I like them. I don't really thrive in situations where I
don't have a lot of agency, but give me the reins and you might get
something amazing. I have a kind of foul temper and can get irritated
easily, but it's rare that I actually get angry at someone, and when I
do I don't stay mad for long.</p>
<p>I like to be sarcastic, but it's probably because I feel kind of
awkward when I'm trying to be nice.That's something I want to work on: I
want to be a person that makes people feel good and I wish it came more
naturally to me.</p>
<p>I'm really picky about the kinds of jokes I tell but I'll laugh at
pretty much anything. Speaking of my laugh, I don't actually laugh most
of the time. Instead, I wheeze like a dying banshee. Multiple people
have expressed concern for me because of this, stop asking questions and
just enjoy the show.</p>
<p>I'm also pretty clumsy, but it's usually because my attention is
always focused on something else when I walk. I've nearly walked into
poles while reading a book, noticing at the last second that something
is appearing right in front of me and rapidly expanding in my peripheral
vision, and I recently did run into a trash can because I was admiring a
tower on the other side of the street. For me it makes life more fun and
I wouldn't have it any other way.</p>
<p>The things I like? Hmm, what most people know about me is that I'm
good at STEM, where STEM is this nebulous thing that they "don't get".
I'm actually not that good at STEM as a whole, believe it or not: I'm
really just good at math and programming. (Not CS, at least not yet.)
But these are some boring things to like for 99% of people (although if
you're on this site, you're probably interested in math, eh?) and I've
already talked enough about math and programming.</p>
<p>So let's talk about architecture! I don't really know that much about
it: Italian architecture goes Romanesque, Gothic, Renaissance, Baroque.
Romanesque is characterized by semicircular arches and Gothic
architecture has really ornate windows/decorations and pointed arches,
not smooth ones. The Santa Maria in Florence is really impressive;
droves of people flocked over there to get in line, and I was lucky that
I found a chance to get in when the line didn't wrap around an entire
side of the church (and that church was <em>big</em>). Nobody was in the
St. Lorenzo though (probably because the ticket in costs nine euros),
and that was just as impressive. Speaking of churches, my hobby in
Europe was going inside churches and admiring the interior and the
paintings. I think I went in 20 churches on my trip.</p>
<p>Architecture was a new obsession I picked up recently (although the
roots of it can probably be traced to the Stanford campus --- I mean,
have you seen the arches and the marble floor, man?), but something I'd
liked for a long time was running. I'm no good at it and it really
frustrates me: my 5k is barely under 20 minutes and my mile time is
around 5:40. I want to get serious about it since it's my last shot ---
I don't see myself competing in college for a myriad of reasons. Cross
country is uniquely difficult for me because I can't run up a hill for
long. I mean, no one can, but for me it's worse. So I've got to work on
that if I want to see any substantial improvement. I love the feeling of
stopping at the top of the mountain and admiring the view though. A
picture of a lake really can't compare to seeing it in person, both from
the summit and right by the shoreline.</p>
<p>I really like writing too --- you can probably tell --- but I feel
like what I write is not really diversifying. I write a lot about
technology because pretty much nobody knows anything about it and it's
really easy for me to write about: just document my workflow. But I want
to write more teaching materials, rather than just occasionally writing
<em>about</em> teaching. I want to write fiction, too --- I've got a
couple of ideas throughout the years and if I come up with something
good I'll consider working on it. But the last several times my excuses
have been "well I have to worry about grades since it's junior year",
"I'll do it after I'm done with all the programming projects I care
about" (which seems like it'll never happen at this rate), and now "I
have to worry about college applications". All of which are true, but
reasons that I'm "too busy for writing" will never go away. I want to
confront the fear I have about writing, because from past experience you
never really get rid of it, you just learn to get over it when you're
writing. (Like now!)</p>
<p>What are some random fun facts about me that I can share? Remembering
them all is a lot harder than I expected it to be, which is why I wish I
kept better records of <em>myself</em> --- in other words, journaling.
Either way, let's give it a go: I like watching anime and reading manga
(2022 recs coming soon!). Minecraft is a fun game, but for the last year
I've been more hooked on Spider Solitaire than I care to admit. I'm
actually getting bored of my mobile games so gaming is kind of taking a
hit in the list of things I like. I read random tech blogs in my free
time on my phone, which might not be too surprising. Everyone thinks I'm
an extrovert but I'm actually really happy when I'm alone, as long as
it's not all the time. I think they have a word for that now,
"ambivert". I like to sing a lot but I'm at best average.I prefer paper
books over ebooks because of the feeling of the pages on my fingers, and
if I get stuck on a page for a while that page will tend to crease a
bit. My favorite fruit right now might be the honeydew, but apples are
really good too because they're so convenient.</p>
<p>Everything I listed before was stuff I remembered about myself, but
I'm going to cheat now and look at my journal because I know I wrote
more. I want to learn more about military tactics, history, and
technology. (I'd watch an anime on the Three Kingdoms if there was a
historically accurate one, rather than stuff based on the Romance of the
Three Kingdoms.) I wish I knew more about natural history so I could
recognize plants and animals when I encountered them in the wild.
Speaking of which, mushrooms are actually really interesting, and I
discovered this because of a mushroom museum. (Did you know Greece has 9
mushroom societies?)</p>
<p>Was this oversharing? Probably, but I think I might as well get used
to it for the next few months. The thing about writing about yourself
and sharing it to other people is that all the doubts in the back of
your head are <em>right</em>. Most people aren't particularly special
and lead fairly ordinary lives, and I'm part of "most people". It takes
a special sense of self-confidence to write about yourself, reveal the
unflattering parts of yourself, and still do it in an interest way.
Let's just say autobiographies impress me a lot more now.</p>
<h2 id="future">Future</h2>
<p>I don't think I'm shameless enough to write down "I did XXX with YYY
and feel ZZZ around them", even in a private diary. My journaling has
looked like my previous two public posts, although surprisingly it has
been more polished, not less. I think I'm going to post some of it to
Gemini (finally I've found a proper use for my capsule). Yeah, I know,
<a
href="https://マリウス.com/gemini-is-solutionism-at-its-worst/">Gemini
is inaccessible</a>, but that's kind of the point.</p>]]></description>
	<pubDate>1 Aug 2022</pubDate>
</item>
<item>
	<title>Economic History Conference (2023)</title>
	<link>https://dennisc.net/writing/blog/econ-conf-2023.md</link>
	<description><![CDATA[<p>This weekend, I went with <em>cursed schedule
guy</em> to the <a
href="https://eh.net/eha/economic-history-association-2023-annual-meeting/">Economic
History Conference</a> because it happened to be in Pittsburgh. A lot of
big-name economics professors happened to be there, and a <em>lot</em>
of working papers were presented.</p>
<p>Let's go through it, day by day.</p>
<p>Disclaimer: I know basically nothing about economics or economic
history.</p>
<h2 id="friday-sep-8">Friday (Sep 8)</h2>
<p>Technically you are supposed to register for the conference, and the
fee is nothing to sneeze at: $75. We just snuck in, and no one really
seemed to care, despite my babyface and lack of a name tag giving away
that I was definitely not a grad student.</p>
<p>We were busy taking our fake (21-341 Linear Algebra), so we missed
the first half of the presentations on Friday. But our other fake
(21-300 Basic Logic) got cancelled, so we could make the second half of
the presentations. We also met one of <em>cursed schedule guy</em>'s PhD
Twitter mutuals (that's how he found out about this conference).</p>
<p>We went to <strong>Session 5: American Political
Economy</strong>.</p>
<ul>
<li>The first paper was about the New Deal Era and how the legislative
branch increasingly <em>delegated</em> its authority to the executive.
As the New Deal is the part of US History I've studied most extensively,
I found that I could mostly keep up... until the discussion started
involving statistics. The methodology is not something that I could
understand in a span of 30 seconds, especially since I wasn't used to
the way economics papers presented their statistical results.</li>
<li>The second paper was about fencing laws. For a bit of background,
there is a principle called <em>Coase's Theorem</em> that stipulates
private individuals can negotiate an optimal solution, given
preconditions that never happen in real life, such as negligible
transaction costs, etc. Fencing laws concern ranchers and farmers:
should ranchers be responsible for fencing animals <em>in</em>, or
farmers responsible for keeping them <em>out</em>, or some combination
thereof? The paper analyzed the effect of these fence laws and their
changes on farmers and ranchers.</li>
<li>The third paper concerned the spread of Confederate Culture to the
North and West. After the South lost the civil war, many former
slaveholders migrated to the North/West for various reasons, and they
brought their culture with them. The paper examines its presence (via a
number of metrics, e.g. Confederate statues) and its effects. One of the
important facts the paper established was that <em>former slaveholders
disproportionately found themselves in positions of power</em>, which is
how their culture had such an outsized negative influence.</li>
</ul>
<p>Then we had a plenary session (plenary means "everyone attends")
about how housewives provide much value to the economy even though they
do unpaid work, and how measures to the productivity of the national
economy (e.g. GDP) can be adjusted to better account for this sector of
the economy.</p>
<p>After a short coffee break that we spent reading papers and talking
to professors (note: I did not do much of the talking), we went to a
different hotel for dinner and probably collectively bummed off at least
$80 worth of food. (It was really high class.) Then we almost tagged
along for the grad students dinner, but then the PhD Twitter mutual said
"free-rider problem (also the grad students are paying for the food)",
so we were like "I get it" and left. I was perfectly fine with it
because I was absolutely exhausted.</p>
<h2 id="saturday-sep-9">Saturday (Sep 9)</h2>
<p>The plan was to attend the Historian's Breakfast at 6:30--8:00 AM,
because history is something I know a lot more about (broadly) than
economics. But due to a series of bad decisions, I ended up sleeping at
around midnight last night, and decided that my health was worth more
than attending the conference. So I barely made it to the second session
of the day.</p>
<p>We went to <strong>Session 10: Innovation, Finance, and
Urban</strong>, but because the bus was running late I could only make
it to the second half.</p>
<ul>
<li>The first paper analyzed the effects of the loss of men in Japan
after World War II. The methodology was very interesting: they used the
change of the gender ratio and the death of male soldiers to find how
many people died in the war. Also, because the US employed the strategy
of island hopping, and regiments were made of people from the same
prefectures, some prefectures saw heavy losses in men while others saw
lighter losses in men. This lent itself easily to a comparative analysis
by prefecture.</li>
<li>The second paper concerned the effect of trade on US ports. As most
history books will tell you, an increase in trade during the late
1800s-early 1900s coincided with industrialization and a decrease in
agriculture.</li>
<li>The third paper was a case study of Red Vienna, a large-scale public
housing complex with cheap rent.</li>
</ul>
<p>I was then going to attend the dissertation session as well, but then
I got a splitting headache and realized I was just a couple of minutes
away from collapsing. So I went back to my dorm and collapsed on the bed
instead.</p>
<h2 id="sunday-sep-10">Sunday (Sep 10)</h2>
<p>I deliberately woke up late again to get breakfast. The bus was late
<em>again</em>, and this time it didn't even let me off on the correct
spot despite stopping there and my pressing the "Stop Requested" button.
So I only made it for two papers. I attended <strong>Session
16</strong>:</p>
<ul>
<li>The second paper was about female hypergamy (a fancy word that means
"marrying for higher social status"). The conclusion drawn was that, at
least in England, hypergamy did not happen. The methodology was twofold:
first, marriage registrations were used, and then for those with rare
surnames not in the records, the average level of wealth for a person of
that surname was used instead. The problem with this is that averaging
data out tends to screw up correlation factors, but I'm not actually
sure how impactful that is here.</li>
<li>The third paper was about the link between the spread of electricity
and birth rates. There were two opposing factors: electricity made it
easier for children to be raised (since many manual tasks were replaced
with machines, e.g. dishwashers), but electricity also created new
skilled jobs, which increased the opportunity cost of having children as
women had a comparative advantage in skilled jobs.</li>
</ul>
<p>And that was the entire conference! It was a lot of fun, and I
learned many things through osmosis. I probably need to study up on
statistics, but economic history papers do not seem to have that high of
a barrier to entry when it comes to reading them. Any layman could
probably understand a good bit of the presentations and conclusions,
even if the methodology is mathematically
challenging.</p>]]></description>
	<pubDate>10 Sep 2023</pubDate>
</item>
<item>
	<title>News Sites are Annoying</title>
	<link>https://dennisc.net/writing/tech/news-sites.md</link>
	<description><![CDATA[<p>Every news website spams you with popups asking
you to subscribe, login, etc. This is annoying, but fortunately there is
an easy way to bypass it: curl.</p>
<p>You can just run <code>curl URL -O</code> to save it as a file, and
then open that file in Firefox. This works, but it requires some manual
intervention. Unfortunately piping it into Firefox also does not work
(because Firefox is a browser, not an actually good application that
respects pipes --- ugh!)</p>
<p>But we can tidy it into a script:</p>
<div class="sourceCode" id="cb1"><pre
class="sourceCode bash"><code class="sourceCode bash"><span id="cb1-1"><a href="#cb1-1" aria-hidden="true" tabindex="-1"></a><span class="va">FILENAME</span><span class="op">=</span>/tmp/<span class="va">$RANDOM</span>.html</span>
<span id="cb1-2"><a href="#cb1-2" aria-hidden="true" tabindex="-1"></a><span class="ex">curl</span> <span class="st">&#39;$1&#39;</span> <span class="at">-o</span> <span class="va">$FILENAME</span></span>
<span id="cb1-3"><a href="#cb1-3" aria-hidden="true" tabindex="-1"></a><span class="ex">firefox</span> <span class="va">$FILENAME</span></span></code></pre></div>
<p>Now, the Firefox add-on API does not just let you run a shell script.
In theory, you could run a script (using JS --- fucking browsers) to</p>
<ul>
<li>intercept certain URLs (you'd need to create such a list, and
unfortunately it doesn't seem there's a Googleable list in
plaintext)</li>
<li>run the shell script shown above.</li>
</ul>
<p>I don't know if it's worth writing a Firefox add-on when the API
changes so fast. Maybe when I have more time --- right now I shouldn't
be on these news sites anyway.</p>]]></description>
	<pubDate>28 Nov 2022</pubDate>
</item>
<item>
	<title>Why latexmk?</title>
	<link>https://dennisc.net/writing/tech/latexmk.md</link>
	<description><![CDATA[<p>latexmk is a build script that allows you to
automate the LaTeX building process, running exactly enough times to
generate the necessary cross-references.</p>
<p>Well, that sentence told you exactly nothing. So instead of asking
what latexmk is, why not ask why we use it?</p>
<h2 id="cross-refs">Cross Refs</h2>
<p>Read <a href="https://www.dennisc.net/writing/tech/tex-overview">A
High-Level Overview of TeX</a>, particularly the "Build Process"
section.</p>
<p>So LaTeX has to run multiple times in order to get crossrefs to work.
But how many times?</p>
<p>With smaller files you can just keep spamming pdflatex until you've
gotten all of the references. But</p>
<ul>
<li>with bigger files each compilation is fairly expensive,</li>
<li>and it's nice to just run one command and know it will run exactly
as long as it needs to.</li>
</ul>
<p>Latexmk runs exactly as many times as you need it to. And it doesn't
get itself stuck in an infinite loop if a reference is just missing, it
stops after seeing that it is missing twice.</p>
<p>Why twice? Well, the first time the reference is supposed to be
missing, as it might get written to the aux file after it is called. The
second time, it should already be in the aux file, so if it is missing
that means it was never written.</p>
<h2 id="asymptote">Asymptote</h2>
<p>If you've ever used Windows + TeXWorks the official asymptote
"solution" is</p>
<div class="sourceCode" id="cb1"><pre
class="sourceCode bash"><code class="sourceCode bash"><span id="cb1-1"><a href="#cb1-1" aria-hidden="true" tabindex="-1"></a><span class="ex">pdflatex</span> FILE</span>
<span id="cb1-2"><a href="#cb1-2" aria-hidden="true" tabindex="-1"></a><span class="ex">asy</span> <span class="at">-f</span> pdf <span class="pp">*</span>.asy</span>
<span id="cb1-3"><a href="#cb1-3" aria-hidden="true" tabindex="-1"></a><span class="ex">pdflatex</span> FILE</span></code></pre></div>
<p>where the second line is replaced by some script in the TeXWorks
compilation options.</p>
<p>This is stupid, we should have one command that does the entire
process, and optimally, if and only if there are any asymptote files
generated. That's part of what latexmk does (at least, if you configure
<code>.latexmkrc</code> properly).</p>]]></description>
	<pubDate>19 Mar 2022</pubDate>
</item>
<item>
	<title>How to sync Dropbox on Alpine Linux with rclone</title>
	<link>https://dennisc.net/writing/tech/alpine-dropbox.md</link>
	<description><![CDATA[<p>The official Dropbox client is fairly difficult
to setup on Alpine. If all you need is file syncing and you're fine with
using a CLI to do it, you can use <a
href="https://rclone.org/docs/">rclone</a>.</p>
<p>Run</p>
<pre><code># apk add rclone</code></pre>
<p>to install rclone.</p>
<p>Then run</p>
<pre><code>$ rclone config</code></pre>
<p>and you will be greeted with a series of interactive prompts.</p>
<p>First you start making a new remote.</p>
<pre><code>n) New remote
d) Delete remote
q) Quit config
e/n/d/q&gt; n</code></pre>
<p>Then you need to give this new remote a name; it hardly matters what
it is, but for this guide we'll just call it "dropbox".</p>
<pre><code>name&gt; dropbox</code></pre>
<p>Then you will be asked what kind of storage you want to use. Look for
the option that says "Dropbox" (as of the time of writing, it is 12),
and input that.</p>
<pre><code>Option Storage.
Type of storage to configure.
Choose a number from below, or type in your own value.
...
Storage&gt; 12</code></pre>
<p>Then you will be asked about "OAuth Client Id" and "OAuth Client
Secret". Just leave those blank by pressing Enter as rclone instructs.
You'll be asked if you wanted to edit the advanced config and use auto
config too. Just press Enter to use the defaults, unless you have a
reason not to.</p>
<p>Finally, you will be prompted to allow rclone OAuth access to
Dropbox. Do this. If all went well, you should get a success message
afterwards.</p>
<p>To sync, run</p>
<pre><code>$ rclone sync dropbox: ~/dropbox</code></pre>
<p>As long as this command is running, your local and remote Dropbox
directories will be synced. If you want, you may set up a daemon to keep
this persistently running.</p>
<p>More detailed usage instructions are also available at <a
href="https://rclone.org/dropbox/">rclone's Dropbox page</a>, and of
course, the man page for rclone.</p>]]></description>
	<pubDate>8 Jun 2022</pubDate>
</item>
<item>
	<title>MAST returns, sort of</title>
	<link>https://dennisc.net/writing/blog/mast-returns.md</link>
	<description><![CDATA[<p>The title is a bit clickbaity: MAST stays dead,
and what I'm going to be doing will differ significantly. But the
substance is there: <strong>starting this August, I will begin accepting
students again.</strong></p>
<p>It will be group lessons, once a week for about an hour. It will be
held online on some platform that is <strong>NOT ZOOM</strong>. There
will be 10 official lessons a semester, all taught by yours truly. The
difficulty will roughly be mid and late AMC/early and mid AIME.
<strong>Tuition is $100 a semester (10 lessons)</strong><a href="#fn1"
class="footnote-ref" id="fnref1" role="doc-noteref"><sup>1</sup></a>,
slides/handouts will definitely be provided, and recordings maybe (if I
remember to record). The timing will probably be 3 PM Sunday EST (hard
start) to 4 PM (soft stop).</p>
<p>The material will be old MAST contents for everything except
geometry. For geometry, I will be piloting the draft of a textbook
called "A Brief Foray Into Euclidean Geometry". It is easier compared to
the content a prospective student might be used to working with for the
other subjects, but I think people <em>really</em> suck at geometry.
(And it is hard to expect otherwise, given the lack of any good intro
level geometry text.) Old MAST materials may have to supplement the
text, depending on how advanced the group I get is and how far I get
into the draft.</p>
<p>I will not be the sole teacher; however, the amount of instruction
other Math Advance staff will do is also to be determined. The only
thing for certain so far is I am teaching intro geometry (i.e. the
lecture associated with <em>Foray</em>).</p>
<p>Something a bit experimental which might not pan out: I want to try
having guest lecturers. This is where other Math Advance staff might be
able to help out, or any interested other people. If it happens, the
content will be whatever they want, maybe keeping in mind your level of
experience. No promises this will happen or to what extent though.</p>
<p>Where I would want staff help is the following:</p>
<ul>
<li>Answering questions</li>
<li>Hosting guest lectures</li>
</ul>
<p>If you are interested in helping as staff, email me at <a
href="mailto:dchen@mathadvance.org">dchen@mathadvance.org</a>.
Otherwise, if you want to apply as a student, hang tight (and spread the
word!) Details will come soon in another post, probably within a week.
(Said details include finalized timing, the registration process, and a
tentative syllabus.)</p>
<h2 id="details">Details</h2>
<p>These details will vary as my and the other instructors' lives shift.
(For instance, we don't know when we have midterms.) But here is what we
know.</p>
<ul>
<li>Read the <a href="/apply-2023.pdf">application document</a> and
follow its instructions to apply by <strong>September 3rd</strong>.</li>
<li>Classes begin September 9th.</li>
<li>After 4 or 5 classes we take a week-long break for midterms. I will
try to time the bulkiest lesson, the intro geo lesson, to be right
before that.</li>
</ul>
<h3 id="syllabus">Syllabus</h3>
<p>Tentative. No promises what order content is covered in, but the
subjects will be interwoven and lectures will be in roughly increasing
order of difficulty.</p>
<p><strong>Algebra</strong></p>
<ul>
<li>Basic algebra, including symmetric manipulations and logs</li>
<li>Polynomials (division, remainder theorem, etc)</li>
<li>Summations (and janky miscellany, e.g. AIME I 2023/10)</li>
</ul>
<p><strong>Combinatorics</strong></p>
<ul>
<li>Introduction to Counting</li>
<li>Perspectives</li>
</ul>
<p>Potentially you will see a guest lecture on efficient casework.</p>
<p><strong>Geometry</strong></p>
<p>The primary text is <em>Foray</em>. If I magically finish Ch. 4 by
the time I teach Triangle Centers, it will use <em>Foray</em> too. A
copy will be provided, free of charge, for students.</p>
<ul>
<li>Angle Chasing (Ch. 1, 2, 5 of Foray)</li>
<li>Triangles (Intended to be Ch. 4, 6 of Foray, but no way I finish
that fast)</li>
<li>How to do trigonometry (for real). <span
class="math inline">sin (<em>a</em> + <em>b</em>)</span> and <span
class="math inline">cos (<em>a</em> + <em>b</em>)</span>, complex
numbers. Sort of a hybrid of algebra and geometry.</li>
</ul>
<p><strong>Number Theory</strong></p>
<ul>
<li>Mods (definitions, FLT, and Chinese Remainder Theorem)</li>
<li>Prime factorization (incl. divisor count, sum of divisors, and <span
class="math inline"><em>ν</em><sub><em>p</em></sub></span>)</li>
</ul>
<h2 id="a-disclaimer">A Disclaimer</h2>
<p>We take our work seriously. This class is meant to be well-designed
and teach you things. However, "perfect is the enemy of good", and as
much as I don't like this philosophy in general, it does apply to this
class. If I were to wait for our team to develop <em>perfect</em>
content for an AIME class before we taught, we'd be completely out of
touch 30-something year olds trying to teach competition math. (Foray,
which does not abide to this philosophy, has taken a breathtakingly long
time to write: the first two chapters took two years.)</p>
<p>Nor is this an incredibly battle-tested curriculum. Yes, we have used
various versions of the materials with an AMC class, an AIME bootcamp,
and MAST. But this is not a class that has been taught a hundred times;
it is the first time we are using this curriculum. We have made changes
after every iteration, and we can only hope they have been for the
better.</p>
<p>By all means, I think you will learn a lot from this class if you
elect to take it. However, it is not my intention to mislead you as to
what this class is. Our team consists of USAMO and MOP participants. Our
students have gone on to participate in these programs too. Yet no
class, least of all this one, will be the magic bullet that gets you
there. It is not some gospel. It is just meant to shift your thinking a
little bit and hopefully give you the boost you need to improve.</p>
<section id="footnotes" class="footnotes footnotes-end-of-document"
role="doc-endnotes">
<hr />
<ol>
<li id="fn1"><p>Obviously financial aid will be offered. If you are in
the position where paying for math contest training is a bad idea, then
your entire tuition will be waived, no questions asked.<a href="#fnref1"
class="footnote-back" role="doc-backlink">↩︎</a></p></li>
</ol>
</section>]]></description>
	<pubDate>17 Aug 2023</pubDate>
</item>
<item>
	<title>Paragraphs</title>
	<link>https://dennisc.net/writing/blog/paragraphs.md</link>
	<description><![CDATA[<p>It's the Sunday before essays are due, and that
means I'm going to have to read a littany of poorly written papers in
exchange for having my equally poorly written paper read.</p>
<p>There are two things about English essays that really bother me: the
lack of paragraph breaks and the boring titles. These two things should
be alarming to any English teacher, particularly because <strong>even
the best writers/papers suffer from this</strong>.<a href="#fn1"
class="footnote-ref" id="fnref1" role="doc-noteref"><sup>1</sup></a></p>
<p>This suggests a problem endemic to English classes. You can't get rid
of the disease just by treating the symptoms, but on the other hand you
need the symptoms to figure out what the problem is.</p>
<h2 id="press-enter">Press Enter</h2>
<p>A lot of people have been given totally wrong ideas about a paragraph
since elementary school. And this is because teachers tell you, "write a
paragraph about your thoughts", and students always ask, "how long does
a paragraph have to be?" So then the teachers, thinking they are doing
their students a favor by not letting them get away with the minimum
possible work,say four to five sentences.</p>
<p>Later a "paragraph" will mean 300 words, or however much space you
need to fit in your mandatory 3 quotes per main idea. And even though no
one would say the definition of a paragraph is "whatever the teacher
says", the way people are writing sure sends a different message.</p>
<p>In a 4 or 5 paragraph paper you have paragraphs sprawling across the
entire page, obscuring the development of separate ideas and jumbling it
all into one giant clusterfuck. If you go on arxiv and look at a random
paper, chances are that each page has 3 or 4 paragraphs, even when some
of the space is taken up by diagrams. So even <em>math research</em> is
easier to read than a high school English essay.</p>
<p>Chances are that everyone knows when to start a new paragraph: at the
place that most optimizes readability. Length and relatedness as two of
the largest factors, but there are plenty more.</p>
<p>If everyone knows when to start a new paragraph, why aren't people
doing it in English class? The answer is pretty boring: because the
teacher told them not to and they don't care enough to.</p>
<h2 id="title">Title</h2>
<p>I suspect the only reason English papers even have titles is because
the MLA format requires them. And the titles are usually pretty boring:
"An Analysis of Luce's Rhetoric" or what have you.</p>
<p>Typically in English class you struggle to pick a title because you
can't think of any. When I struggle in my own essays it's for the
opposite reason: there are so many good choices I can make.<a
href="#fn2" class="footnote-ref" id="fnref2"
role="doc-noteref"><sup>2</sup></a></p>
<p>A title is just a really short version of a hook. And a hook explains
why you wrote your essay. For instance "Force Multipliers" is about how
tools can have multiplicative rather than additive value. "Hook" is how
you get someone to read what you wrote. And so on.</p>
<p>If I were really honest in my titles for English class, it would be
"Please give me an A I want to go to MIT." That won't fly, so "Into the
Unknown" it is.</p>
<section id="footnotes" class="footnotes footnotes-end-of-document"
role="doc-endnotes">
<hr />
<ol>
<li id="fn1"><p>There's no such thing as a well-written or interesting
English paper, so by "best papers" I really just mean "the crap that
gets you a good grade".<a href="#fnref1" class="footnote-back"
role="doc-backlink">↩︎</a></p></li>
<li id="fn2"><p>Although the only one I've even thought of alternative
titles for was Settling for Mediocrity. And even then, I knew I was
going to use Settling for Mediocrity because that was the old title
before I rewrote it.<a href="#fnref2" class="footnote-back"
role="doc-backlink">↩︎</a></p></li>
</ol>
</section>]]></description>
	<pubDate>13 Feb 2022</pubDate>
</item>
<item>
	<title>Two questions on free modules over a PID</title>
	<link>https://dennisc.net/writing/blog/pid.md</link>
	<description><![CDATA[<p>While reading about free modules over a PID I
had two natural questions come up. To provide some context, here are two
standard facts:</p>
<ol type="1">
<li>every submodule of a free module over a PID is free, and the proof
involves the well-ordering principle,</li>
<li>given <span class="math inline"><em>N</em> ≤ <em>M</em></span> where
<span class="math inline"><em>M</em></span> has finite rank, there
exists a basis <span
class="math inline">{<em>m</em><sub>1</sub>, …, <em>m</em><sub><em>k</em></sub>}</span>
of <span class="math inline"><em>M</em></span> and ring elements <span
class="math inline"><em>r</em><sub>1</sub> ∣ … ∣ <em>r</em><sub><em>j</em></sub></span>
such that <span
class="math inline">{<em>r</em><sub>1</sub><em>m</em><sub>1</sub>, …, <em>r</em><sub><em>j</em></sub><em>m</em><sub><em>j</em></sub>}</span>
is a basis of <span class="math inline"><em>N</em></span>. (Of course
<span class="math inline"><em>N</em></span> and <span
class="math inline"><em>M</em></span> are over a PID.) The standard
proof is over the Smith Normal Form and requires us to rely on the fact
that the required row/column operations we do to perform a change of
basis are finite.</li>
</ol>
<h2 id="relationship-to-the-axiom-of-choice">Relationship to the Axiom
of Choice</h2>
<p><a
href="https://math.stackexchange.com/questions/4966748/does-every-submodule-of-a-free-module-under-a-pid-is-free-imply-the-axiom-of-c">Relevant
StackExchange</a></p>
<p>What is the relationship of the first fact to the Axiom of Choice?
For context we know "every vector space has a basis" is equivalent to
Choice. So it does not seem implausible that the first fact is
equivalent to Axiom of Choice too.</p>
<h2
id="nice-bases-of-a-submodule-of-a-free-module-of-infinite-rank">Nice
bases of a submodule of a free module of infinite rank</h2>
<p><a
href="https://math.stackexchange.com/questions/4967770/nice-bases-for-submodules-of-infinite-free-modules-over-a-pid">Relevant
StackExchange</a></p>
<p>Is the second fact true if <span
class="math inline"><em>M</em></span> has infinite rank? If not, which
<span class="math inline"><em>M</em></span> disprove it? Alternatively
what extra conditions do we need to put on the underlying ring of <span
class="math inline"><em>M</em></span>? (For instance we know making it a
field is sufficient.) So on and so forth.</p>]]></description>
	<pubDate>8 Sep 2024</pubDate>
</item>
<item>
	<title>An Abstract Algebra Primer</title>
	<link>https://dennisc.net/writing/blog/algebra-primer.md</link>
	<description><![CDATA[<p>I have written an <a
href="/alg-primer.pdf">abstract algebra primer</a>. The official pitch
on the math section of my website:</p>
<blockquote>
<p>This is a medium-length (113 pages) introduction to abstract algebra.
Intuition is emphasized, fully formalizing arguments takes a back seat,
the theory is extremely streamlined (so many important and interesting
ideas are omitted).</p>
</blockquote>
<p>There is not much to say here that I have not already said in the
primer. This covers much more than a standard one-semester undergraduate
course and is probably closer to the content of a graduate course, but a
lot of details and exercises are not included since brevity is one of
the main goals. I imagine the level of detail is somewhere between Evan
Chen's Napkin and Dummit/Foote.</p>
<h2 id="errata">Errata</h2>
<p>If the date displayed on your PDF is later than the date listed, the
error has already been fixed.<a href="#fn1" class="footnote-ref"
id="fnref1" role="doc-noteref"><sup>1</sup></a></p>
<p><strong>Only errors are listed here.</strong> Other changes, such as
additional exercises, streamlined notation, etc. are not included. To
see all changes, you may peruse the <a
href="https://gitlab.com/chennisden/handouts/algebra-primer">Git
log</a>.</p>
<h3 id="aug-05-2025">Aug 05, 2025</h3>
<ul>
<li><strong>Homset Adjunctions</strong>: The direction of arrows
(namely, <span class="math inline"><em>f</em></span> versus <span
class="math inline"><em>f</em><sup>op</sup></span>) were
incorrect/inconsistent. This has been fixed (in Figures 10 and 11).</li>
<li><strong>Homset Adjunctions</strong>: The roles of <span
class="math inline"><em>f</em></span> and <span
class="math inline"><em>h</em></span> were inconsistent in Figure 10.
This has also been fixed.</li>
</ul>
<h3 id="jun-27-2025">Jun 27, 2025</h3>
<ul>
<li><strong>Coproducts</strong>: The inclusion arrows <span
class="math inline"><em>i</em><sub><em>c</em></sub></span> should be of
the form <span
class="math inline"><em>i</em><sub><em>c</em></sub> : <em>c</em>− &gt; ⨁</span>,
rather than <span
class="math inline"><em>i</em><sub><em>c</em></sub> : ⨁− &gt; <em>c</em></span>.</li>
</ul>
<h3 id="apr-12-2025">Apr 12, 2025</h3>
<ul>
<li><strong>Algebraic Closures</strong>: To show that a maximal element
of <span class="math inline">ℱ</span> is an algebraic closure, we show
that any non-trivial algebraic extension has an isomorphism to some
field <strong>in <span class="math inline">ℱ</span></strong> which
<strong>fixes <span class="math inline">$\overline{F}$</span></strong>,
not <span class="math inline"><em>F</em></span>.</li>
</ul>
<h3 id="feb-13-2025">Feb 13, 2025</h3>
<ul>
<li><strong>Natural Transformations</strong>: Fix some inconsistent
notation. In particular, any time "<span
class="math inline"><em>a</em><sub>1</sub></span>" or "<span
class="math inline"><em>a</em><sub>2</sub></span>" was mentioned, I
really meant to write <span
class="math inline"><em>c</em><sub>1</sub></span> and <span
class="math inline"><em>c</em><sub>2</sub></span>.</li>
<li><strong>Concluding Remarks</strong>: No group of order <span
class="math inline">56</span> is <em>simple</em>. Previously the text
said "finite" instead, which is clearly not true...</li>
</ul>
<h3 id="nov-25-2024">Nov 25, 2024</h3>
<ul>
<li><strong>Products/Coproducts</strong>: All mentions of a function
<span class="math inline"><em>f</em></span> were supposed to be <span
class="math inline"><em>ϕ</em></span>.</li>
</ul>
<h3 id="oct-31-2024">Oct 31, 2024</h3>
<ul>
<li><strong>Exercise 2.11.</strong> Significant typo; meant to write
<span
class="math inline"><em>g</em><sub>1</sub><sup>(</sup> − 1)<em>g</em><sub>2</sub><em>i</em><em>n</em><em>H</em></span>
rather than <span
class="math inline"><em>g</em><sub>1</sub><em>g</em><sub>2</sub><sup>(</sup> − 1)<em>i</em><em>n</em><em>H</em></span>.</li>
<li><strong>Exercise 2.29.</strong> Significant typo; meant to write
<span class="math inline"><em>N</em> ∩ <em>H</em> ⊲ <em>H</em></span>
rather than <span
class="math inline"><em>N</em> ∩ <em>H</em> ⊲ <em>G</em></span>.</li>
<li><strong>Proof of Theorem 2.31 (Second Isomorphism).</strong> Minor
typo; meant to write <span
class="math inline"><em>N</em> ∩ <em>H</em></span> instead of <span
class="math inline"><em>n</em> ∩ <em>H</em></span>.</li>
</ul>
<section id="footnotes" class="footnotes footnotes-end-of-document"
role="doc-endnotes">
<hr />
<ol>
<li id="fn1"><p>To be clear, the date listed is the last version to
contain the error.<a href="#fnref1" class="footnote-back"
role="doc-backlink">↩︎</a></p></li>
</ol>
</section>]]></description>
	<pubDate>31 Oct 2024</pubDate>
</item>
<item>
	<title>Advanced mapm Tips</title>
	<link>https://dennisc.net/writing/tech/mapm.md</link>
	<description><![CDATA[<p>This guide assumes you have a basic
understanding of how mapm works. If you do not, read the documentation
at <a href="https://mapm.mathadvance.org/">mapm.mathadvance.org</a>.<a
href="#fn1" class="footnote-ref" id="fnref1"
role="doc-noteref"><sup>1</sup></a> Basic fluency with the command line
is expected, and for Windows users, an understanding of the Unix
commands <em>and</em> the ability to translate them to whatever shell
you are using.<a href="#fn2" class="footnote-ref" id="fnref2"
role="doc-noteref"><sup>2</sup></a></p>
<h2 id="collaboration">Collaboration</h2>
<p>mapm is meant to be used with other people, but it is not opinionated
on how you do this. There are two main ways: Dropbox<a href="#fn3"
class="footnote-ref" id="fnref3" role="doc-noteref"><sup>3</sup></a> and
Git. I would recommend the former.</p>
<p>The problem directory for a profile <code>foo</code> is
<code>~/.config/mapm/problems/foo</code>. So you can symlink whatever
directory contains your problems to the aforementioned path. For
example, Math Advance uses <code>~/Dropbox/MAC/problems</code> as our
problems directory, so we would run</p>
<div class="sourceCode" id="cb1"><pre
class="sourceCode bash"><code class="sourceCode bash"><span id="cb1-1"><a href="#cb1-1" aria-hidden="true" tabindex="-1"></a><span class="fu">ln</span> <span class="at">-s</span> ~/Dropbox/MAC/problems ~/.config/mapm/problems/mathadvance</span></code></pre></div>
<p>as our profile is called <code>mathadvance</code>.</p>
<p>You can do something similar with Git; just don't forget to push and
pull when appropriate.</p>
<h2 id="multiple-contest-files-for-the-same-contest">Multiple contest
files for the same contest</h2>
<p>mapm was designed for Math Advance contests, first and foremost ---
this means it works best with MAT as well as "smaller" contests like the
AMCs and AIME. Something expansive like HMMT would not fit well in a
single contest file. Fortunately, there is a sane way to compile
contests in mapm.</p>
<p>Let's use HMMT as an example. The Combinatorics and Geometry rounds
have nothing to do with each other --- how hard problem X is on combo
has no effect on how hard problem Y is on geo. Therefore, the two rounds
can be considered independent, and thus should have separate contest
files. It may also be worth noting that they do not need a separate
template file; a <code>subject</code> template variable would
suffice.</p>
<p>Here is a heuristic for this independence: do these rounds exist in
separate PDFs? For ARML and MAT, where the subject and difficulty
distribution of rounds should be taken as a composite, the entire
individual test is in one PDF. Thus they should have one contest
file.</p>
<h2 id="no-solutions">No solutions</h2>
<p>Sometimes you might be lazy and not want to put solutions in a
problem. If you're using a release of <code>mapm-cli</code> before
v2.1.0, you can pass <code>solutions: []</code> into your problem file.
If you're using a release after v2.1.0, the field is optional and the
library will interpret no <code>solutions</code> field as an empty
array.</p>
<h2 id="cli-tricks">cli tricks</h2>
<h3 id="change-default-editor">Change default editor</h3>
<p>When running <code>mapm edit</code>, the <code>EDITOR</code>
environment variable is used. It is strongly recommended that you set it
to a terminal editor, like nano or vim, so as to minimize context
switching.</p>
<h3 id="list-problem-names">List problem names</h3>
<p>There is no built-in feature to list problems in the command line
interface, but <code>mapm find show</code> should suffice; it finds
every problem, and shows no tags. You may also pass filters into
<code>find</code> for a filtered list.</p>
<section id="footnotes" class="footnotes footnotes-end-of-document"
role="doc-endnotes">
<hr />
<ol>
<li id="fn1"><p>If you don't know what mapm is at all, it is a LaTeX
contest compiler that allows you to create templates and compile contest
drafts based on problem names, instead of manually changing LaTeX (in
potentially many places).<a href="#fnref1" class="footnote-back"
role="doc-backlink">↩︎</a></p></li>
<li id="fn2"><p>It is strongly recommended you use Powershell and not
cmd.<a href="#fnref2" class="footnote-back"
role="doc-backlink">↩︎</a></p></li>
<li id="fn3"><p>"Dropbox" is just a catch-all for any cloud sync
service.<a href="#fnref3" class="footnote-back"
role="doc-backlink">↩︎</a></p></li>
</ol>
</section>]]></description>
	<pubDate>13 Jan 2022</pubDate>
</item>
<item>
	<title>Two Points of Pedantry</title>
	<link>https://dennisc.net/writing/blog/pedantry.md</link>
	<description><![CDATA[<h2 id="linear-maps-vs.-matrices">Linear Maps vs.
Matrices</h2>
<p>You probably learned that matrices were arrays of numbers in high
school pre-calculus. Arrays that you can add and do this magical
"multiplication". And then later down the road, you learn that matrices
are actually <em>linear maps</em>.</p>
<p>That, too, is a lie. A white lie, given that matrices and linear maps
are deeply related. (In fact, there is an isomorphism between matrices
and linear maps.) But they are not <em>quite the same</em>.</p>
<p>Let me use "change in basis" as an example. You have this "array of
numbers" <span class="math inline"><em>T</em></span>, and you can
"magically" "transform" it into something "similar" called <span
class="math inline"><em>P</em><sup>−1</sup><em>T</em><em>P</em></span>
by "changing the basis". Note all the air quotations; you're not
<em>exactly</em> changing the basis. You're just doing something
analogous.</p>
<p>When you're considering a linear map <span
class="math inline"><em>T</em>: <em>V</em> → <em>V</em></span>, you
<em>analyze</em> what happens to basis vectors for different choices of
bases. So in a "change in basis" you don't actually change the linear
map <span class="math inline"><em>T</em></span> whatsoever. You are just
considering the behavior of a different set of vectors.</p>
<p>Meanwhile, when you have a similar matrix <span
class="math inline"><em>P</em><sup>−1</sup><em>T</em><em>P</em></span>,
it is actually different. Yes, it's different the same way <span
class="math inline">$\frac{4}{6}$</span> is different from <span
class="math inline">$\frac{2}{3}$</span>, but it is different. These are
different representations; the array of numbers is literally not the
same. Sure, these similar matrices belong in the same equivalence class
(where two matrices are equivalent if they are similar), but two similar
matrices are not actually identical. A "change of basis", from the
perspective of a matrix, is <em>actually</em> a change.</p>
<p>These distinctions are subtle. Obviously there is still a very close
connection between matrices and linear maps. But --- especially as you
go further --- the distinctions between a matrix and a linear map can be
important. Rather than blindly knowing how to do matrix calculations or
turning a blind eye to concepts that more naturally originate from
matrices (yet still have solid grounding in the theoretical, "only
consider linear transformations" side of things), it is most fruitful to
understand how both perspectives work in tandem.</p>
<p>...but that won't change the fact that, the first time you learn
linear algebra, you should try to avoid matrices as much as possible.
Learning the matrix perspective after you learn the theory perspective
is not so hard. The other way around is much worse.</p>
<h2 id="polynomials-vs.-polynomial-functions">Polynomials vs. Polynomial
Functions</h2>
<p><a
href="https://math.stackexchange.com/questions/815440/polynomials-vs-polynomial-functions">For
more details see StackExchange.</a></p>
<p>You are likely familiar with these things that look like <span
class="math inline"><em>a</em><sub>0</sub> + ⋯ + <em>a</em><sub><em>n</em></sub><em>x</em><sup><em>n</em></sup></span>,
where each of the <span
class="math inline"><em>a</em><sub><em>i</em></sub></span> are an
element of some field <span class="math inline"><em>F</em></span>. But
what is <span class="math inline"><em>x</em></span>? It turns out <span
class="math inline"><em>x</em></span> is just some meaningless
symbol.</p>
<p>Then you have these things called polynomial functions that look like
<span
class="math inline"><em>f</em>(<em>x</em>) = <em>a</em><sub>0</sub> + ⋯ + <em>a</em><sub><em>n</em></sub><em>x</em><sup><em>n</em></sup></span>.
And initially you might think, "Okay, this is just a distinction without
a difference; surely a polynomial like <span
class="math inline"><em>x</em><sup>2</sup></span> corresponds to the
polynomial function <span
class="math inline"><em>f</em>(<em>x</em>) = <em>x</em><sup>2</sup></span>."
And yes, this intuition usually holds; in any infinite field, there is a
bijection between polynomials and polynomial functions. But this is not
the case in a finite field. Consider the polynomials <span
class="math inline">0</span> and <span
class="math inline"><em>x</em><sup>2</sup> + <em>x</em></span> in <span
class="math inline">𝔽<sub>2</sub></span>. Clearly these are different
polynomials, yet the polynomial functions <span
class="math inline"><em>f</em>(<em>x</em>) = 0</span> and <span
class="math inline"><em>f</em>(<em>x</em>) = <em>x</em><sup>2</sup> + <em>x</em></span>
are identical; they exhibit identical behavior.<a href="#fn1"
class="footnote-ref" id="fnref1" role="doc-noteref"><sup>1</sup></a></p>
<p>So our notions of equality among polynomials and polynomial functions
are not always identical. (Although if you see the StackExchange link
above, modifications can be made so that the two notions do once again
coincide.)</p>
<section id="footnotes" class="footnotes footnotes-end-of-document"
role="doc-endnotes">
<hr />
<ol>
<li id="fn1"><p>This is because <span
class="math inline"><em>x</em>(<em>x</em> + 1)</span> is always
divisible by 2.<a href="#fnref1" class="footnote-back"
role="doc-backlink">↩︎</a></p></li>
</ol>
</section>]]></description>
	<pubDate>11 Nov 2023</pubDate>
</item>
<item>
	<title>Algebraic Data Types</title>
	<link>https://dennisc.net/writing/tech/algebraic.md</link>
	<description><![CDATA[<p>Today, I'm not going to talk about unions or
Cartesian products or even set theory. Instead, I want to explain
intuitively what algebraic data types are, and relatedly, why you should
consider AND as multiplication (<code>*</code>) and consider OR as
addition (<code>+</code>).</p>
<p>Prerequisites: have some knowledge of at least one programming
language. Not mandatory but helpful, know what a struct is. Also know
that <code>&amp;&amp;</code> and <code>||</code> are used for the AND
and OR operators.</p>
<h2 id="data-types">Data Types</h2>
<p>Each data type in a struct is logically joined together by the AND
operator. For instance, let us say we have items in a store represented
by the <code>Item</code> type. Each item has a name and a price. If you
have a struct (code not written in any specific language)</p>
<pre><code>struct Item {
    int price;
    string name;
}</code></pre>
<p>then every <code>Item</code> must have a <code>price</code> AND
<code>name</code>. Whereas if you're trying to identify an item in a
store, you can either use the name or the barcode:</p>
<pre><code>union Identifier {
    int code;
    string name;
}</code></pre>
<p>Unlike a struct like <code>Item</code>, with <em>both</em> a price
and name, a union like Identifier must contain only one of an
<code>int code</code> OR a <code>string name</code>.</p>
<p>So we've established that there are two data types: an AND data type
and an OR data type. In functional programming, the AND data type is
called a "product type" and the OR data type is called a "sum type".
Why?</p>
<p>To rigorously and mathematically define our product and sum types,
where each variable of a type could have infinite possibilities, we'd
need to turn to set theory. Since we're trying not to do that, we'll
instead build intuition by only considering the case where each variable
has finite possibilities.</p>
<p>As an example, take our <code>Item</code> struct. Say that each item
in the store is sold for one of 10 possible prices and takes one of 10
possible names. Then we have <span
class="math inline">10 × 10 = 100</span> possible Items with distinct
data. This is why the AND data type is the product type.</p>
<p>For the OR data type, take our <code>Identifier</code> union. Say
that each item in the store has one of 10 possible barcodes and takes
one of 10 possible names. Then, in the case we describe an item by its
barcode we have <span class="math inline">10</span> possibilities, and
in the case we describe an item by its name we have <span
class="math inline">10</span> more possibilities, giving us a total of
<span class="math inline">10 + 10 = 20</span>. This is why the OR data
type is the sum type.</p>
<h3 id="aside-why-are-unions-called-unions">Aside: why are unions called
unions?</h3>
<p>I promised that I wouldn't talk about set theory, and I lied. (If you
don't understand set theory feel free to skip this part!)</p>
<p>In set theory, if we have a set <span
class="math inline"><em>A</em></span> of prices and a set <span
class="math inline"><em>B</em></span> of names, then the set of items
described by a price and a name would be the Cartesian product <span
class="math inline"><em>C</em> = <em>A</em> × <em>B</em></span>.
Basically, each element of <span class="math inline"><em>C</em></span>
would be an ordered pair of a price and a name.</p>
<p>Now, if we want a set <span class="math inline"><em>C</em></span> of
all the elements that are either in set <span
class="math inline"><em>A</em></span> or set <span
class="math inline"><em>B</em></span>... well, that would be a union. If
<span class="math inline"><em>A</em></span> is the set of barcodes and
<span class="math inline"><em>B</em></span> is the set of names, then
<span class="math inline"><em>C</em> = <em>A</em> ∪ <em>B</em></span> is
the set of possible identifiers for an item.</p>
<h3 id="aside-2-unions-are-actually-called-tagged-unions">Aside 2:
Unions are actually called tagged unions</h3>
<p>Actually, in some lower level languages like C and C++ (and for some
reason, in some higher level languages like Java too), there is no
native support for checking that exactly one field of a union is filled
out. Possibly multiple fields could have been assigned values, and
there's no way to check, especially since when initializing the union,
all fields could be null. In this case, the programmer must indicate
somehow which data type the union actually is. This is done through a
tag, and this is why sum types are strictly called "tagged unions".</p>
<p>Using our <code>Identifier</code> example, to actually create a
tagged union, we'd need to write a struct like this:</p>
<div class="sourceCode" id="cb3"><pre class="sourceCode c"><code class="sourceCode c"><span id="cb3-1"><a href="#cb3-1" aria-hidden="true" tabindex="-1"></a><span class="kw">enum</span> Tag <span class="op">{</span></span>
<span id="cb3-2"><a href="#cb3-2" aria-hidden="true" tabindex="-1"></a>    CODE<span class="op">,</span> NAME</span>
<span id="cb3-3"><a href="#cb3-3" aria-hidden="true" tabindex="-1"></a><span class="op">};</span></span>
<span id="cb3-4"><a href="#cb3-4" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb3-5"><a href="#cb3-5" aria-hidden="true" tabindex="-1"></a><span class="kw">union</span> Identifier <span class="op">{</span></span>
<span id="cb3-6"><a href="#cb3-6" aria-hidden="true" tabindex="-1"></a>    <span class="dt">int</span> code<span class="op">;</span></span>
<span id="cb3-7"><a href="#cb3-7" aria-hidden="true" tabindex="-1"></a>    string name<span class="op">;</span></span>
<span id="cb3-8"><a href="#cb3-8" aria-hidden="true" tabindex="-1"></a><span class="op">};</span></span>
<span id="cb3-9"><a href="#cb3-9" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb3-10"><a href="#cb3-10" aria-hidden="true" tabindex="-1"></a><span class="kw">struct</span> TaggedIdentifier <span class="op">{</span></span>
<span id="cb3-11"><a href="#cb3-11" aria-hidden="true" tabindex="-1"></a>    <span class="kw">enum</span> Tag tag<span class="op">;</span></span>
<span id="cb3-12"><a href="#cb3-12" aria-hidden="true" tabindex="-1"></a>    <span class="kw">union</span> Identifier identifier<span class="op">;</span>  </span>
<span id="cb3-13"><a href="#cb3-13" aria-hidden="true" tabindex="-1"></a><span class="op">};</span></span></code></pre></div>
<p>(This code is written in C. An <code>enum</code> in C is a datatype
that must take the value of one of several constants. These tags are
said constants in the case of a tagged union.)</p>
<h2 id="booleans">Booleans</h2>
<p>Consider the boolean function <code>x &amp;&amp; y</code>. For
<code>x &amp;&amp; y</code> to be true, we need both <code>x</code> and
<code>y</code> to be true. Similarly, if we want
<code>x &amp;&amp; y &amp;&amp; z</code> to be true, then we need
<code>x</code>, <code>y</code>, and <code>z</code> to all be true.</p>
<p>This motivates the following observation: if we do the hack where we
assign true as <code>1</code> and false as <code>0</code>, then
<code>x &amp;&amp; y = x * y</code>, and
<code>x &amp;&amp; y &amp;&amp; z = x * y * z</code>, etc. So the AND
operator is very clearly equivalent to multiplication.</p>
<p>The OR operator is not as direct an analogue to addition in this case
(the better analogue is exclusive or, aka XOR). In this case,
<code>x || y = x + y &gt; 0</code>.</p>]]></description>
	<pubDate>3 Jun 2023</pubDate>
</item>
<item>
	<title>Asymptote is the best Asymptote compiler</title>
	<link>https://dennisc.net/writing/tech/asy.md</link>
	<description><![CDATA[<p>People joke that they like to use AoPS TeXeR in
order to compile their Asymptote diagrams, but enough people seriously
believe it's a good idea that I felt I needed to write this post.</p>
<p>Asymptote is a language totally separate from TeX. You should treat
it as a stroke of fate that it <em>happens</em> to support some aspects
of TeX like denoting labels in math mode. Asymptote is a standalone
language and it can compile without the help of a LaTeX document or
compiler, thank you very much.</p>
<p>Typically I see people who use Overleaf leveraging TeXeR, because
Overleaf is buggy and can't compile Asymptote properly. If/when they
move to a local editor, bad habits carry over for Asymptote, because
Overleaf has obscured stuff so much that no one even knows how Asymptote
works.</p>
<p>Here is a brief summary of how the LaTeX asymptote package,
<strong>which should not be confused for Asymptote the language
itself</strong>, works:</p>
<ul>
<li>When you run <code>pdflatex</code> on your <code>.tex</code> file,
the asymptote package extracts the code inside every <code>asy</code>
environment and outputs it to a set of <code>.asy</code> files.</li>
<li>You run asymptote (and this time, it is asymptote proper) on each
<code>.asy</code> file.</li>
<li>When you run <code>pdflatex</code> again, the asymptote package
detects the <code>.pdf</code> files that you got by running
<code>asy</code> on the <code>.asy</code> files, and inserts them into
the proper location in the PDF.</li>
</ul>
<p>Actually, this is one of the reasons you need latexmk: to automate
this asymptote process whenever necessary. This is because --- and I
cannot stress this enough --- <strong>Asymptote is not TeX</strong>.
LaTeX cannot build Asymptote for you because LaTeX doesn't implement the
compiler, Asymptote does. This is in contrast to TikZ, which does not
need a whole separate build process because TikZ <em>is</em> part of
TeX.</p>
<p>This means that there is a separate compiler for Asymptote. And it is
<em>fast</em>. If you want to test whether an asymptote diagram compiles
correctly, and if so what it looks like, here is what you do:</p>
<ul>
<li>Copy the asymptote code.</li>
<li>Open up a terminal.</li>
<li><code>vim test.asy</code></li>
<li>Paste the asymptote code inside <code>test.asy</code>.</li>
<li><code>:wq</code></li>
<li><code>asy test.asy</code></li>
<li><code>zathura test.eps&amp;</code></li>
</ul>
<p>Bonus points if you make an asymptote-specific keybinding for the
compile+preview process.<a href="#fn1" class="footnote-ref" id="fnref1"
role="doc-noteref"><sup>1</sup></a></p>
<p>If you use Vim you have no excuse for using TeXeR. Doubly so if you
are also using a tiling window manager. Why take the time to open a
browser, wait for TeXeR to load, manually add the BBCode nonsense that
AoPS expects from you, and have TeXeR fail on you for no good reason
with about a 20% chance?</p>
<p>So what are the reasons you would use TeXeR? There are two I can
think of.</p>
<ul>
<li>You can't run LaTeX on your machine for some reason. Perhaps your
only computer (maybe it's a phone) is super weak, and you need to
leverage the browser to perform expensive calculations. Or perhaps
you're stuck at the public library and forgot to bring your laptop.</li>
<li>You don't know how to use your own computer.</li>
</ul>
<section id="footnotes" class="footnotes footnotes-end-of-document"
role="doc-endnotes">
<hr />
<ol>
<li id="fn1"><p>Someone smarter than me could probably make it possible
to extract the code <em>inside</em> an asymptote environment, pipe it to
some temporary file, compile that temporary file, and preview the
result.<a href="#fnref1" class="footnote-back"
role="doc-backlink">↩︎</a></p></li>
</ol>
</section>]]></description>
	<pubDate>27 Mar 2022</pubDate>
</item>
<item>
	<title>Getting a new SSD and switching to Alpine</title>
	<link>https://dennisc.net/writing/tech/ssd-alpine.md</link>
	<description><![CDATA[<p>After working faithfully for 6 years, my Lenovo
IdeaPad 710S laptop's SSD finally gave out: after using it for 30
minutes to an hour, I'd encounter i/o errors and the laptop would stop
working pretty much entirely.</p>
<p>So, instead of throwing out the entire laptop, the rest of which
worked fine, I did the sensible thing and just replaced the SSD. We were
(as of the time of writing, "are") leaving for Chicago and so I wanted
my SSD soon. Thus we went to Best Buy, even though I could've gotten a
fully functional SSD for around $20 less if I bought it online. Since I
was using a 256GB NVMe SSD, I figured I might as well get another NVMe
SSD. The cheapest option was a 512GB SSD, so I ended up getting
that.</p>
<p>Replacing the SSD was pretty straightforward: unscrew the cover,
unscrew the SSD, replace the SSD, and put all the screws back in
place.</p>
<p>If I wanted to, I could've cloned the old SSD onto the new one.
However, I decided against it for several reasons:</p>
<ul>
<li>The old SSD is failing, so I had no idea how or even if the cloning
would succeed.</li>
<li>I'd have to put both SSDs inside the same machine (my desktop), and
I didn't want to go to the trouble of disassembling that too.</li>
<li>My old Bedrock system was pretty complicated, and I didn't feel like
I gained anything from this extra complexity.</li>
<li>All my important files are in Git repositories somewhere off my
laptop.</li>
</ul>
<p>So I decided to install Alpine Linux on my new SSD. In terms of how
easy to setup Alpine is, it's a mixed bag in a couple of interesting
ways. It's by no means "beginner-friendly", but for an experienced user
the setup is so much easier than Arch Linux.</p>
<ul>
<li>Installation is straightforward: you just run
<code>setup-alpine</code>. A little bit of Googling might be involved if
you don't know what some of the options mean.</li>
<li>Actually getting a graphical desktop environment and setting up
networking is a bit hard, especially if your only experience is
systemd/your distro took care of it for you before. I didn't try
installing X11, but it seems fairly involved to get i3 working; getting
Sway and Wayland to work, however, was much easier.</li>
</ul>
<p>I like Alpine's apk a lot more than pacman. pacman has arcane letters
where apk's operations are very simple to understand. I also like that
apk also doesn't ask you to confirm where every other package manager
does. I believe apk is also a bit faster, but in terms of how fast
package managers are, apk and pacman are approximately as fast with
everything else being a lot worse.</p>
<p>Alpine also takes a lot of cues from the BSDs. They use doas instead
of sudo, and OpenRC instead of systemd. I like doas, and don't really
care about OpenRC vs. systemd.</p>
<p>I've had pleasant experiences with Alpine, sans OpenSSL not working
(I've replaced it with rustls in my projects). Someday I might migrate
the Math Advance server to Alpine, in which case my dev and server
environments will be identical.<a href="#fn1" class="footnote-ref"
id="fnref1" role="doc-noteref"><sup>1</sup></a></p>
<section id="footnotes" class="footnotes footnotes-end-of-document"
role="doc-endnotes">
<hr />
<ol>
<li id="fn1"><p>I've also been thinking about moving my server to
FreeBSD, but the advantage of migrating to Alpine is that I can just
export Mailcow from Ubuntu to Alpine. As far as I know, it's not
possible to run Mailcow on FreeBSD.<a href="#fnref1"
class="footnote-back" role="doc-backlink">↩︎</a></p></li>
</ol>
</section>]]></description>
	<pubDate>5 Jun 2022</pubDate>
</item>
<item>
	<title>Check that your programs work in musl libc</title>
	<link>https://dennisc.net/writing/tech/musl-libc.md</link>
	<description><![CDATA[<p>Most programs are compiled with GNU's
implementation of libc. This is not surprising, given that pretty much
every Linux distribution uses glibc. In fact, the only ones I knew of
that didn't were Alpine and Gentoo (which you can use glibc for anyway),
and the only other one I should've known about was Void. (For
completeness, here's a <a
href="https://wiki.musl-libc.org/projects-using-musl.html">list of musl
libc distributions</a>.)</p>
<p>So it's no surprise that a lot of programs break on musl libc. <a
href="https://github.com/lcn2/calc">calc</a>, for instance, does not
work on musl libc. (A good alternative is libqalculate, for everyone
else on musl libc.) Even my programs had issues; <a
href="https://gitlab.com/chennisden/dotfiles/bootstrap">bootstrap</a>
for my dotfiles and the MAT website<a href="#fn1" class="footnote-ref"
id="fnref1" role="doc-noteref"><sup>1</sup></a> used OpenSSL, which does
not work well on Rust + Alpine. Thus I switched to rustls, which is
better than OpenSSL anyways and works on all the hardware I need it
to.</p>
<p>There are plenty of merits to using musl libc which you can easily
find online. The wisdom of using musl libc on a desktop environment may
be debatable, since some software (mostly propreitary software that's
been built against glibc, like Dropbox or Steam) won't run. This means
you'll have to get glibc, one way or another. Thus Alpine, through no
fault of its own, may not be suitable for casual desktop use if, for
instance, your goal is to play games with minimal hassle: Ubuntu is a
better choice for that.</p>
<p>In any case, if your programs do not support musl libc, it should not
be a decision made out of ignorance. It's usually less of a big deal if
you don't write a lot of C, but a lot of things in other languages can
refuse to work for subtle reasons involving glibc/musl. And if you're,
say, running Rust servers on Alpine, it's also important to understand
that the reason your program is segfaulting is because Rust + OpenSSL
does not work well on musl. If you want your programs to be reusable,
part of that is making it portable, and if you want them to be portable,
don't have them rely on glibc extensions.</p>
<h2 id="sidenote">Sidenote</h2>
<p>This post was almost called "Stop relying on glibc", but besides musl
I know of no other libc's that are part of a major libre operating
system.<a href="#fn2" class="footnote-ref" id="fnref2"
role="doc-noteref"><sup>2</sup></a> There are things that work in glibc
and musl but not, say, dlls, but I could frankly care less about
them.</p>
<section id="footnotes" class="footnotes footnotes-end-of-document"
role="doc-endnotes">
<hr />
<ol>
<li id="fn1"><p>Source will be released for MAT website when the rewrite
is done.<a href="#fnref1" class="footnote-back"
role="doc-backlink">↩︎</a></p></li>
<li id="fn2"><p>Note from the future: Embarrassingly enough I forgot
about the BSDs and their own libc's. (Yes, I consider the BSDs to be
major.)<a href="#fnref2" class="footnote-back"
role="doc-backlink">↩︎</a></p></li>
</ol>
</section>]]></description>
	<pubDate>7 Jun 2022</pubDate>
</item>
<item>
	<title>Discord on Alpine Linux</title>
	<link>https://dennisc.net/writing/tech/discord-on-alpine.md</link>
	<description><![CDATA[<p>So I finally got Discord (and the official
client, not 6cord or gtkcord) to work on Alpine Linux! Should work on
any musl libc distribution, but I haven't tested for any besides
Alpine.</p>
<p>For those of you who don't have experience with musl libc
distributions or proprietary software, this is a big deal because
<strong>most proprietary software is compiled with GNU libc</strong>
(glibc for short). To vastly oversimplify, these programs will be
expecting functionality provided by glibc and glibc only.</p>
<p>I don't love the official Discord client. It takes up way too much
space and I like working in the terminal regardless (which is why I'm
often on 6cord). But each of these unofficial clients have their own
problems. 6cord takes a while to switch between channels and the voice
chat doesn't work.<a href="#fn1" class="footnote-ref" id="fnref1"
role="doc-noteref"><sup>1</sup></a> gtkcord4 is doing some weird stuff
with keyrings (i.e. not remembering my login) and despite many attempts,
it refuses to respect my theming preferences (maybe this is just a GTK
problem). It's technically against TOS too (not like I really care
though). Still, I'm looking for any excuse to ditch Discord, or at least
its official client. Hopefully one day this will happen.</p>
<p>Anyway, here's how I did it:</p>
<ul>
<li>install gcompat and patchelf through
<code>doas apk add gcompat patchelf</code></li>
<li><a
href="https://discord.com/api/download?platform=linux&amp;format=tar.gz">install
Discord as a tarball</a> through
<code>wget -O discord.tar.gz https://discord.com/api/download?platform=linux&amp;format=tar.gz</code>
(or click on the link)</li>
<li><code>cd</code> to whatever directory contains
<code>discord-0.0.x.tar.gz</code> (<code>x</code> is the version
number). This file will be called <code>discord.tar.gz</code> if you
fetched it using <code>wget</code>, in which case replace
<code>discord-0.0.x.tar.gz</code> with <code>discord.tar.gz</code>.</li>
<li><code>tar -xvzf discord-0.0.x.tar.gz</code></li>
<li><code>cd Discord/</code></li>
<li><code>patchelf --set-interpreter /lib/ld-musl-x86_64.so.1 Discord</code></li>
<li><code>patchelf --add-needed libgcompat.so.0 Discord</code></li>
</ul>
<p>You may need to run <code>ldconfig</code> and/or reboot for this to
work.</p>
<p>To run Discord, do <code>./Discord --no-sandbox</code>. I'm not sure
if the <code>--no-sandbox</code> flag is necessary on Xorg-based
systems, but it probably is required on Wayland (definitely is for
Sway). Blame Discord for shipping an out-of-date version of Electron
/shrug</p>
<section id="footnotes" class="footnotes footnotes-end-of-document"
role="doc-endnotes">
<hr />
<ol>
<li id="fn1"><p>Chances are that it's just a me problem and I haven't
configured voice properly. But still, it doesn't just "work by default"
(not that the official client does either).<a href="#fnref1"
class="footnote-back" role="doc-backlink">↩︎</a></p></li>
</ol>
</section>]]></description>
	<pubDate>3 Nov 2022</pubDate>
</item>
<item>
	<title>Using sshuttle to bypass school wifi</title>
	<link>https://dennisc.net/writing/tech/sshuttle.md</link>
	<description><![CDATA[<p>So! School is in session again which sucks, and
what really sucks is the school wifi which blocks half the internet.
Fortunately, if you're on a Mac, Linux, or BSD machine, it's pretty easy
to bypass this.</p>
<p>I use a tool called <a
href="https://github.com/sshuttle/sshuttle">sshuttle</a> to tunnel all
my traffic through a server which I have SSH access to. (Installation
for sshuttle is straightforward and can be found on the project's
README.) This set of conditions is not very common since "people who
need to bypass school wifi and have SSH access to a server" basically
just describes high school sysadmins.</p>
<p>But if this describes you, here's what you do:</p>
<div class="sourceCode" id="cb1"><pre
class="sourceCode bash"><code class="sourceCode bash"><span id="cb1-1"><a href="#cb1-1" aria-hidden="true" tabindex="-1"></a><span class="ex">sshuttle</span> <span class="at">-vvvv</span> <span class="at">-r</span> user@0.0.0.0 0/0</span></code></pre></div>
<p>where you substitute <code>user@0.0.0.0</code> with your server and
the user you want to SSH into (the user doesn't actually
matter).</p>]]></description>
	<pubDate>17 Aug 2022</pubDate>
</item>
<item>
	<title>The problem with MAT</title>
	<link>https://dennisc.net/writing/blog/mat-tb.md</link>
	<description><![CDATA[<p>The 2023 Summer MAT happened last week. Our
contestant count, as does the count for every other contest (including
the AMCs) is dropping, though it was still decently high. That is mildly
worrying, but it is not the problem we discuss today.</p>
<h2 id="background">Background</h2>
<p>The MAT's tiebreaker format is as following: there is one tiebreaker
set, and ties are broken first on points then on time. Another way to
think about each tiebreaker problem is worth <span
class="math inline">$\frac{1}{3}$</span> of a point.</p>
<p>To understand the problems with tiebreaker formats, I have to first
present the <em>Fundamental Theorem of Tiebreakers</em>:</p>
<blockquote>
<p>If two people have identical performances, then there is no way to
rank them differently.</p>
</blockquote>
<p>It is not necessarily true that it is always possible for two people
to have identical performances; it depends how you measure it. For an in
person contest, you might use "submission order" as a tiebreaking
method. (Indeed, we use "time" as a proxy for this.) However, for our
purposes,</p>
<blockquote>
<p>It is always possible for two people to have an identical
performance.</p>
</blockquote>
<p>In fact, for MAT it is quite feasible. For two people to score the
same on the main sets and the tiebreakers, and for them both to forget
to submit until they've used all 30 minutes, is not impossible. Though
we avoided it the last two years, this year the jig is up: we had two
ties (3rd and 7th).</p>
<h2 id="submit-earlier-stupid">"Submit earlier, stupid"</h2>
<p>This was our initial reaction. If only someone decided "hey I'm not
going to get the problem in the last 10 seconds, let's submit at 29:50".
But unfortunately that is not how real life works; people are not always
optimal strategists. Even more so in a contest like MAT.</p>
<p>The MAT was designed not to require much strategy. That is why we
have split the contest into several sets. You do not need to wonder,
"hey should I check questions 1-5 or take a stab at question 9 which I
left for later or reach for questions 11-15"? All you can do is solve
what is in front of you.</p>
<p>Contests like HMMT Guts require a lot of strategy, and that can be
fun. But focusing on solving problems is much better when it comes to
developing logical skills in the long run, and personally I think it is
more enjoyable. We're not the only ones who think this way: top
contestants have directly contacted us to express the same
sentiment.</p>
<p>So tiebreakers requiring a strategic decision (time or problems?) is
already a jarring break from our philosophy. Realize it or not, but the
first three sets lower peoples' guard. It gets them thinking, "thank god
for a contest I can just relax in". Which is a great mentality to have,
but the downside is it increases the risk of ties after tiebreakers.</p>
<p>However, I think a reminder on the contest page during the tiebreaker
set ("Remember that ties are broken on time if scores are identical.")
might help with that, since people have told me they forgot tiebreakers
was even time based.</p>
<h2 id="estimathon">Estimathon</h2>
<p>When originally designing the MAT, I considered using an estimathon
(or even just one estimation question) as a tiebreaking method. In
theory, if you make the upper bound for the answer around <span
class="math inline">10<sup>5</sup></span> ("how many primes are less
than 10000?"), then it will be very unlikely people guess the same
thing. Add multiple such problems and add contrived formulas for the
estimation score and bam. No more ties.</p>
<p>There's a couple of problems with that. One: the more complicated
your scoring formula, the more complicated the optimal strategy. Which
means that contestants will either have to perform suboptimally, or
shift their focus away from solving problems. Two: people gravitate
towards certain numbers. Whether they are seen as funny, or look nice
(multiples of 5, multiples of large powers of 10, etc). So someone is
more likely to guess 2500 than 2583. Although with multiple problems,
the second point is more moot.</p>
<p>Furthermore, estimation problems tend to have less clean solutions,
if any at all. The skills we are trying to reinforce do not include
"throw out wild guesses at random questions and guess less badly than
everyone else". It would be such a stark departure from our contest
format too, and it would drastically reduce the problem quality (even if
it is quarantined in tiebreakers). An estimathon would be jarring and
feel out of place. So we bite the bullet and accept that our tiebreaker
format might lead to ties.</p>
<h2 id="breaking-less-ties">Breaking less ties</h2>
<p>I floated an idea around recently, though it is one we are unlikely
to adopt: who cares about ties? After biting the bullet once, it seems
much more acceptable to think that way now. Instead of making a
compromise on our philosophy with the tiebreaks format --- ties being
broken by time --- why not just ignore time?</p>
<p>Because it could lead to massive ties, too large to be acceptable.
Last year (not this year), we had a four-way tie for 1st if one only
considers main set scores and tiebreaker score (i.e. if one ignores
time). And looking back, it was a disaster narowly averted. If people
decided to submit a couple minutes later, we may have had ties with a
tiebreak time of 30:00.</p>
<p>But think of it another way: four people all score 8 points on the
main sets and ace the tiebreakers. The only difference is, their
submission times are 25, 26, 27, and 28 minutes. Are their performances
really qualitatively different? No. We only acknowledge this difference
because they all came in with the shared expectation, "time matters".
Yet that mostly awards strategic skills, not mathematical ones --- and
strategic skills based on extrospection, rather than introspection. The
role of a math contest is to develop <em>problem-solving
introspection</em>. So a contest format with an optimal strategy based
on "what would other people likely do here", even if very tangentially,
is not desirable.</p>
<p>Yet it too is a bullet we must bite for prize reasons. Many of our
prizes are discrete items that cannot just be "split" between massive
ties. And on some level, it is good to have a winner --- the adrenaline
of winning a math contest is part of the fun. So we will likely continue
using time as a tiebreaker method. It is imperfect. Indeed, it is the
worst tiebreaker method, besides all the others that have been
tried.</p>]]></description>
	<pubDate>12 Aug 2023</pubDate>
</item>
<item>
	<title>mapm and XDG</title>
	<link>https://dennisc.net/writing/tech/mapm-xdg.md</link>
	<description><![CDATA[<p>Recent versions of the mapm-cli tool put all
the mapm files in the <code>.config/mapm</code> directory (i.e.
<code>$XDG_CONFIG</code>). I don't know if this is entirely correct,
particularly for <code>profile</code> and <code>problems</code>, but
here are my justifications.</p>
<p>Data that a user manually edits makes the most sense in config. If
you look at <code>.local/share</code> on your machine, chances are that
it's filled with incomprehensible machine-readable but not
human-readable data. (And that it's all from GUI prorams.) And even
though problems are not config files in the traditional sense, you are
writing <code>key: val</code> pairs anyway, so in spirit it really is a
config file.</p>
<p>Also, it makes things ten times simpler if all mapm data is stored
inside the same directory. This is why <code>profile</code>, which
arguably <em>does</em> belong in <code>$XDG_DATA_DIR</code>, stays in
<code>.config/mapm</code> just like the rest of mapm-cli's files.</p>
<p>As for mapm-gui, comments etc will not be directly edited by users,
but will be interacted through the mapm gui interface. So I am thinking
that mapm gui information will go in <code>$XDG_DATA_DIR</code>. That
makes the setup process a bit more complicated for people working
together, but whoever's in charge of tech in an organization using mapm
should be competent enough to write an install script that abstracts it
all away. (That "someone" in Math Advance is me right now.)</p>
<p>A little off-topic, but thoughts on mapm-gui: since LinkedHashMap
doesn't implement Serde in Rust (or is it the other way around?) there
are no guarantees for the structural integrity of problem files,
<em>particularly with respect to comments</em>, if you edit fields
through an interface. So I am thinking that similar to a forum post, you
see the "rich text render" when you are not editing, and when you are
editing the problem yml itself pops up in a pane somewhere. Trying to
work out manual text replacement/editing seems too buggy to be worth it,
especially since YAML is pretty simple/readable
anyway.</p>]]></description>
	<pubDate>4 Mar 2022</pubDate>
</item>
<item>
	<title>Math Advance is looking for Rust developers</title>
	<link>https://dennisc.net/writing/tech/mathadvance-rust.md</link>
	<description><![CDATA[<p>The title of the post says that we are looking
for Rust developers. Indeed, the language all Math Advance projects are
written in is Rust, some of which interfaces with LaTeX. However, if you
are willing to learn, Rust knowledge is not necessary! All that is
needed is patience and diligence.</p>
<p>Due to some poor initial technical decisions by our tech lead (read:
me), Math Advance has been straddled with a bit of tech debt. To
summarize, we have stuff written in crappy not-Rust languages (typically
Node JS) and want it written in Rust. It will be largely from scratch,
though we will keep some legacy components of the MAT website (due to me
not wanting to reimplement it all), so the tech debt is not something
any new developers will be straddled with. There will be no crappy
codebases to struggle through.</p>
<p>A list of Math Advance related projects, from my most to least
recommended:<a href="#fn1" class="footnote-ref" id="fnref1"
role="doc-noteref"><sup>1</sup></a></p>
<ul>
<li><p>Math Advance logo (not actually software): We have one for MAST
and MAT but not one for MA as a whole. Currently I'm working through
some prototypes but if you have any ideas yourself let me know!</p></li>
<li><p><a href="https://sr.ht/~dennisc/mapm">mapm</a>: mapm is the
software we use to compile our contests. This is my top software
recommendation because it's the one that sees the most real-world use
today (read: I'm not the only one that uses it) and has the most
flexibility in contributing! Some ways of contributing do not even
require any Rust experience.</p>
<p>The mapm ecosystem is currently in an alpha-state, where it is usable
for our purposes and few others. Naturally, I would like that to change!
Some areas of research include a GUI (which is helped by the fact I
planned ahead and separated the core mapm library into another crate), a
mapm-specific package manager for templates, more templates<a
href="#fn2" class="footnote-ref" id="fnref2"
role="doc-noteref"><sup>2</sup></a>, and manpages/shell-completion for
the CLI.</p></li>
</ul>
<ul>
<li><a href="https://mathadvance.org">mathadvance.org</a>: When you go
on our current landing page you learn absolutely nothing about Math
Advance. Sexy, but impractical (and also JS! Blegh!) It's just going to
be a Makefile and some custom config since a) it's gonna be a static
site and b) I hate every static site generator out there. It's very
simple, but design help is appreciated!</li>
<li><a href="https://mast.mathadvance.org">mast.mathadvance.org</a>:
Currently only works with JS. I intend to rewrite this website so that
everything is server-side generated, i.e. no JS. It will be one
monolithic codebase written in Rust, much like what Glee is intended to
be. No design skills necessary, we'll stick with the same design; it
just needs to be re-implemented in not Tailwind.</li>
<li>sysadmin: I've got a couple sysadmin scripts for MAST I should
write/migrate. Improving the mailserver and setting up SourceHut mailing
lists are on my to-do list as well; I'm currently using Mailcow and I
don't like that it uses Docker, that kind of blackboxes things for me.
Nothing super permanent can happen with regards to sysadmin though,
because so much of what I need to do is based on GitLab which we'll
hopefully replace with Glee soon anyways.</li>
<li>glee: See my <a href="/writing/tech/glee-design">initial post</a>
and <a href="/writing/tech/glee-addendums">followup</a>. I did mention
Svelte in the followup but my position has become more hardline:
<strong>no JS shenanigans</strong>, which means no SvelteKit. We're
going to use Rust (probably axum as web framework), plain old HTML, and
CSS, tied together with a healthy dose of NGINX. The way I'm going to
approach this project is very opinionated, so unless you are
experienced, know my opinions, and share them, I recommend you look at
something else. There's a lot in the Math Advance world worth looking
at, eh?</li>
<li><a href="https://mast.mathadvance.org">mat.mathadvance.org</a>: It's
currently a living nightmare; I don't recommend you work on this.<a
href="#fn3" class="footnote-ref" id="fnref3"
role="doc-noteref"><sup>3</sup></a> We'll unfortunately still be using
Javascript, because I am <em>not</em> rewriting the frontend.</li>
</ul>
<p>Of course, the nature of open source is that it is distributed. You
do not have to join the Math Advance team itself to send patches! Total
commitment is not necessary, especially for mapm --- which is why, if
you want to help but don't know what to pick, I seriously suggest you
pick that.</p>
<p>If any of this interests you, shoot me an email! Alternate forms of
contact OK too, if you have them.</p>
<section id="footnotes" class="footnotes footnotes-end-of-document"
role="doc-endnotes">
<hr />
<ol>
<li id="fn1"><p>Note this does not reflect my level of investment in the
project, just how suitable I think it is for an outsider to Math
Advance, or maybe even programming.<a href="#fnref1"
class="footnote-back" role="doc-backlink">↩︎</a></p></li>
<li id="fn2"><p>An AMC, AIME, MATHCOUNTS or Olympiad template would be
helpful! Any popular contest format would really greatly benefit the
ecosystem, so ARML, HMMT, etc are also on the table. It just requires
some LaTeX skills.<a href="#fnref2" class="footnote-back"
role="doc-backlink">↩︎</a></p></li>
<li id="fn3"><p>Actually, I'm half-inclined to decline help from anyone
who isn't already experienced with Rust AND Next JS, since this project
won't teach you much valuable anyway. Or at least, the frontend won't.<a
href="#fnref3" class="footnote-back" role="doc-backlink">↩︎</a></p></li>
</ol>
</section>]]></description>
	<pubDate>24 Jun 2022</pubDate>
</item>
<item>
	<title>A Brief Overview of Git</title>
	<link>https://dennisc.net/writing/tech/git-overview.md</link>
	<description><![CDATA[<p>In this post I want to cover some Git
misconceptions (or rather, lack of conception?)</p>
<h2 id="addcommitpush">add/commit/push</h2>
<p>Commits are the smallest unit of reasonable change. In between two
commits should lie the smallest possible meaningful change that doesn't
break anything. Notably, it should not be reasonably possible to break a
commit into two smaller commits.</p>
<p>("Commit" as a noun means "a specific version of the repository
history", while "commit" as a verb means "create a new version with the
smallest reasonable difference from the current version.")</p>
<p><code>git add</code> is the "scratchwork" as you are making the edits
you need for your next commit. <code>git commit</code>, well, actually
creates the version. <code>git push</code> is irrevocable<a href="#fn1"
class="footnote-ref" id="fnref1" role="doc-noteref"><sup>1</sup></a> and
updates the rest of the world about your changes.</p>
<h2 id="merge-conflicts">Merge conflicts</h2>
<p>Merging/rebasing is a way to reconcile the history of two divergent
branches.</p>
<p>There are two types of divergent branches:</p>
<ul>
<li>branches whose changes commute,</li>
<li>and branches whose changes do not.</li>
</ul>
<p>As a concrete example, let us say I create file A and you create file
B. Then, no matter what order we do that in, the end result is the same:
files A and B have been created.</p>
<p>Git uses <em>diffs</em> (the difference between two branches) to
calculate the changes made. So, for instance, if we start with a file
that says</p>
<div class="sourceCode" id="cb1"><pre
class="sourceCode diff"><code class="sourceCode diff"><span id="cb1-1"><a href="#cb1-1" aria-hidden="true" tabindex="-1"></a>b</span></code></pre></div>
<p>and I add a character <code>a</code> above the <code>b</code>, it
will look like</p>
<div class="sourceCode" id="cb2"><pre
class="sourceCode diff"><code class="sourceCode diff"><span id="cb2-1"><a href="#cb2-1" aria-hidden="true" tabindex="-1"></a><span class="va">+a</span></span>
<span id="cb2-2"><a href="#cb2-2" aria-hidden="true" tabindex="-1"></a>b</span></code></pre></div>
<p>while if you add a character <code>c</code> above the <code>b</code>,
it will look like</p>
<div class="sourceCode" id="cb3"><pre
class="sourceCode diff"><code class="sourceCode diff"><span id="cb3-1"><a href="#cb3-1" aria-hidden="true" tabindex="-1"></a>b</span>
<span id="cb3-2"><a href="#cb3-2" aria-hidden="true" tabindex="-1"></a><span class="va">+c</span></span></code></pre></div>
<p>and Git is smart enough to realize that the change isn't, "Dennis
overwrote the file <code>b</code> to <code>ab</code>, while you
overwrote the file <code>b</code> to <code>bc</code>" --- rather, Git
recognizes that I added <code>a</code> before <code>b</code> and you
added <code>c</code> after <code>b</code>. Therefore, <em>even if we
edit the same file</em>, there is a possibility that
<code>git merge</code> spits out</p>
<div class="sourceCode" id="cb4"><pre
class="sourceCode diff"><code class="sourceCode diff"><span id="cb4-1"><a href="#cb4-1" aria-hidden="true" tabindex="-1"></a><span class="va">+a</span></span>
<span id="cb4-2"><a href="#cb4-2" aria-hidden="true" tabindex="-1"></a>b</span>
<span id="cb4-3"><a href="#cb4-3" aria-hidden="true" tabindex="-1"></a><span class="va">+c</span></span></code></pre></div>
<p>because under a <em>diff</em> based system, the order in which we
apply our changes does not matter. You can write <code>c</code> below
<code>b</code> before I write <code>a</code> above <code>b</code> and we
will still end up with the same result. (By the way, diffs are performed
on a line-by-line basis: it will not work if I change <code>b</code> to
<code>ab</code> while you change <code>b</code> to <code>bc</code>.)</p>
<p>However, if I do</p>
<div class="sourceCode" id="cb5"><pre
class="sourceCode diff"><code class="sourceCode diff"><span id="cb5-1"><a href="#cb5-1" aria-hidden="true" tabindex="-1"></a><span class="va">+a</span></span>
<span id="cb5-2"><a href="#cb5-2" aria-hidden="true" tabindex="-1"></a>b</span></code></pre></div>
<p>but this time, you do</p>
<div class="sourceCode" id="cb6"><pre
class="sourceCode diff"><code class="sourceCode diff"><span id="cb6-1"><a href="#cb6-1" aria-hidden="true" tabindex="-1"></a><span class="va">+c</span></span>
<span id="cb6-2"><a href="#cb6-2" aria-hidden="true" tabindex="-1"></a>b</span></code></pre></div>
<p>the order which we apply the changes matters. If we apply my change
first, we get</p>
<div class="sourceCode" id="cb7"><pre
class="sourceCode diff"><code class="sourceCode diff"><span id="cb7-1"><a href="#cb7-1" aria-hidden="true" tabindex="-1"></a><span class="va">+a</span></span>
<span id="cb7-2"><a href="#cb7-2" aria-hidden="true" tabindex="-1"></a><span class="va">+c</span></span>
<span id="cb7-3"><a href="#cb7-3" aria-hidden="true" tabindex="-1"></a>b</span></code></pre></div>
<p>while if we apply your changes first, we get</p>
<div class="sourceCode" id="cb8"><pre
class="sourceCode diff"><code class="sourceCode diff"><span id="cb8-1"><a href="#cb8-1" aria-hidden="true" tabindex="-1"></a><span class="va">+c</span></span>
<span id="cb8-2"><a href="#cb8-2" aria-hidden="true" tabindex="-1"></a><span class="va">+a</span></span>
<span id="cb8-3"><a href="#cb8-3" aria-hidden="true" tabindex="-1"></a>b</span></code></pre></div>
<p>Git can automatically merge for you if the order does not matter; any
reasonable interpretation of the changes (my changes first or your
changes first) gives the same result. However, <strong>when the order of
the changes matters</strong> (i.e. the order of lines is not necessarily
fixed), that is when you get a merge conflict and must manually resolve
it.</p>
<h3 id="a-more-abstract-example-with-mathematical-functions">A more
abstract example with mathematical functions</h3>
<p>To make an analogy, consider the functions <span
class="math inline"><em>f</em>(<em>x</em>) = <em>x</em> + 1</span> and
<span
class="math inline"><em>g</em>(<em>x</em>) = <em>x</em> + 2</span>. Then
<span
class="math inline"><em>f</em>(<em>g</em>(<em>x</em>)) = <em>g</em>(<em>f</em>(<em>x</em>)) = <em>x</em> + 3</span>.
In other words, it doesn't matter what order you apply the changes (i.e.
<span class="math inline"><em>f</em></span> and <span
class="math inline"><em>g</em></span>) in: the end result is still the
same.</p>
<p>However, if <span
class="math inline"><em>f</em>(<em>x</em>) = <em>x</em> + 1</span> and
<span class="math inline"><em>g</em>(<em>x</em>) = 2<em>x</em></span>,
then <span
class="math inline"><em>f</em>(<em>g</em>(<em>x</em>)) = 2<em>x</em> + 1</span>
while <span
class="math inline"><em>g</em>(<em>f</em>(<em>x</em>)) = 2<em>x</em> + 2</span>.
Here, the order in which you apply the changes matters.</p>
<section id="footnotes" class="footnotes footnotes-end-of-document"
role="doc-endnotes">
<hr />
<ol>
<li id="fn1"><p>Not actually, <code>git push -f</code> can override
history, but let's pretend it's irrevocable because you really should
treat it as such.<a href="#fnref1" class="footnote-back"
role="doc-backlink">↩︎</a></p></li>
</ol>
</section>]]></description>
	<pubDate>11 Jan 2023</pubDate>
</item>
<item>
	<title>How to remember what h, j, k, and l do in Vim</title>
	<link>https://dennisc.net/writing/tech/vim-hjkl.md</link>
	<description><![CDATA[<p>At least personally, the biggest reason I took
so long to start hjkl'ing in Vim is because I never could remember what
each of them did. Specifically, how to tell j and k apart, because h and
l are kind of obvious (h is on the left so it goes left, l is on the
right so it goes right).</p>
<p>Here's a trick to remember that j is down (and thus by process of
elimination, k is up). j looks like a fishing hook, so you can visualize
a fishing hook going down.</p>]]></description>
	<pubDate>5 Jun 2022</pubDate>
</item>
<item>
	<title>With apologies to RSS readers</title>
	<link>https://dennisc.net/writing/tech/apologies-to-rss.md</link>
	<description><![CDATA[<p>Until very recently, the RSS feed was basically
non-functional because I forgot to include the
<code>&lt;pubDate&gt;</code> tag in each entry. This means that RSS
readers assumed that each entry was published on whatever day the feed
was refreshed, which made for a very unsatisfactory user experience. Now
it is fixed.</p>
<p>With this, the number of times each file's metadata (i.e. the title
and date fields) is parsed has increased to three: one for the All
Writing page, once for whichever one of the Essays/Blog/Tech pages it
falls into, and one for the RSS feed. It would likely be possible to
fold it all into one Rust script, which reads only the metadata (i.e.
doesn't try to parse LaTeX as Pandoc does, which would already make it a
lot faster), and only reads it once. This will probably decrease the
build times of my website, at the cost of some additional complexity in
the form of another language. (On the bright side, the code will look
nicer because I have <code>fmt</code> strings.) But my build times right
now are longer than 10 seconds, which is unacceptably slow for a static
site.</p>
<h2 id="puzzle-fixes">Puzzle fixes</h2>
<p>I fixed a couple of small things in my older puzzles recently too. In
Starry Sums, there was no mention of the positive diagonal restriction
in the rules, and I just now added the solution to the example puzzle in
Alphabet Soup. (By the way, I really recommend you give Alphabet Soup a
try.)</p>]]></description>
	<pubDate>17 May 2023</pubDate>
</item>
<item>
	<title>The principles of client-server communication</title>
	<link>https://dennisc.net/writing/tech/client-server-auth.md</link>
	<description><![CDATA[<p>Are you new to backend? Do you want to learn
how to authenticate users properly? This post will not go over any of
the specfics, but it will describe the general principles of
client-server communication you need to understand to successfully write
a backend and connect it to your web users. These principles do not just
cover the web --- they cover any form of client-server communication ---
but that will be the main focus here.</p>
<p>Roughly speaking, there are two things you need to know:</p>
<ul>
<li>The server has no "memory" of you, it cannot recognize if two
requests come from the same person/machine/etc. (They can
<em>technically</em> use your IP but that's not reliable for
authentication --- consider a public library!) Thus the client must
authenticate for each request.</li>
<li>Anyone can be a client and send an arbitrary request for your
server, so you must verify all requests.</li>
</ul>
<p>Either way it boils down to the same thing: <strong>verify all your
requests and make sure you make no assumptions about them when handling
them server-side.</strong> In particular, this means do not rely on any
client-side form controls: Inspect Element or just curl can trivially
disable them. Client-side checks exist for convenience, not
security.</p>
<h2 id="authenticate-for-each-request">Authenticate for each
request</h2>
<p>The client will make separate requests for each distinct action it
wants to take with the server. For instance, if I wanted to write a new
topic in a forum that would be a POST request (POST requests are
generally used for write operations to the server's database). If I
wanted to then reply to that same topic, it would be a separate POST
request. And if I wanted to read said topic and reply later, that would
be a GET request (generally used for read-only operations). Each action
the client takes is one request. (This applies for <em>loading</em> a
page too: when you go to dennisc.net, you're making a GET request to the
route <code>/</code>.)</p>
<p>To protect against malicious requests the client has to prove
<strong>within each request</strong>, via means of a cookie or a token,
that they are who they say they are. This is authentication.</p>
<p>There are two common ways to authenticate on the web that we will
cover: username/password and session tokens.. To simplify, a website
usually works as thus:</p>
<ul>
<li>use your username/password combination to generate a session token
and set it as a cookie (this is what happens when you "log in")</li>
<li>for any other GET or POST requests, the client should send the
session token to verify its identity.</li>
</ul>
<p>The browser automatically sends the session token to verify its
identity by storing it in a <strong>cookie</strong>, which it then
automatically sends on every request. This is what cookies are: just
information the browser sends on your behalf for every request to a
website.</p>
<h2 id="anyone-can-make-an-arbitrary-request">Anyone can make an
arbitrary request</h2>
<p>Whenever people first try to write a full-stack web "app"<a
href="#fn1" class="footnote-ref" id="fnref1"
role="doc-noteref"><sup>1</sup></a>, they inevitably fall into the trap
of thinking that only officially approved clients (i.e. only the
frontend of your website, and not any external actors malicious or
otherwise) will send requests to your server. This leads to embarrassing
things like "authenticating" requests based on username rather than
something verifiable like a session ID.<a href="#fn2"
class="footnote-ref" id="fnref2" role="doc-noteref"><sup>2</sup></a></p>
<p>Personally, downloading Postman has been really informative. Not only
is it possible, it is also easy for any user to send whatever they want
to your endpoints. cURL should be similarly enlightening.</p>
<p>In any case, you can either only allow your website to act as a
client (this is done for forms using a CSRF token, but you should not
<em>solely</em> rely on this) or accept that clients can send whatever
they want. This also means that any clientside checks in formdata must
also be done serverside.</p>
<h2 id="summary">Summary</h2>
<p>The server has no memory of clients, so they must send identifying
information on each request. Anyone can act as a client and they can
send anything, and you must verify the validity of each request
server-side.</p>
<p>Basically, assume every request is made with malicious intent until
they prove otherwise.<a href="#fn3" class="footnote-ref" id="fnref3"
role="doc-noteref"><sup>3</sup></a></p>
<section id="footnotes" class="footnotes footnotes-end-of-document"
role="doc-endnotes">
<hr />
<ol>
<li id="fn1"><p>Scarequotes because most of the time you don't need
client-side interactivity besides what HTML and CSS provide, which is a
lot.<a href="#fnref1" class="footnote-back"
role="doc-backlink">↩︎</a></p></li>
<li id="fn2"><p>This mistake is a lot easier to make if you use a
Javascript framework because then you have the ability to determine
identity client-side. If your only method of determining identity is
server-side, you won't make the mistake of trusting client-side. Another
reason not to! I've done it, and <a
href="https://krebsonsecurity.com/2021/11/hoax-email-blast-abused-poor-coding-in-fbi-website/">so
has the FBI</a>.<a href="#fnref2" class="footnote-back"
role="doc-backlink">↩︎</a></p></li>
<li id="fn3"><p>Obviously this only applies for write or confidential
read operations; if a client is request a public static page, you can
serve it to them without checking their identity.<a href="#fnref3"
class="footnote-back" role="doc-backlink">↩︎</a></p></li>
</ol>
</section>]]></description>
	<pubDate>3 Aug 2022</pubDate>
</item>
<item>
	<title>Time</title>
	<link>https://dennisc.net/writing/blog/time.md</link>
	<description><![CDATA[<p><em>"Work expands to fill the time allotted to
it." --- Parkinson's Law</em></p>
<p>When you were a little kid your teachers and parents probably
emphasized the value of hard work. So much so that the act of putting in
effort itself was seen as virtuous, rather than working as a means to an
end. Certainly motivation is a problem for most people, but chances are
if you're reading the blog the opposite is true. I would be incredibly
shocekd if someone unmotivated decided to spend their time reading
<em>essays</em> instead of, I don't know, playing BTD Battles 2 instead.
Which would be fair enough, since I would do the same.</p>
<p>A lot of people do a lot of their work on a computer. If you're
anything like me, you probably get distracted easily when you're working
on a computer and encounter resistance. After all, the friction of
checking your phone only needs to be less than the friction of the
problem you're working on for you to check it. Checking your phone is
easy and worthwhile work is hard, so it's really easy to waste a lot of
time.</p>
<h2 id="quotas">Quotas</h2>
<p>We think of work quotas as being "spend at least X hours on Y task."
This turns out to be a very wasteful approach. It might be more helpful
instead of set a maximum time limit instead; say, only spending up to
two hours of free time a day on your work. Instead of thinking "I want
to do vague X, how much time do I need?" think "How much can I squeeze
out of T time?"</p>
<p>There's a reason the people best at what they do are minimalists.
Novice writers think "How many pages can I stretch this out to?" The
best think "How little space do I need to fit everything in?" Computer
noobs think sexy is "Wow, look at how pretty my Windows screensaver is."
Power users think "Wow, look at how much I can do with so few resources
and such little clutter."</p>
<h2 id="experiment">Experiment</h2>
<p>I'm going to go full circle and try something: a screentime limit.
Here are the details:</p>
<ul>
<li>At home I can only use the computer two hours a day. Homework counts
(incentive for me to do it faster).</li>
<li>Using my computer at school doesn't count, since my butt is already
in a chair, it would be too hard to count, and I actually spend my time
at school programming instead of playing games (mostly).</li>
<li>I'm recording time on little slips of paper. I think it'd be ironic
if I wrote scripts on the computer to prevent myself from using it. Also
if something critical happens (read: the English essay I don't give a
shit about is due when I get to class and it's 5 AM in the morning), I
want to be able to use the computer. (Or if I'm just transcribing an
essay from paper to computer, I really don't care if I go over for
that.)</li>
</ul>
<p>In principle I think you could omit the general ban altogether and
just limit your work. After all, the point of this restriction is to
make work more efficient, not because the computer is a boogeyman that
will kill you if you stare into it for too long. That being said, I
still think a general computer limitation is better:</p>
<ul>
<li>It's harder to get distracted. Especially for power users like me, I
can just press <code>$Mod+d</code> to open <code>dmenu</code>, then run
<code>steam</code>, and enter into some game from there. It's not as
easy to put down my pencil, walk over to my computer, deal with the
guilt of committing not to work midway through my work, and also commit
to wasting my two hours of computer time. It's also hard to switch back
to working, so it's less likely I fool myself into thinking "I'll just
finish it later, how hard could it be to switch to Workspace 1 where my
Vim terminal is open?"</li>
<li>Health. This really requires no explanation, it's just common
sense.</li>
</ul>
<p>Note this only works for academics --- limiting your exercise time is
not likely to work the same way, even though in principle some people do
need stop exercising as much (injured people. I learned that the hard
way.) This is because when you're seriously studying there's only one
pace --- a full-on sprint. Whereas when you're exercising there are long
days, hard days, recovery days, etc. all with different paces.</p>
<h2 id="sucks">Sucks</h2>
<p>There are some things that really suck about limitations like this
though, at least for me. They are somewhat specific so someone else
trying this probably won't face these.</p>
<ul>
<li><strong>Writing.</strong> There are some times when I can think much
faster than my hand to move. This problem is mostly solved when I'm
typing because I can type really fast and also am an absolute Vim[^vim]
lord. This is why I always do revisions by typing, because I can
basically think on the fly and translate it to words. (Though forcing me
to write on paper has gotten me to write more, even if it takes longer.)
[^vim]: I actually kind of suck, I still don't use hjkl in Vim (though I
do know how to use it in programs with vim-like keybindings, thank you
very much).</li>
<li><strong>EdPuzzles.</strong> Imagine if your teacher forced you to
watch an unskippable ad, except instead of being 30 seconds long it's 30
minutes long. And instead of being about Google's new phone it's about
the Civil War. I guess I can use it to get some gaming time in?</li>
<li><strong>Music.</strong> Although I already know how I'm going to
handle this: I'll just use the TV to play whatever song on YouTube while
I'm working out. (Obviously it won't count as "computer time.")</li>
</ul>
<p>These really won't be issues, I'm already thinking of them as
features and not as bugs.</p>
<p>I would say on the whole that this experiment is probably a good
idea. Part of me is slightly embarrassed that I'm publicly admitting I
use the computer so much that I need to give myself a screentime
restriction, grade-school style, but in the end I think it would be more
embarrassing <em>not</em> to acknowledge this
problem.</p>]]></description>
	<pubDate>6 Dec 2021</pubDate>
</item>
<item>
	<title>Every web developer should understand &quot;fullstack&quot;</title>
	<link>https://dennisc.net/writing/tech/fullstack.md</link>
	<description><![CDATA[<p>If you are in web development, there really is
no exuse not to generally understand the languages and protocols the web
is built on.<a href="#fn1" class="footnote-ref" id="fnref1"
role="doc-noteref"><sup>1</sup></a></p>
<p>Part of why people compartmentalize the web is because its standards
and features are so expansive. With almost a hundred status codes (and
418 I'm A Teapot isn't exactly helping), media queries for
<em>printers</em><a href="#fn2" class="footnote-ref" id="fnref2"
role="doc-noteref"><sup>2</sup></a>, and a million different
Javascript-based frameworks, it's no wonder that the frontend devs don't
want to deal with the backend on top of all this. And for the same
reason, backend developers understandably stay the hell away from this
abomination.</p>
<p>But rather than learning everything webdev related, you should try to
do as much as you can using as little as you can. You don't need
Tailwind when CSS variables exist, you shouldn't POST to ajax.php when
you can just set up an endpoint for the same page you sent the GET
request to for a form (come on, forms aren't proper APIs anyway), and
you shouldn't use cloud-based databases like Firebase because that
surrenders control and incurs extra complexity. Web development can be a
simple process --- you're just requesting and sending data according to
established protocols --- you just have to commit to making it so.</p>
<p>I've been saying "frontend" and "backend" developers this whole time.
However, a more accurate way to characterize them is "people who don't
fully understand the web". There's no shame in admitting it! The
internet is filled with awful advice, bloated and unnecessary Javascript
frameworks are presented as the norm, and servers are blackboxed instead
of being treated as just another Linux machine, just with certain ufw
rules set. But if you commit to using a small subset of the web's
features, avoid Javascript unless absolutely necessary, and <a
href="client-server-auth">understand the principles of client-server
authentication</a>, creating full-fledged websites on your own will not
be too far off.</p>
<section id="footnotes" class="footnotes footnotes-end-of-document"
role="doc-endnotes">
<hr />
<ol>
<li id="fn1"><p>The exception, depending on what kind of website you are
building (i.e. very little clientside interactivity) is Javascript: you
can choose not to learn how it works or ever use it and you will be just
as effective 99% of the time. Some, including myself, may argue that not
having a good grasp of Javascript actually makes you better because it
makes you more reluctant to fall back on it.<a href="#fnref1"
class="footnote-back" role="doc-backlink">↩︎</a></p></li>
<li id="fn2"><p>I actually think the media queries for printers are
useful (I use it on this site), but it is not necessary knowledge for
most people.<a href="#fnref2" class="footnote-back"
role="doc-backlink">↩︎</a></p></li>
</ol>
</section>]]></description>
	<pubDate>3 Aug 2022</pubDate>
</item>
<item>
	<title>An upper bound on antichains</title>
	<link>https://dennisc.net/writing/blog/antichains.md</link>
	<description><![CDATA[<p>Consider the powerset <span
class="math inline">𝒫(<em>n</em>)</span> (recall that <span
class="math inline"><em>n</em></span> is equal to the set <span
class="math inline">{0, 1, …, <em>n</em> − 1}</span>). Take some family
<span class="math inline">ℱ ⊆ 𝒫(<em>n</em>)</span> such that for any
distinct <span class="math inline"><em>A</em>, <em>B</em> ∈ ℱ</span>,
neither <span class="math inline"><em>A</em></span> nor <span
class="math inline"><em>B</em></span> is a subset of the other. What is
the maximum number of subsets of <span
class="math inline"><em>n</em></span> that can be contained in <span
class="math inline">ℱ</span>?</p>
<p>For example, taking <span class="math inline">3 = {0, 1, 2}</span>,
we may take <span
class="math inline">ℱ = {{0, 1}, {1, 2}, {2, 0}}</span>.</p>
<p>I claim the maximum is <span class="math inline">$\binom{n}{\lfloor
\frac{n}{2} \rfloor}$</span>. Equality is obvious, just put every subset
of size <span class="math inline">$\lfloor \frac{n}{2} \rfloor$</span>
into <span class="math inline">ℱ</span>.</p>
<p>To show the upper bound, we will prove that</p>
<p><span class="math display">$$\sum\limits_{A \in \mathcal F}
\frac{1}{\binom{n}{|A|}} \leq 1.$$</span></p>
<p>This suffices because</p>
<p><span class="math display">$$\sum\limits_{A \in \mathcal F}
\frac{1}{\binom{n}{|A|}} \geq \sum\limits_{A \in \mathcal F}
\frac{1}{\binom{n}{\lfloor \frac{n}{2} \rfloor}} = \frac{|\mathcal
F|}{\binom{n}{\lfloor \frac{n}{2} \rfloor}}$$</span></p>
<p>and multiplying by <span class="math inline">|ℱ|</span> on both sides
would yield <span class="math inline">$|\mathcal F| \leq
\binom{n}{\lfloor \frac{n}{2} \rfloor}$</span>. Now we show this bound
indeed holds.</p>
<p>Take a random maximal chain <span
class="math inline">𝒞 ∈ 𝒫(<em>n</em>)</span>. For example, taking <span
class="math inline">3</span>, we might get <span
class="math inline">𝒞 = {∅, {0}, {0, 1}, {0, 1, 2}}</span>. And
obviously <span class="math inline">|ℱ ∩ 𝒞| ≤ 1</span>: remember that no
members of <span class="math inline">ℱ</span> are subsets of each other.
Thus <span class="math inline"><em>E</em>[|ℱ ∩ 𝒞|] ≤ 1</span>.</p>
<p>But by Linearity of Expectation,</p>
<p><span class="math display">$$E[|\mathcal F \cap \mathcal C|] =
\sum\limits_{A \in \mathcal F} P[A \in \mathcal C] = \sum\limits_{A \in
\mathcal F} \frac{1}{\binom{n}{|A|}}.$$</span></p>
<p>To elaborate, <span class="math inline">$P[A \in \mathcal C] =
\frac{1}{\binom{n}{|A|}}$</span> by symmetry: <span
class="math inline">𝒞</span> contains exactly one member of cardinality
<span class="math inline">|<em>A</em>|</span>, and there are <span
class="math inline">$\binom{n}{|A|}$</span> such sets in <span
class="math inline">ℱ</span> to choose from.</p>
<p>And that's it!</p>]]></description>
	<pubDate>7 Sep 2024</pubDate>
</item>
<item>
	<title>Let's separate identities and permissions</title>
	<link>https://dennisc.net/writing/tech/identity-permission.md</link>
	<description><![CDATA[<p>I use ZX2C4's <a
href="https://www.passwordstore.org/">pass</a> to manage my passwords
and finally got around to changing my Gmail passwords. The night I did
this (which is the night I'm writing this post) my dad needed to do
something on my Google Fi, which requires him to be logged into my
Google account.</p>
<p>Currently the easiest way to do this would be to share my password
with him. Well, drats. How do I share my password with him? I'd have to
send it to him (bad idea), he'd have to copy it from his texts (mildly
annoying), then he'd have to switch to the Google Fi app (unnecessary
context switch), and finally he would be able to paste it.</p>
<p>Technically in some cases it is possible to exercise proper access
control, like with Google Brands (for YouTube and presumably Google Plus
before it died), but Google sucks so much at documenting their services
that even many veteran Google users (read: pretty much the entire world)
don't have any idea something this essential exists. We need a culture
shift where it's <em>expected</em> that different people can do
something on the same account without sharing passwords.<a href="#fn1"
class="footnote-ref" id="fnref1" role="doc-noteref"><sup>1</sup></a></p>
<p>Maybe we <em>shouldn't</em> be sharing passwords. It's a terrible
idea for security and it's inconvenient to boot. The same way that
multiple people can SSH into the same user of a server, maybe we should
allow multiple people (using separate <em>identities</em>) to perform
actions with the same account (same <em>permissions</em>). This is what
Glee does: there are multiple users (identities) which are assigned a
role: admin or user, depending on the permissions I want them to
have.</p>
<p>Access control is a hard problem. GitHub and GitLab manage to mess it
up royally and make it a major pain to use, which is why you have people
spending hours and even creating entire teams just to manage access
control. It's also why I'm building my Git service with access control
in the center of my mind. It might not be easy to design a solution that
works elegantly, but can we please, please not have the default solution
to "two people want to do things on one account" be "your use-case is
unsupported (so you have to share passwords, deal with it)"?</p>
<section id="footnotes" class="footnotes footnotes-end-of-document"
role="doc-endnotes">
<hr />
<ol>
<li id="fn1"><p>I don't think you should be able to share access to
Gmail accounts, whereas there are other things where access sharing
should work. This is one of the reasons I don't like monolithic
services, they're awkward when they try to fit largely unrelated items
together.<a href="#fnref1" class="footnote-back"
role="doc-backlink">↩︎</a></p></li>
</ol>
</section>]]></description>
	<pubDate>25 Aug 2022</pubDate>
</item>
<item>
	<title>MAT 2021 is on mapm</title>
	<link>https://dennisc.net/writing/tech/mat-2021-archive.md</link>
	<description><![CDATA[<p>I just wrote <a
href="https://gitlab.com/mathadvance/contest-releases">a script for
Linux users</a> to fetch a mapm contest from Math Advance. This ensures
that every contest can be built from source. As the title says, MAT 2021
was added to this archive of Math Advance contests.<a href="#fn1"
class="footnote-ref" id="fnref1" role="doc-noteref"><sup>1</sup></a></p>
<p>Additionally I posted a tutorial called <a
href="https://gitlab.com/mapm/zero-to-mapm">From Zero to mapm</a>, to
bootstrap anyone who is generally competent with computers (you should
know the basic shell commands and Git commands) with the tools needed to
install mapm. The only runtime dependency is LaTeX and the only
buildtime dependency is Rust; the tutorial also instructs the user to
install Git because templates should be hosted with Git.</p>
<p>Currently the tutorial only has Mac and Linux, but I plan to write
one for Windows soon! I'm just quite rusty with Windows, what with it
breaking every convention known to man.</p>
<p>I hope this is as exciting for you as it is for me. Even though we do
not have a GUI yet (optimistic estimate, mid-summer), the command-line
interface is expressive though a bit awkward at times<a href="#fn2"
class="footnote-ref" id="fnref2" role="doc-noteref"><sup>2</sup></a>,
and the documentations, tutorials, examples, etc are quite rich for such
a simple program. mapm has been battle-tested against some members of
Math Advance, who've gone through the grueling work of setting it up
manually, writing documentation themselves (thanks especially to Prajith
for the Mac OS documentation, which I used as a reference for "From Zero
to mapm"), and it works without major hiccups on all major operating
systems.</p>
<p>If you are writing a math contest and really want it to be good I
suggest you try mapm, if you've got a tolerance for dealing with any
issues that might arise. The ability to recompile drafts in the matter
of seconds is super helpful, especially since we can be confident that
all problems are coming from the same source, the mapm problems
directory. (I'll probably shill harder in the future once we've got a
GUI: for now we are sort of in a beta stage. If that doesn't sound like
your cup of tea yet, please come back to mapm in a few months!)</p>
<p>P.S. mapm is always stylized with all lowercase letters, even when it
starts a sentence. I sort of implicitly set that convention for myself
and now explicitly follow it after I realized. You can feel free to
respect or break this in your personal conversations, but any official
docs should abide by this. Let me know if they don't.</p>
<section id="footnotes" class="footnotes footnotes-end-of-document"
role="doc-endnotes">
<hr />
<ol>
<li id="fn1"><p>Yes, I did make some administrative edits (mostly
linting for <code>\textbf</code> or <code>\textit</code> vs
<code>\emph</code>, and punctuation inside math mode vs outside).<a
href="#fnref1" class="footnote-back" role="doc-backlink">↩︎</a></p></li>
<li id="fn2"><p>In particular, no Bash completion yet. I would be very
grateful if someone sent in a pull request, but of course, no one
besides me is under any obligation to work on it.<a href="#fnref2"
class="footnote-back" role="doc-backlink">↩︎</a></p></li>
</ol>
</section>]]></description>
	<pubDate>14 Mar 2022</pubDate>
</item>
<item>
	<title>Visiting UT Austin</title>
	<link>https://dennisc.net/writing/blog/ut.md</link>
	<description><![CDATA[<p>Yesterday I visited the University of Austin at
Texas. I haven't actually written anything about college apps yet (I
have a couple of off-the-cuff remarks from long ago written down in my
notebook but not typed up), but for this story to make sense, I'll have
to reveal a couple of college results. So here goes.</p>
<h2 id="college-decisions">College decisions</h2>
<ul>
<li>REA Princeton =&gt; Defer</li>
<li>EA UT Austin + Turing =&gt; Accept!</li>
<li>RD MIT/CalTech =&gt; Reject</li>
</ul>
<p>I think --- or perhaps, thought --- I have the kind of personality
that aligns itself with MIT/CalTech best. Now I am rethinking this, and
this is only partially me malding and seething over the rejections,
because the reasoning against MIT/CalTech applies to some other schools
(most notably CMU).</p>
<p>For people who don't know, UT Austin is a Texas state school that is
really good at computer science for undergrad (top 10 on US News, or
whatever other metric you want to use). Turing is an honors program that
selects less than 100 of the incoming freshman CS class, and this is
very biased, but I think it's really good.<a href="#fn1"
class="footnote-ref" id="fnref1" role="doc-noteref"><sup>1</sup></a>
There's a tight-knit community already forming within (some subset of)
the admitted class of 2027, and apparently Dr. Lin (the director of the
Turing program) has dropped bombshells like "The difference between an
Ivy and Turing is a Lambo, pick the Lambo". I recommend that the class
of '24 applies to this program!</p>
<p>Anyway, the point of this post isn't about college decisions, it's
just about a fun visit.</p>
<h2 id="visit">Visit</h2>
<p>We left WARP for the airport at about 12 PM. Looking back, the cohort
of us who wanted to travel should have requested an earlier group, but
until then I wasn't even aware there were people with ridiculously late
flights (and were interested in coming to Austin). But anyway, I vaguely
remembered (and fortunately, my memory was correct) that we had to catch
the bus on route 20, and as luck would have it, we caught a bus right as
it was about to leave.</p>
<p>I didn't have enough coins to pay for all 5 of us, so the bus driver
just said "forget it" and let us on the bus after I inserted some number
of dollar bills (probably because we were holding up the line). The bus
took much longer to get to Deen-Keaton than I would have hoped (45
minutes, as opposed to ~25 on Uber), but since we didn't have to wait
for an Uber at the airport it was probably okay.</p>
<p>After scrutinizing Google Maps for the entire bus ride to know when
we were supposed to get off, we found ourselves at the perimeter of UT
Austin, which means that it was the intersection of UT and downtown.
None of us had lunch, so the first thing we did was get In-N-Out. Three
of us were European and never had In-N-Out before, and suffice it to
say, their entire worldview got shattered.</p>
<p>Then we walked around campus with the limited time we had left and
took a couple of pictures near weird structures. We went past Moody, the
biotech(?) and chemistry sections, and saw the sign for the Cockrell
School of Engineering. Funnily enough, I was <em>not</em> able to find
the Computer Science building, which is ostensibly what I visited for in
the first place! (If I had more time, I definitely would have gone
looking for it.)</p>
<p>Impressions of the campus:</p>
<ul>
<li>Seems lively! Integrated with downtown, lots of cool stores and
stuff to do in Austin. Also there is an In-N-Out right outside of
campus, which is very important and awesome.</li>
<li>The architecture is on point. Unlike Northwestern, the campus
actually looks <em>consistent</em>; every building has the same vibe,
color palette, and materials. And unlike Harvard, it's actually really
pretty.</li>
<li>I'm concerned about the lack of trails that I saw (which maybe is a
problem with how little we explored). Google/Reddit says that there's
stuff nearby, but you actually have to run pretty far to get there or
take the bus, neither of which is a great choice.</li>
</ul>
<p>Everyone else had a flight at ~6 PM while my flight was at ~8 PM (or
it was, until it got delayed a stupid amount), so we headed back pretty
early and had to get to the airport fast. The bus was too slow, so I
decided to Uber instead, but Uber was being stupid and kept reserving
taxis at 17:45 when I clearly inputted 15:45, <strong>twice</strong>.
When I realized, I went "fuckfuckfuck" and just reserved an Uber to come
pick us up, NOW. Our driver was initially going pretty slowly but once
we texted him that we had flights to catch, he put in the full stops to
make sure we got to the airport as fast as possible.</p>
<p>Then when I passed through TSA Pre, I got mistaken for a SXSW
attendee, then correctly identified as class of '23. Right as I was
about to leave I said "Longhorns" and the agent was like "that's what
we're talking about". Everyone in Austin (and even Woodcreek, where WARP
was held --- which is quite far from Austin proper!) seems to be very
proud of their flagship university, which is a far cry from what happens
in California.</p>
<h2 id="airport">Airport</h2>
<p>FUCK SOUTHWEST.</p>
<p>So "because of weather" (which is somewhat reasonable, fine, I
guess), the first leg of my flight got delayed by an hour. Then
Southwest put my layover in Las Vegas instead of Dallas, which seemed
reasonable enough, and initially it would've taken off at 8, as
originally planned. Then it too got delayed until 9. Trouble is, the
second leg of my flight decided to come on time, so now I had to catch a
flight that left at 5:25 AM instead. Well, that's great!</p>
<p>It would've been OK if Southwest actually, y'know, provided
accommodations given that I paid for a continuous-ish flight from AUS to
SFO, but OK! Apparently they do not provide accommodations "because the
delays were solely due to weather", which accounts for... pretty much
every delay? Never mind what the customer is supposed to do about this
situation --- either sleep on the floor of the airport or pull an
all-nighter and die of sleep deprivation because Southwest ALSO decided
to change my boarding group from A to C, which means that basically the
only seat left was a middle seat next to a guy who... did not leave a
lot of room left for me, let's just say. (My other neighbor decided to
try and steal my armrest --- the only armrest I had because my other
neighbor couldn't fit without putting the armrest separating us up ---
until I just laid down the law and put my arm there.)</p>
<p>So now I am stuck in Las Vegas, after pulling two consecutive
all-nighters, with no food in my stomach and shitty water fountain
water. I'm not happy about Southwest's response to this situation, but
as for the situation itself, it's pretty acceptable. This is the risk I
took when I decided to book a late flight in order to visit UT Austin,
and I think it was a risk worth taking --- the flight part just panned
out really poorly for me this time. The only lesson for me to learn is
to book flights a little earlier because they will probably get delayed
and certainly will not leave early.</p>
<p>Overall it was a fun trip worth taking, and a nice way for me to
close out WARP by hanging out with the boys even after we left camp
premises. Scout mindset.</p>
<section id="footnotes" class="footnotes footnotes-end-of-document"
role="doc-endnotes">
<hr />
<ol>
<li id="fn1"><p>UT Austin (not even Turing) is among the top 5 schools
recruited by Jane Street, and JS pays Turing for the privilege of
advertising itself to the students. Also 75% of freshmen get an
internship in the summer (or some ridiculous number).<a href="#fnref1"
class="footnote-back" role="doc-backlink">↩︎</a></p></li>
</ol>
</section>]]></description>
	<pubDate>16 Mar 2023</pubDate>
</item>
<item>
	<title>Your middleware is noncommutative</title>
	<link>https://dennisc.net/writing/tech/noncommutative.md</link>
	<description><![CDATA[<p>Any half-decent programmer knows that in almost
all languages, <strong>functions are non-commutative</strong>. The order
in which you call two different functions matters in general.</p>
<p>But people forget this frighteningly often specifically when dealing
with middleware in web servers. (An example of applying middleware is
altering <em>every response</em> to return the appropriate CORS headers,
because it would be a massive pain in the ass to manually do that for
every response.)</p>
<p>Let me give you two examples. First I was trying to <a
href="https://git.sr.ht/~dennisc/glee/commit/b732c5fef4d9cfcb4b3053795ca4f4a41d566a51">update
Glee's dependencies</a>. You may as well just read the commit
message:</p>
<blockquote>
<pre><code>Update dependencies

Important changes:
- fallback (i.e. 404) is no longer into_service()
- axum::Server is gone, need to use tokio::net::TcpListener as in the
  axum example

      https://docs.rs/axum/latest/axum/index.html#example
- as Form is an Extractor that might consume the request body, we must
  put the Form extractor *last*.

  https://docs.rs/axum/latest/axum/struct.Form.html
  https://docs.rs/axum/latest/axum/extract/index.html#the-order-of-extractors

  Important to remember from second link: *the order of extractors
  matters*. They are applied left-to-right and then the request is
  fed, and *generally extractors do not commute*.</code></pre>
</blockquote>
<p>You don't say, right? But I managed to chase this error for <em>two
hours</em> before realizing that <em>my middleware was
non-commutative</em>.</p>
<p>Today I was working on a web project for K-Scale Labs. We had been
facing perpetual, mysterious CORS errors. I spent several hours
wondering if, despite the configuration for CORS being piss-easy in
FastAPI, I had somehow managed to mess it up. It turns out that my API
calls were incorrectly formatted. Fixing them <em>magically made my CORS
errors go away</em>. What on earth was going on?</p>
<p>My leading hypothesis as of half an hour ago was "some inexplicable
bullshit is going on that I will never understand". Only <em>then</em>
did I actually decide to look at how the CORS middleware was set up
<em>in the context of the rest of the app</em>, not just the one or two
lines that set up the CORS middleware itself.</p>
<p><em>Oh</em>. The project was passing every request to the appropriate
handler <strong>BEFORE</strong> applying the CORS middleware, and those
requests would return appropriate error responses by <strong>RAISING AN
EXCEPTION</strong>. My CORS configuration was perfectly fine. Instead,
<em>every actual error was being swallowed by a CORS error</em> because
the webserver raising an exception stopped execution before the CORS
middleware could be applied.</p>
<p>And I overlooked all of this because this code and the structure were
not set up by me.<a href="#fn1" class="footnote-ref" id="fnref1"
role="doc-noteref"><sup>1</sup></a> I was just taking it all for
granted. There is a lesson here: confusing things are very often the
cause of non-commutative middleware, especially when you don't
understand the structure of the overall web application.</p>
<p>In some ways this is an obvious principle. If I asked you explicitly,
"do your middleware commute", well of course they don't. But you don't
have a fairy godmother hovering over your shoulder asking "do your
middleware commute" at the exact right times. You are bound to forget
once or twice, which is precisely what makes this class of problems so
irritating.</p>
<p>But you can do the next best thing: anytime <em>anything is going
wrong and you can't figure out why</em>, you should <em>always</em> ask
yourself if the cause is non-commutativity. Be your own fairy godmother.
Non-commutativity in general is <em>the</em> most rich source of bugs
and unpredictable behavior. Even more so when it comes to web projects,
which tend to have a lot of complexity.</p>
<section id="footnotes" class="footnotes footnotes-end-of-document"
role="doc-endnotes">
<hr />
<ol>
<li id="fn1"><p>I have strong objections to the idea of "raise an
exception and convert that into an error HTTP response (i.e. a 4xx or
5xx response)", among many other parts of the architecture that I do not
have control over. Largely because deliberately cutting execution short
without thinking about the consequences tends to make these
non-commutativity bugs more pernicious in the first place!<a
href="#fnref1" class="footnote-back" role="doc-backlink">↩︎</a></p></li>
</ol>
</section>]]></description>
	<pubDate>4 Jun 2024</pubDate>
</item>
<item>
	<title>I hate squash and merge with a burning passion</title>
	<link>https://dennisc.net/writing/tech/squash-and-merge.md</link>
	<description><![CDATA[<p>Now, let's be perfectly clear. Using
<code>git merge --squash</code> is not <em>always</em> a bad thing, the
premise being that</p>
<ul>
<li>you have a branch with a bunch of garbage WIP commits;</li>
<li>you can edit the default commit message and write something
non-terrible.</li>
</ul>
<p>But let's be real. We already had a tool for squashing garbage
commits: it's called <code>git rebase -i</code>. Just fix up the garbage
commits, because surely if you have made a change non-trivial enough to
require WIP commits, it can't be trivial enough to fit in a single
commit, now can it?</p>
<p>But <code>git merge --squash</code> is not the target of my ire
today. No. It is GitHub, and it is the people who <em>enforce</em> only
using the squash and merge option on pull requests.</p>
<p>Listen. The only reason I have ever heard for enforcing squash and
merge is "it makes for a cleaner commit history". Cleaner my foot. The
only way to have a good commit history is to commit with intention and
rebasing to clarify and clean up. Squashing will not get you there.
Sure, your two-thousand line diff is now compressed in one commit with a
terrible message like <code>refactor backend</code>, rather than ten
commits with even worse messages like <code>wip</code> and
<code>done</code> and <code>oops</code>. But that is still a terrible
commit history, only now the terribleness is compressed in less
commits.</p>
<p>Worse, squashing will actually <em>delete</em> any commits made with
intention. And unless you really expect every commit to be a PR, which
is patently ridiculous, you are actually <em>removing</em> good history
and actively making it worse.</p>
<p>Furthermore, say you want to squash and merge and actually have a
good commit message. Suppose you rewrite the entire commit message or
whatever. A good commit message has appropriate line wrapping, something
my editor (vim) is perfectly capable of handling properly. GitHub does
not even give a whit of an indication when a line is too long. So
<em>you can't even write a proper commit message</em>. Ridiculous.</p>
<p>So what should you do? Just merge. Merge like a normal person.</p>
<pre><code>git merge --no-ff</code></pre>
<p>This makes a merge commit even when you could have fast-forwarded,
because it explains <em>why</em> you are merging a certain feature.<a
href="#fn1" class="footnote-ref" id="fnref1"
role="doc-noteref"><sup>1</sup></a></p>
<hr />
<p>While I'm at it, GitHub pull requests are a disaster. As usual, the
<a href="https://docs.kernel.org/maintainer/pull-requests.html">Linux
Kernel</a> is the gold standard.</p>
<p>When you want to merge <code>feature</code> into <code>master</code>
you should run <code>git merge feature</code> while in the
<code>master</code> branch. And obviously you take care of any merge
conflicts in this merge. In particular, you do not "back merge"
<code>master</code> into <code>feature</code> without <em>good
reason</em> because</p>
<pre><code>Merge branch &#39;feature&#39;

Merge branch &#39;master&#39;</code></pre>
<p>is a really stupid commit history! But GitHub, especially with a lot
of its automated CI/CD stuff encourages maintainers to put the
responsibility of fixing conflicts on the people writing the PRs. So now
the only thing they can do is rebase on top of master, and then re-test
every commit because otherwise they'd be lying.</p>
<section id="footnotes" class="footnotes footnotes-end-of-document"
role="doc-endnotes">
<hr />
<ol>
<li id="fn1"><p>If you want to fast-forward, that is also fine, but in
my opinion the times you should fast-forward are precisely the times
when you should rebase. Yes, a fast-forward merge and rebase are
identical, but it really "belongs" with rebasing.<a href="#fnref1"
class="footnote-back" role="doc-backlink">↩︎</a></p></li>
</ol>
</section>]]></description>
	<pubDate>7 Aug 2024</pubDate>
</item>
<item>
	<title>How I update my website on my server</title>
	<link>https://dennisc.net/writing/tech/build.md</link>
	<description><![CDATA[<p>If you're self-hosting, it's actually
surprisingly hard to find the "right way" to update your website on
push. Ideally you would be self-hosting Git and would be able to
directly add a <code>recieve-pack</code> hook to build whatever you need
server-side. But for the following reasons:</p>
<ul>
<li>not self-hosting a Git server,</li>
<li>not having the necessary build tools on your server (and there might
actually be good reason for this: do you really want to install TeX Live
on your server?)</li>
</ul>
<p>automatically building stuff on your website becomes a major
PITA.</p>
<p>So let me suggest another approach: instead of automating "server
receives stuff =&gt; server builds", why not automate "client pushes
=&gt; client builds =&gt; client sends build output to server"?
Particularly for smaller sysadmins like myself, the server is not
actually more powerful than the client: I'm running a low-resource Vultr
cloud instance, but other people might be self-hosting with their own
hardware like a Raspberry Pi. For us, building client-side may actually
be the better solution.</p>
<p>Here's how it works. I write a pre-push hook (I would've preferred
post-push, but it doesn't really matter and post-push hooks don't exist)
that looks like this:</p>
<div class="sourceCode" id="cb1"><pre
class="sourceCode bash"><code class="sourceCode bash"><span id="cb1-1"><a href="#cb1-1" aria-hidden="true" tabindex="-1"></a><span class="fu">make</span></span>
<span id="cb1-2"><a href="#cb1-2" aria-hidden="true" tabindex="-1"></a><span class="fu">tar</span> <span class="at">-czhf</span> dennisc.tar.gz build/<span class="pp">*</span></span>
<span id="cb1-3"><a href="#cb1-3" aria-hidden="true" tabindex="-1"></a><span class="fu">scp</span> dennisc.tar.gz HOST:dennisc.tar.gz</span>
<span id="cb1-4"><a href="#cb1-4" aria-hidden="true" tabindex="-1"></a><span class="fu">ssh</span> HOST <span class="st">&quot;tar -xvf dennisc.tar.gz &amp;&amp; rm -rf dennisc.net &amp;&amp; mv build dennisc.net&quot;</span></span></code></pre></div>
<p>where <code>HOST</code> is the IP of my server. In order to
automatically authenticate into SSH, you need to set up an SSH key and
configure <code>HOST</code> to use said SSH key in
<code>~/.ssh/config</code>. What my SSH config looks like is</p>
<pre><code>Host mathadvance
    Hostname 45.32.70.22
    IdentityFile ~/.ssh/mathadvance
    User mast</code></pre>
<p>(I'm revealing the IP of our server since it's public information
anyway: <code>ping dennisc.net</code> will get you it.)</p>
<p>Anyway, what this hook does is it builds my website using the
Makefile, creates a zipped tarball from the build output, copies the
tarball to my server, and extracts the tarball/moves it to the proper
location. It's nothing complicated, though it is mildly annoying that I
have to set this up on all my devices.</p>]]></description>
	<pubDate>31 Jul 2022</pubDate>
</item>
<item>
	<title>How I plan to organize my Git repos in Glee</title>
	<link>https://dennisc.net/writing/tech/glee-org.md</link>
	<description><![CDATA[<p>Glee stores repositories hierarchically, like a
filesystem. I plan to host two Git servers --- one for dennisc.net and
another for mathadvance.org.</p>
<h2 id="dennisc.net">dennisc.net</h2>
<pre><code>glee
dennisc.net
dennisc-gemini
dotfiles
    sway
    i3blocks
    ... (nvim, etc.)
    bin
        musiclist
        latex-lint
        ... (dlatexmk, etc.)
math
    mvc-am-gm
    linalg-notes
    ...
misc
    musiclist
    rust-beam
    beam (planned)
    min-tex-install
tex
    bounce
    nature
password-store (private)</code></pre>
<h2 id="mathadvance.org">mathadvance.org</h2>
<pre><code>mapm
    cli
    lib
    gui (planned)
mast
    units
        APV-Log
        ...
    unit-drafts
        ...
    diagnostics
        season1
        ...
    lectures
        ...
    mast.cls
    mast.mathadvance.org
contests
    mat.mathadvance.org
    archive
    summer-mat.cls
    winter-mat.cls
books (private)
    mabook.cls
    foray</code></pre>]]></description>
	<pubDate>1 Sep 2022</pubDate>
</item>
<item>
	<title>Potential Abstract Algebra course in Summer 2024</title>
	<link>https://dennisc.net/writing/blog/absalg-2024-summer.md</link>
	<description><![CDATA[<p>I will, in all likelihood, be in the Pittsburgh
area this summer. <em>If</em> there is sufficient interest, I will be
holding an introductory in-person abstract algebra course in person.<a
href="#fn1" class="footnote-ref" id="fnref1"
role="doc-noteref"><sup>1</sup></a> (The in-person aspect is
non-negotiable since I think my teaching is far more effective with the
in-person component.)</p>
<p>If this course were to happen, here would be the details (many of
them are still quite flexible). The course would probably last 6-8
weeks, meeting twice a week 75 minutes each time, with a focus on groups
and fields/vector spaces (we will do some linear algebra). Rings will
likely be mentioned too though. Maybe some categorical theoretic ideas.
It will be an introductory course, which means we will spend a good
amount of time on first principles. However it will be designed to be as
hard as possible while still keeping students interested in the material
and without being overwhelming. <strong>Most importantly, the course
will either be free of charge or low cost</strong> (think on the order
of 100 dollars with <a href="/writing/blog/finaid">financial
aid</a>).</p>
<p>The intended audience is largely high-school students (rising college
freshmen included). <strong>No math contest experience is expected,
required, encouraged, etc</strong> (everyone with sufficient
mathematical background and curiosity to learn is welcome). Here's a
quick pitch for the course that aims to answer the following
questions:</p>
<ul>
<li>What is abstract algebra about?</li>
<li>Why should I take it?</li>
<li>Why should I take it with you?</li>
</ul>
<p>Structure begets structure. This is what abstract algebra is about.
Doubtless you are familiar with the integers modulo <span
class="math inline"><em>p</em></span>. Consider the set of all the
non-zero residues <span
class="math inline"><em>G</em> = {1, 2, …, <em>p</em> − 1}</span>.
Clearly they are closed under multiplication modulo <span
class="math inline"><em>p</em></span> and we also know each element has
an inverse. Given a fixed <span
class="math inline"><em>g</em> ∈ <em>G</em></span>, the map <span
class="math inline"><em>h</em> ↦ <em>g</em><em>h</em></span> (recall
both <span class="math inline"><em>g</em></span> and <span
class="math inline"><em>h</em></span> are non-zero residues modulo <span
class="math inline"><em>p</em></span>) is a permutation (i.e. a
bijection from a set to itself). Furthermore we know <span
class="math inline"><em>g</em><sup><em>p</em> − 1</sup> ≡ 1 (mod  <em>p</em>)</span>
for all residues <span class="math inline"><em>g</em></span>, and in
fact, if <span class="math inline"><em>k</em></span> is the smallest
positive integer such that <span
class="math inline"><em>g</em><sup><em>k</em></sup> ≡ 1 (mod  <em>p</em>)</span>,
we must have <span
class="math inline"><em>k</em> ∣ <em>p</em> − 1</span>.</p>
<p>It turns out that neither of these facts are all that unique to
multiplication modulo <span class="math inline"><em>p</em></span>. For
instance, take <em>addition</em> modulo <span
class="math inline"><em>p</em></span>: with <span
class="math inline"><em>G</em> = {0, …, <em>p</em> − 1}</span>, <span
class="math inline"><em>h</em> ↦ <em>g</em> + <em>h</em></span> is a
permutation too and the smallest integer <span
class="math inline"><em>k</em></span> satisfying <span
class="math inline"><em>g</em><em>k</em> ≡ 0 (mod  <em>p</em>)</span>
also satisfies <span class="math inline"><em>k</em> ∣ <em>p</em></span>.
Or consider the permutations of <span
class="math inline">{1, 2, 3, 4}</span>, of which there are <span
class="math inline">24</span>. If we repeatedly apply the same
permutation <span class="math inline"><em>k</em></span> times and get
back to where we started --- <span
class="math inline">{1, 2, 3, 4}</span> --- and <span
class="math inline"><em>k</em></span> is minimal, then <span
class="math inline"><em>k</em> ∣ 24</span>.</p>
<p>What on earth do integers modulo <span
class="math inline"><em>p</em></span> and permutations have in common?
How can we abstractly capture these commonalities and use them to derive
maximally general results? And there are differences too between the
integers modulo <span class="math inline"><em>p</em></span> and
permutations. For one, multiplication is commutative. Composing
permutations is not. When do these differences matter? And in what
ways?</p>
<p>Abstract algebra also connects well with combinatorics. Take
Burnside's Lemma for instance, a good way to take care of overcounts
caused by symmetry in counting problems. It is precisely because of
facts in elementary group theory (buzzwords: "orbit-stabilizer theorem",
"class equation"). There are many examples of mathematics you know that
will provide clarity to abstract algebra, and many parts of abstract
algebra that serve to clarify deeper properties of things you know.</p>
<p>Hopefully you are convinced abstract algebra is an interesting
subject. But you have plenty of interesting things to do, and you can
take abstract algebra at any time. Why now? The obvious reason is that
it gives you a leg up. If you've gotten exposure to algebra and have a
decent understanding of the motivations behind the ideas (even if you
don't quite remember the ideas themselves), with a bit of self-study you
can set yourself up to take a graduate-level algebra class your first
semester of college.<a href="#fn2" class="footnote-ref" id="fnref2"
role="doc-noteref"><sup>2</sup></a> But there are subtler reasons.
Abstract algebra as a first course leads well into a lot of other
subjects: examples are category theory and topology. You <em>could</em>
technically study those without algebra, but it is so much better when
algebra gives you (part of) the reason to care.</p>
<p>And in my personal opinion, algebra is the hardest subject to do
wrong. You could study QR/LU/SVD decompositions for months in a standard
linear algebra class, to say nothing of row reductions. (Also I think
the study of matrices, which is a common interpretation of <a
href="/writing/blog/pedantry">linear algebra</a>, is not particularly
interesting.) And most the proofs in analysis are long and painful, and
all it takes is a teacher without good judgment as to which proofs to
skip to make it mindless computation. Algebra, meanwhile, pretty much
only has cool stuff. It has combinatorial arguments, number theoretic
arguments, and direct ties to both subjects too. It develops the widest
repertoire of skills while being the least painful.</p>
<p>My teaching philosophy, which I will expound on in a later post, is
simply to <em>give people a reason to care</em>. Instead of saying "Here
is Theorem 238, with a random setup and random conclusion," my aim is to
say, "here is a concrete example, generalize it and you will get Theorem
238." The words <em>concrete example</em> may instill dread in you,
perhaps because your previous teachers used it to mean "hyperspecific
nonsense no one cares about." Instead I mean a natural example we
already care about. For example, take the integers <span
class="math inline">ℤ</span>, something we all have a good feel for. One
of the reasons we care about integers is because they uniquely factorize
into primes (e.g. <span
class="math inline">120 = 2<sup>3</sup> ⋅ 3 ⋅ 5</span>), and this allows
us to do things like define the notion of a GCD. A natural question
would be: which definitions/properties/procedures work because we're
working with integers in particular, and which ones hold just because we
have some notion of unique prime factorization?</p>
<p>These questions are quite abstract and nebulously defined, and that's
the point. Ring theory and the notion of <em>Unique Factorization
Domains</em> came about because we wanted more precise answers to
questions like these. And when the student is aware of this, it is much
easier to notice the nuances of the general theory at hand, because now
we have some idea what we should care about! Much better than saying "a
unique factorization domain is a ring with properties X, Y, and Z"
right?</p>
<p>And finally there's the mandatory spiel about how I've been teaching
for however many years: this is far from my first rodeo. I've been
teaching every year for the last 7 years, I think my students enjoy my
lectures and get a lot out of them, and empirically they do quite well
for themselves afterwards. (Not that I think the causal link is super
strong though.) So if circumstances permit, I do think this class would
be worth your while.</p>
<p>Are you interested? In the Pittsburgh area this summer? Email me at
<a href="mailto:dchen@mathadvance.org">dchen@mathadvance.org</a> to
discuss details! <strong>This class will only run if enough interest is
expressed</strong> (something like at least 5 people).</p>
<section id="footnotes" class="footnotes footnotes-end-of-document"
role="doc-endnotes">
<hr />
<ol>
<li id="fn1"><p>I've gotten a bit burned out from teaching online
courses, particularly as that was how I taught the majority of my
courses for the past four years. I suspect students are equally burned
by them.<a href="#fnref1" class="footnote-back"
role="doc-backlink">↩︎</a></p></li>
<li id="fn2"><p>It seems that jumping ahead in the curriculum is not
particularly popular for some reason. Part of the argument against is
that "you could take these intro math classes, <em>but with a
world-class professor</em>". But if you can learn introductory content
just as well (or even better) without going through a college class, why
on earth would you fork over so much cash for someone to tell you things
you could've easily learned by yourself? Especially when the alternative
is taking classes with world-class professors, but now the subjects are
advanced and nuanced enough where their expertise really does make the
difference.<a href="#fnref2" class="footnote-back"
role="doc-backlink">↩︎</a></p></li>
</ol>
</section>]]></description>
	<pubDate>4 Apr 2024</pubDate>
</item>
<item>
	<title>Eager evaluation makes functions hard to reason about mathematically</title>
	<link>https://dennisc.net/writing/tech/lazy-eval.md</link>
	<description><![CDATA[<p>In CMU's 15-150 Functional Programming, we're
using a language called SML. SML uses <em>eager evaluation</em>, which
means that when you have some code like</p>
<div class="sourceCode" id="cb1"><pre
class="sourceCode sml"><code class="sourceCode sml"><span id="cb1-1"><a href="#cb1-1" aria-hidden="true" tabindex="-1"></a>f(x) = x + <span class="dv">1</span>;</span>
<span id="cb1-2"><a href="#cb1-2" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb1-3"><a href="#cb1-3" aria-hidden="true" tabindex="-1"></a>f(<span class="dv">1</span> div <span class="dv">0</span>)</span></code></pre></div>
<p>SML will say, "OK let us look at <code>1 div 0</code> first". And
then it will raise a <code>Div</code> exception because hey, you can't
do that!</p>
<p>A language like Haskell, in contrast, will use <em>lazy
evaluation</em>. What Haskell will do is first expand <code>f</code>
with no regards to its input to get something like</p>
<div class="sourceCode" id="cb2"><pre
class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb2-1"><a href="#cb2-1" aria-hidden="true" tabindex="-1"></a>f(<span class="dv">1</span> <span class="fu">div</span> <span class="dv">0</span>) <span class="ot">=&gt;</span> (<span class="dv">1</span> <span class="fu">div</span> <span class="dv">0</span>) <span class="op">+</span> <span class="dv">1</span> <span class="ot">=&gt;</span> <span class="dt">Div</span> <span class="fu">error</span></span></code></pre></div>
<p>(OK, Haskell actually gives you <code>Infinity</code>. But pretend
that we're dealing with SML except it does lazy evaluation instead.)</p>
<h2 id="why-does-this-matter">Why does this matter?</h2>
<p>Often we will want to prove one piece of code is equivalent to
another, via structural induction or whatever. If we have a function
like</p>
<pre><code>f(a, b) = a + b</code></pre>
<p>then we should be able to say that</p>
<pre><code>f(g(a), g(b)) = g(a) + g(b)</code></pre>
<p>But no! We cannot! Because the way equality works is (roughly) that
<em>two pieces of code have to evaluate to the same thing</em>. So you
actually have to prove that <code>g(a)</code> and <code>g(b)</code> even
evaluate to <em>something</em>, as opposed to not raising an
exception.</p>
<p>It turns out that in this case it is equal, regardless of whatever
you set <code>g</code>, <code>a</code>, and <code>b</code> to, because
<span class="math inline">+</span> is a simple enough function. But it
is annoying to prove, which is exactly my point, and if we set
<code>f</code> to something more complicated we would not be able to
prove this.</p>
<p>A case where (with eager evaluation) mathematical equality breaks is
with</p>
<pre><code>f(x) = raise Fail &quot;&quot;</code></pre>
<p>(A quick definition: <code>raise Fail ""</code> just raises the
exception <code>Fail</code>.)</p>
<p>You'd want to be able to say that <code>f(x)</code> evaluates to
<code>Fail</code> --- in other words, <code>f(x) = Fail</code> (in the
mathematical sense) regardless of what <code>x</code> is, right? It'd
only make sense for <code>f(x) = raise Fail</code> in code to mean the
same thing as <code>f(x) = Fail</code>.</p>
<p>But no! Plug in <code>1 div 0</code> and all the sudden
<code>f(1 div 0) = Div</code>. Arghhh!!! This function had one job, to
just raise the exception <code>Fail</code>! Why can't it do something
that simple?</p>
<p>This makes it annoying to mathematically reason about functions. Now
you have to handle edge cases (i.e. where errors pop up), or just work
in the world where everything behaves as you want and never handle said
edge cases. The former is unappealing, and the latter misses the point.
For a paradigm of programming all about formal verification and relying
on mathematics, not being able to rely on the very definition of a
function isn't very mathematical.</p>
<h2 id="eager-evaluation-has-its-advantages...">Eager evaluation has its
advantages...</h2>
<p>but mathematical verification is not one of them. I understand that
when writing real-world code, which is chock-full of side effects, lazy
evaluation might make things a bit harder to work about. But also
running real-world code should not require an eternity and then some, so
I'm not sure "practicality in the real world" is exactly the main
concern of functional languages :)</p>
<h2 id="appendix-run-it-yourself">Appendix: run it yourself!</h2>
<p>If you have SML New Jersey installed on your machine, run</p>
<pre><code>fun f (x : int) : int = raise Fail &quot;&quot;;
f(1);
f(1 div 0);</code></pre>
<p>in the SML REPL. You should get <code>Fail</code> and
<code>Div</code> errors, respectively.</p>]]></description>
	<pubDate>23 Sep 2023</pubDate>
</item>
<item>
	<title>Why I Switched to GitLab</title>
	<link>https://dennisc.net/writing/tech/gitlab.md</link>
	<description><![CDATA[<p>Last weekend I migrated all of my serious
GitHub projects over to GitLab (<a
href="https://gitlab.com/chennis"><span class="citation"
data-cites="chennis">@chennis</span></a>). A couple of my friends, who
are hobbyists who haven't developed as much, asked me why I'm making
this move and why I'm not using GitHub instead, especially since it's so
much more popular. Well, here's the reasoning behind my decision.</p>
<h2 id="git-github-and-gitlab">Git, GitHub, and GitLab</h2>
<p>For a well-informed discussion about these two tools, it's necessary
to get a clear understanding of what they <em>are</em> first. (If you
don't already know the difference, this is just a brief introduction ---
I recommend you look this up in greater detail on your own time.)</p>
<p>Git is a version control software. If you're using the command line
to interact with Git, then all the commands you run are built on Git.
They have nothing to do with GitHub or GitLab.</p>
<p>Git hosting services, like GitHub and GitLab, are just places where
you can host Git repositories so as to centralize them, to some extent.
This way people actually have a codebase they can consistently
<em>reference</em>, which is especially helpful for beginners.</p>
<p>The important concept to grasp is the direction of dependency.
GitHub/Lab rely on Git, not the other way around.</p>
<h3 id="gitlab">GitLab</h3>
<p>The term "GitLab" is even trickier to define because it can mean two
sort-of different things. Because GitLab is open source (hooray!) you
can host your own instance of GitLab. So when I opened with "I moved all
my serious projects to GitLab," it was actually ambiguous: did I mean
the website <a href="https://gitlab.com">gitlab.com</a>, or my own
private GitLab instance?</p>
<p>It turns out that for people like me (developers with their own
server), it doesn't really matter. I can migrate my GitLab projects from
the public GitLab website onto my own private Git server, and vice
versa. The reason I'm hosting on the GitLab website is because of
<em>accessibility</em>. This way, all my personal code is publicly
accessible, and whatever non-sensitive Math Advance stuff is also
publicly accessible. It hasn't been long enough after the switch for
Google to start caring about my GitLab projects, but I'm sure that over
time it'll eventually start displaying something vaguely related.</p>
<h2 id="the-good">The Good</h2>
<p>Every comparison of GitHub and GitLab I see lists features of each
tool and does a superficial side-by-side of them. The conclusion is
always the same: there are reasons to choose one or the other, it
depends on your circumstances. This is fair and all, but not very
helpful if you don't actually elaborate on which tool better fits which
circumstances. In my eyes, <strong>GitLab is vastly superior</strong>
when it comes to organizations that are creating a large number of
discrete things.</p>
<p>Keep in mind that I didn't say a large organization, just a large
number of discrete things. For instance, MAST has a lot of units (around
30 at least at the moment), even though the team actively working on
them is quite small. In contrast, if your organization is really only
working on one project or website or whatever, GitHub will be fine,
though I don't think GitLab is inferior for these purposes either.<a
href="#fn1" class="footnote-ref" id="fnref1"
role="doc-noteref"><sup>1</sup></a></p>
<p><strong>The real nice thing about GitLab is
groups/subgroups.</strong> Groups function similarly to organizations in
GitHub. But you can also think of a group as a root directory, and
subgroups as nested directories. Learning this is what <em>finally</em>
got me to make the switch over.</p>
<p>Back when MAST was still using GitHub, we had <em>one</em> repository
with all the units inside of it, along with some extra garbage. Why in
tarnation would we ever do that, when the LaTeX for two separate units
has <em>absolutely no relation to each other</em>? There was absolutely
no reason for it --- not even when using GitHub --- but I believe that
one reason was because there were no nested directories in GitHub. If I
made a separate repository for each MAST unit, I'd end up flooding the
organization with <code>mathadvance/CQV-Perspectives</code> around
thirty times over. Oh, and I'd also have to grant access to the MAST
team for <em>every single one</em> of these repositories.<a href="#fn2"
class="footnote-ref" id="fnref2" role="doc-noteref"><sup>2</sup></a>
Maybe keeping everything in the same repository <em>wasn't</em> a
mistake, and that is horrifying.</p>
<p>In GitLab we have <code>mathadvance/MAST/units</code> as a subgroup,
and unit repositories in the subgroup. Much simpler, and navigating
through the group actually makes sense now without external READMEs or
whatever, which helps with DRY --- no need to note in separate places
how your projects are organized if it's self evident.</p>
<h2 id="differences">Differences</h2>
<p>These are not issues with GitLab. Rather, they are challenges that I
faced because I was used to GitHub, or just things that are plain
<em>different</em>.</p>
<p>First off, GitLab doesn't have the equivalent of GitHub for students,
or whatever it's called, that gives students free GitHub PRO. As far as
I'm concerned there is no significant difference --- if your
organization or codebase is big enough that the limits start posing an
issue, you can afford to pay for whatever you're using. (Or self-host on
a server.)</p>
<p>Something I really miss is a personal README (a la <a
href="https://github.com/chennisden/chennisden">chennisden/chennisden</a>
on GitHub). This is totally a vanity feature, and I don't need it
whatsoever because I have a <em>website</em> to show off my tech stuff.
But it'd still be nice to have it on my GitLab profile too.</p>
<p>I think GitLab by design encourages a lot more <em>caution</em>,
which probably makes it more suited for organizations whereas GitHub
might be better for individuals who are just starting out.<a href="#fn3"
class="footnote-ref" id="fnref3" role="doc-noteref"><sup>3</sup></a>
Repositories (or projects, as GitLab calls them) are private by default.
And by default you have to wait seven days for a project to soft-delete
in a group. Then there's how GitLab interacts with Git: by default, you
can't delete protected branches (or any branches, depending on who you
are), you can't force push, etc. It's nice to have this here, actually,
because I only really need the ability to force push in certain
repositories anyway.</p>
<p>The one real struggle I had with GitLab was the lack of a central CLI
tool. There are plenty: there's one in Go, several in Ruby, one in NPM
as well --- and depending on what you search for, your first result will
be totally different. And some of these CLIs have incredibly abtruse
documentation; I couldn't figure out how to specify a (sub)group to make
a project in for one of them, for crying out loud. In contrast, GitHub's
official CLI is very self-explanatory, and you can use it without having
to search for documentation.</p>
<p>I will be explicit and say that I think GLab is the best of these by
far. In fact, it's might be better than GitHub's official CLI tool is
for GitHub. And, at least on Arch, it's just as easy to install --- one
<code>yay -S gitlab-glab-bin</code> and you are done.</p>
<h2 id="concluding-thoughts">Concluding Thoughts</h2>
<p>Contrary to what it might seem like, this isn't me trying to get
<em>everyone</em> reading to start using GitLab instead of GitHub ---
just <em>some</em> people. Specifically, if you're doing
organization-style stuff you might want to check out GitLab. But if
you're just a beginner with two wholly unrelated repositories, the
granular level of control GitLab gives you is probably not necessary
<em>yet</em>.</p>
<p>Something I never mentioned yet is that GitLab makes it very easy to
import your GitHub repositories. This made it a lot easier for me to
migrate over, but if you have more projects you may want to consider
scripting with GLab instead and doing everything on the terminal.</p>
<h3 id="addendum">Addendum</h3>
<p>Update from Dec 5 2021: Apparently you cannot create subgroups under
a user. This kinda sucks, and apparently <a
href="https://gitlab.com/gitlab-org/gitlab/-/issues/19944">I'm not the
only one who thinks this</a>. The workaround I'm using is just making a
group called 'chennisden' but that's kinda nasty to be honest.</p>
<section id="footnotes" class="footnotes footnotes-end-of-document"
role="doc-endnotes">
<hr />
<ol>
<li id="fn1"><p>The reason I'm going to stay on GitLab even for personal
projects or one-project groups is because of <em>consistency</em>. It's
easier to use the same service for everything, and GitLab is perfectly
good even when you don't have complicated directory structures. And even
then, I might realize that I need a group or some subgroups (see the
disastrous organization of my TeX repos in GitHub), and I can just move
stuff.<a href="#fnref1" class="footnote-back"
role="doc-backlink">↩︎</a></p></li>
<li id="fn2"><p>It's possible to write a script that uses <a
href="https://docs.github.com/en/rest/reference/actions#enable-a-selected-repository-for-github-actions-in-an-organization">GitHub's
API</a> to programmatically grant access to your team in, say, every
folder in a directory. But at this point you're better off managing your
own Git server, whereas on GitLab, permissions are <em>inherited</em>.<a
href="#fnref2" class="footnote-back" role="doc-backlink">↩︎</a></p></li>
<li id="fn3"><p>The one exception, though, is authentication: GitHub
forces you to authenticate with an SSH key, whereas in GitLab, you can
just use a plain username/password combo.<a href="#fnref3"
class="footnote-back" role="doc-backlink">↩︎</a></p></li>
</ol>
</section>]]></description>
	<pubDate>9 Nov 2021</pubDate>
</item>
<item>
	<title>My First Puzzle</title>
	<link>https://dennisc.net/writing/blog/my-first-puzzle.md</link>
	<description><![CDATA[<style>
img {
    margin-left: 0;
    width: 40%;
    height: 40%;
}
</style>
<p><em>Spoilers ahead for <a href="/puzzles/x-marks-the-spot/penpa">X
Marks the Spot</a>, so please try it yourself first! It is 4 or 4.5
stars in difficulty and is a thermo/arrows sudoku puzzle with no numbers
given. This post won't make much sense until you've finished it
anyway.</em></p>
<p><em>Many thanks to all my testsolvers! Without you, I would've posted
a broken puzzle --- thanks for taking the time to do the puzzle even
after the first version was broken.</em></p>
<p>Recently I've been doing a lot of sudoku puzzles on sites like
gm-puzzles, and I noticed that long thermos/long arrows are particularly
constraining. (I mean, duh.) So I thought, "huh, what if I slammed down
a long thermo and arrow, and had them intersect?"</p>
<p><img src="1.png" alt="First step of puzzle construction"></p>
<p>This has the added bonus of creating the theme, "X Marks the Spot",
and cool stuff <em>probably</em> happens because of it, so I'll build
the rest of the puzzle around this. (This cool stuff ends up becoming
the logic in the cross in the final puzzle.)</p>
<p>(You might see that the thermo doesn't match what's on the final
draft. I only realize it doesn't need to be this long later.)</p>
<p>Now I have some ideas of bounding the center, determining a large
portion of the thermo. I know this isn't enough though, so I just throw
some random crap at the wall.</p>
<p><img src="2.png" alt="Second step of puzzle construction"></p>
<p>You will notice that the two rightmost arrows seem very constraining
--- and that is exactly so! Even though I randomly added them, I had the
instinct that they would be the most helpful. So I do a bit of logicking
and discover the following:</p>
<p><img src="2-logic.png" alt="Some logic after the second step of puzzle construction"></p>
<p>This is based on the idea that the two thermos have to add up to at
least 16. There are 5 numbers on in arrow in the rightmost column, and
the five smallest numbers add up to 15. Add the other number on the
arrow which is at least 1, and the sum of the circles is at least
16.</p>
<p>At this point, everything besides the thermos and the rightmost
arrows is irrelevant. Note that A and B represent 1 and 2 in some order.
The important problem is this: in the rightmost row, the smallest
numbers on the bottom arrow are B, 3, and 4, meaning that the sum in the
circle is 7+B. But also note that the sum in the center arrow is
B+A+4+B=7+B, contradiction. Crap.</p>
<p>Well, what if we make the thermo a little shorter?</p>
<p><img src="3.png" alt="Third step of puzzle construction"></p>
<p>(I removed the arrows that weren't doing anything at this point,
because now I'd honed in on some actual ideas I could work around.)</p>
<p>Okay, now we have some numbers determined, but this isn't nearly
enough. Time to constrain things a little more. This time, instead of
throwing crap at the wall, I deliberately force 1 and 2 to not be in the
center row.</p>
<p><img src="4.png" alt="Fourth step of puzzle construction"></p>
<p>Now I come up with the idea to restrain the locations of 1 and 2 in
the center row. I notice the 1 and 2 in the third column and immediately
realize the most natural way to do it is with a thermo.</p>
<p>After some more logic, however, I find that it doesn't work.</p>
<p><img src="4-fails.png" alt="Fourth step of puzzle construction fails"></p>
<p>There's nowhere the 5 can go in the center row (check the thermo).
The solution I eventually come up with is flipping the thermo a la the
final puzzle, but first I shorten the thermo, forget that I can have 2
in the row now that the thermo is shortened, and send this ill-fated
first draft to my testsolvers.</p>
<p><img src="draft-1.png" alt="Failed first draft"></p>
<p>However, this failed draft did give me something --- the ideas with
the arrow on the bottom and the diamond arrow on top (since 7, 9 were
restricted on the second row, 1, 2, on the third row, and 1, 2, 3, on
the third column) which I thought were cool and still tried to preserve
in the final draft.</p>
<p>Eventually I settle on doing the right thing --- flipping the
thermo.</p>
<p><img src="5.png" alt="Fifth step of puzzle construction"></p>
<p>At this point, I bring back the arrows, because I still think it's
underconstrained anyway (it is) and want to add them back and adapt to
the new circumstances. I quickly realize the bottom arrow is not
constrained enough.</p>
<p><img src="6.png" alt="Sixth step of puzzle construction"></p>
<p>So I bend the bottom arrow to constrain the first number to be 1 or 2
again.</p>
<p><img src="7.png" alt="Seventh step of puzzle construction"></p>
<p>Now some logic:</p>
<p><img src="7-logic.png" alt="Some logic after the seventh step of puzzle construction"></p>
<p>There are a lot of steps, many of which align with the final puzzle:
the fact that 3 is in the bottom of the bottom arrow and so on. I won't
lie, a lot of these deductions went over my head when I was constructing
the puzzle at the end until I used a computer to find some common
similarities between all the possible solutions.</p>
<p>After some more computer analysis, I concluded that adding a thermo
would finish the puzzle.</p>
<p><img src="/puzzles/x-marks-the-spot/puzzle.png" alt="Final puzzle"></p>
<p>The end.</p>
<h2 id="future">Future</h2>
<p>I'd always intended this to be a one-off thing, at least until I
finished. I wanted to make the most out of the ideas I had... and I
would've followed my plan, had I not thought of an even more crazy
puzzle idea. This one will take a while longer, as the logic is so
intricate that even I'm currently stumped by it. Look forward to at
least one more release!</p>]]></description>
	<pubDate>3 Nov 2022</pubDate>
</item>
<item>
	<title>Modifiers</title>
	<link>https://dennisc.net/writing/essays/modifiers.md</link>
	<description><![CDATA[<p>There is plenty of advice telling you to drop
modifiers such as "I think" from your speech and writing. There is
virtually no one telling you to do the opposite, which is a shame, since
modifiers are quite useful for communicating.</p>
<p>If an honest writer drops the modifiers in their writing, just like
their teachers tell them to, they typically also drop its nuances. Any
essay consisting only of absolute, unqualified truths is not worth
reading. <a href="/writing/essays/hook">It's not even worth writing</a>.
That's why every high school English paper looks like it was written by
an elementary schooler. It's not because the author is a dunce. It's
because they don't allow themselves to say anything a dunce doesn't
already know.</p>
<p>Besides the obvious function of modifying a statement, modifiers have
another use: pacing. When you say "I think" or "maybe" it weakens the
statement. When you omit modifiers and pointedly deliver a line, you
emphasize it. But why would you want to express weakness in your
argument? Because it helps you communicate clearly. What do you think,
and what do you <em>know</em>? What's concrete advice, and what's just a
potential option?</p>
<p>Any advice telling you to discard a tool that creates variety is
almost always wrong. You might not think removing modifiers would change
the substance of your writing all that much. But if you want to write
better, you have to change the way you write. (Or in this case, you have
to stop letting your English teacher change the way you write.)
Sometimes a modifier might not seem to convey any additional
information. But modifiers aren't just a matter of practicality, they're
a matter of style.</p>
<p>And I think it makes for damn good style.</p>]]></description>
	<pubDate>6 Dec 2021</pubDate>
</item>
<item>
	<title>Getting my email to work again (after a year)</title>
	<link>https://dennisc.net/writing/tech/mail-fix.md</link>
	<description><![CDATA[<p><strong>UPDATE</strong> dchen@dennisc.net is
back!</p>
<p><strong>TL;DR use reychen@dennisc.net from now on</strong></p>
<p>Well! After some failed experiments with self-hosting on bare metal
(which I may try again at some point in my life, once I actually have
stable housing), I realized I haven't been able to send email, only
receive. I had no idea what was happening and didn't really dig into it
because I was a bit busy dying at college. But now I know what's
happened, and for now I'm using Zoho to have a functional email address.
The self hosting experiment may continue at some point in the future,
probably <em>after</em> I graduate.</p>
<p>To anyone whose emails I haven't responded to: my apologies!
Particularly if it concerns teaching. I have been really busy lately,
but now that my email actually works, please feel free to send your
email again. (Any emails sent in the past year or so have forever been
lost to time, so please paste the <em>full</em> body of any relevant
emails.)</p>
<h2 id="so-what-happened">so what happened?</h2>
<p>It's a pretty boring story. I could receive emails and not send them,
and that was because Vultr silently blocked port 587.<a href="#fn1"
class="footnote-ref" id="fnref1" role="doc-noteref"><sup>1</sup></a> I
eventually realize this is the case when I try actually reading the
messages and pinging port 25/587, and getting no response. A quick
internet search confirms that my suspicions were right. A month or so
later, I decide to actually get down to fixing it.</p>
<p>However, Zoho is... more than a little buggy. For some unknown
reason, it believes that <code>dchen@dennisc.net</code> is a used alias
when it is not. And I really cannot be bothered to figure out what is
actually going on, so here we are.</p>
<section id="footnotes" class="footnotes footnotes-end-of-document"
role="doc-endnotes">
<hr />
<ol>
<li id="fn1"><p>I am quite annoyed that this happened without prominent
notice, but it may also be because I wasn't paying attention/was
self-hosting at the time.<a href="#fnref1" class="footnote-back"
role="doc-backlink">↩︎</a></p></li>
</ol>
</section>]]></description>
	<pubDate>18 Jun 2025</pubDate>
</item>
<item>
	<title>Fast vs. short</title>
	<link>https://dennisc.net/writing/essays/fast.md</link>
	<description><![CDATA[<p>The goal of writing is to communicate ideas
efficiently, both to others and to yourself. A lot of people think that
efficient communication means less words, maybe because they've been
conditioned to by the word limits plastered in every process. But
efficient communication is about having your words be read and
understood as fast as possible, not word golf.</p>]]></description>
	<pubDate>30 Aug 2022</pubDate>
</item>
<item>
	<title>Use the most specific word possible</title>
	<link>https://dennisc.net/writing/essays/specific.md</link>
	<description><![CDATA[<p><em>The premise of this essay will seem
extremely obvious, but this is a concept too few people have drilled
into their head.</em></p>
<p>Today a student in my Fall 2023 AIME course submitted some solution
writeups which contained the following line:<a href="#fn1"
class="footnote-ref" id="fnref1" role="doc-noteref"><sup>1</sup></a></p>
<blockquote>
<p>We can simplify <span
class="math inline"><em>x</em><sup>2</sup> + <em>x</em><em>y</em></span>
into <span
class="math inline"><em>x</em>(<em>x</em> + <em>y</em>)</span>.</p>
</blockquote>
<p>And the gist of my feedback was,</p>
<blockquote>
<p>Instead of saying <em>simplify</em>, it's better to say
<em>factor</em>.</p>
<p>Imagine you are teaching a class to students. And you say "do a thing
to this thing and get a thing" instead of saying "apply the function
<span class="math inline"><em>f</em></span> to the integer <span
class="math inline"><em>x</em></span> and receive a string". Very
unspecific, right?</p>
<p>In my eyes, "we can simplify" is like that. It could mean a bunch of
things: you could be expanding a factored polynomial, factoring an
expanded polynomial, cancelling terms, etc. It's basically the same as
"we do a thing to the equation". What thing?</p>
<p>When the word "factor" is used, it is much clearer.</p>
</blockquote>
<p>To be clear, the proof was written very well (which is why I bothered
to be nitpicky like this). But this is a good segue into some thoughts I
have about proofs and communication, so I'll use it as an excuse to talk
about them.</p>
<p>Being <em>clear</em> in a proof is the most important thing. Sure, it
should be reasonably correct, in that it shouldn't claim anything that's
untrue and should be reasonably<a href="#fn2" class="footnote-ref"
id="fnref2" role="doc-noteref"><sup>2</sup></a> complete. But the
primary responsibility of a proof-writer is to make it clear, "Hey this
is what I am doing right here and now," at every step of the proof. Yes,
compromises need to be made between being explanatory and being concise.
But using the most specific word possible is being more explanatory
without being any less concise. In other words, it is an improvement you
can get for free, so take it.</p>
<p>Pedantic? Yes. But when you're proving something, your job is not to
say "and the things I said are <em>right</em>". It is for the reader to
say, "I see what you did, I am convinced it is correct, and I get what
you're doing." So even if being more specific doesn't make your proof
more correct, it is still just as valuable.</p>
<section id="footnotes" class="footnotes footnotes-end-of-document"
role="doc-endnotes">
<hr />
<ol>
<li id="fn1"><p>I'm simplifying this example (i.e. making up all of the
details) because the actual factorization doesn't matter; just the word
choice.<a href="#fnref1" class="footnote-back"
role="doc-backlink">↩︎</a></p></li>
<li id="fn2"><p>"Reasonably" because fully proving some things like the
Soundness Theorem would be a major pain in the ass. Especially in cases
like these, the <em>vibes</em> of these proofs are more important than
the details. No one cares about the details, they are trivial once you
get the vibe down.<a href="#fnref2" class="footnote-back"
role="doc-backlink">↩︎</a></p></li>
</ol>
</section>]]></description>
	<pubDate>1 Oct 2023</pubDate>
</item>
<item>
	<title>Compactness in model theory</title>
	<link>https://dennisc.net/writing/blog/model-compactness.md</link>
	<description><![CDATA[<p><em>This is the second in a series of posts
about model theory.</em></p>
<p><a href="/writing/blog/many-worlds">Last time</a> we discussed the
limitations of mathematical logic and how it leads to many worlds of
mathematics, regardless of whatever system of rules we choose. This
time, we will discuss a theorem known as <strong>compactness</strong>
which allows us to do some powerful things in mathematics, as well as
demonstrate some more limitations of first order logic.</p>
<p>To motivate this, let's start with a theorem:</p>
<blockquote>
<p>If every finite subgraph of an infinite graph is <span
class="math inline"><em>k</em></span>-colorable, then the entire graph
is <span class="math inline"><em>k</em></span>-colorable.</p>
</blockquote>
<p>At first glance this is not obvious. But with compactness, we will be
able to show this very easily.</p>
<h2 id="terminology">Terminology</h2>
<p>Before we dive into compactness, let me first informally define some
terminology.</p>
<ol type="1">
<li>A <strong>theory</strong> is a set of rules. It is a purely
syntactic object.</li>
<li>A <strong>model</strong> of a theory is a concrete mathematical
object that satisfies the theory's rules.</li>
</ol>
<p>For example, the vector space axioms form <strong>the theory of
vector spaces</strong>, and <span
class="math inline">ℝ<sup>3</sup></span> is a <strong>model</strong> of
this theory.</p>
<h2 id="compactness">Compactness</h2>
<p>Suppose we have an inconsistent theory. That means we may derive a
contradiction. The important thing about a contradiction is that it is
<em>finite</em>, as it is a proof of a false statement, and every proof
is a finite sequence of steps. This means that the contradiction must
reference a finite number of rules.</p>
<p>Therefore, if a theory is inconsistent, it has a finite inconsistent
subtheory. Taking the converse of this statement, we get the
following:</p>
<blockquote>
<p>A theory is consistent if every finite subtheory is consistent.</p>
</blockquote>
<p>How does this prove our theorem? Here is how we do it: given a graph
<span class="math inline"><em>G</em></span>, we construct a theory that
describes <span class="math inline"><em>k</em></span>-colorings of <span
class="math inline"><em>G</em></span>. If it is consistent, then Godel's
Completeness says <span class="math inline"><em>G</em></span> is <span
class="math inline"><em>k</em></span>-colorable.</p>
<p>Let me be a little more descriptive: our theory describes functions
from <span class="math inline"><em>V</em></span> (the set of vertices of
<span class="math inline"><em>G</em></span>) to the set <span
class="math inline">1, …, <em>k</em></span>. For every edge <span
class="math inline">(<em>u</em>, <em>v</em>) ∈ <em>E</em></span> (the
set of edges of <span class="math inline"><em>G</em></span>), we have
the following rule: the color of <span
class="math inline"><em>u</em></span> must not equal the color of <span
class="math inline"><em>v</em></span> (more formally, <span
class="math inline"><em>f</em>(<em>u</em>) ≠ <em>f</em>(<em>v</em>)</span>).</p>
<p>To show the consistency of this theory, we just need to show the
consistency of every finite subtheory. Each finite subtheory only
references a finite number of vertices, say <span
class="math inline"><em>S</em></span>. And by assumption, the finite
subgraph <span class="math inline"><em>S</em></span> is <span
class="math inline"><em>k</em></span>-colorable, so the finite theory
has a model. Therefore, it must be consistent.</p>
<p>And we have just proved the theorem!</p>
<h2 id="upwards-lowenheim-skolem">Upwards Lowenheim-Skolem</h2>
<p><em>Aka: Blowing up models of a theory.</em></p>
<p>There is a theorem that roughly says the following:</p>
<blockquote>
<p>If I have a theory <span class="math inline"><em>T</em></span> and an
<strong>infinite</strong> model <span
class="math inline"><em>M</em></span> of <span
class="math inline"><em>T</em></span>, then I can construct a model
<span class="math inline"><em>M</em><sup>′</sup></span> of <span
class="math inline"><em>T</em></span> that is as big as I wish.</p>
</blockquote>
<p>Here is how you prove it: consider the theory <span
class="math inline"><em>T</em><sup>′</sup></span> that consists of the
rules in <span class="math inline"><em>T</em></span>, as well as some
rules expressing "I have <span class="math inline"><em>λ</em></span>
many elements, and all of them are distinct." (Here <span
class="math inline"><em>λ</em></span> is a cardinality.) The sentences
we use to specify they are distinct is "element <span
class="math inline"><em>c</em><sub><em>i</em></sub></span> and element
<span class="math inline"><em>c</em><sub><em>j</em></sub></span> are not
equal" for every pair of elements <span
class="math inline"><em>c</em><sub><em>i</em></sub>, <em>c</em><sub><em>j</em></sub></span>
whose existences we mandate.<a href="#fn1" class="footnote-ref"
id="fnref1" role="doc-noteref"><sup>1</sup></a></p>
<p>If we have a model of <span
class="math inline"><em>T</em><sup>′</sup></span>, then it is also a
model of <span class="math inline"><em>T</em></span> with <span
class="math inline"><em>λ</em></span> many elements. By Godel's
Completeness, we just need to show <span
class="math inline"><em>T</em><sup>′</sup></span> is consistent. And by
compactness, we just need to appeal to finite subtheories.</p>
<p>Note that any finite subtheory references a finite number of elements
<span class="math inline"><em>c</em><sub><em>i</em></sub></span>.
Therefore, all we need to do is have a finite number of distinct
elements in our model of this finite subtheory. But since <span
class="math inline"><em>M</em></span> is infinite, it already does the
trick.</p>
<h2 id="limitations-of-first-order-logic">Limitations of first-order
logic</h2>
<p>You may know about the Archimedean property of an ordered field,
which states</p>
<blockquote>
<p>A field <span class="math inline"><em>F</em></span> is Archimedean if
for every <span class="math inline"><em>x</em> ∈ <em>F</em></span>,
there is some <span class="math inline"><em>n</em> ∈ ℕ</span> such that
<span class="math inline"><em>n</em> &gt; <em>x</em></span>.</p>
</blockquote>
<p>In English, it states that for every element of the field, there is a
larger natural number. Most ordered fields you know are Archimedean;
think the rationals and reals.</p>
<p>In propositional logic, we can write things such as "<span
class="math inline"><em>p</em> ⟹ <em>q</em></span>". First-order logic
allows us to access the entire universe of our model: for instance, if
we are working in the theory of ordered fields, then we can write
statements such as "for all elements <span
class="math inline"><em>x</em></span> in our field <span
class="math inline"><em>F</em></span>, if <span
class="math inline"><em>x</em></span> is not <span
class="math inline">0</span>, then <span
class="math inline"><em>x</em></span> has an inverse; furthermore, that
inverse has the same sign as <span
class="math inline"><em>x</em></span>."</p>
<p>The Archimedean property is what we call a "second-order property".
This is because we have two <em>universes</em> we are quantifying over:
we are writing <span
class="math inline">∀<em>x</em> ∈ <em>F</em></span>, which is
quantifying over <span class="math inline"><em>F</em></span>
(first-order), but then we have <span
class="math inline">∃<em>n</em> ∈ ℕ</span>, and quantifying over <span
class="math inline">ℕ</span> is <em>not</em> something you can do in
first order logic.</p>
<p>You may try to express the Archimedean property in first order logic.
You may even try to establish a theory with an <em>infinite</em> number
of sentences that is equivalent to being Archimedean (i.e. if it is
satisfied, then the ordered field is Archimedean, and if it is not
satisfied, then the ordered field is not Archimedean). Both of these
will fail. Is there a way to prove this?</p>
<p>It turns out Upwards Lowenheim Skolem gives us a very easy way to
prove this. There is one important thing you need to know: every
Archimedean field is isomorphic to a subfield of <span
class="math inline">ℝ</span>. In particular, this means that no
Archimedean field has a bigger cardinality. Just take this fact for
granted.</p>
<p>Great. Now assume for the sake of contradiction that there is some
theory of <em>Archimedean</em> ordered fields. We have an infinite
Archimedean ordered field: <span class="math inline">ℝ</span>. Now blow
it up to a model with cardinality larger than <span
class="math inline">|ℝ|</span> that satisfies this theory,
contradiction.</p>
<p>There are other properties that cannot be expressed in the language
of first order logic. Two of them are the phrase "this field is
algebraic" and "this ordering is a well-ordering". And the way we prove
neither of these are expressible is quite similar to the proof for the
Archimedean property.</p>
<section id="footnotes" class="footnotes footnotes-end-of-document"
role="doc-endnotes">
<hr />
<ol>
<li id="fn1"><p>This part is a little loosey-goosey: I have skipped over
a lot of technical setup to make this series more approachable without
talking precisely about what a "language" is in model theory. I chose to
make this tradeoff because the point is to showcase some of the cooler,
more easily accessible aspects of model theory without getting drowned
in technicalities. There are a plethora of books that develop this
subject in greater detail, so I will not tread the same path as them.<a
href="#fnref1" class="footnote-back" role="doc-backlink">↩︎</a></p></li>
</ol>
</section>]]></description>
	<pubDate>27 May 2025</pubDate>
</item>
<item>
	<title>Arch Install Primer</title>
	<link>https://dennisc.net/writing/tech/arch-install.md</link>
	<description><![CDATA[<p>This is not an instruction manual on how to
install Arch Linux, it's simply a big picture explanation of what the
steps sum up to. Meant for beginners, but this post answers "how" and
not "why" you would install Arch.</p>
<p><a href="https://www.youtube.com/watch?v=1XBqhMLsXYk">EF --- Linux
Made Simple</a></p>
<h2 id="list">List</h2>
<ul>
<li>Partition your disk</li>
<li>Boot into ISO (can be swapped with partitioning disk, not
recommended for beginners)- Mount the appropriate filesystems</li>
<li>Pacstrap into the mounted filesystem</li>
<li>Chroot into the mounted filesystem and perform setup operations
(timezone, keyboard, locale, etc)</li>
</ul>
<h2 id="why">Why?</h2>
<h3 id="partitioning">Partitioning</h3>
<p>You are installing Arch Linux <em>to</em> somewhere, and it has to be
somewhere on your hard drive. (Or SSD if you use that.) When you are
partitioning your disk you are telling your system "an OS is installed
here". So you basically create a place for the OS to be installed,
before you actually install it.</p>
<h3 id="boot-into-iso">Boot into ISO</h3>
<p>The ISO <em>itself</em> is an operating system, though incredibly
minimalist.<a href="#fn1" class="footnote-ref" id="fnref1"
role="doc-noteref"><sup>1</sup></a> What's useful is the scripts inside
it. The scripts don't even have to be contained in a separate OS --- you
could just package a set of scripts that installs the OS to the
appropriate partition. (In fact, if you are already using Linux, you can
do this!) The reason that installing through an ISO is popular is
because of accessibility. Most people, <em>especially</em> those
installing Linux for the first time, are using a shitty OS like Windows
or Mac (which tends to be why they switch). Said operating systems make
it harder (particularly Windows) to install the necessary tools than it
needs to be, and packaging everything in an ISO is just better for
uniformity.</p>
<h3 id="mounting">Mounting</h3>
<p>This one is the hardest to explain.</p>
<p>To access a filesystem in Linux you have to mount it. Your partition
that you want to install Linux is a filesystem. By mounting your
filesystem, you expose it to the current directory tree.</p>
<h3 id="pacstrap">Pacstrap</h3>
<p>By running <code>pacstrap</code> you are installing some base
packages <em>into your mounted filesystem</em>, i.e. where your new Arch
operating system will reside. <code>pacstrap</code> is one of those
utilities provided to you by the ISO, so it should not be surprising
that it doesn't exist anymore when you chroot (since you no longer need
it).</p>
<h3 id="chroot-setup">Chroot + Setup</h3>
<p>Chrooting is largely for convenience, theoretically you could
probably install Linux without chrooting.<a href="#fn2"
class="footnote-ref" id="fnref2" role="doc-noteref"><sup>2</sup></a> (It
would be really annoying to do so.) Basically, by chrooting, you are
entering the filesystem of your new OS, exposing its commands to you.
For instance, the essential commands provided to you by
<code>pacstrap</code>.</p>
<p>You should know that <strong>when you chroot, you are essentially
running inside the OS that you installed on your desktop.</strong>
Beforehand, you are running inside the live boot environment, which is
an OS that you installed on your USB stick <strong>in order to install
Arch Linux to your desktop</strong>. So you will not be able to get
access to the live-environment tools once you arch-chroot (which is
typically why you do that last; you are supposed to arch-chroot once you
no longer need the live environment).</p>
<p>This is also why you can't run <code>iwctl</code> after chrooting or
when booting into your Arch Linux install <em>without</em> the USB
stick, because that tool wasn't installed into your OS; it only exists
inside the live install environment.<a href="#fn3" class="footnote-ref"
id="fnref3" role="doc-noteref"><sup>3</sup></a></p>
<p>Some of the setup (locale, timezone, keyboard) is non-essential,
especially if you use a QWERTY US keyboard by default. You are just
setting some system preferences, it does not really matter if you do it
now or later. (Best to do it now though, so you can take care of
everything at once, but if you somehow find yourself screwing it up
that's ok.)</p>
<p>Other parts of the setup are essential. For instance, the bootloader
is what helps you boot Linux properly. And the hostname file is also
important since it helps you connect to the internet.</p>
<h2 id="after-install">After Install</h2>
<p>Don't pay too much attention to this section until you have finished
your Arch Linux install.</p>
<p>After the installation process you have a very minimal installation
of Arch Linux. All it does it boot, you literally do not even have Vim.
At best you set up wifi before you rebooted your system.</p>
<p>At the very least you want a graphical interface which allows you to
display windows of programs. To do this, you need a window system at the
bare minimum, like X11 or Wayland. You <em>probably</em> want X11,
though Wayland is the future.</p>
<p>If you want a traditional desktop environment (Windows and Mac both
have traditional desktop environments), you can install Gnome, KDE,
XFCE, etc. I recommend you pick something lightweight or else boot times
are going to start to resemble Windows machines. If you do decide to do
this, you don't need to worry about X11/Wayland.</p>
<p>I strongly recommend you get a tiling window manager (TWM) instead
though. For X11, you have i3, Xmonad, dwm, awesomewm, etc. Wayland has
some window managers too, like Sway (based on i3), dwl (based on dwm),
etc, but the selection size is smaller. It's hard to explain why a TWM
is so good, and I certainly won't try to, google it yourself if you're
interested.</p>
<p>You need a terminal emulator too. If you are using a desktop
environment, one is typically provided for you so you can ignore this.
But if you are using a tiling WM, some popular choices are Alacritty,
kitty, urxvt, tmux, etc. I personally use Alacritty because it has sane
defaults + I don't need tiling in Alacritty because I use a TWM.</p>
<p>You are also going to want to install some programs, like Vim (to
edit text), Firefox/Surf/Links2 (for browsing), TeX Live/Tectonic
(typesetting TeX files), etc. But this is increasingly swaying further
away from the install process, so I will end this post here.</p>
<section id="footnotes" class="footnotes footnotes-end-of-document"
role="doc-endnotes">
<hr />
<ol>
<li id="fn1"><p>If you've ever wondered why Ubuntu's ISO is so goddamn
fat, it's because Ubuntu's ISO comes with a graphical environment. Among
other things.<a href="#fnref1" class="footnote-back"
role="doc-backlink">↩︎</a></p></li>
<li id="fn2"><p>You could probably just do this by prepending /mnt to
the correct paths when executing commands.<a href="#fnref2"
class="footnote-back" role="doc-backlink">↩︎</a></p></li>
<li id="fn3"><p>Networking is (in)famously regarded as being difficult
to set up on Arch Linux. But it really isn't. You have to understand
that you have to setup your network twice for two different reasons:
once in the live install so you can properly pacstrap into your new
Linux partition, and another time in the chroot so that you can use the
internet inside your new OS.<a href="#fnref3" class="footnote-back"
role="doc-backlink">↩︎</a></p></li>
</ol>
</section>]]></description>
	<pubDate>9 Mar 2022</pubDate>
</item>
<item>
	<title>February 2023 Updates</title>
	<link>https://dennisc.net/writing/blog/feb-2023-updates.md</link>
	<description><![CDATA[<p>It's been quite a hectic month and some pretty
cool things have happened. I've also got a couple of projects
planned.</p>
<h2 id="puzzle-goals">Puzzle Goals</h2>
<p>It's midway through February and I think this challenge is going to
be pretty hard because of what I've enjoyed setting lately (Killer
Cages). As a refresher, the original goal was to use 4 new variants,
whether classic or my own invention. I'm weakly considering changing it
to 4 <em>common</em> variants that I haven't used before, like Quads or
Sandwich. But either way you count it, I'm behind.</p>
<p>On January 31st I sniped myself by setting Genome: I used Renban
Lines and Kropki, two easy constraints. (Hey, it's good to make the
setting challenge a bit hard for myself!) And right now, I've mostly
been setting Killer Cage puzzles along with a few Star Battles, so I'm
not exactly treading a lot of new ground variant-wise here. But
honestly, I'm not too concerned about failing, because I can just
arbitrarily extend the challenge or move it to a different month or
something. (Not like I've figured out a challenge for every month anyway
--- not even close...)</p>
<p>Under the most generous interpretation, I've set puzzles with two new
variants: Diagonals (classic) and <a
href="/puzzles/x-lines/sudokupad">X-Lines</a>. Right now I'm trying to
set a Thermo Quad<a href="#fn1" class="footnote-ref" id="fnref1"
role="doc-noteref"><sup>1</sup></a>, and Fortress, Extra Regions, and
Sandwich also seem promising.</p>
<p>Oh, and check out <a
href="https://logic-masters.de/Raetselportal/Raetsel/zeigen.php?id=000CZD">Class
of '23</a>.</p>
<h3 id="puzzle-book">Puzzle Book</h3>
<p>For the puzzle book, I will probably include some classic sudoku and
killer cage sudoku even though the focus is on "homemade variants". Two
reasons: one, a lot of my puzzles use cages or at least arithmetic (and
obviously all sudoku puzzles use sudoku, so classic is always good), and
two, it helps pad the length of the book :)</p>
<p>Also, I'd like to think that I'd include Highway, Stairs, Class of
'23, etc, because otherwise that means I've made no progress this entire
month. (Well, that wouldn't be true, I invented X-Lines two days ago so
now I have more flexibility.)</p>
<h2 id="math-things">Math things</h2>
<p>Objectively speaking, I don't know much math. Most of my friends that
do math have finished at least abstract algebra and real anaysis, and I
have not really done either. So I plan to read a book on one of these
--- probably linear algebra --- and type up a few notes. On the bright
side, I think linear algebra has finally clicked for me. Turns out, that
all I had to do was keep repeating to myself that matrices are linear
functions from <span
class="math inline">ℝ<sup><em>m</em></sup> → ℝ<sup><em>n</em></sup></span>,
that's all.</p>
<p>Math Advance has been in a lull lately, especially since our
leadership is concentrated in the class of '23. I also need to collate
Winter MAT results, hopefully that will happen soon. The Summer MAT is
taking longer to start writing than usual (mid-February and still only
initial drafting stages, as opposed to sending out serious drafts in
December the last two years), so we need to get that going fairly
quickly.</p>
<h2 id="code-stuff">Code stuff</h2>
<h3 id="mapm">mapm</h3>
<p>Yesterday I adjusted mapm to support multiple choice tests and today
I released mapm 6.1.0, which has MC support. I also fixed the bug where
<code>mapm preview</code> and <code>mapm preview-all</code> don't care
if the problem doesn't satisfy the preview template's variable
requirements.</p>
<p>As for how many people (or rather how few) people are using mapm, I
think most people are uninterested in setting up mapm on their own
computers, especially the people who are not good with computers (and
math contest kids, by and large, are bad with computers). Even asking
people to install a GUI would be a pretty tough ask, so I think I'm
going to write a web host to import/export problems from instead.</p>
<p>The benefits of writing a web host besides increased adoption is that
LaTeX in non-HTML GUIs is hell, and I don't really want to use Tauri for
a GUI because that would be pretty cursed. I'll do the research (and
maybe some of the work for) LaTeX in GUI but this will probably be after
Glee is stable and the mapm web client is done.</p>
<h2 id="glee">Glee</h2>
<p>(This is mostly hardware stuff.)</p>
<p>I'm participating in Hack Club's Winter Wonderland, a hardware event
that lasts for 10 days. Right now I need to get my Orange Pi set up in
some trivial way, so that I can move on to getting the
temperature/humidity sensor, establishing a static IP address/routing
through a static address that hopefully our ISP is providing us (more
research needed here), and migrating some less mission-critical
projects, like mathadvance.org, dennisc.net --- mostly static websites
--- to the physical server.</p>
<p>Glee itself will obviously take more than 10 days, but I might try to
get something rudimentary set up during this 10 day span. Of course, I
can and do intend to continue working on it even after the event.</p>
<h2 id="crosswords">Crosswords</h2>
<p>Just something miscellaneous that I wanted to add: crossword
construction seems pretty interesting. Unlike Sudoku, whereI think I
have a handle on what makes a good puzzle, I don't have the slightest
clue about crosswords.<a href="#fn2" class="footnote-ref" id="fnref2"
role="doc-noteref"><sup>2</sup></a></p>
<p>For comparison, I started solving Sudokus pretty intensely for six
weeks or so before I tried setting my first puzzle, and even then I had
some experience prior to those six weeks.<a href="#fn3"
class="footnote-ref" id="fnref3" role="doc-noteref"><sup>3</sup></a>
Whereas my crossword experience mostly consists of failing to solve them
on airplanes and trying a couple these past few weeks.</p>
<p>Well, I think that's all for now. See you next time!</p>
<section id="footnotes" class="footnotes footnotes-end-of-document"
role="doc-endnotes">
<hr />
<ol>
<li id="fn1"><p>Funny story: I transferred my puzzle to paper and then
thought my logic was wrong. Turns out, I shifted one quad up a cell and
another quad down a cell...<a href="#fnref1" class="footnote-back"
role="doc-backlink">↩︎</a></p></li>
<li id="fn2"><p>Well, besides symmetry, but that's obvious.<a
href="#fnref2" class="footnote-back" role="doc-backlink">↩︎</a></p></li>
<li id="fn3"><p>I think I watched a little bit of CTC my freshman
year.<a href="#fnref3" class="footnote-back"
role="doc-backlink">↩︎</a></p></li>
</ol>
</section>]]></description>
	<pubDate>16 Feb 2023</pubDate>
</item>
<item>
	<title>Interregnum</title>
	<link>https://dennisc.net/writing/blog/interregnum.md</link>
	<description><![CDATA[<p><em>I wrote this in my notebook on April 1, but
haven't had the energy to type this up until tonight. Not a good sign of
how the rest of break will go, but oh well.</em></p>
<p>Yesterday, my last college decisions came out.</p>
<p>Yesterday, my school's spring break started.</p>
<p>It seems fair to describe this month as an interregnum, before high
school final exams and AP exams begin ramping up for the last time.
Before I have to make the one decision that <em>really matters</em> off
of very little information.</p>
<hr />
<p>A long time ago, I had the idea to share my college applications and
reflect on them in their entirety, hopefully providing useful advice to
future classes applying for college. But now, I don't have the energy to
do this, and nor do I think my college results are good enough to
justify giving advice. In fact, given my stats, I did really badly. So I
will merely describe rather than prescribe.</p>
<p><strong>Acceptances:</strong></p>
<ul>
<li>UCLA math</li>
<li>UCSD undeclared (rejected from CS)</li>
<li>UCI CS with honors</li>
<li>UCSB CS</li>
<li>UIUC math (rejected from CS)</li>
<li>UT Austin CS, Turing Scholars<a href="#fn1" class="footnote-ref"
id="fnref1" role="doc-noteref"><sup>1</sup></a></li>
<li>UWash "pre-major" with $5,400/yr scholarship (rejected from CS ---
so I'm good enough to get a scholarship but not good enough to study
CS...)</li>
<li>CMU CS</li>
</ul>
<p><strong>Rejections:</strong></p>
<ul>
<li>UCB (applied for math)</li>
<li>Cambridge math</li>
<li>All Ivies except Dartmouth and Penn</li>
<li>MIT/CalTech</li>
<li>Stanford</li>
<li>JHU</li>
<li>Harvey Mudd</li>
<li>GaTech (applied CS)</li>
<li>Duke</li>
</ul>
<p>So yeah, I had about a 33% acceptance rate, and taking out
safeties/CS rejections (because I'm not going to UWash to study not-CS)
plummets it to 10-15%. Interestingly, I expected to get screwed for CS
and decently for HYPSM, and the exact opposite happened. Surprising,
given my total lack of CS achievements. (No research/significant
projects --- where "significant" means sufficient reach/fame --- and
only USACO Silver, <em>before</em> difficulty inflated.)</p>
<hr />
<p>In some sense I've won. If I knew in August that I'd get into CMU CS,
I would've been really relieved --- relieved enough not to care about
the absolute slaughter I went through. (Also I'd be really confused why
future me is telling me about this Turing Scholars thing so
enthusiastically.)</p>
<p>In another sense, I've lost. I expected to get in some of HYPSM, and
there are definitely people who have a lot more choice than I do when
deciding where to go.</p>
<p>But the thing about college apps is it always feels like you're
losing. As long as I don't have to wonder, <em>what would've happened if
I got into a top college?</em> everything will be fine.</p>
<hr />
<p>CMU is apparently really strong at AI. Unfortunately I don't have
much interest in it (mostly because I despise applied math).</p>
<p>Maybe I'll change my mind in 4 years. Hopefully I do.</p>
<hr />
<p>For the last 4 years, I've been convinced that I was going to study
math and major in math and become this professor guy in math that does
Important Research.</p>
<p>But why was I so convinced? Probably because I figured out I was good
at math a long time ago, decided "OK and now I will like math", and then
went with it. So what if I got really good at CS in the next few months
and the next few years, and just decided to myself, "now I will like
CS"?</p>
<p>I find the theoretical stuff really interesting at least, even if I
don't know a lot about it. I hear it's basically just mathematicians
pretending to do Not Math. At the minimum, I should enjoy that...</p>
<hr />
<p>I'm probably going to CMU. But whichever of CMU and Austin I went to,
I'll feel like I'm missing out on something. CMU's core curriculum
aligns really well with my views on CS education, and it's ranked #1 for
CS --- that's gotta count for something. But Austin is a tech hub and
sends a ton of people to quant and will be a boatload of fun that I
will, with all probability, not experience.</p>
<p>If only I had two lives. If only I could experience both of these
universities.</p>
<p>If only I could study math at UCLA too. Once upon a time I was really
convinced I wanted to do math at a UC. Wouldn't it still be worth doing?
What fundamentally changed in the last 4 months?</p>
<p>I <em>am</em> very excited about going to CMU. But some part of me
<em>knows</em> that I'd also be really excited to go to Austin. What if
I end up sitting alone in my room for god knows how many days and asking
to myself, "what if I went to Austin instead, what if I didn't have 50
hours of work every week? What if I valued my mental state more than my
superficial ego?"</p>
<p>The scariest thing is, I won't ever find out if the grass
<em>was</em> greener on the other side. And there's a 50% chance that it
is.</p>
<hr />
<p>I don't know a lot of CS. Scratch that, I don't know a lot of
anything, including math.</p>
<p>I want to study ahead over the summer.</p>
<p>I want to work on the things that interest me. Finish up some
projects before school starts, because god knows I won't have the time
to do that in school.</p>
<p>I want to get the ball rolling before it's too late.</p>
<hr />
<p>I'm about to graduate. Some part of me is having trouble really
believing this.</p>
<p>I have two to three more months to make some final memories with
people in high school. Aside from a couple of outliers, I probably won't
ever talk to them ever again.</p>
<p>Near the end of WARP, I was intellectually aware that I'd never see
most these people again. But emotionally it never registered.</p>
<p>And I really mean never, not even now. I just said, "huh OK WARP is
forever over", and went back to my normal life. For a week, normal meant
sitting in the Lodge saying stupid shit with my friends. Climbing rocks.
Swimming in the pool. But now it's just a distant memory, something that
I know happened but don't really feel anything about.</p>
<p>I feel the same way about high school. Next year, I'll be looking
back at all four years of high school, and hell, maybe even middle
school, and just think "huh I guess these things happened. And I knew
these people." I don't think I'll really <em>miss</em> high school, even
though in the moment it was really fun. Junior year already feels like
an eternity away. Hell, even first semester senior year. I feel like it
was just yesterday that I was in middle school geometry, showing off
like the immature brat I was. Intellectually I know that all of high
school happened and I should probably treasure these memories or
whatever. But on an emotional level, I'm finding it hard to feel much of
anything. I mean, I'm excited for college and excited for more than 50%
of my classes not to be a steaming pile of fucking nonsense. But I don't
feel sad at all that I'm going to be leaving high school, even though
high school has been nothing short of great.</p>
<p>It's weird that I'll cry over a fucking imaginary pink elephant dying
in a kid's movie, but not over literally leaving everyone I have ever
known in my entire life.</p>
<p>Y'know what? I think it's probably OK.</p>
<p>But if you're from the area and I know you, and you're reading this,
let's hang out or something.</p>
<p>Before it's too late.</p>
<hr />
<p><em>Before it's too late. Before it's too late. Before it's too
late.</em></p>
<p>Why is it, when I've had for years to do these things, I decide to
wait until it's almost too late?</p>
<p>I should study math and CS.</p>
<p>I should finish my geometry book and Git hosting software.</p>
<p>I should say goodbye to some people.</p>
<p>But thinking and doing stuff is hard, and this <a
href="https://logic-masters.de/Raetselportal/Raetsel/zeigen.php?id=0008RD">Whispers
Skyscrapers</a> puzzle seems a lot more appealing.</p>
<section id="footnotes" class="footnotes footnotes-end-of-document"
role="doc-endnotes">
<hr />
<ol>
<li id="fn1"><p>If you haven't finished applying to college yet and you
don't know what Turing Scholars is, do yourself a favor and Google it.<a
href="#fnref1" class="footnote-back" role="doc-backlink">↩︎</a></p></li>
</ol>
</section>]]></description>
	<pubDate>4 Apr 2023</pubDate>
</item>
<item>
	<title>Git Tricks I Wish I Knew</title>
	<link>https://dennisc.net/writing/tech/git-tricks.md</link>
	<description><![CDATA[<p>When you first start using Git, everything goes
perfectly fine as long as you don't ever mess up. Perfect commit
messages right from the get-go, no temporary or throwaway commits needed
for any reason, never forgetting to pull, etc. But that's not how
reality works: often you will forget to commit files like an idiot and
your next commit message will read, "forgot to push files". Fortunately
Git has ways to correct these mistakes.</p>
<h2 id="for-beginners-git-add-and-commit">For beginners: git add and
commit</h2>
<p>Git's history is built on commits. The way you tell Git what you want
to commit next is through the staging area, and to add something to the
staging area you just run <code>git add</code>. Sometimes when a file
isn't being tracked by Git, <code>git add</code> will also make Git
track the file. This is why people run <code>git add --a</code> and then
<code>git commit -a -m "msg"</code> whenever they want to add a new
file. (Don't do this, by the way, it's terrible practice.)</p>
<p>You can do <code>git commit FILE</code> as a shortcut instead of
running <code>git add FILE; git commit</code>. But a lot of beginners do
not get the difference between <code>git add</code> and
<code>git commit</code>. If that describes you, try this for a day:
never add any arguments or flags after <code>git commit</code>, and
you'll get the idea really quick.</p>
<p>"Flags" includes <code>-m</code>, and if you're using said flag your
commit messages are probably not detailed enough. <strong>When editing
your commit message, you see what files are being committed</strong>.
That way, you will never accidentally commit a file you didn't mean to,
because you will have ample time to see exactly what you are
committing.</p>
<h2 id="global-.gitignore">Global .gitignore</h2>
<p>If you are a soydev on MacOS or Windows (Mac users are by far the
worst offenders), you probably have committed <code>.DS_Store</code> or
<code>desktop.ini</code> once in your lives. First off, that is a sign
your workflow is stupid and you don't know what you're doing: you should
never <code>git add --a; git commit -a</code> unless you
<strong>absolutely know what is being committed</strong>.<a href="#fn1"
class="footnote-ref" id="fnref1" role="doc-noteref"><sup>1</sup></a> But
even then, it's good to have some safety against ever committing garbage
like <code>.DS_Store</code>: you will never have a legitimate file named
<code>.DS_Store</code>, so it's perfectly fine to just
<code>gitignore</code> it.</p>
<p>But instead of adding it to the <code>.gitignore</code> of each
project, you can instead add it to your personal global
<code>.gitignore</code>. This means that, across all local repositories,
you will never be able to add any files in your personal gitignore to
the staging area.</p>
<p>You can read <a
href="https://gist.github.com/subfuzion/db7f57fff2fb6998a16c">this
GitHub Gist</a>, it's quite comprehensive. If you follow the links in
the comments you will also find the default locations for the git
config/ignore files. I will tell you explicitly that for Linux, you want
to create the files <code>~/.config/git/ignore</code> and
<code>~/.config/git/config</code>. If the directory
<code>~/.config/git</code> doesn't exist (it probably won't), make that
too.</p>
<p>What I recommend is you make a <code>git</code> repository in your
dotfiles, and then clone it in <code>~/.config</code>. (The repository
should then be <code>~/.config/git</code>.) This is not so feasible in
GitHub because you don't have nesting (groups and subgroups in <a
href="gitlab">GitLab</a>), but I still think you should make separate
repositories: your git config files have nothing to do with your vimrc
or whatever else you have.</p>
<p>Here is where my advice becomes more personal taste. I think your
project <code>.gitignore</code> should only contain things that
<em>everyone</em> will see. That's why my TeX projects don't have a
<code>.gitignore</code>; my build files all go inside a
<code>build</code> directory, because I use my own custom script called
<a
href="https://gitlab.com/chennisden/dotfiles/bin/dlatexmk">dlatexmk</a>.
And OS-specific files like <code>.DS_Store</code> definitely should not
be in a <code>.gitignore</code>.<a href="#fn2" class="footnote-ref"
id="fnref2" role="doc-noteref"><sup>2</sup></a><a href="#fn3"
class="footnote-ref" id="fnref3" role="doc-noteref"><sup>3</sup></a></p>
<h2 id="pull-fetch-mergerebase">pull = fetch + merge/rebase</h2>
<p>A lot of beginners don't know what <code>git pull</code> does and
just assume it magically updates their repository.</p>
<p>Even though your local branch might be named <code>master</code> and
push to a remote branch named <code>master</code>, your local and remote
branches are two totally separate things. You just synchronize the two
via --- you guessed it --- <code>git push</code> and
<code>git pull</code>.</p>
<p>Just google <code>git pull = fetch + merge</code> to get a more
complete picture, dozens of guides on the internet exist about this
already.</p>
<p>If you forget to pull before making some changes, committing, and
trying to push, you're typically left in a quite precarious situation.
You can either try to merge and get a messy commit you never wanted, or
(more frequently) give up, re-clone the repo, and copy your changes
there. But if, say, the remote had file A changed and you changed file
B, then your commits are independent and present no conflicts. In this
case, wouldn't it be nice if, say, you could make it as if you were
working on the latest commit from the remote?</p>
<p>And that's exactly what rebasing does: it applies your changes on top
of the remote branch's. Thus <code>git pull --rebase</code> will do the
job.</p>
<h2 id="staging-part-of-a-file">Staging part of a file</h2>
<p>When I only wanted to commit part of my code I would usually manually
delete it, commit my file, then undo. Turns out you don't have to do
this: <code>git add -p FILE</code> gives you a way to do this
interactively.</p>
<p>It will give you options <code>[y, n, q, a, d, e, ?]</code> for each
hunk, and sometimes <code>s</code> as well. Most options are quite
obvious, but the two I find most useful are <code>e</code> and
<code>s</code>. The <code>e</code> option lets you edit the patch
line-by-line, so you can remove lines starting with <code>+</code> or
<code>-</code> to change what you stage.</p>
<h2 id="rebase--i">rebase -i</h2>
<p>If you haven't pushed to master (it's OK if you've pushed to
feature/dev branches) and realize that a commit is stupid or you forgot
to add something to a commit or whatever, you can use
<code>git rebase -i</code> to drop, squash, reword, or reorder your
changes.</p>
<p>If you have pushed to remote, you will need to perform
<code>git rebase -i HEAD~n</code> where <code>n</code> is however many
commits back you want to go. So <code>git rebase -i HEAD~5</code>, for
instance.</p>
<p>At this point the remote will reject your changes, because your local
branch and remote branch have divergent histories. You can do
<code>git push -f</code> to force Git to accept your changes. Needless
to say, this will rewrite history and is an awful idea if anyone relies
on your branch history at all. (Which is why dev branches are good.)</p>
<section id="footnotes" class="footnotes footnotes-end-of-document"
role="doc-endnotes">
<hr />
<ol>
<li id="fn1"><p>It's probably okay if you're just committing config
files, especially if you're migrating stuff. If you're making
<code>~/.config/git</code> a repository, for example.<a href="#fnref1"
class="footnote-back" role="doc-backlink">↩︎</a></p></li>
<li id="fn2"><p>The GitHub Gist I linked to agrees with me, so clearly
I'm not the only one who thinks this way.<a href="#fnref2"
class="footnote-back" role="doc-backlink">↩︎</a></p></li>
<li id="fn3"><p>If I added <code>.DS_Store</code> to a project-level
<code>.gitignore</code> that you frequently push to, it's probably
because I think you're an idiot, not because I forgot what goes into a
gitignore.<a href="#fnref3" class="footnote-back"
role="doc-backlink">↩︎</a></p></li>
</ol>
</section>]]></description>
	<pubDate>13 Feb 2022</pubDate>
</item>
<item>
	<title>Creative processes make me optimistic</title>
	<link>https://dennisc.net/writing/essays/creative.md</link>
	<description><![CDATA[<p>Say Alice can solve 100% of calculus problems
and Bob can solve 80% of them. If Alice and Bob are taking a group
test<a href="#fn1" class="footnote-ref" id="fnref1"
role="doc-noteref"><sup>1</sup></a> together in math class, the
existence of Alice totally removes any value that Bob brings to the
table. Because if Alice can just do what Bob does and more, what's the
point of Bob doing anything anyway?</p>
<p>Fortunately, this is not how creating things works. Let's say that
Alice writes crosswords and sudoku, while Bob only writes sudoku. Even
if we were to argue that Alice is a better puzzle constructor than Bob
is, because Alice can do strictly more things, that doesn't mean Alice's
sudoku puzzles are better than Bob's. Or even that their sudokus will
cover the same ideas, mind you.</p>
<p>In the group quiz example, Bob is practically useless because Alice
<em>will</em> do everything that Bob could've. <em>Will</em>, not
<em>can</em>. The difference is that, in the real world, a great puzzle
setter certainly <em>could</em> construct something as good as your
puzzle --- but they didn't. Because there are so many things to create
(such as puzzles) and discover (such as math theorems), it is actually
very unlikely for someone else to come up with and execute on your idea,
provided it is sufficiently novel.</p>
<p>So yeah, there are probably people who are better than you at making
whatever it is you make. But the upshot is even if there are people
better than you, you can still provide value that they don't. Because if
both you and Alice can contribute something, then chances are, you won't
care so much which one of you two is better at it.</p>
<section id="footnotes" class="footnotes footnotes-end-of-document"
role="doc-endnotes">
<hr />
<ol>
<li id="fn1"><p>Yes, these really exist.<a href="#fnref1"
class="footnote-back" role="doc-backlink">↩︎</a></p></li>
</ol>
</section>]]></description>
	<pubDate>25 Jan 2023</pubDate>
</item>
<item>
	<title>How to end an essay</title>
	<link>https://dennisc.net/writing/essays/endings.md</link>
	<description><![CDATA[<p>Merely ending an essay with a summary or
restatement of your ideas feels wrong. The main points of your essay
should be <a href="framework">obvious from its structure</a>, and if you
want your readers to refresh themselves you should make it <a
href="reread">easy to reread</a>.</p>
<p>Nor does a "big takeaway" work. If your essay is long enough to have
some sort of overarching conclusion to draw everything together, you
shouldn't be saving your main points for the end anyway. Otherwise
you'll leave the reader scratching their head while you're refusing to
tell them what your examples mean, and by the time they get to the end
they'll have forgotten. People can only remember so many things at
once.</p>
<p>End your essays with advice. It won't work for everyone who's
reading, but it should be relevant for people who're facing what you're
describing. Try to make it positive advice as well: describe what your
readers should do instead of listing a subset of what they
shouldn't.</p>
<p>What should your readers do after reading your essay? How should they
change? In a way, this is a "big takeaway" --- with the extra
restriction that it's specific and actionable, even if not immediately
so.</p>]]></description>
	<pubDate>10 Sep 2022</pubDate>
</item>
<item>
	<title>Hard Classes</title>
	<link>https://dennisc.net/writing/essays/difficulty.md</link>
	<description><![CDATA[<p>Whenever someone asks how hard a class is, your
mind should turn to two things: how much homework there is and how hard
the tests are. Yet we often fail to separate the two, possibly because
the two tend to be highly correlated. If the ests are harder, then of
course there's more homework: the teacher has more material to cover, or
it's more difficult, and thus you need more practice. Or the other way
around: if there's a lot of homework, then there's more things to be
tested on; ergo, the tests must be harder.</p>
<p>That's the common conception. But even if there's a relationship
between the homework and tests, the two factors are totally orthogonal.
Or at least, what they represent is orthogonal.</p>
<p>The amount of homework there is in a class represents its
<em>required effort</em>. How likely you are to pass the class after
putting in this required effort is the <em>risk</em> of taking the
class.</p>
<p>There is a lot of debate over how hard some classes are, like AP
Statistics. But it turns out the disagreement is more narrow than its
difficulty; it's based on the <em>risk</em> of taking the class. No one,
not even the people who perform terribly in the class, feels a
particular need to sink dozens of hours a week into the class. You hit a
barrier really quickly and returns begin to diminish. Rather, what
differs from person to person is the risk of failing the tests; some
people have less innate ability than others or less experience doing
math, and so their risk is higher.</p>
<p>What's important is that these two components, risk and required
effort, don't change much for a person. Sure, there is wide variance
across different people, and these traits are not totally immutable. But
over the span of a year, and maybe even all four years of high school,
you do not often see significant variance. Particularly because the
people in charge and the students themselves ignore that these two
factors are what really matter, and instead waste time with a tutor
without ever decreasing the inherent risk in harder classes or the
amount of effort they require. For these traits change globally; it's a
matter of habits and values, not of specific knowledge.</p>
<p>When people ask if a class is worth taking they are really asking
about the potential reward. That is, what lies at the end if you manage
to succeed? Maybe you learn something, or more frequently, it looks nice
on your college applications. Implicitly they are also considering the
cost of failure: tanking their grade point average. And really, that's
all the factors that you need to make a decision: required effort, cost
of failure, risk, and potential gains.<a href="#fn1"
class="footnote-ref" id="fnref1" role="doc-noteref"><sup>1</sup></a></p>
<section id="footnotes" class="footnotes footnotes-end-of-document"
role="doc-endnotes">
<hr />
<ol>
<li id="fn1"><p>I also think this is the order you should consider the
factors in. If the required effort is too much, it doesn't really matter
if you can afford to fail or if success is guaranteed. But earlier
factors do not totally trump later ones, they are just weighted a bit
heavier.<a href="#fnref1" class="footnote-back"
role="doc-backlink">↩︎</a></p></li>
</ol>
</section>]]></description>
	<pubDate>26 Jan 2022</pubDate>
</item>
<item>
	<title>On &quot;well-defined&quot; functions</title>
	<link>https://dennisc.net/writing/blog/well-defined-functions.md</link>
	<description><![CDATA[<p>As a TA for CS251 I frequently see people
verify that a function is well-defined when there is no need to. And
just as often I see the opposite. So let's set the record straight here:
what exactly is a function, and when do we need to check whether
something is genuinely a function?</p>
<blockquote>
<p>Given two sets <span class="math inline"><em>X</em></span> and <span
class="math inline"><em>Y</em></span>, a <strong>function</strong> if
<span class="math inline"><em>f</em>: <em>X</em> → <em>Y</em></span> is
just a subset of the Cartesian product <span
class="math inline"><em>X</em> × <em>Y</em></span> such that for each
<span class="math inline"><em>x</em> ∈ <em>X</em></span>, there is
exactly one <span class="math inline"><em>y</em> ∈ <em>Y</em></span>
such that <span
class="math inline">(<em>x</em>, <em>y</em>) ∈ <em>f</em></span>.</p>
</blockquote>
<p>As you expect, we write <span
class="math inline"><em>f</em>(<em>x</em>)</span> to denote said unique
<span class="math inline"><em>y</em></span>.</p>
<p>So what happens when we attempt to define a function? Essentially, we
are associating each <span
class="math inline"><em>x</em> ∈ <em>X</em></span> with some subset of
elements in <span class="math inline"><em>Y</em></span>. For example, in
the function <span class="math inline"><em>f</em> : ℕ → ℕ</span> where
<span class="math inline"><em>f</em>(<em>x</em>) = 2<em>x</em></span>,
we are associating <span class="math inline"><em>x</em></span> with
<span class="math inline">{2<em>x</em>}</span>. For example, we just
associate <span class="math inline">1</span> with <span
class="math inline">2</span>, <span class="math inline">2</span> with
<span class="math inline">4</span>, and so on.</p>
<blockquote>
<p>When we attempt to define a function <span
class="math inline"><em>f</em></span>, we would like to have <span
class="math inline"><em>f</em></span> associate each <span
class="math inline"><em>x</em></span> with exactly one value in <span
class="math inline"><em>y</em></span>.</p>
</blockquote>
<p>Most of the time we write a function as <span
class="math inline"><em>f</em>(<em>x</em>) = …</span> and in this case
there are no problems. If it is some formula of <span
class="math inline"><em>x</em></span>, this is always fine. Perhaps it
is a piecewise formula, where you first have to check whether <span
class="math inline"><em>x</em></span> is even or odd. No matter.
<strong>This will always be fine.</strong></p>
<p>Now let me give you a very quick <em>bad</em> definition of a
function. Suppose that we are attempting to map the positive rationals
to positive integers. Suppose you say, "we associate the rational <span
class="math inline"><em>p</em>/<em>q</em></span> (where <span
class="math inline"><em>p</em></span>, <span
class="math inline"><em>q</em></span> are integers) with the integer
<span class="math inline"><em>p</em> + <em>q</em></span>." News flash:
we associate <span class="math inline">2/3</span> with <span
class="math inline">2 + 3 = 5</span> and <span
class="math inline">4/6</span> with <span
class="math inline">4 + 6 = 10</span>. Since <span
class="math inline">2/3 = 4/6</span>, we have associated multiple
elements with the same rational.</p>
<p>Now what is the actual issue? When we define a function, we are
associating a <em>representation</em> of an element in <span
class="math inline"><em>X</em></span> with some value in <span
class="math inline"><em>Y</em></span>. What we are really doing when we
say "<strong>for all <span
class="math inline"><em>x</em> ∈ <em>X</em></span></strong>, <span
class="math inline"><em>f</em>(<em>x</em>) = 2<em>x</em></span>" is that
we are representing each element of <span
class="math inline"><em>X</em></span> as <span
class="math inline"><em>x</em></span>. The "for all <span
class="math inline"><em>x</em></span>" quantifier guarantees that each
element in <span class="math inline"><em>X</em></span> is accessed
exactly once with the representation <span
class="math inline"><em>x</em></span>, and then we associate each <span
class="math inline"><em>x</em></span> with <span
class="math inline">2<em>x</em></span>.</p>
<p>But when we look at <span
class="math inline"><em>f</em>(<em>p</em>/<em>q</em>) = <em>p</em> + <em>q</em></span>,
what we are doing is associating a value to <em>every</em> fractional
representation of a number. And we have already seen that a rational
number has many fractional representations, such as <span
class="math inline">2/3 = 4/6</span>. Of course, the way we fix this is
stipulate "for all relatively prime <span
class="math inline"><em>p</em>, <em>q</em></span>, we have <span
class="math inline"><em>f</em>(<em>p</em>/<em>q</em>) = <em>p</em> + <em>q</em></span>".
Now this genuinely is a function, because we have ensured that we are
only associating values to <em>one</em> representation of each rational
number.</p>
<blockquote>
<p>If we are earnestly trying to define a function <span
class="math inline"><em>f</em></span>, we are not going to associate a
representation of an element with more than one value. Because if we do,
the subset of <span class="math inline"><em>X</em> × <em>Y</em></span>
we are describing automatically is not a function anymore.</p>
</blockquote>
<p>Now, we do not need ascribe <em>every</em> representation of an
element in <span class="math inline"><em>X</em></span> with a value in
<span class="math inline"><em>Y</em></span>. Ideally, we would like to
ascribe exactly one representation of an element with a value, which is
why there is no need to check that functions of the form "for all <span
class="math inline"><em>x</em> ∈ <em>X</em></span>, <span
class="math inline"><em>f</em>(<em>x</em>) = …</span>" are well-defined.
There is nothing to check! It is obviously a function.</p>
<p>But what of functions where you genuinely have no choice but to
associate a value to multiple representations of an element? In this
case, I personally say we check for <strong>representation
invariance</strong> of the function, or that such a function is
<strong>representation invariant</strong>.</p>
<p>As an example, take modular arithmetic. We would like to be able to
define <span class="math inline">13 + 10</span> modulo <span
class="math inline">12</span> the same way that <span
class="math inline">1 + 10</span> is defined modulo <span
class="math inline">12</span>, and it turns out that <span
class="math inline">13 + 10 ≡ 1 + 10</span> modulo <span
class="math inline">12</span>. Likewise, <span
class="math inline">13 ⋅ 10 ≡ 1 ⋅ 10</span> modulo <span
class="math inline">12</span>. So it is okay to ascribe a value to
multiple representations when defining multiplication, because they are
all consistent.</p>
<p>In general, what we need to check here is <strong>representation
invariance</strong>. In other words, if <span
class="math inline"><em>a</em> ≡ <em>b</em></span> and <span
class="math inline"><em>c</em> ≡ <em>d</em></span>, we need to make sure
that <span
class="math inline"><em>a</em><em>c</em> ≡ <em>b</em><em>d</em></span>.
(All these equivalences are modulo <span
class="math inline"><em>n</em></span>.) And it is easy to check that
this is indeed true, so multiplication can be properly defined in
modular arithmetic.</p>
<p>To summarize,</p>
<ul>
<li>a function is a subset of <span
class="math inline"><em>X</em> × <em>Y</em></span>,</li>
<li>we associate values in <span class="math inline"><em>Y</em></span>
to <em>representations</em> of values in <span
class="math inline"><em>X</em></span> when we attempt to define a
function,</li>
<li>ideally for each element in <span
class="math inline"><em>X</em></span>, we only ascribe values to
<em>one</em> representation of the element,</li>
<li>but sometimes we genuinely need to ascribe a value to multiple
representations of the element, in which case we must check that the
ascribed value is the same across all representations we access.</li>
</ul>
<p>And the last bullet point is the only time you need to check that a
function is "well-defined".</p>]]></description>
	<pubDate>30 Oct 2024</pubDate>
</item>
<item>
	<title>Remarks on the MAT</title>
	<link>https://dennisc.net/writing/blog/mat-remarks.md</link>
	<description><![CDATA[<p>In my initial contest report, there were a
couple of remarks I didn't make because I didn't have enough to say or
they'd distract from the main point. Well, here they are.</p>
<h2 id="future">Future</h2>
<p>We have already started constructing the second MAT, and we made a
lot of progress very recently (yesterday, actually). If you're
interested in testsolving, please email me at <a
href="mailto:dchen@mathadvance.org">dchen@mathadvance.org</a>.<a
href="#fn1" class="footnote-ref" id="fnref1"
role="doc-noteref"><sup>1</sup></a></p>
<p>Because contest production is confidential (I will not discuss any
particulars of the next contest), there is not much I can say. But there
are a few things I still want to note.</p>
<p>The score distribution was much lower than we anticipated or desired.
There are a couple of things we are doing moving forward.</p>
<p>First off, we are making the first problem in each round more
approachable. This year's P1 was perfectly fine, but P4 and P7 tripped
some people up. P4 required knowledge of Ptolemy's, and P7 required
knowing the formula for <span class="math inline"><em>ϕ</em></span>. I
think the first three problems were perfect introductions <em>for an
audience we did not have</em>. So next time, problem 1 will be about as
hard and problems 4 and 7 will be a lot easier. The rest of the contest
will also go down in difficulty, particularly problem 8.</p>
<p>We've reviewed a lot of geometry problems, and the verdict on many of
them was "this problem is good, but does not feel like a MAT problem."
Generally this is due to difficulty or subject matter (think more
complicated geometric structures and theorems). But there are many
easier problems as well that did not make the cut for MAT, but would
feel right on place in a geometry contest. So after the 2022 MAT (which
is projected to happen around New Year's), the next contest we are
planning to host is a geometry contest.</p>
<p>The JMCs are going a lot less smoothly than the MAT. But I am also
not as involved in the production, since MAT production is a lot easier
and more fun. And I also should focus on getting the MAST backend up so
I can put applications up, because at this rate decisions are going to
come out after the AMCs.</p>
<p>Fortunately next time around, we're going to have a year between test
production instead of half a year. Between Year 1 and Year 2 we had six
months because we made the first contest at July rather than January. We
have around six months this time around because the AMCs this time are
on November. And we have never been utilizing all six months, because
Math Advance does a lot of things other than JMCs. So perhaps JMCs will
not be such a strain on us next time.</p>
<h2 id="fun">Fun</h2>
<p>I actually added a brief note on fun to the contest report because I
thought it was important enough to include. But I'll expand some more.
(I didn't include this bit in the MAT contest report because it has
nothing to do with the MAT. Most of my thoughts here are on established
contests like the AMCs and HMMT.)</p>
<p>I think a lot of contests lately have not been fun to take. Out of
all the problems, there were very few that I was drawn to do. And I
think this is a result of the test construction processes. They are
quite cold. There is so much focus placed on whether each problem is the
right difficulty or the right subject. But past a certain point you are
just approximating, and your opinions just guesses. So much weight is
placed on these guesses, and nobody asks: does anyone actually feel like
doing these problems?</p>
<p>Many people say the AMCs are becoming less approachable. I do not
really agree with this assessment. I think the problems have been about
as fun in 2021 as they were in 2016 or 2018. (Not to say they are/were
fun, or that they aren't/weren't fun.) As for difficulty, I think that
is just rounding error. Maybe on average the first ten problems have
gotten somewhat harder. But the goal shouldn't be to get more people to
show up, do ten problems, and not care about the contest after. It
should be to make the first ten problems interesting enough so students
want to actually go past that and try the next fifteen. <a
href="https://artofproblemsolving.com/wiki/index.php/2021_AMC_10A_Problems/Problem_5">And
come on, we can do a lot better than we are doing now.</a></p>
<p>I think HMMT suffers from the same issue. Certainly the problems are
hard, and that contributes to low accessibility. But oh my Lord, look at
some of those problem statements. Half of the algebra/number theory
section looks absolutely unappetizing. I don't want to read it, let
alone solve it. And this is the issue that comes up when you just judge
problems after you solve them. <strong>You are considering them from an
omniscient perspective, not the perspective of an uninformed
contestant.</strong> This is why I frequently talk about my initial
impression of the problem. That way, people have a train of thought they
can follow and know more about how the problem felt.</p>
<p>If a problem looks a little gross but the solution is very
interesting, is it worth including on the contest? Answers vary, but for
us it has almost always been no. We have enough problems that we can
choose the ones with pretty statements and solutions. Even if this isn't
the case, I think a lot of problems are not so resistant to a little bit
of rephrasing.</p>
<p>You want to package the problem neatly. It's a bit like food that
looks or smells gross but actually tastes good. Sure, it might be
enjoyable in the end, but what if you could excise that initial
revulsion? Contests like the HMMT, and more notoriously, BMT/SMT/CHMMC,
could stand to follow this principle more often. Their problems often
have great ideas and terrible packaging. And when there are prettier
problems to pick from, there's little reason to do the ones that are
ugly.</p>
<p>From a more pragmatic perspective, it doesn't matter if an ugly
problem has a beautiful solution, because no one will want to do the
ugly problem anyways.</p>
<section id="footnotes" class="footnotes footnotes-end-of-document"
role="doc-endnotes">
<hr />
<ol>
<li id="fn1"><p>Totally unrelated: I set up a mailing server for Math
Advance yesterday as well! "Set up" is used very generously since I just
followed a tutorial and installed mailcow and docker-compose. Mailcow is
great, trying to set up a server and configure everything myself
manually with courier proved to be way more effort than it was worth.
The additional server costs (since Mailcow takes an active GB of RAM
even after turning off some stuff) aren't a huge concern either since we
have money and the means to make it.<a href="#fnref1"
class="footnote-back" role="doc-backlink">↩︎</a></p></li>
</ol>
</section>]]></description>
	<pubDate>27 Sep 2021</pubDate>
</item>
<item>
	<title>Propositional Formulae</title>
	<link>https://dennisc.net/writing/blog/propositional-formulae.md</link>
	<description><![CDATA[<p>This is the next entry of my Logic notes, half
a year after the last entry. (Previous entries: <a
href="/writing/blog/inductive-structures">Inductive Structures</a>, <a
href="/writing/blog/unique-readability">Unique Readability</a>.)</p>
<p>We have laid the groundwork for propositional logic with the last two
entries. As one might expect, propositional formulae are a uniquely
readable inductive structure (this is why we bothered to define these
two concepts).</p>
<p>I am going to assume you have a working idea of what a <em>boolean
expression</em> (think computer science) is. For instance, if I give you
the expression</p>
<pre><code>(a &amp;&amp; b) || !c</code></pre>
<p>you should be able to tell me exactly which triples
<code>a, b, c</code> satisfy (i.e. make true) this boolean
expression.</p>
<p>The notation for computer science and formal logic differ. Instead of
<code>&amp;&amp;, ||, !</code>, we use <span
class="math inline">∧</span>, <span class="math inline">∨</span>, <span
class="math inline">¬</span>. And we have another symbol: <span
class="math inline">⟹</span> (read as "implies"). Semantically <span
class="math inline"><em>a</em> ⟹ <em>b</em></span> is equivalent to
<span class="math inline">(¬<em>a</em>) ∨ <em>b</em></span>. This
meaning is connected to what it does in the rest of mathematics: "<span
class="math inline"><em>b</em></span> follows from <span
class="math inline"><em>a</em></span>", meaning that if <span
class="math inline"><em>a</em></span> is true then <span
class="math inline"><em>b</em></span> better be true. But it doesn't
matter what happens when <span class="math inline"><em>a</em></span> is
false (since implication only concerns what happens when <span
class="math inline"><em>a</em></span> is true). If you work through it,
you will quickly realize that implications are satisfied if either <span
class="math inline"><em>a</em></span> is false or <span
class="math inline"><em>b</em></span> is true, which is precisely when
<span class="math inline">(¬<em>a</em>) ∨ <em>b</em></span> is
satisfied.</p>
<h2 id="formal-treatment">Formal treatment</h2>
<blockquote>
<p><strong>Definition (Propositional Alphabet)</strong> A propositional
alphabet consists of</p>
<ul>
<li>a set of propositional symbols <span
class="math inline"><em>P</em></span>,</li>
<li>the connectives <span class="math inline">∧, ∨, ⟹,¬</span>,</li>
<li>constants <span class="math inline">⊤, ⊥</span>,</li>
<li>and parentheses <span class="math inline">( , )</span>.</li>
</ul>
</blockquote>
<p>For our convenience we will refer to the set of propositional symbols
and constants (i.e. <span
class="math inline"><em>P</em> ∪ {⊤, ⊥}</span>) as <span
class="math inline"><em>P</em><sup>*</sup></span>.</p>
<p>Technically a propositional alphabet consists of <span
class="math inline"><em>P</em></span> as well as the connectives,
constants, and parentheses, but <span
class="math inline"><em>P</em></span> uniquely identifies it so we will
refer to the alphabet just as <span
class="math inline"><em>P</em></span>.</p>
<p>A pedagogical note: we have defined these technical terms
"propositional symbols", "connectives", etc. They are intentionally
evocative, so you may be inclined to search for the differences in
function between each of these sets. However, so far we have made no
real distinction between these sets (besides that <span
class="math inline"><em>P</em></span> can be arbitrary while the other
sets are fixed). This is about to change.</p>
<blockquote>
<p><strong>Definition (Propositional Formulae)</strong> The set of
propositional formulae of the alphabet <span
class="math inline"><em>P</em></span>, which we will refer to as <span
class="math inline"><em>X</em></span>, is the closure of the inductive
structure <span
class="math inline">(<em>P</em><sup>*</sup>, {<strong>∧</strong>, <strong>∨</strong>, <strong>⟹</strong>, <strong>¬</strong>})</span>,
where</p>
<ul>
<li><span class="math inline"><strong>∧</strong></span> is a function
taking <span
class="math inline"><em>a</em>, <em>b</em> ∈ <em>X</em></span> to <span
class="math inline">(<em>a</em> ∧ <em>b</em>)</span>,</li>
<li><span class="math inline"><strong>∨</strong></span> is a function
taking <span
class="math inline"><em>a</em>, <em>b</em> ∈ <em>X</em></span> to <span
class="math inline">(<em>a</em> ∨ <em>b</em>)</span>,</li>
<li><span class="math inline"><strong>⟹</strong></span> is a function
taking <span
class="math inline"><em>a</em>, <em>b</em> ∈ <em>X</em></span> to <span
class="math inline">(<em>a</em> ⟹ <em>b</em>)</span>,</li>
<li>and <span class="math inline"><strong>¬</strong></span> is a
function taking <span class="math inline"><em>a</em> ∈ <em>X</em></span>
to <span class="math inline">(¬<em>a</em>)</span>.</li>
</ul>
</blockquote>
<p>Note that the functions <span
class="math inline"><strong>∧</strong></span>, <span
class="math inline"><strong>∨</strong></span>, and <span
class="math inline"><strong>⟹</strong></span> behave very similarly.
Indeed, with only a syntactic structure, they are virtually
indistinguishable. (We define all these symbols so that we may perform
distinct operations on them related to their semantics.) For convenience
we will let <span class="math inline">⋆</span> be a stand-in for any of
<span class="math inline">∧, ∨, ⟹</span> and their associated functions
<span
class="math inline"><strong>∧</strong>, <strong>∨</strong>, <strong>⟹</strong></span>.
So we may instead just say "<span class="math inline">⋆</span> is a
function taking <span
class="math inline"><em>a</em>, <em>b</em> ∈ <em>X</em></span> to <span
class="math inline">(<em>a</em> ⋆ <em>b</em>)</span>".</p>
<p>Pedagogical note: It is important to recall that these propositional
formulae are just strings consisting of the characters in the alphabet
<span class="math inline"><em>P</em></span>. Note that we have bolded
the logical connectives in the definition as <span
class="math inline"><strong>∧</strong></span>, etc are <em>not</em> the
symbols in <span class="math inline"><em>P</em></span>. They are
functions that are heavily related to the symbol <span
class="math inline">∧</span>, etc.</p>
<p>Another pedagogical note: The propositional formula <span
class="math inline">((<em>a</em> ∧ <em>b</em>) ∨ (¬<em>c</em>))</span>
is surely evocative of the boolean formula
<code>(a &amp;&amp; b) || !c</code>. But unlike the latter, the former
doesn't mean anything yet. (Much later, when we introduce semantics and
proof rules, we will be able to attach meaning to these formulae too in
an unsurprising way.)</p>
<p>Final note: <strong>The parentheses matter!!</strong> They establish
unique readability, which in turn gives us an unambiguous notion of
semantics. (This is something worth proving yourself.)</p>
<p>Because propositional formulae are uniquely readable, we can define
functions on <span class="math inline"><em>X</em></span> (the set of
propositions) by induction. Here is an example.</p>
<blockquote>
<p><strong>Definition (Rank)</strong></p>
<p>The rank <span class="math inline"><em>r</em> : <em>X</em> → ℕ</span>
of a proposition is defined inductively as</p>
<ul>
<li><span class="math inline"><em>r</em>(<em>p</em>) = 0</span> for
<span
class="math inline"><em>p</em> ∈ <em>P</em><sup>*</sup></span>,</li>
<li><span
class="math inline"><em>r</em>((<em>a</em> ⋆ <em>b</em>)) = max (<em>r</em>(<em>a</em>), <em>r</em>(<em>b</em>)) + 1</span>
for <span
class="math inline"><em>a</em>, <em>b</em> ∈ <em>X</em></span>,</li>
<li>and <span
class="math inline"><em>r</em>((¬<em>a</em>)) = <em>r</em>(<em>a</em>) + 1</span>
for <span class="math inline"><em>a</em> ∈ <em>X</em></span>.</li>
</ul>
</blockquote>
<p>Intuitively, the rank of a formula is a metric for how complicated it
is. More precisely, it is the smallest <span
class="math inline"><em>n</em></span> such that <span
class="math inline"><em>X</em><sub><em>n</em></sub></span> contains
<span class="math inline"><em>a</em></span>, where <span
class="math inline"><em>X</em><sub><em>n</em></sub></span> is defined as
it was for the proof of the closure of an inductive structure.</p>
<blockquote>
<p><strong>Exercise.</strong> Prove that every propositional formula has
an even number of parentheses. (Hint: recursively describe a function
that returns the number of parentheses in a formula.)</p>
</blockquote>
<h2 id="a-bigger-picture">A bigger picture</h2>
<p>This is about the time some may start asking "what on earth is
happening here, and why should I care?" (At least I asked myself these
questions at this time.) The rules and system we are setting up are
beginning to seem somewhat arbitrary, as if we have capriciously chosen
the symbols in our propositional alphabet. This is not entirely false,
so I will aim to explain at a broad level why this is OK.</p>
<p>One may verily ask, "why these particular symbols in our
propositional language?" (For instance, <span
class="math inline">⟹</span> is semantically redundant since it can be
expressed with <span class="math inline">∧, ∨, ¬</span>. Actually
because of De Morgan's, we may remove <span class="math inline">∧</span>
as well.) It turns out that the specifics of our <em>proof system</em>
(the propositional language and the rules for manipulating formulae
which we will later introduce) are not particularly important.</p>
<p>What is important? We need something expressive enough to eventually
describe set theory (spoiler, propositional logic is not enough: we need
quantifiers). We will architect a set of "proof rules" with which we can
"manipulate" certain formulae into other formulae. Introducing semantics
(i.e. actually attaching truth values and meaning to our propositional
formulae) will give us a notion of <em>soundness</em> and
<em>completeness</em>. In very broad terms, a logical system being
<em>sound</em> means that "if you can syntactically prove something, the
semantic implication will always hold". And <em>completeness</em> means
"if some semantic implication holds, you can syntactically prove it".
Both are very non-obvious traits of a logical system, and being able to
equate syntax and semantics gives us powerful tools to study
propositional formulae.</p>
<p>Furthermore one may ask, "will we start exclusively using this
logical system to prove things about this logical system?" And the
answer is no. There would be problems of circularity (e.g. Godel's
Incompleteness Theorems), and on a more philosophical note, there are
always mathematical concepts we will have to take for granted.
(Specifically, we cannot "rigorously" define set membership.) So we will
have two fairly distinct notions of a proof: one is the standard English
proofs that you and I are used to, and another will be the syntactical
"proofs" that we will soon begin to develop. The latter happens to be a
fantastic model of the former (after all, that is one of the reasons we
care about formal logic), but we will be using plain English proofs to
develop our formal logical system.</p>
<p>Of course, we are not introducing this logical system just for fun.
Eventually we will reach the point where we can more easily study some
aspects of plain English proofs by modeling them as syntactical proofs
(e.g. soundness/completeness and Godel's Theorems). This is the main
point, and we are ju building up to it.</p>]]></description>
	<pubDate>28 Apr 2024</pubDate>
</item>
<item>
	<title>Be around smart people</title>
	<link>https://dennisc.net/writing/essays/be-with-smart-people.md</link>
	<description><![CDATA[<p>Everyone knows it's good to be around smart
people. But why?</p>
<p>One common semi-misconception is that smart people will teach you
things. Well, yes and no. They will talk about complicated ideas they
understand, and you will not know a good chunk of them in advance. But
come on. A five minute conversation could not possibly transmit all of
the nuances of, say, the Spectral Theorem, or the requisite background
in inner-product spaces, let alone its applications with positive
operators, square roots, or SVD.</p>
<p>But being around smart people <em>primes</em> you to learn these
things. You might be a curious individual learning about something like
group theory, and you probably would not randomly encounter the Spectral
Theorem before properly learning linear algebra, or the construction of
the reals via Dedekind cuts before real analysis on your own. But if
someone is telling you about orthonormal bases of eigenvectors and
relating it to diagonal matrices, and afterwards you take linear
algebra, it is hard not to go "Oh! So <em>that's</em> the Spectral
Theorem. I get it now!" And even if you would've encountered the
Spectral Theorem by looking around on your own (which is very possible
--- this is why it is good to stay curious and do undirected reading on
your own), there are many other things that you would not have seen.</p>
<p>You probably will not directly learn a lot just by hanging around
smart people. You still have to stay curious, follow up on
conversations, and read on your own. But if we consider intelligence to
roughly be the ability to learn and solve problems quickly, then being
around smart people actually makes you <em>smarter</em>. That on its own
is not good for much. But if you also work hard, it just might provide
the boost you need to learn --- and do --- great
things.</p>]]></description>
	<pubDate>23 Aug 2023</pubDate>
</item>
<item>
	<title>The break-in is all in my head</title>
	<link>https://dennisc.net/writing/essays/breakin.md</link>
	<description><![CDATA[<p>When I set puzzles, obviously I will use
setting software or at the very least, pen and paper. But increasingly,
I find that I am setting my breakins entirely in my head.</p>
<p>Not that I'll have all the details down: many times I will adjust the
breakin so it flows more smoothly or because it subtly breaks in some
way. Often I don't even determine important aspects of the puzzle like,
"how many rows and columns will it have?" or "where will the breakin
be?" Nevertheless, the entire <em>idea</em> of the breakin is in my
head.</p>
<p>As an example, take my latest puzzle <em>River</em>. The main idea is
that Renbans of length 4 or greater must have at least one of 46. This
is about how far I was able to get with the breakin in my head:</p>
<p><img src="/writing/essays/breakin/river.svg" alt="Image of River breakin."></p>
<p>I've mostly begun doing this out of necessity: there are a lot of
situations where I don't have access to setting software (sleeping,
dinner with family friends, graduation, etc) and I get bored easily, so
I start thinking of puzzles in my head. But I do think that constructing
breakins in your head does ensure they are good: it ensures that there
is actually some idea behind the breakin, rather than just being a
series of details to whittle down. Because if your "breakin" is just a
bunch of uninteresting details, you won't be able to remember all that
in your head.</p>
<p>P.S. If you spot me spaced out, it's probably because I'm
constructing a puzzle in my head.</p>]]></description>
	<pubDate>30 Jul 2023</pubDate>
</item>
<item>
	<title>Disaster</title>
	<link>https://dennisc.net/writing/tech/disaster.md</link>
	<description><![CDATA[<p><strong>Feb. 13 update: I can receive emails
now.</strong> (I still can't send, unfortunately, but I can just reply
with any other email address. So functionally speaking, my email
works!)</p>
<p>As you may have noticed, this website and everything related (puzz,
Math Advance) have been down for a week or so. Here is the story,
roughly, of why that happened.</p>
<p>When I went home for break, I bought a Raspberry Pi and set up a
server back home. Then I moved all the websites and email onto there,
with no clear backup plan for what I'd do if everything went bust. Not
everything was fully migrated, but I decided it was good enough.
Satisfied, I shut down my virtual Ubuntu server that had been running
for several years and called it a day.</p>
<p>Well, everything went bust.</p>
<p>A few days after I leave for college, I realize my emails are
suspiciously empty. That was the first sign that the installation was
somewhat botched, and upon investigating, the problem is with the
mailcow docker process. Okay, maybe mailcow just doesn't work on
Raspberry Pis. So I spin up a test server, and it seems like Alpine is
actually the issue. So I can't install mailcow on the Raspberry Pi. That
leaves me two options:</p>
<ul>
<li>Set up another VPS just to handle mail,</li>
<li>or mystically figure out how to install Postfix (grr I wish the
documentation were better).<a href="#fn1" class="footnote-ref"
id="fnref1" role="doc-noteref"><sup>1</sup></a></li>
</ul>
<p>I am a busy college student. Life has many demands. So after trying
the second route for a bit, I decide that getting my email working
couldn't be <em>that</em> important. It could wait...</p>
<p>But then everything, and I mean <em>everything</em>, came crashing
down.</p>
<p>I notice this when I check on my puzzle website. It's down. Hmm, odd.
My first suspicion is that the connection in our house died, and that
indeed was the culprit. I couldn't SSH into the server, and nor could my
family. This posed a big problem: I stupidly left the Pi plugged in
somewhere where no monitor could realistically be moved to it. Because
Raspberry Pis are pieces of shit, they don't have a power switch. And no
one can SSH into it. This means, effectively, that no one can see what
is going on in the screen.</p>
<p>So my brother has to blindly type out commands that I dictate (none
of which he really understands) to try and attempt to either reconnect
to the internet or shut the Pi down (so it can safely be moved to a
monitor). Neither works.</p>
<p>Exasperated, I decide to take the risk and instruct him to unplug the
Raspberry Pi. I read online that it usually would not corrupt the data
on the SD card. Apparently it did. The damn thing would not boot, or so
I was informed. Either way, being a coast away meant that I couldn't
look at it myself. So I needed to set up something in Pittsburgh.</p>
<p>I think about setting up an Orange Pi. But then I realize, a) our
room doesn't have an Ethernet port (at least I have not been able to
find it in a semester and counting), b) I don't have a monitor or a USB
keyboard, and c) it would be a massive pain in the ass. So I go back to
where I started: a virtual cloud server.</p>
<h2 id="lessons">Lessons</h2>
<ul>
<li>Always have direct access to your hardware.</li>
<li>Don't host somewhere with shoddy wifi.</li>
<li>Plan for and <em>simulate</em> failures. What happens if the Wi-Fi
is out? What can you do?</li>
</ul>
<p>All these seem so obvious in retrospect. It's the kind of thing that
they tell everybody running a server anywhere. Yet it seems, for better
or worse, that I have to learn the hard way: reliability above all
else.</p>
<h2 id="what-now">What now?</h2>
<p>Only dennisc.net and puzz.dennisc.net are up as of right now. Here is
what I plan to do:</p>
<ul>
<li>Get email working. This is the top priority.</li>
<li>Get mathadvance.org back up. This isn't really too hard to do, but
it's also not that important.</li>
<li>Get mat.mathadvance.org back up. Past contests are on there, so this
is quite important, but also trying to host a Node JS application seems
quite difficult. (There are some really big dependency hell issues,
mostly because Node 16.7.0 -&gt; Node 17+ contained a breaking change
that fixed <em>SSL</em> of all things, and I have not been able to
figure them out yet.) So it's high priority, but also realistically high
effort.</li>
<li>Get the rest of the random stuff up, like git.dennisc.net and
mast.mathadvance.org (which effectively have no content).</li>
</ul>
<p>It's likely that I pay for this cloud server for the foreseeable
future. (In the time between installing my old server and the new one,
the minimum price went down from $10/month to $6/month.) But when I move
into a real house, it is also quite possible that I give the whole
Raspberry Pi thing another go. As annoying as system administration is,
it can be rewarding to have a whole homegrown setup as opposed to
outsourcing the server somewhere far away. And with more free time in
the summer, it is quite likely I will have the motivation to try it
again.</p>
<section id="footnotes" class="footnotes footnotes-end-of-document"
role="doc-endnotes">
<hr />
<ol>
<li id="fn1"><p>I'm sure the documentation is very thorough. But I wish
there was a tutorial for people not using Debian (since Debian has a
slightly strange install process) that just guides people through
getting their email to work.<a href="#fnref1" class="footnote-back"
role="doc-backlink">↩︎</a></p></li>
</ol>
</section>]]></description>
	<pubDate>13 Feb 2024</pubDate>
</item>
<item>
	<title>ChatGPT, by ChatGPT</title>
	<link>https://dennisc.net/writing/essays/chatgpt-by-chatgpt.md</link>
	<description><![CDATA[<p>Prompt: Write an essay about why ChatGPT is not
a threat to humanities classes because people should not be writing like
a chatbot anyway. Compare this to how computers cannot generate good
sudoku puzzles and are merely an assistant.</p>
<blockquote>
<p>As an AI language model, ChatGPT is designed to generate human-like
responses to written prompts. However, this does not mean that it poses
a threat to humanities classes. On the contrary, people should not be
writing like chatbots, and AI language models such as ChatGPT can serve
as useful tools for students and educators.</p>
<p>One of the primary goals of humanities classes is to teach students
how to express their thoughts and ideas in writing. While AI language
models such as ChatGPT can generate grammatically correct and coherent
sentences, they lack the nuance and creativity that humans bring to
their writing. Writing is a form of expression that reflects an
individual's unique perspective, experiences, and voice. Chatbots, on
the other hand, are designed to mimic human language without having an
individual perspective.</p>
<p>Furthermore, the ability to write well is a valuable skill that is
highly sought after in the professional world. Employers are looking for
individuals who can communicate effectively in writing and express their
ideas in a clear and concise manner. Relying solely on AI language
models to write on our behalf would not only hinder our ability to
develop this skill but also undermine the value of human creativity and
individuality.</p>
<p>It's important to note that AI language models such as ChatGPT are
not meant to replace humans in the writing process. Instead, they can
serve as useful tools to assist individuals in their writing. Just as
computers cannot generate good Sudoku puzzles on their own, they can
serve as an assistant to those who enjoy playing the game. Similarly, AI
language models can help students and educators in generating ideas,
suggesting sentence structures, and correcting grammatical errors. This,
in turn, can save time and increase productivity.</p>
<p>Moreover, AI language models can be used to analyze and evaluate
written works. By inputting essays or articles into the system, students
and educators can receive feedback on the clarity, coherence, and
organization of their writing. This feedback can help them improve their
writing skills and develop their own unique style.</p>
<p>In conclusion, ChatGPT is not a threat to humanities classes. People
should not be writing like chatbots anyway, as writing is a form of
expression that reflects an individual's unique perspective,
experiences, and voice. Instead, AI language models such as ChatGPT can
serve as useful tools to assist individuals in their writing, just as
computers can assist Sudoku players. By using AI language models as an
assistant rather than a replacement, students and educators can improve
their writing skills while maintaining the value of human creativity and
individuality.</p>
</blockquote>
<p>Yeah, ChatGPT kind of sucks. Its weaknesses?</p>
<ul>
<li>Way too verbose</li>
<li>Its tone is always the same; it doesn't know how to
<em>emphasize</em> anything</li>
<li><strong>It lacks domain-specific knowledge</strong>, particularly
about soft skills (e.g. creativity, intent)<a href="#fn1"
class="footnote-ref" id="fnref1"
role="doc-noteref"><sup>1</sup></a></li>
</ul>
<p>ChatGPT as of now is just a toy, one that happens to have a modest
level of utility for smaller/less high-stakes situations. And yes,
<em>maybe</em> I could've gotten it to write like me if I engineered a
prompt to do that, but that would've literally taken longer than writing
it myself.</p>
<section id="footnotes" class="footnotes footnotes-end-of-document"
role="doc-endnotes">
<hr />
<ol>
<li id="fn1"><p>Just look at how badly it botched the explanation of
sudoku puzzles! You don't even need to have written or done a single
puzzle in your life to tell ChatGPT is full of shit.<a href="#fnref1"
class="footnote-back" role="doc-backlink">↩︎</a></p></li>
</ol>
</section>]]></description>
	<pubDate>21 Mar 2023</pubDate>
</item>
<item>
	<title>The midpoint of simplicity and complexity for web design</title>
	<link>https://dennisc.net/writing/tech/web-simplicity.md</link>
	<description><![CDATA[<p>Take the union of the styling for dennisc.net,
<a href="https://mathadvance.org">mathadvance.org</a>, and <a
href="/writing/tech/glee-solidify">the styling I've revealed for Glee's
registration page</a>. The style for these websites is unique --- I
would be pretty surprised if you've seen a design that feels like this
before.</p>
<p>Compare this to basically any site with a big, flashy marketing
homepage. Think <a href="https://github.com">GitHub</a>, <a
href="https://gitlab.com">GitLab</a>, or <a
href="https://prisma.io">Prisma</a> --- they all feel the same. Sure,
there are lots of differences between the sites, but those mostly lie in
the details.<a href="#fn1" class="footnote-ref" id="fnref1"
role="doc-noteref"><sup>1</sup></a> These websites do look nice and all,
but in a sea of complicated web design a simple website can be a nice
break from it all.</p>
<p>Why do all complex websites look the same? There's two reasons for
that feeling. The first is that even if there are <span
class="math inline">10<sup>5</sup></span> unique complex website designs
versus <span class="math inline">10<sup>3</sup></span> simple ones,
everyone is going for complex these days. The second is that people
actually pay a lot of attention to complexity: it's one of the first
things people notice, especially if they don't understand the nuances of
web design. Think about art: if you don't really know art all that well,
you probably mentally categorize paintings into three kinds: the normal
ones, the super minimalist ones, and then the plain weird ones (think
cubism).</p>
<p>Of course, there's another reason websites like mine feel so rare on
the internet: because a lot of "simple websites" literally do not have
any CSS styles whatsoever, so you get the ass-ugly default browser
theme. Most the other people who design websites like these do it a la
<a
href="https://perfectmotherfuckingwebsite.com/">perfectmotherfuckingwebsite</a>
to make a point. So on personal and business websites, you either get
people applying a lot of styling or none whatsoever.<a href="#fn2"
class="footnote-ref" id="fnref2" role="doc-noteref"><sup>2</sup></a></p>
<p>Yes, it may seem like your CSS isn't doing anything and you haven't
really scratched your design itch if it has very few classes and
declarations. But you know, not adding a bunch of stuff is a design
decision too, and it's not one people take very often. There are very
few websites with more than a page's worth of content that look like
this, so whatever you make is bound to be unique. Plus, this may just be
my personal taste, but I think websites with a tasteful amount of
styling are the ones that look the best.</p>
<section id="footnotes" class="footnotes footnotes-end-of-document"
role="doc-endnotes">
<hr />
<ol>
<li id="fn1"><p>It doesn't help that the content layout (or rather, the
lack of content) is also common between these three sites; I'd
personally appreciate a summary of the actual technical merits of the
product rather than some faffing.<a href="#fnref1" class="footnote-back"
role="doc-backlink">↩︎</a></p></li>
<li id="fn2"><p>Or it can just be incredibly ugly like my personal
website was circa 2018. It is possible to apply the wrong styles, and
that's another reason you should be conservative about adding them: it's
hard to mess up if you aren't really doing anything.<a href="#fnref2"
class="footnote-back" role="doc-backlink">↩︎</a></p></li>
</ol>
</section>]]></description>
	<pubDate>29 Jul 2022</pubDate>
</item>
<item>
	<title>Addendums to the design of a small self-hosted Git service</title>
	<link>https://dennisc.net/writing/tech/glee-addendums.md</link>
	<description><![CDATA[<p>I've done a bit of thinking on what my <a
href="/writing/tech/glee-design">self-hosted Git service</a> might look
at. I agree with all of the conceptual decisions I've made in my
previous post, but I'm going to specify some of the technology I'm going
to use.</p>
<p>For the API, I'm going to use Rust, period. I'm probably going to
keep my Tide + Postgres + Redis stack that I'm using for MAT-web. (This
means no wacky filesystem shenanigans that I described in the previous
post.) I also am going to try adding GraphQL, since I think it'll be
useful for the frontend.</p>
<p>I don't know about the frontend, which indicates that I really ought
to learn how to do it. Maybe SvelteKit? It seems promising. Anyway, I'm
going to set out a preliminary goal of 100KB or less per page request.<a
href="#fn1" class="footnote-ref" id="fnref1"
role="doc-noteref"><sup>1</sup></a> If SvelteKit doesn't pan out, I
might just server-side generate all of my pages, since</p>
<ul>
<li>the frontend does not have to scale</li>
<li>but it has to load fast for people using it.</li>
</ul>
<p>I will have to test on some old hardware with a throttled connection,
just to make sure</p>
<p>So when I call this Git service "small", it doesn't mean that the
codebase necessarily will be small. Heck, look at CGit --- it has 10390
lines.<a href="#fn2" class="footnote-ref" id="fnref2"
role="doc-noteref"><sup>2</sup></a></p>
<p>With regards to authentication, I want to make things simple AND
force people to do things the right way. To authenticate with the
frontend, you will login with your credentials (duh). The only way I
will allow authentication with Git is through an SSH key, because that
is the only way you should be authenticating in Git to begin with.
Username-password based solutions are hacky, stupid, and insecure.</p>
<p>Redirects are now low priority: in fact, I'll probably ship them out
only after I start dogfooding (i.e. host the development of Glee on my
Glee instance).</p>
<h2 id="cli-tool">CLI Tool</h2>
<p>The Glee CLI is going to be written in Rust too, since I want to
leverage <a href="https://docs.rs/clap/latest/clap">clap</a>. All the
standard stuff, like making directories, creating a new repo, etc will
be in it. However, the ergonomics are going to lean heavily on the
filesystem model that Glee is using. This means that instead of
<code>glee-cli group create PATH</code>, we will use
<code>glee-cli mkdir PATH</code>. And of course, authentication will be
based on SSH keys.</p>
<p>Of course, you will need some way of specifying a remote. There are
two ways to do this: either have the user build from source and have the
remote be specified compile-time (probably the worse option by far), or
read the remote from a config file at runtime (probably what I will
do).</p>
<p>A big feature that isn't in any other CLI I want to add is
<code>fscopy</code>. Basically, if you run</p>
<pre><code>glee-cli fscopy SOURCE TARGET</code></pre>
<p>it should clone SOURCE from the remote to TARGET on your filesystem,
using the default branches. The reason this is a big dealis because
fscopy, unlike git clone, would be recursive by default.<a href="#fn3"
class="footnote-ref" id="fnref3" role="doc-noteref"><sup>3</sup></a>
This is definitely possible in GitLab (which is the only other Git
hosting service that this would make sense for), but because GitLab
doesn't lean into the "Git hosting service as filesystem" mentality that
I will, I only thought of this while making the preliminary designs for
Glee (i.e. writing this post).</p>
<p>There are other operations that fit better when you consider the fs
model. For instance, in <a
href="https://glab.readthedocs.io/en/latest/">GLab</a> there is no way
to change the permissions of a repo/group, and this is likely because
it's hard to design. But for us,
<code>glee-cli chmod -r PATH --view=user --push=admin</code> will do the
job. (I intend for chmod to have an <code>-r</code> flag just because
there are times you want to change permissions recursively and times you
just want to change the default permissions for a directory. The
difference between chmod and fscopy is that one is a write operation
while the other is just a read operation.)</p>
<p>By the way, here I used the name <code>glee-cli</code> because it's
unambiguous what it does; it acts as the CLI for glee. But to make
typing it easier, I might change it to <code>glee</code> or
<code>gcli</code> when I actually write the CLI.</p>
<h2 id="patches">Patches</h2>
<p>Just like in Sourcehut, patches are expected to be sent by email. If
you're hosting software that's big enough to need a coordinated way to
send patches, it's probably a better idea to use something like
Sourcehut.</p>
<p>For purposes totally unrelated to Glee, I've wanted to get a mailing
list service for a while. Of course, reinventing the wheel here would be
silly, so I will probably try <a
href="https://lists.sr.ht/">lists.sr.ht</a> (obviously it will be
self-hosted). If nothing I find works well for me, I will write a
mailing list myself, but I really would rather not resort to that.</p>
<h2 id="licensing">Licensing</h2>
<p>AGPL-v3, duh. Yes, my previous stuff either uses MIT or BSD-3. But
that's because its potential use cases were so limited that there really
was no risk of exploitation, commercial or not. But since "Git hosting
service" is quite broad, even though few people will use this specific
design, any improvements better find their way back to me. There is no
legitimate reason for a Git hosting service not to be open source.</p>
<h2 id="this-will-likely-be-my-last-big-project">This will likely be my
last big project</h2>
<p>Given what's currently on my plate and the time I have before
college, this will probably be the last big project I have time to do on
my own, at least as a hobbyist. I don't even know if I want to work as a
programmer as my day-job. Here's what's coming up before:</p>
<ul>
<li>Whatever maintenance of mapm is necessarily</li>
<li>Maybe mapm-gui</li>
<li>mat-web</li>
<li>Maybe a MAST-web rewrite</li>
<li>My geometry book (probably will happen in parallel --- not a
software engineering project, but I will likely focus on that
first)</li>
</ul>
<p>I don't really want to do any of these besides mat-web and the
geometry book, so I will probably get started on Glee soon. Making a new
Git service will likely be a significant undertaking, even if I'm not
offering it as a SaaS. I'm fine with this becoming my flagship software
product for the next five years or so.</p>
<section id="footnotes" class="footnotes footnotes-end-of-document"
role="doc-endnotes">
<hr />
<ol>
<li id="fn1"><p>This is compressed on a fresh page load.<a
href="#fnref1" class="footnote-back" role="doc-backlink">↩︎</a></p></li>
<li id="fn2"><p>This figure was gotten from <code>wc -l *.c *.h</code>.
The actual significant lines of code is probably less than this.<a
href="#fnref2" class="footnote-back" role="doc-backlink">↩︎</a></p></li>
<li id="fn3"><p>If you wanted something non-recursive you'd just use
<code>git clone</code>.<a href="#fnref3" class="footnote-back"
role="doc-backlink">↩︎</a></p></li>
</ol>
</section>]]></description>
	<pubDate>8 Jun 2022</pubDate>
</item>
<item>
	<title>Drawing right angles in Asymptote</title>
	<link>https://dennisc.net/writing/tech/asy-right-angles.md</link>
	<description><![CDATA[<h2 id="background">Background</h2>
<p>Most people in AoPS use AoPS' olympiad.asy module to draw their
diagrams. It provides functionality such as
<code>circumcenter(A,B,C)</code>, <code>rightangle(A,B,C)</code>, and so
on --- it provides methods for common olympiad geometry
constructions.</p>
<p>But olympiad.asy is not a standard Asymptote module, it is an
external library. And there already is a module in the standard library
that does what olympiad.asy does, and arguably better. It is
geometry.asy.</p>
<p>As an analogy, consider using an external library in your programming
language of choice for string replacement rather than using the standard
library. It doesn't matter if the external library is written well,
because the standard library exists and it works well too. Why rely on
an external dependency when you don't need to?</p>
<p>By the same reasoning, you should avoid using olympiad.asy. Its
functionality can be completely replicated by the standard geometry.asy
module, which you have installed with Asymptote whether you know it or
not.</p>
<h2 id="drawing-a-right-triangle-in-geometry.asy">Drawing a right
triangle in geometry.asy</h2>
<p>Unfortunately geometry.asy's <code>perpendicular</code> function is
not the most intuitive. The function (simplified to only the arguments
we care about) looks like this:</p>
<div class="sourceCode" id="cb1"><pre
class="sourceCode latex"><code class="sourceCode latex"><span id="cb1-1"><a href="#cb1-1" aria-hidden="true" tabindex="-1"></a>perpendicular(pair vertex, pair direction, pair offset)</span></code></pre></div>
<p>The vertex is where the right angle will be drawn. The offset
determines one of the non-base vertices of the "right triangle" (only
the direction is relevant, not the magnitude), and the direction
determines the angle bisector relative to the line formed by
<code>vertex</code> and <code>vertex + offset</code>.</p>
<p><img class="asy" src="rightangle.svg"></p>
<p>A really simple example:</p>
<div class="sourceCode" id="cb2"><pre
class="sourceCode latex"><code class="sourceCode latex"><span id="cb2-1"><a href="#cb2-1" aria-hidden="true" tabindex="-1"></a>import geometry;</span>
<span id="cb2-2"><a href="#cb2-2" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb2-3"><a href="#cb2-3" aria-hidden="true" tabindex="-1"></a>perpendicular((0,0), NE, (1,0));</span></code></pre></div>
<p>It will generate the right angle above (without any of the extra
labels, lines, dots, etc).</p>]]></description>
	<pubDate>9 Aug 2022</pubDate>
</item>
<item>
	<title>Causative Assessments</title>
	<link>https://dennisc.net/writing/essays/causative-assessments.md</link>
	<description><![CDATA[<p>There's a great amount of debate about what the
SAT measures. Does it measure income? Intelligence? Preparation? Or some
combination thereof? But for all the buzz about what the SAT measures,
no one ever asks what the SAT <em>changes</em>.</p>
<p>When you're measuring the height of a plant, the plant could care
less. At least, until you start selecting for or against height. But
testing students will affect what you are measuring, because people are
sentient. So no test can be a truly accurate measurement of achievement,
because the very existence of said test distorts whatever measure of
achievement you are using. It's like Heisenberg's uncertainty principle;
by observing it, it changes.<a href="#fn1" class="footnote-ref"
id="fnref1" role="doc-noteref"><sup>1</sup></a></p>
<p>If the existence of a test affects how you learn, we should demand
that it has a positive effect on learning. Especially if you still have
things to learn down the road. And there is always something more to
learn.</p>
<p>Preparing for the tests we take is also incredibly time consuming.
Let's say that in junior year, you spend two hours a week preparing for
the SAT, from August to March. That comes out to be about 60 hours. If a
kid wasted that much time on video games his parents would be mad. But
when it comes down to it video games teach you more than the SAT.</p>
<p>Sixty hours is a lot of time. It was enough for me to learn Linux and
become fairly proficient in it. I took less time to write and ship a
functional first version of <a href="mapm.mathadvance.org">mapm</a> ---
library, command-line interface, and documentation. Not every chunk of
sixty hours will be this valuable. But multiply a lot of tests to study
for and the entire population of the United States, and you get a sense
of how much productivity has been lost.</p>
<p>It's true that whatever high school students do mostly amounts to
chump change. But just as we give kids allowances to promote responsible
spending, we also have to promote responsible learning.</p>
<p>Some tests have been able to do this. I think any major STEM contest
(especially the AMCs) does this well. You can't just "study to the
test", or more accurately, the only effective way to study is to
genuinely learn. For the AMCs, you don't agonize over the specific
format or types of questions,<a href="#fn2" class="footnote-ref"
id="fnref2" role="doc-noteref"><sup>2</sup></a> you just work on
problem-solving and learning new things.</p>
<p>In all fairness you can't reliably "hack" the SATs anyway. <a
href="https://slate.com/technology/2019/04/sat-prep-courses-do-they-work-bias.html">Evidence
of a significant benefit from prep programs is limited at best.</a> But
the problem is, if the SAT is an IQ test that also determines your
future, two things are true: you have extremely high incentive to study
for the SATs, and you can't get better at the SATs.</p>
<p>So what should a good test look like? Pretty much the opposite of the
SATs. It should not be too high-stakes, because even an initially
positive distortive effect taken to an extreme becomes harmful, it
should not be something worth specifically studying for, because it
should measure things that align with skills people find worth
developing, and it should also be possible (<a
href="https://web.evanchen.cc/faq-raqs.html#R-3">though not
guaranteed!</a>) to improve significantly with hard work. And perhaps
most importantly, it should be fun.</p>
<section id="footnotes" class="footnotes footnotes-end-of-document"
role="doc-endnotes">
<hr />
<ol>
<li id="fn1"><p>For anyone who actually understands Heisenberg's
uncertainty principle, I am sorry for this terrible pop science
analogy.<a href="#fnref1" class="footnote-back"
role="doc-backlink">↩︎</a></p></li>
<li id="fn2"><p>At least you shouldn't. This doesn't stop some younger
students from pointless speculation.<a href="#fnref2"
class="footnote-back" role="doc-backlink">↩︎</a></p></li>
</ol>
</section>]]></description>
	<pubDate>15 Mar 2022</pubDate>
</item>
<item>
	<title>To parents: stop emailing me</title>
	<link>https://dennisc.net/writing/essays/dont-email.md</link>
	<description><![CDATA[<p>I'm really, really hesitant to issue a blanket
statement that amounts to "don't contact me." I like to think of myself
as a pretty nice person who tries to help people learn math when I can,
and I also like to think that most of the time my emails are helpful.
But there is one big exception: parents.</p>
<p>Most of the time when parents email me I don't really know how to
respond. And it's because I've only had the perspective of a student,
which means that any answer I give will be tailored for students. Since
students won't be reading emails sent to their parents, it honestly
feels like a waste of time.</p>
<p>Let me put it this way. I receive about a dozen emails a month asking
for math instruction ("Can I apply for MAST" included). I'd say about
2/3 of it comes from students and the other 1/3 come from parents. So
far every student has gotten a helpful answer from me, and as far as I
can tell, no parent has gained anything from emailing me.</p>
<p>So if you are a parent, what should you do? I think the answer
differs depending on how old your child is and who you're asking, but
here are a couple of pointers.</p>
<ul>
<li>If you are forcing your kid to do math contests (especially if it is
for college), just stop. I have a lot of harsh things that I want to say
to these people, but I will leave such comments to the imagination.</li>
<li>If your kid has just started math contests and might not be as
willing to cold contact people, then cc your child in the email. The
reason parent emails are a waste of my time is because the kids don't
read them.</li>
<li>If your kid is really young, i.e. too young to send an email
themselves, unless they are an AIME qualifier I don't think I'll be of
much help anyway. If they are an AIME qualifier, look at <a
href="https://mast.mathadvance.org">MAST</a>.</li>
<li>If your kid is old enough to send an email, then please have them do
it themselves. Typically I can glean a lot more information from
students than I can from parents.</li>
</ul>
<p>I wrote this essay not to discourage people from emailing me ---
there are certainly many useful emails parents can send me! But I do
hope that my future emails become more productive. Every email I've
received from parents are of the form "my kid is in Xth grade and wants
to prepare for contests A,B,C". Really, the only difference X makes is
whether the kid is old enough to send an email on their own, and the
contests they want to prepare for invariably are the AMC 10 and maybe
AIME or MATHCOUNTS. It's very hard for me to give any guidance, or even
to tell whether my classes would be appropriate, with such little
information.</p>
<p>So in summary: have students email me if possible, cc them otherwise,
make sure I have a direct avenue to communicate with them, and give me
specifics. If you write and send your email in a way that makes it easy
for me to help, then there is no reason for me not
to.</p>]]></description>
	<pubDate>21 Apr 2022</pubDate>
</item>
<item>
	<title>ChatGPT</title>
	<link>https://dennisc.net/writing/essays/chatgpt.md</link>
	<description><![CDATA[<p>I'm no expert on AI or ML (I barely know
anything about either), but I do have a couple of thoughts about ChatGPT
and the effect it might have on the humanities.</p>
<h2 id="sudoku">Sudoku</h2>
<p>Sudoku puzzles have been computer-generateable for a long time now,
so the role of computers in creating puzzles is pretty well-established.
And what setters have found is that computers are pretty good
assistants<a href="#fn1" class="footnote-ref" id="fnref1"
role="doc-noteref"><sup>1</sup></a>, but they are terrible at
independently setting puzzles.</p>
<p>That's because computers have no intent. They can't actually design a
break-in or a finish or anything in between. They just throw shit at the
wall until they set something that <em>technically</em> works, and these
kinds of puzzles are terrible.</p>
<p>You can easily tell the difference between a computer-generated
puzzle and a handcrafted one. Computer in no way have replaced puzzle
constructors.</p>
<h2 id="writing">Writing</h2>
<p>So why is ChatGPT such an existential threat to the humanities? I
freely admit that there are substantial differences: language is much
easier to codify than logic, and you do have some control over the
output with prompts (in other words, you can inject some intention).</p>
<p>But at its core, the role of computers in the two are the same. If
you're setting puzzles like a computer, then stop setting puzzles like a
computer. And if you're writing like a chatbot, then <em>stop writing
like a chatbot</em>.</p>
<p>I predict that a lot of English-adjacent humanities, particularly
literary criticism, will be existentially threatened, because what they
do is just <a href="https://en.wikipedia.org/wiki/Sokal_affair">putting
nonsense words down on paper</a>. And people have already managed to do
this before ChatGPT.</p>
<p>Ultimately, I think ChatGPT might pose a threat to some humanities
classes, but I regard this as a good thing. Because if a class is
literally making you write like a robot and no one can tell the
difference, maybe you're better off actually writing it with a
robot.</p>
<section id="footnotes" class="footnotes footnotes-end-of-document"
role="doc-endnotes">
<hr />
<ol>
<li id="fn1"><p>What they're most useful for is making sure a puzzle
isn't broken. I use F-Puzzles solver pretty often to finish my puzzles,
since at that point it's typically just discovering the one best clue
that will resolve the entire grid.<a href="#fnref1"
class="footnote-back" role="doc-backlink">↩︎</a></p></li>
</ol>
</section>]]></description>
	<pubDate>17 Feb 2023</pubDate>
</item>
<item>
	<title>Exhaustion</title>
	<link>https://dennisc.net/writing/blog/exhaustion.md</link>
	<description><![CDATA[<p>In high school, I found it odd how many kids in
TV shows would fall asleep during school. It was a funny gag, sure, but
there was just <em>no way it happened in real life</em>. How the hell do
you get so tired that you involuntarily fall asleep during the middle of
the day, sitting in the most uncomfortable chair ever known to mankind?
Meanwhile, I'd try as hard as humanly possible to fall asleep whenever I
finished a test (because we couldn't leave early), and the best I ever
managed to do was lie on a desk for fifteen minutes without getting
bored.</p>
<p>How blessed I was. As a college student now, let me tell you: there
isn't a single class I <em>haven't</em> fallen asleep in. And this isn't
because the professors are boring.<a href="#fn1" class="footnote-ref"
id="fnref1" role="doc-noteref"><sup>1</sup></a> All of my professors
during the spring of my freshman year were downright fantastic, and yet
I could not keep the lights on in my head.</p>
<p>And I didn't even find CMU unreasonably hard. I wasn't staying up
many nights to finish assignments. I <em>was</em> staying up some nights
for really stupid reasons, like destroying some scrubs in Smash. But
even on the nights where I would sleep at a reasonable time, I'd just be
perpetually <em>exhausted</em>.</p>
<p>In fact, this has been a concerning trend in my life. In elementary
school I would never want to take a nap because I just had <em>so much
energy</em>. High school, I'd wake up tired some days, but I'd be more
or less at full power whenever I needed to. This year, <em>I don't think
I've been fully sharp for more than 30 days</em>. This is
<em>terrifying</em>. Sure, after this year I can tell you all about the
universal property of the free group. But despite this, I now feel like
a useless moron most of the time because <em>my brain is too exhausted
to do anything beyond the bare minimum</em>.</p>
<p>Back in the day, I'd take plenty of long walks with no distractions
and think about something meaningful. Or just sit down, breathing in the
fresh air, with the only thing on my mind being "how do I make this
puzzle work?" Now in college (especially during Tuesdays last semester
when I had eight hours of classes) I just shuffle between classes,
wishing for the day to end so I can just go and play Smash with my
friends, goddamnit.</p>
<p>Despite the bad parts of high school (and college is by far an
improvement), at least I spent most of my waking hours fairly sharp.
Yes, every day of high school was 8 hours of classes, which was absurdly
exhausting too, but I was just bored. My brain wasn't completely fried,
and when I got back from track practice, more often than not I'd be
itching to work on something.</p>
<p>Now I am at an internship, and it is so exhausting that I don't think
I spend a single day being <em>sentient for more than two hours</em>.
And many days the amount of time I spend being sentient is a big fat
zero.</p>
<p>At least in my internship, I have two saving graces: it is a startup,
so the internship program is much less bullshit<a href="#fn2"
class="footnote-ref" id="fnref2" role="doc-noteref"><sup>2</sup></a>
than it would be at big tech,<a href="#fn3" class="footnote-ref"
id="fnref3" role="doc-noteref"><sup>3</sup></a> and I am going to be
back in school at the end of the summer, which helps to stave off a lot
of identity crises.</p>
<p>It is no coincidence that in my senior year of high school,
<em>despite college apps</em>, I was able to publish nearly fifty
puzzles. After college started, I have only published five. A similar
trend has followed in my writing, though thankfully to a much less
alarming extent.<a href="#fn4" class="footnote-ref" id="fnref4"
role="doc-noteref"><sup>4</sup></a> And it isn't because school takes
more time --- if anything it is the opposite. And I actually enjoyed
most of my homework, rather than wanting to skewer my brain with a
screwdriver while doing it like I did in high school. So the rigors of
college, however high they might be, do not entirely explain this
change.</p>
<p>I can only imagine that --- at least in the average case --- things
will not get much better in the typical software engineering job. If
left unchecked, my life is heading towards a trajectory where I become
more lifeless as time goes on, until one day a Dementor comes and eats
my soul wholesale.</p>
<h2 id="dreams">Dreams</h2>
<blockquote>
<p>In the months that follow you bend to the work, because it feels like
hope, like grace – and because you know in your lying cheater's heart
that sometimes a start is all we ever get.</p>
</blockquote>
<p>Of course, I have no such plans to ossify. But it has been important
for me to note that I have been more and more exhausted as time has gone
on, and that this trend does not seem likely to reverse itself on its
own.</p>
<p>In some sense I have been living my life by the greedy algorithm. I
skipped the introductory math courses because it would make my academic
experience more interesting. I took on a ridiculous courseload because
each individual class seemed interesting to me. And the hard part is,
many of these were good decisions, at least when taken individually. But
putting it all together, I have spent my life becoming unnecessarily
good at math and computer science. Do I really envision doing this for
the rest of my life? Or will the greedy algorithm just lead me to a
local maximum, stuck in the middle of a valley and surrounded by
alternative possibilities far more worth living?</p>
<p>Potentially math. There's a real case made for being a professor,
though from what I can see the road there is quite painful. But I
couldn't envision <em>programming</em> becoming anything more than a
hobby: if I'm going to program something, I'm going to take the time to
do it well, but I cannot be assed to spend time writing shitty code I
don't give two shits about for eight hours a day, five days a week,
forty weeks a year for the rest of my life. In the long term, this rules
out most big tech. Because if I have to write another line of React or
<code>import magic</code> from Python again, I might actually go
<em>insane</em>.</p>
<p>But in the ideal world, the world where I have a trillion dollars and
the skies in Pittsburgh are clear every day, I'd want to read, write,
and maybe even draw stories. I can't say for certain, but gun to my
head, that would be a more appealing future than doing math ---
<em>especially</em> if there comes a point when math literally stops
making sense for me. At the very least, it is about equally as important
to me as math. Yet I have spent half of my waking hours in college doing
math, and yet not a single story has been written in the past three
years (let alone been published anywhere, including this website).</p>
<p>Why such the disparity? Because I'm much better at math than writing
stories, and people are much more likely to pay me exorbitant sums to be
good at math than to write. That's the problem with following the greedy
algorithm: at any point in time, specializing even further in the thing
I am good at is the only move that makes sense.</p>
<p>But in the grand scheme of things, I am terrible at writing stories
and just slightly less terrible at math. There is still time to decide
to never listen to another word of math again, learn enough CS to
graduate, get a part-time software engineering job and spend the rest of
my life in a Starbucks with some pen and paper. Ditto for a thousand
other things I want to try but am too scared to take seriously.</p>
<p>Yet I am still in a tech internship building badass robots<a
href="#fn5" class="footnote-ref" id="fnref5"
role="doc-noteref"><sup>5</sup></a> and still enrolled for a graduate
class where I will learn how to show that CH is independent of ZFC. It's
not for practical reasons: there is no universe where <em>model
theory</em> makes me rich or even employed. But even with the many other
things I want to do in my life, model theory is <em>goddamn cool</em>.
Math is cool. There is no way I'm ever completely giving up a subject
where you can look at a quintic polynomial and conclude it is
unsolvable, and then turn around and prove the Fundamental Theorem of
Algebra using the same tools (Galois Theory). Life would be a lot less
complicated if math was just this terrible, disgusting subject, but it
just is not.</p>
<p>Even computer science is cool. Functional paradigms are cool, Rust is
cool, systems and comparch are cool (but massive pains in the ass). And
I really do want to learn more about each of these subjects, even though
going to college for computer science <em>is the reason</em> I'm so
exhausted.</p>
<p>But the simple arithmetic of time means if I want to spend time
learning how to write, draw, and push around comically large weights in
the gym, something has to give. It's not going to be sleep, I'm already
barely functioning as it is. It's not going to be socialization or video
games because that's the only thing that unfries my brain. I do need to
read less manga, but that won't be enough. By sheer process of
elimination... it's got to be math or computer science.<a href="#fn6"
class="footnote-ref" id="fnref6" role="doc-noteref"><sup>6</sup></a> As
unfortunate as it is, I really cannot justify learning category theory
or the Curry-Howard Isomorphism if it comes at the expense of writing
the things I want to write. If it comes at the expense of not taking
myself seriously in any domain besides mathematics.</p>
<blockquote>
<p>Have you considered not spending three hours a day solving logic
puzzles---</p>
</blockquote>
<p>Hahahahaa that's a funny one.</p>
<p>Listen, I'm fully aware someone's going to say "you're just a college
sophomore. Why are you thinking so hard?" You're right. I haven't even
truly experienced the life of the working man. But at some point in my
life, I will be wondering what went wrong and start digging through the
past like a complicated stacktrace. And the stacktrace certainly will
not have started now, this summer, or even this year. It may have
started when my stupid little brain decided to prioritize getting better
at multiplying over anything else. But I can't do anything about that
now, can I?</p>
<p>What I <em>can</em> do is at least <em>think about</em> how I'm going
to steer off this course of being constantly exhausted and only giving
half-caring about my work. I would rather try and adjust my life right
now as the naive little idiot I am, instead of waiting until I am a
jaded old idiot wondering why I want to drive a skewer through my
eyeballs every time I see someone commit <code>.DS_Store</code> to a
goddamn Git repo. I may not have lived for very long, but it doesn't
take a genius with significant life experience to figure out that
<em>churning out CRUD APIs with a lifetime of precisely 0 seconds on
prod</em> is not the ideal life.</p>
<p>And unfortunately, though the things I am learning are very cool, the
habit of "focusing on the right things" that studying computer science
is building is very not cool. One day, it will feel deeply wrong to do
computer science, and that is when it will make sense for me to immerse
myself in computer science. But for now, I need to decouple it from my
increasing risk aversion and the future where I sit in front of a screen
and write ultimately inconsequential code for eight hours a day for the
rest of my life. Even if that inconsequential code makes me a lot of
money.</p>
<h2 id="puzzles">Puzzles</h2>
<blockquote>
<p>The silly puzzle man strikes again</p>
</blockquote>
<p>This post is sectioned into three sections. The first is on my
concerns about where my life is headed. Then where I want my life to
head. Now I will pat myself on the back for not <em>completely blowing
it</em>. If you have any understanding of me or this blog --- an
understanding that takes all of eight seconds to achieve --- you know
that I spend half my waking hours thinking about logic puzzles. Well, I
am glad to report that nothing can stand between me and my puzzles, and
I'm goddamn proud of it.</p>
<p>That's not to say my puzzle hobby came out unscathed. A year ago I
had the stamina to write <a
href="https://puzz.dennisc.net/#alphabet-soup">Alphabet Soup</a> and my
brain was fed puzzles zany enough to construct my <a
href="https://puzz.dennisc.net/?tag=Fillomino">Fillomino puzzles</a>. I
like to think the last few puzzles I've published are really good too,
but you don't have to be very observant to realize I've been exclusively
using Killer Cages and Arrows for the past <em>half year</em>. I no
longer have the chutzpah to cook up a new variant that'll take an entire
week to resolve, and I think both me and the world are worse off for it.
Because if I don't wrap up a puzzle neatly, I get to wake up to a
million other responsibilities that need to be taken care of before I
finish the puzzle. The takeaway is that I need to make time for myself
where things just stop piling onto me, or more realistically, where I at
least get to pretend they don't exist for half a week.</p>
<p>I'll admit it. Right now I'm completely out of ideas. Nothing I've
really solved recently has inspired me, which is no fault of those
incredible puzzles. The last puzzle I posted was the result of a stupid
idea I had while lifting weights, and I just got really damn lucky that
it worked out somehow. But you know, I just set a puzzle less than a
week ago. I think it makes sense to be a little optimistic right now,
even if I have no clue how I'm going to set the next one.</p>
<blockquote>
<p>But what do puzzles have to do with writing stories---</p>
</blockquote>
<p><em>Everything</em>. I've written stories before, though looking back
I'd like to beat the life out of each one of them with a fireplace
poker. And I write puzzles, of course, that's at least an eighth of my
personality. And even though one seems like a purely logical endeavor,
while the other is emotional, I believe they speak to the same part of
the soul. The part that hopes the ideas you want to tell fit together,
the part that screams in relief when it all just <em>works</em>. The
part that reaches for an easy conclusion, and the part that says Wait.
You can do better. There is a good way to finish this puzzle, to finish
this story, and it's somewhere in you, so you better start looking
goddamnit.</p>
<p>So maybe I'm not completely screwed. I believe that the part of my
soul that writes puzzles can be rekindled to help me write stories
again, and to nurture that part of my soul I will proceed to spend the
next 3 hours doing nothing but puzzles---</p>
<h2 id="takeaways">Takeaways</h2>
<p>There are none.</p>
<p>I dunno, life is really complicated. If I knew what I was doing, if I
could coherently tell you what I wanted to do in the future, it wouldn't
have taken me three thousand words to do it.</p>
<p>There is a story I want to write that is still fresh in my head. Only
time will tell if it will be good, and above all, whether I have the
courage and stamina to go through with it. I want to end this on a
hopeful note, so I'll say this: please look forward to it sometime in
the future.</p>
<section id="footnotes" class="footnotes footnotes-end-of-document"
role="doc-endnotes">
<hr />
<ol>
<li id="fn1"><p>Although there is a certain quality to the voices of
some speakers that makes it easy to fall asleep. During the fall of my
freshman year, I attended the Pittsburgh Number Theory seminar and
proceeded to knock out during the first presentation. The second
presenter was much more energetic, and I didn't even have to
<em>try</em> to stay awake then. Although maybe the (involuntary) nap I
took during the first presentation helped with that...<a href="#fnref1"
class="footnote-back" role="doc-backlink">↩︎</a></p></li>
<li id="fn2"><p>In fact, the few things I find bullshit about the job
can probably be attributed to me being a moron who has no real useful
skills. If I actually had the ability to do stuff in the hardware space,
I would probably be extremely happy and sentient. Alas, my only skill is
learning and writing about <a href="/math">abstract nonsense</a>. This
is not a skill that translates over particularly well to <em>doing
useful stuff</em>, especially when compared to a background of having
done useful stuff before. Not that I'd trade math for any of it, of
course.<a href="#fnref2" class="footnote-back"
role="doc-backlink">↩︎</a></p></li>
<li id="fn3"><p>My friends at a certain big tech company have written
three Java classes in <em>a month</em>.<a href="#fnref3"
class="footnote-back" role="doc-backlink">↩︎</a></p></li>
<li id="fn4"><p>At a quick glance I'd say I've written half as much
stuff this school year as I did last school year. Considering my
absolutely monstrous pace last year, and considering the ratio of
decrease is only 50% as opposed to 90%, this is actually a success all
things considered.<a href="#fnref4" class="footnote-back"
role="doc-backlink">↩︎</a></p></li>
<li id="fn5"><p>Okay, I'm not the one building the robots, sorry for
lying to you. But it sounds a lot cooler than "I wrote some crud API
that might get deployed to prod eventually".<a href="#fnref5"
class="footnote-back" role="doc-backlink">↩︎</a></p></li>
<li id="fn6"><p>Fortunately I can make a lot of time for myself by just
not reading Hacker News and learning about random computer science
topics that way. Unfortunately, the difficulty in life is energy
management rather than time management, and to me reading Hacker News is
unwinding.</p>
<p>...yes, I am a nerd.<a href="#fnref6" class="footnote-back"
role="doc-backlink">↩︎</a></p></li>
</ol>
</section>]]></description>
	<pubDate>26 Jun 2024</pubDate>
</item>
<item>
	<title>Good writing is about standards</title>
	<link>https://dennisc.net/writing/essays/standards.md</link>
	<description><![CDATA[<p>Everyone knows that <em>one person</em> who
just can't clean up after themselves. You look at their room or whatever
and it's super nasty, and any reasonable person would have gone "ick
this feels wrong I need to fix it" by that point, but somehow they
don't.</p>
<p>This is the kind of thing good writers want to avoid. A good writer
can know that a sentence <em>feels</em> wrong, not because of some
specific grammatical rule, but because it just seems nasty. Where other
writers might think, "I have expressed my idea, this is fine", a good
writer will only be satisfied with "I have expressed my idea and <em>it
sounds right</em>."</p>
<p>A good writer also doesn't follow arbitrary rules just because some
authority figure told them to. They have a good instinct for what
conventions they should naturally adopt. For instance, it makes perfect
sense for me to use the personal pronoun when signposting. When English
teachers tell you not to use the word "we", they're wrong: <em>even
English papers use "we"</em>. That's because it sounds right.</p>
<p>If you want to write well, develop good hygiene. Learn to be icked
out when phrases or sentences are awkward.<a href="#fn1"
class="footnote-ref" id="fnref1" role="doc-noteref"><sup>1</sup></a> Be
aware of how your sentences sound. And above all, when your writing
starts getting nasty, clean it up. Make it a compulsion. If you can't
tolerate bad writing, you won't do it. It doesn't get any simpler than
that.</p>
<section id="footnotes" class="footnotes footnotes-end-of-document"
role="doc-endnotes">
<hr />
<ol>
<li id="fn1"><p>Unfortunately, I am unsure of how much this skill can be
developed. Tidiness is somewhat intrinsic, and some people cannot find
it in themselves to care.<a href="#fnref1" class="footnote-back"
role="doc-backlink">↩︎</a></p></li>
</ol>
</section>]]></description>
	<pubDate>15 Sep 2023</pubDate>
</item>
<item>
	<title>Write what you don't believe</title>
	<link>https://dennisc.net/writing/essays/write-what-you-dont-believe.md</link>
	<description><![CDATA[<p>The goal in my essays isn't writing what I
believe --- it's writing what's true.</p>
<p>It seems counterintuitive, but writing about things you don't feel
passionately about can actually make you better at writing --- and it
might turn out to be better writing to boot. It's the difference between
acknowledging something as true and ardently believing that it must be.
With the former, you are just finding the dots and connecting them, and
with the latter, you can get easily blindsided because you are putting
<em>yourself</em> out there.</p>
<p>Not every essay on something you're passionate about will turn out
bad. But not every good essay has to be on something you're passionate
about. The reflective side is just as powerful as the passionate, and
it's okay to sometimes be a little disconnected from your words. That's
the power of writing: you can say things you never even would've thought
about otherwise.</p>]]></description>
	<pubDate>22 Oct 2022</pubDate>
</item>
<item>
	<title>Hook</title>
	<link>https://dennisc.net/writing/essays/hook.md</link>
	<description><![CDATA[<p>People don't have trouble beginning a
conversation the same way they do when writing something. To be sure,
conversations may not always be easy to start. But it's not hard for the
same reason an essay is hard to write. Conversations are hard to begin
because you don't know where they'll end up. But essays are hard to
begin because you don't know where they'll start.</p>
<p>Usually I begin with a surprise. Not the sort of surprise that
contradicts the reader's intuition, but rather a surprise that confirms
and clarifies it. It's something that I expect the audience to know on
some level but the general public does not. It's almost like letting
them in on a secret: you've established a common ground with your
audience, and nobody else knows about it.</p>
<p>Hooks get people interested when it tells them your writing is worth
their time. And a surprise is a sure sign that what you have to say is
worth their while. It means you've told them something that they don't
know, and more importantly, surprise means it's interesting. But that's
not why I start with surprises. It's not merely cold calculation that
shapes my essays. In fact, it mostly isn't cold calculation.</p>
<p>It's really hard to bullshit your way through a piece of writing.
Imagine what your favorite book would look like if the author didn't
care. It'd be really easy to tell. Maybe not on its own, but the
difference is night and day if you compare it with something the author
<em>wanted</em> to say. That's what shapes my writing. What do I think
is worth saying, and how do I say it?</p>
<p>Typically I write things in the order I think of them, at least
roughly. It seems to work in the middle, for the most part. Maybe in the
end I have a conclusion whose points I didn't clarify. Sometimes this
means abandoning my old draft and writing the essay I really meant to.
Other times I figure out there are a couple more points to add.<a
href="#fn1" class="footnote-ref" id="fnref1"
role="doc-noteref"><sup>1</sup></a> But the beginning is always the
scariest, because I have no clue where I want to go.</p>
<p>When I start writing it's always because I have more ideas than I can
remember. Going in, it seems that I have enough to write about. But my
ideas start out with a lot of breadth and not a lot of depth. In fact,
my private writing notes look a lot like this too. I have a long list of
things I want to write about and most of them are half-formed ideas.
This may be the threshold for being a good writer: having depth be a
larger focus than breadth.<a href="#fn2" class="footnote-ref"
id="fnref2" role="doc-noteref"><sup>2</sup></a></p>
<p>I think depth is a lot more interesting to read than breadth. It
certainly is more fun to write with depth. So I do a depth-first search
when it comes to figuring out what I want to write about. But I don't
pick my first node at random. I look for what'll most likely lead me
down a rabbithole. I look for <em>surprises</em>.</p>
<p>What a smart audience wants is not a random factoid, or clickbait, or
even a specific topic. They just want to see that there's something to
explore, that the rabbithole doesn't end abruptly. This sounds
remarkably similar to what makes something worth writing. Indeed, what
the reader wants and what the writer wants converges the smarter the
audience gets. So you just need to convince the reader your essay was
interesting enough to be worth writing.</p>
<p>I thought it was interesting that the beginning of an essay was so
hard to write. But why is it interesting? Because it's <em>unusual</em>.
It's not the same kind of hard to start a conversation, write a report,
or send an email, because at least there you have an idea what you want
to do. For an essay you have to convince yourself it's worth writing,
because nothing will happen to you if you don't write it. And you have
to convince the reader it's worth reading, because nothing will happen
to them if they don't read it.</p>
<p>The hook is taking what made you start writing and putting it into
words. When you're finished that reason might have changed. But that's
fine. An essay is supposed to be a train of thought anyways, not merely
a list of points supporting a predetermined conclusion.</p>
<section id="footnotes" class="footnotes footnotes-end-of-document"
role="doc-endnotes">
<hr />
<ol>
<li id="fn1"><p>If there's a point I want to make in the conclusion but
forget to make in the body, it suggests that I need to update my mental
model. These sorts of realizations are why I write.</p>
<p>(Of course, "body" and "conclusion" are not very well-defined, but I
am using these terms in a colloquial sense.)<a href="#fnref1"
class="footnote-back" role="doc-backlink">↩︎</a></p></li>
<li id="fn2"><p>I think English class is the antithesis of good writing.
When you do a "deep analysis of a quote" you are not really analyzing it
with depth. You are analyzing it with breadth. This is probably by
necessity, because when you do literary or rhetorical analysis, you
maybe have around three sentences of stuff to say. So you have to focus
on breadth to make your essay long enough.</p>
<p>But teachers (and students) like to think English class is deep. So
they use big words like <em>logos</em> instead of logic, or
<em>diction</em> instead of word choice, and this serves to distract
from the lack of depth in English class. At the end of the day though,
English papers are still long lists. It's just a little harder to read
than usual.<a href="#fnref2" class="footnote-back"
role="doc-backlink">↩︎</a></p></li>
</ol>
</section>]]></description>
	<pubDate>22 Sep 2021</pubDate>
</item>
<item>
	<title>The best output given two inputs</title>
	<link>https://dennisc.net/writing/essays/best-output.md</link>
	<description><![CDATA[<p>Once upon a time, I had an interview question
that went something like this. You are trying to predict some event
<span class="math inline"><em>E</em></span>, and you have a model <span
class="math inline"><em>M</em></span> with which to do so. Suppose there
is some other model <span class="math inline"><em>N</em></span>. How
should <em>you</em> personally value model <span
class="math inline"><em>N</em></span>?</p>
<p>Here is the naive answer. Suppose <span
class="math inline"><em>P</em>(<em>M</em>)</span> and <span
class="math inline"><em>P</em>(<em>N</em>)</span> are the performances
of models <span class="math inline"><em>M</em></span> and <span
class="math inline"><em>N</em></span>, respectively. (Maybe <span
class="math inline"><em>P</em>(<em>M</em>)</span> is the amount of money
that <span class="math inline"><em>M</em></span> makes you.) Then the
value of model <span class="math inline"><em>N</em></span> is <span
class="math inline"><em>P</em>(<em>N</em>) − <em>P</em>(<em>M</em>)</span>
if <span
class="math inline"><em>P</em>(<em>N</em>) &gt; <em>P</em>(<em>M</em>)</span>,
and otherwise <span class="math inline"><em>N</em></span> is worthless
to you. Basically, <em>the value of <span
class="math inline"><em>N</em></span> is how much better <span
class="math inline"><em>N</em></span> does than <span
class="math inline"><em>M</em></span>.</em></p>
<p>But this is very much the wrong answer. <strong>The value of <span
class="math inline"><em>N</em></span> is based on the best model you can
get by combining <span class="math inline"><em>M</em></span> and <span
class="math inline"><em>N</em></span>.</strong> Let me illustrate this
for you with a concrete example.</p>
<p>Suppose I have a model <span class="math inline"><em>M</em></span> to
predict yes/no events. It is correct only <span
class="math inline">2/3</span> of the time. Suppose you and your friend
have two models <span class="math inline"><em>N</em><sub>1</sub></span>
and <span class="math inline"><em>N</em><sub>2</sub></span> which do the
same. Individually, they are no better than guessing. However, the
models have an interesting relation: <em>The majority vote of the models
is always correct.</em> Simply put, if at least two of the models think
the answer is "yes", then it is "yes". Likewise for "no".</p>
<ol type="1">
<li>correct, correct, incorrect</li>
<li>correct, incorrect, correct</li>
<li>incorrect, correct, correct</li>
</ol>
<p>Do you see how by acquiring <span
class="math inline"><em>N</em><sub>1</sub></span> and <span
class="math inline"><em>N</em><sub>2</sub></span>, models which
<em>individually</em> do just as well as <span
class="math inline"><em>M</em></span>, <em>combined with <span
class="math inline"><em>M</em></span></em> do much better?</p>
<p>Now this is a bit of a contrived example. But the point remains the
same. This is quite literally a mathematical example of the power of
teamwork.</p>
<p>What's the upshot? A lot of people implicitly hold the naive view
that because they are worse than someone else in their group or team,
they hold no value in it.<a href="#fn1" class="footnote-ref" id="fnref1"
role="doc-noteref"><sup>1</sup></a> Two years ago, I wrote about how <a
href="/writing/essays/creative">I don't believe this is the case for
creative fields</a>. Two years later, I am glad to report that this is
this is the case even for fields with objectively right answers. That
group test? Unless Alice is literally perfect, the A-student Alice and
B-student Bob do better than Alice could alone, <em>even though Alice
gets better scores than Bob every test.</em></p>
<p>On a related note, there are some people who believe that generative
AI will render humans completely useless. Again, this is not the case.
Even if a moron with generative AI can produce code faster than a
skilled software engineer working alone,<a href="#fn2"
class="footnote-ref" id="fnref2" role="doc-noteref"><sup>2</sup></a>
that skilled software engineer will be leagues more useful with
generative AI.</p>
<section id="footnotes" class="footnotes footnotes-end-of-document"
role="doc-endnotes">
<hr />
<ol>
<li id="fn1"><p>Some people cope with this by lying to themselves and
pretending it's rare for someone to <em>just be better than you in every
way</em> (in some area). But if you've ever talked to anyone smart, you
know this happens all the time.<a href="#fnref1" class="footnote-back"
role="doc-backlink">↩︎</a></p></li>
<li id="fn2"><p>And based on reports of <a
href="https://hbr.org/2025/09/ai-generated-workslop-is-destroying-productivity">"workslop"</a>,
this is decidedly not the case in the medium to long run.<a
href="#fnref2" class="footnote-back" role="doc-backlink">↩︎</a></p></li>
</ol>
</section>]]></description>
	<pubDate>20 Oct 2025</pubDate>
</item>
<item>
	<title>Bostock v. Clayton County analysis</title>
	<link>https://dennisc.net/writing/blog/bostock.md</link>
	<description><![CDATA[<p>I read the entire released opinion for Bostock
v. Clayton County, including the dissents. Here is my analysis.</p>
<h2 id="background">Background</h2>
<p>Several people were fired for being gay or transgender. Both the
plaintiffs (the people fired) nor the defendants (the employers who had
fired them) agreed that these firings were discrimination on the basis
of sexual <em>orientation</em>. <a
href="https://www.eeoc.gov/statutes/title-vii-civil-rights-act-1964">Title
VII of the 1964 Civil Rights Act</a> states:</p>
<blockquote>
<p>It shall be an unlawful employment practice for an employer ... to
fail or refuse to hire or to discharge any individual, or otherwise to
discriminate against any individual with respect to his compensation,
terms, conditions, or privileges of employment, because of such
individual's <strong>race, color, religion, sex, or national
origin</strong></p>
</blockquote>
<p>Notice that sexual orientation and gender expression do not appear
there (despite many efforts to amend Title VII to include it). Both
parties agreed that Title VII applied to the employers. The question
just is: if sexual orientation is not explicitly protected in Title VII,
then is it protected all the same?</p>
<h2 id="majority-opinion-by-neil-gorsuch">Majority opinion, by Neil
Gorsuch</h2>
<p>The 6-3 majority (liberals + Gorsuch and Roberts; at this point
Ginsburg was still on the court) ruled that Title VII prohibits
discrimination on the basis of sexual orientation and gender expression,
<strong>because you cannot discriminate on the basis of sexual
orientation/gender expression without discriminating on the basis of
sex</strong>. Rather than being a case of constitutional law, this is a
case of statutory interpretation: SCOTUS ruled based on the text they
had and not any constitutional considerations.</p>
<p>Gorsuch starts with a brief historical note on the Civil Rights Act
of 1964: no one intended for Title VII to protect sexual orientation or
gender expression. But,</p>
<blockquote>
<p>Those who adopted the Civil Rights Act might not have anticipated
their work would lead to this particular result. Likely, they weren't
thinking about many of the Act's consequences that have become apparent
over the years, including its prohibition against discrimination on the
basis of motherhood or its ban on the sexual harassment of male
employees. But the limits of the drafters' imagination supply no reason
to ignore the law's demands. When the express terms of a statute give us
one answer and extratextual considerations suggest another, it’s no
contest. Only the written word is the law, and all persons are entitled
to its benefit.</p>
</blockquote>
<p>Then he establishes the background of the case. Some gay and
transgender people were fired after the companies discovered they were
gay/transgender. District courts had different rulings. The background
is not incredibly complicated or central, because everyone agrees what
the facts are: the employees were fired for being gay/transgender. The
entire case hinges on whether Title VII protects against this
discrimination.</p>
<p>One major detail about the established facts:</p>
<blockquote>
<p>The only statutorily protected characteristic at issue in today’s
cases is “sex”—and that is also the primary term in Title VII whose
meaning the parties dispute. Appealing to roughly contemporaneous
dictionaries, the employers say that, as used here, the term “sex” in
1964 referred to “status as either male or female [as] determined by
reproductive biology.” The employees counter by submitting that, even in
1964, the term bore a broader scope, capturing more than anatomy and
reaching at least some norms concerning gen- der identity and sexual
orientation. But because nothing in our approach to these cases turns on
the outcome of the par- ties’ debate, and because the employees concede
the point for argument’s sake, we proceed on the assumption that “sex”
signified what the employers suggest, referring only to biological
distinctions between male and female.</p>
</blockquote>
<p>Now for the meat.</p>
<h3 id="but-for-causation">But-for causation</h3>
<p>The word "because" implies but-for causation. If X not being true
would've prevented Y from happening, then X is a but-for cause of Y. In
Gorsuch's words,</p>
<blockquote>
<p>A but-for test directs us to change one thing at a time and see if
the outcome changes. If it does, we have found a but-for cause.</p>
</blockquote>
<p>Then he follows up with an example:</p>
<blockquote>
<p>So, for example, if a car accident occurred both because the
defendant ran a red light and because the plaintiff failed to signal his
turn at the intersection, we might call each a but-for cause of the
collision.</p>
</blockquote>
<p>Notably, it is important that Congress chose to use "because of", and
not "solely because of" or any stricter standard.</p>
<h3 id="discrimination">Discrimination</h3>
<p>Gorsuch spends a while rigorously defining discrimination, but for
our purposes the major point is this:</p>
<p><strong>Discrimination is illegal on an individual basis, not just a
group basis.</strong> This is important because</p>
<blockquote>
<p>The consequences of the law’s focus on individuals rather than groups
are anything but academic. Suppose an employer fires a woman for
refusing his sexual advances. It's no defense for the employer to note
that, while he treated that individual woman worse than he would have
treated a man, he gives preferential treatment to female employees
overall. The employer is liable for treating <em>this</em> woman worse
in part because of her sex.</p>
</blockquote>
<p>Therefore, firing both lesbians and gays doesn't mean the homophobia
"balances itself out", provided we establish that firing people for
being attracted to the same sex is sex discrimination. (We establish
that next.)</p>
<h3
id="why-sexual-orientationgender-identity-discrimination-is-sex-discrimination">Why
sexual orientation/gender identity discrimination is sex
discrimination</h3>
<p>Now here is the main point: take some man who is attracted to men but
is otherwise inoffensive to the employer. Now change his gender, and we
have a woman attracted to men. The employer has no reason to fire this
hypothetical woman now, and so the man's sex is a but-for cause. This
is, plain and simple, what "discriminating because of sex"
<em>means</em>.</p>
<p>Similarly, take someone born as a man but who presents as a woman who
is fired by an employer because of this. Someone born as a woman who
presents at a woman would not have been fired. Sex is, again, a but-for
cause.</p>
<p>Gorsuch then buttresses this with SCOTUS precedent: the "simple
test", i.e. this but-for analysis, has held water for a number of
unexpected applications of Title VII. This is but the latest.</p>
<h3 id="common-refrains">Common refrains</h3>
<p>Gorsuch addresses two common refrains in his opinion. I'll let his
own words do the trick here.</p>
<p><strong>Refrain 1:</strong> Sexual discrimination must be
<em>willful</em>. How can it be willful if the employer doesn't even
know the sex of an applicant?</p>
<blockquote>
<p>Sup- pose an employer asked homosexual or transgender appli- cants to
tick a box on its application form. The employer then had someone else
redact any information that could be used to discern sex. The resulting
applications would dis- close which individuals are homosexual or
transgender without revealing whether they also happen to be men or
women.</p>
<p>Doesn’t that possibility indicate that the em- ployer’s
discrimination against homosexual or transgender persons cannot be sex
discrimination?</p>
<p>No, it doesn’t. Even in this example, the individual ap- plicant’s
sex still weighs as a factor in the employer’s deci- sion. Change the
hypothetical ever so slightly and its flaws become apparent. Suppose an
employer’s application form offered a single box to check if the
applicant is either black or Catholic. If the employer refuses to hire
anyone who checks that box, would we conclude the employer has com-
plied with Title VII, so long as it studiously avoids learning any
particular applicant’s race or religion? Of course not: By intentionally
setting out a rule that makes hiring turn on race or religion, the
employer violates the law, whatever he might know or not know about
individual applicants.</p>
</blockquote>
<p><strong>Refrain 2:</strong> In the <em>but-for</em> analysis, you
changed a <em>gay</em> man into a <em>straight</em> woman! Two things
changed at once! Now you can't prove it was sex discrimination rather
than sexual orientation discrimination.</p>
<blockquote>
<p>When we apply the simple test to Mr. Bostock—asking whether Mr.
Bostock, a man attracted to other men, would have been fired had he been
a woman— we don’t just change his sex. Along the way, we change his
sexual orientation too (from homosexual to heterosexual). If the aim is
to isolate whether a plaintiff’s sex caused the dismissal, the employers
stress, we must hold sexual orien- tation constant—meaning we need to
change both his sex and the sex to which he is attracted. So for Mr.
Bostock, the question should be whether he would’ve been fired if he
were a woman attracted to women. And because his em- ployer would have
been as quick to fire a lesbian as it was a gay man, the employers
conclude, no Title VII violation has occurred.</p>
</blockquote>
<p>In response, Gorsuch makes the following analogy:</p>
<blockquote>
<p>Consider an employer eager to revive the workplace gender roles of
the 1950s. He enforces a policy that he will hire only men as mechanics
and only women as secretaries. When a quali- field woman applies for a
mechanic position and is denied, the “simple test” immediately spots the
discrimination: A qualified man would have been given the job, so sex
was a but-for cause of the employer’s refusal to hire. But like the
employers before us today, this employer would say not so fast. By
comparing the woman who applied to be a me- chanic to a man who applied
to be a mechanic, we’ve quietly changed two things: the applicant’s sex
and her trait of fail- ing to conform to 1950s gender roles. The “simple
test” thus overlooks that it is really the applicant’s bucking of 1950s
gender roles, not her sex, doing the work. So we need to hold that
second trait constant: Instead of comparing the disappointed female
applicant to a man who applied for the same position, the employer would
say, we should compare her to a man who applied to be a secretary. And
because that jobseeker would be refused too, this must not be sex
discrimination.</p>
</blockquote>
<p>And he basically concludes with, "the conclusion in this hypothetical
is ridiculous, the <em>simple test</em> has worked consistently for
every other instance of sex discrimination where sex was a tangential
cause, there is no reason for it not to hold here."</p>
<h3 id="conclusion">Conclusion</h3>
<p>I've left out a lot of details in order to summarize the majority
opinion, and you should read the full text on your own time. This is a
remarkably simple case, so the majority opinion stands at a slim (by
SCOTUS standards) 37 pages. This section has mostly been summary instead
of analysis because the majority opinion is just <em>correct</em>.
There's nothing left out, and there's nothing wrong. The
<em>dissents</em>, on the other hand...</p>
<h2 id="alitos-dissent">Alito's dissent</h2>
<p><em>Joined by Thomas.</em></p>
<p>The dissent essentially goes like this: "No one expected Title VII to
cover sexual orientation and gender identity so it doesn't". Never mind
that interracial marriage wasn't intended to be covered by the 14th
Amendment either. Apparently legislative intent overrides the clear
plaintext of the statute. Purposivism as a legal framework is pretty
sketchy anyway, so if that's the best Alito can muster, the dissent
holds little water.</p>
<p>Alito appeals to originalism:</p>
<blockquote>
<p>our duty is to interpret statutory terms to "mean what they conveyed
to reasonable people at the time they were written."</p>
</blockquote>
<p>Yet any reasonable person would conclude that but-for causation is
enough, more than enough, to satisfy "because". It does not matter
whether these but-for causes were anticipated by the legislature or not.
(Gorsuch's majority opinion notes many examples such as motherhood where
it not being expected to be covered by Title VII, and gender not being
the <em>primary</em> cause, are irrelevant.)</p>
<p>Alito then spends some time saying, "sex was not construed to cover
sexual orientation or genedr identity":</p>
<blockquote>
<p>Determined searching has not found a single dictionary from that time
that defined "sex" to mean sexual orientation, gender identity, or
"transgender status."</p>
</blockquote>
<p>Nobody contests this. He even concedes this a page later. Now he gets
to his main point:</p>
<blockquote>
<p>If an employer takes an employment action solely because of the
sexual orientation or gender identity of an employee or applicant, has
that employer necessarily discriminated because of biological sex?</p>
</blockquote>
<p>Uh, yeah? The majority opinion literally covers this. Discriminating
against a man who is attracted to men, when the employer would've had no
issue with a woman being attracted to men, is sex discrimination.</p>
<p>I will not belabor the point: Alito's dissent makes no real
counterargument to any of the majority opinion's arguments. He instead
dances around the fact that you cannot define sexual orientation and
gender identity without sex (and therefore cannot discriminate against
either without discriminating against sex).</p>
<p>However, this quote is so awful that I had to just include it. Just
one more...</p>
<blockquote>
<p>Contrary to the Court’s contention, discrimination because of sexual
orientation or gender identity does not in and of itself entail
discrimination because of sex. An employer can have a policy that says:
"We do not hire gays, lesbians, or transgender individuals." And an
employer can implement this policy without paying any attention to or
even knowing the biological sex of gay, lesbian, and transgender
applicants. In fact, at the time of the enactment of Title VII,
<strong>the United States military had a blanket policy of refusing to
enlist gays or lesbians, and under this policy for years thereafter,
applicants for enlistment were required to complete a form that asked
whether they were "homosexual."</strong></p>
</blockquote>
<p>Yikes. I mean, wow. This is impressive. Alito is appealing to
authority, and the best part is, <em>he's not even appealing to the
right authority</em>. If the Court was bound by the executive's
interpretation of laws<a href="#fn1" class="footnote-ref" id="fnref1"
role="doc-noteref"><sup>1</sup></a>, then what exactly is the Court
supposed to do? Affirm illegal/unconstitutional executive actions
because the executive said "trust me bro"?</p>
<blockquote>
<p>If an employer discriminates against individual applicants or
employees without even knowing whether they are male or female, it is
impossible to argue that the employer intentionally discriminated be-
cause of sex.</p>
</blockquote>
<p>Counterexample: An employer has a policy that men who like Barbies
and women who like Hot Wheels cannot work at their institution. They
apply this policy without knowing whether they are discriminating
against a man who likes Barbies or a woman who likes Hot Wheels. So
apparently it's "impossible" for this to be discrimination? Alito
blathers on about this point for quite a while, ignoring the fact that
it is very possible for this to occur. Helpfully, the majority opinion
already provides numerous other examples.</p>
<p>I'm not going to analyze every quote from this dissent, because it is
quite long and everything is just wrong in the exact same way. Summary:
the dissent argues about things that do not matter and it does not feel
like Alito even read the majority opinion.</p>
<h2 id="kavanaughs-dissent">Kavanaugh's dissent</h2>
<p>If Alito's dissent was aggressively wrong, Kavanaugh's is wrong in a
more measured sense. For some reason, I'm a lot more sympathetic to this
dissent.</p>
<p>Initially, he makes much the same arguments as Alito does: appealing
to the history of the 1964 Civil Rights Act, and failed attempts to
amend Title VI/VII to include sexual orientation and gender identity. He
also appeals to separation of powers, essentially saying "it's not our
job to make laws, just to interpret them".</p>
<p>However, his jurisprudence soon diverges from Alito's: where Alito
claims that <em>no</em> reading of Title VII extends to sexual
orientation and gender identity. However, Kavanaugh makes a significant
concession:</p>
<blockquote>
<p>For the sake of argument, I will assume that firing someone because
of their sexual orientation may, as a very literal matter, entail making
a distinction based on sex. But to prevail in this case with their
literalist approach... <strong>The plaintiffs must establish that
courts... adhere to literal meaning rather than ordinary
meaning</strong>... Or alternatively, the plaintiffs must establish that
the ordinary meaning of "discriminate because of sex"... encompasses
sexual orientation discrimination.</p>
</blockquote>
<p>(Note: All parties agreed that the ordinary meaning of "sex" does not
encompass sexual orientation. Therefore I only focus on the bolded
portion.)</p>
<p>This is a very reasonable framework. Where Alito has his head in the
sand and does not admit there is any reading of Title VII that agrees
with the majority opinion, Kavanaugh understands that one exists.
Instead, his primary focus is, "should we <em>prefer</em> the literal
approach over the ordinary one?" This is a much more decisive question,
and honestly, many of the people celebrating the literalist approach
because of the result it brought would likely bemoan such a literalist
approach in another case (e.g. a 4th Amendment case).</p>
<p>Kavanaugh's conclusion is where I diverge from him. The "reasonable
interpretation" does not mean you pick some random passerby off the
streets from 1964 and ask them. Even if the average person does not know
"because" means but-for causation, the "reasonable person" would have to
understand this. Given that, Kavanaugh fails to explain why
discriminating on the basis of gender paired with whether they applied
to be a mechanic or secretary, while unexpected to the (truly) average
person, is prohibited under Title VII, yet discriminating based on
sexual orientation somehow is permissible. It is not the majority's job
to show that sexual orientation is somehow special when being included
in Title VII; rather, it is the dissent's job to show that it is somehow
special and should <em>not</em> be included. The dissent fails to do
this, and this is why I disagree with Kavanaugh's conclusion.</p>
<p>Regardless, I am somewhat sympathetic to his claim that few really
expected Title VII to apply to sexual orientation, and other (subtly
different) cases have been decided differently by the Court. That is why
I think Title VII should be amended to explicitly include it, so
everyone knows how far it extends: all the way (more on this later; note
how, for instance, Bostock makes no mention of bisexual people).</p>
<p>One last point: Kavanaugh mentions that Clinton's 1998 Executive
Order explicitly mentioned sexual orientation, and somehow this reveals
that Clinton thought sex discrimination didn't cover sexual orientation.
This is wrong, because even if you think sexual orientation is covered
in a <em>literal</em> sense, there's no harm in making doubly sure by
explicitly spelling it out. Also, explicitly banning sexual orientation
discrimination is good policy: it prevents the need for cases like
Bostock v. Clayton County in the first place. A years-long litigation
process would not need to ensue: the (prospective) employee can simply
say, "Look, they said they fired me because I'm transgender and the law
literally says it's illegal right here." Even if Kavanaugh is correct in
assuming that Clinton thought sex and sexual orientation as distinct
concepts, Clinton could've been wrong. For much the same reason as
Alito's appeal to the US military's policies, Kavanaugh's appeals to
authority and history hold little water.</p>
<h2 id="title-vii-should-be-amended">Title VII should be amended</h2>
<p>The ruling is correct. However, this ruling is somewhat narrow and
may not actually amount to a blanket ban on discrimination on the basis
of sexual orientation. Consider this: a man is fired for being attracted
to both men and women. Sex is not a but-for cause here, because if that
man were a woman, they would also be fired for being attracted to both
men and women. (Gorsuch's hypothetical, where a person walks in with a
woman to a company gala, would probably still protect a bisexual woman
from being fired because they are dating a woman, but makes no promises
as to their <em>general</em> attraction.) Perhaps this would still
violate Title VII under the eyes of this SCOTUS, but the best way to
make sure is to amend the law.</p>
<p>We saw what happened when the legislature and the public took
abortion rights for granted because of Roe v. Wade. I'm not suggesting
that such a similar thing might happen here, but with civil rights you
do not fuck around and find out. Especially when SCOTUS has been
overturning lots of precedents, there is no reason not to buttress a
narrow protection with a proper, comprehensive amendment to Title VII,
rather than relying on a ruling whose wider consequences may not be
immediately clear.<a href="#fn2" class="footnote-ref" id="fnref2"
role="doc-noteref"><sup>2</sup></a> <em>Regardless of your personal
beliefs</em>, if you have any respect for the premise of Amendment 14
and Title VII, then you should understand that immutable characteristics
<em>such as sexual orientation</em> ought to be protected just the same
as race, etc.</p>
<p>The clauses in Title VI and VII about unlawful discrimination are
identical. Just as this ruling applies to Title VII, it also applies to
Title VI. Title VI should be similarly amended for the same reasons.
Apparently I'm not the only one who thinks so: attempts to pass the
Equality Act have occurred every two years, and Biden issued an
executive order that extended "sex" to "sexual orientation and gender
identity".</p>
<section id="footnotes" class="footnotes footnotes-end-of-document"
role="doc-endnotes">
<hr />
<ol>
<li id="fn1"><p>The Chevron Doctrine (which binds the judiciary to trust
any "reasonable" interpretation of a statute by an executive agency)
exists. I think it's problematic for both separation of powers and fair
notice reasons.<a href="#fnref1" class="footnote-back"
role="doc-backlink">↩︎</a></p></li>
<li id="fn2"><p>This is one place where Alito's dissent has a point.
However, the "sweeping consequences" of applying the law properly is no
reason to not do so. The branch of government responsible for ironing
out future related laws in response to a ruling is the legislature, not
the judiciary.<a href="#fnref2" class="footnote-back"
role="doc-backlink">↩︎</a></p></li>
</ol>
</section>]]></description>
	<pubDate>20 Jul 2023</pubDate>
</item>
<item>
	<title>Another way to tell if your contest format sucks</title>
	<link>https://dennisc.net/writing/essays/contest-formats-part-2.md</link>
	<description><![CDATA[<p>Quick! How many problems can you recall
from</p>
<ul>
<li>MATHCOUNTS?</li>
<li>The AMC 8/10/12?</li>
<li>AIME?</li>
<li>USAMO/IMO?</li>
<li>College contests like HMMT?</li>
</ul>
<p>If your answers are anything like mine, you'll have noticed a
pattern: <em>contests with less problems are more memorable</em>.</p>
<p>On the surface this is a really obvious observation. If there are
less problems, it's easier to remember each individual problem. But why
does this matter?</p>
<p>The primary purpose of math contests is education. You want good,
thoughtful problems on contests, and you want to learn as much as you
can for each problem. This is why, besides "for fun" events like Number
Sense, you don't really want filler problems to appear on contests.</p>
<p>The second purpose of math contests is for math socialization. You
conveniently bring everyone together to do the same set of problems,
thereby giving them something to talk about: said problems. But
especially with MATHCOUNTS and HMMT, there are so many problems that
<em>the problems one contestant wants to discuss can easily be forgotten
by other contestants</em>. And this is literally seconds after the
contest ends!</p>
<p>So here is the second way to tell if your contest format sucks: if
you have more problems in one contest than you can remember, the format
sucks. If you have so many problems that a contestant cannot reasonably
discuss them all, the format sucks. Put a small number of problems in
your contests so everyone can learn from every
problem.</p>]]></description>
	<pubDate>26 Dec 2022</pubDate>
</item>
<item>
	<title>Counting Hours</title>
	<link>https://dennisc.net/writing/essays/counting-hours.md</link>
	<description><![CDATA[<p>You ever hear the saying that "it takes 10,000
hours of work to become a master at something"? It may or may not be
true, but regardless, it's the wrong way to think about learning a
skill.</p>
<h2 id="diligence">Diligence</h2>
<p>Picture this. You'd like to learn how to sing, but you know you don't
sound very good. So you don't really make a big deal out of it.</p>
<p>Maybe one day, when you are feeling exceptionally brave or ambitious,
you will sign up for lessons. You will feel really good about yourself
when you go to your one or two hours of lessons every week --- so good
that you don't feel much of a compulsion to sing outside of it.</p>
<p>Sure, you'll have improved, and it's a lot better than nothing. But
you will never be as good as the people who sing in the shower.</p>
<hr />
<blockquote>
<p>My parents were always out at work — surprisingly, I didn’t really
hang out with friends too much back then. My friends all lived quite far
from me. My sister would be studying. I’d have nothing to do. I’d watch
TV for three hours, and by the end I’d be bored, so I’d start playing
the piano, until my parents literally said, “We need to sleep now! Can
you be quiet?”</p>
<p>(Source: <a
href="https://www.rollingstone.com/music/music-features/blackpink-rose-new-music-solo-on-the-ground-1356345/">Rolling
Stone Interview</a> with Rosé)</p>
</blockquote>
<p>In my university, the drama majors and theater kids have to practice
for a long time, getting out late in the night. Every time I see them
leave, they are always singing.</p>
<p>I doubt they are doing it for the extra ten or fifteen minutes of
practice which will make them marginally better. Instead, they're
singing because they just love singing that much. They can't imagine
<em>not</em> singing. It's a good opportunity too - no one else is
around anyways, so why not just go for it?</p>
<p>What happens as a result? They accumulate the practice that you
don't. They are singing while taking a walk, waiting at the bus stop, or
taking a shower. That probably adds up to hours every day. If you
consciously had to take three hours out of every day to sing, you would
get sick of it. The only reason they are able to sustain this is because
it is almost subconscious. <em>It is just the natural thing to
do.</em></p>
<h2 id="details">Details</h2>
<p>My sense of rhythm is not particularly good. For the longest time, I
believed it was because I wasn't diligent enough to practice my rhythm.
But one day, my friend showed me how he could tap out an
eighth-note/triplet polyrhythm,<a href="#fn1" class="footnote-ref"
id="fnref1" role="doc-noteref"><sup>1</sup></a> and the way he talked
about it, he made it seem like the most entertaining thing in the world
to try. Eventually it dawned on me: <em>he's passionate about rhythm
itself</em>, not just broadly passionate about the instrument he
plays.</p>
<p>And I realized the reason I couldn't do polyrhythms wasn't because I
didn't have the discipline to drill them. It's because when I'm waiting
for food at a restaurant, I am not tapping my legs with my hands while
counting "1, 2, 3, 4, 5, 6, ..." It's because I am not tapping my feet
in that rhythm at the bus stop. It's because, whenever I'm bored and
take out my phone to check my email, I don't feel the compulsion to find
some rhythm exercises on YouTube instead.</p>
<p>I might have a passion for singing as a whole, but for the longest
time, I dismissed details as just that: things you need to diligently
drill in order to become good, pain points you just have to get over.
No. <em>You have to be passionate about the details to be any good at
them.</em></p>
<section id="footnotes" class="footnotes footnotes-end-of-document"
role="doc-endnotes">
<hr />
<ol>
<li id="fn1"><p>For those of you less familiar with musical terminology,
imagine tapping with your left hand every <span
class="math inline">$\frac{1}{3}$</span> of a second and with your right
hand every <span class="math inline">$\frac{1}{2}$</span> of a second.
Then your left hand is tapping out "triplets", and your right hand is
tapping out "eighth notes" at <span class="math inline">60</span> beats
per minute.<a href="#fnref1" class="footnote-back"
role="doc-backlink">↩︎</a></p></li>
</ol>
</section>]]></description>
	<pubDate>21 Feb 2026</pubDate>
</item>
<item>
	<title>Teaching ideas, not just results</title>
	<link>https://dennisc.net/writing/essays/ideas-vs-results.md</link>
	<description><![CDATA[<p>There is a proof of the <a
href="https://personal.math.ubc.ca/~feldman/m320/bolzano.pdf">Bolzano-Weierstrass
Theorem</a> that roughly goes like this:</p>
<ul>
<li>If we divide an interval in half, then one of these intervals must
have an infinite number of points in the sequence. (Else the union of
the intervals contain a finite number of points.)</li>
<li>We can take the interval with infinite points, keep doing this, and
converge to the limit of the lower bounds of the intervals.</li>
</ul>
<p>The natural thing for a professor or textbook to do afterwards is
assign exercises that either directly use Bolzano-Weierstrass or look
very similar. And to be clear, this is <em>good</em>: if we're teaching
an idea, we better use it. But I would additionally assign <a
href="https://proofwiki.org/wiki/K%C3%B6nig%27s_Tree_Lemma">Konig's Tree
Lemma</a>: on the surface it looks fairly different, but the underlying
ideas in the proof are quite similar.<a href="#fn1" class="footnote-ref"
id="fnref1" role="doc-noteref"><sup>1</sup></a></p>
<p>When I read the proof of Konig's Tree Lemma, I understood it very
quickly because I had seen the proof of Bolzano-Weierstrass. So it
stands to reason the converse might be true: learning the proof of Konig
helps you better understand the proof of Bolzano-Weierstrass too.
Explicitly, we ought to assign a couple more exercises using the
<em>ideas</em> of theorems rather than their <em>results</em>.</p>
<p>There is some subtlety here. For one, we need to avoid being overly
broad with what we assign. The idea that "a finite partition of an
infinite set must have an infinite part" is generally useful, but it is
also known as the Pigeonhole Principle. Konig is a suitable exercise
because it recursively uses this method to generate an infinite "path",
just as Bolzano-Weierstrass does. It is this high degree of similarity
that keeps it from being just another randomly assigned exercise.</p>
<p>This is hard to do well, and I'm skeptical we could afford to do this
for <em>every</em> theorem we proved. But I think we could stand to do
it more often.</p>
<section id="footnotes" class="footnotes footnotes-end-of-document"
role="doc-endnotes">
<hr />
<ol>
<li id="fn1"><p>Another problem that uses the same idea is ISL
2021/C1:</p>
<blockquote>
<p>Let <span class="math inline"><em>S</em></span> be an infinite set of
positive integers such that there exist four pairwise distinct <span
class="math inline"><em>a</em></span>, <span
class="math inline"><em>b</em></span>, <span
class="math inline"><em>c</em></span>, <span
class="math inline"><em>d</em> ∈ <em>S</em></span> with <span
class="math inline">gcd(<em>a</em>, <em>b</em>) ≠ gcd(<em>c</em>, <em>d</em>)</span>.
Prove that there exist thre pairwise distinct <span
class="math inline"><em>x</em></span>, <span
class="math inline"><em>y</em></span>, <span
class="math inline"><em>z</em> ∈ <em>S</em></span> such that <span
class="math inline">gcd(<em>x</em>, <em>y</em>) = gcd(<em>y</em>, <em>z</em>) ≠ gcd(<em>z</em>, <em>x</em>)</span>.</p>
</blockquote>
<p>It is a little more involved than Bolzano or Konig, but worth trying
if you want to cement this idea in your head.<a href="#fnref1"
class="footnote-back" role="doc-backlink">↩︎</a></p></li>
</ol>
</section>]]></description>
	<pubDate>21 Jun 2024</pubDate>
</item>
<item>
	<title>On advice: direction and magnitude</title>
	<link>https://dennisc.net/writing/essays/dir-mag.md</link>
	<description><![CDATA[<p>When giving advice, it should generally be
aimed at the direction of people's efforts, not at the magnitude.</p>
<p>What do I mean by direction and magnitude? Perhaps a couple of
examples would best illustrate the distinction. "The algebra 1 professor
this semester does not teach well, take algebra next semester and
analysis 1 this semester instead" is <em>directional advice</em>. It
substitutes one thing with another thing of a similar difficulty. On the
other hand, if you see someone working 60 hours a week, "take some
breaks and stop working so hard" is <em>advice on magnitude</em>. It
removes (or possibly adds) difficulty.</p>
<p>These components are not precisely orthogonal. But the overlap is
small enough that this is still a useful distinction to make. And both
forms of advice can be useful! "Stop working 60 hours a week" is still
good advice, full stop.</p>
<p>But by and large --- especially for people who already have things
figured out --- advice on magnitude is at best useless. Unless you have
known someone for very long, chances are they know their limits much
better than you do.</p>
<p>So when someone is trying to do something ambitious, the least
helpful thing you could do is say "don't try to be ambitious".
<em>They're not going to listen</em>. They aren't looking for advice on
magnitude. They are looking for advice on direction.</p>
<p>It also works the other way: if someone is spending 50 hours a week
and still struggling, the least helpful thing you could say is "well
just try harder". What do you mean, <em>try harder</em>? They're already
going to every lecture, every office hours, and making extensive use of
resources like Piazza. There is no possible way they could try harder.<a
href="#fn1" class="footnote-ref" id="fnref1"
role="doc-noteref"><sup>1</sup></a> This is why many of the people being
generally unhelpful to the people who are ahead also cannot really give
good advice to the people who are struggling.</p>
<p>However, where the correct<a href="#fn2" class="footnote-ref"
id="fnref2" role="doc-noteref"><sup>2</sup></a> <em>magnitude</em> of
someone's efforts is largely determined by internal factors, the correct
direction of someone's effort is more affected by external factors. For
instance, the CMU math department does not have a lot of opportunities
for algebra. So if you want to study math at CMU, it makes more sense to
direct your energy towards another field or cross-register at Pitt.
Either way, <em>something</em> in the direction of your efforts should
change because of this external factor.</p>
<p>Whereas the internal factors affecting someone are best understood by
themselves, the external factors are a different story. Say you are an
upperclassman giving some freshman advice on what courses to register
for. You don't know nearly as well as they do what they can handle, but
you do know much better what the courses are about. Closing this
knowledge gap is probably the most helpful thing a piece of advice can
do, and I think it should be the explicit <em>aim</em> of said
advice.</p>
<p>Of course, this isn't to say "course X is generally regarded to be
hard" is bad advice to give. But maybe your gut reaction to "I want to
take course X" anyway shouldn't be to issue a blanket statement
discouraging them. Just my two cents.</p>
<section id="footnotes" class="footnotes footnotes-end-of-document"
role="doc-endnotes">
<hr />
<ol>
<li id="fn1"><p>There's only one kind of exception I can think of:
people who excel spend their downtime (e.g. time waiting for the bus)
reading, say, articles about Haskell, whereas people who struggle do
not. But that kind of effort, I argue, must accompany a change in
direction.<a href="#fnref1" class="footnote-back"
role="doc-backlink">↩︎</a></p></li>
<li id="fn2"><p>"Correct" is a very loaded term here that could mean a
bunch of different things. You don't need to think too deeply about what
it means.<a href="#fnref2" class="footnote-back"
role="doc-backlink">↩︎</a></p></li>
</ol>
</section>]]></description>
	<pubDate>24 Sep 2023</pubDate>
</item>
<item>
	<title>Linux Distros</title>
	<link>https://dennisc.net/writing/tech/linux-distros.md</link>
	<description><![CDATA[<p>You've all heard it: "All Linux distros are the
same". This came in response to distro-hoppers basically just trying out
reskins of Arch/Debian with a different desktop environment, many of
which ultimately provide a more opaque experience. In that context, they
are totally right. Debian is still Debian under the hood, no matter what
coat of paint you apply to it. But distros have very real differences,
some of which you cannot just "patch out" or "work around" without
serious effort and a dedicated team. For example, "Arch Linux but
without systemd" is a whole separate distribution that has to be
maintained (Artix).</p>
<p>So what are the main differences? Here's a list in roughly descending
order of significance:</p>
<ul>
<li>package manager (apt, dnf, pacman, etc...)</li>
<li>libc implementation (for almost every distro it's glibc)</li>
<li>init system</li>
<li>kernel version</li>
<li>default desktop environment installed and default theme (important
for overall "market share of Linux", which I don't really give a rat's
ass about, but totally unimportant for an individual user)</li>
</ul>
<p>Obviously this post will be opinionated, otherwise it'd be useless.<a
href="#fn1" class="footnote-ref" id="fnref1"
role="doc-noteref"><sup>1</sup></a> So for transparency, my
allegiances:</p>
<ul>
<li>apk</li>
<li>musl libc (but some people <em>need</em> glibc)</li>
<li>runit, but openrc is also quite good</li>
<li>I typically run a very recent kernel.</li>
<li>sway (but please don't install shit with my distro, I'd rather login
from a tty and manually run <code>sway</code>)</li>
</ul>
<p>I have three machines --- a desktop running on Bedrock, an old laptop
on Alpine Linux, and a new laptop running Void Linux.</p>
<p>I'll be going through the distros in roughly descending order of
popularity. A couple of distros I know exist but decided to omit due to
lack of knowledge are Gentoo, Fedora, and RHEL/CentOS. Since most
systems use glibc/systemd (and the purism of your libc and init system
probably don't matter much to you), I will make no comment unless a
distro uses something other than glibc/systemd.</p>
<p>This post isn't really meant for Linux beginners, by the way,
although I think Linux beginners can glean some useful information
here.</p>
<h2 id="debian-based-e.g.-ubuntu">Debian-based (e.g. Ubuntu)</h2>
<p>Even though they certainly have a place in the Linux world, I really
don't like Debian-based distributions (mostly Ubuntu, which I will
primarily focus on for the rest of this section). That said, if you use
Ubuntu, you are by no means a "bad Linux user" --- ease of installation
should be a pride point and there's nothing cool about pre-archinstall
Arch being super hard to install.</p>
<p>Debian's package manager (technically frontend for the real package
manager <code>dpkg</code>, but come on, who actually uses
<code>dpkg</code> for anything besides <code>.deb</code> files)
<code>apt</code> is one of the more intuitive package managers, at least
on the surface. But this is only on the surface. Dependency management
is hell and there are a bajillion different binaries you need to
actually manage your system. It's also super slow and super out of date.
It is literally an order of magnitude slower than <code>pacman</code>,
and <code>texlive</code>/<code>pandoc</code>, two fairly significant
programs, are <em>years behind</em> (texlive is on 2020 and the stable
pandoc package is using a version from 2019). Of course, you can
mitigate this somewhat by going on an unstable branch, but even then
there is no way to get anything super recent. For programs like pandoc,
there are subtle breaking differences between one version and the next,
and all things consider you really want to be on latest.</p>
<p>(Yes, I know Debian recommends <code>aptitude</code>, but the fact
that exactly 0 Ubuntu/Mint users know it exists is kind of my point.
There are just way too many frontends for <code>dpkg</code> and no one
can make heads or tails out of it!)</p>
<p>That said, it is almost always not a big deal to have a Debian
server, because most critical infrastructure is up to date enough. You
really shouldn't even have Pandoc installed on your server, because the
way you are supposed to update a website is by building and then sending
a tarball with your files to prod... same for TeX Live, really. However,
I'll probably stop using Debian when I clean-install a new server
because I see very little technical advantage in continuing to use it.
Desktop though? Yeah... no. Have fun adding PPAs for shit while everyone
else is using the AUR or xbps-src.</p>
<p>Also re Ubuntu snaps: LOL, let's hate on Ubuntu for a bit.</p>
<ul>
<li>It's closed source. (Yeah, parts of it are open source, but you
cannot make a useful Snap app store because you don't have the
closed-source backend.)</li>
<li>It's slow as FUCK, and not just for installations --- apparently
Firefox takes 15 seconds to start if you're calling the Snap. (This is
likely an exaggeration and not collected using <code>time</code>.)</li>
<li>Chromium and Firefox are snaps by default. If you run
<code>apt install chromium</code> you get a Snap. Linux is all about
transparency. Even if you have nothing against snaps, there is literally
no reason for <code>apt</code> to use anything other than a
<code>.deb</code> file from either the Debian repositories or a close
downstream derivative.</li>
</ul>
<p>At this point Ubuntu is literally pulling the wool over your eyes
much like Windows (but not as bad). Sure, everything is technically
documented, but everything's so opaque by merit of "a bunch of crap no
one wants is shoved in your face." So yeah, for new users: I don't
really recommend Ubuntu. Ubuntu also asks you to update your software a
bajillion times. Mint patches out the Ubuntu-specific bullshit, so it
seems to be a better choice for now, but I really recommend
<code>archinstall</code> and <a
href="https://wiki.archlinux.org/title/Sway">setting up Sway on Arch</a>
if you have a weekend to spare instead.</p>
<h2 id="arch">Arch</h2>
<p>Arch's package manager <code>pacman</code>, unlike <code>apt</code>,
is fast, recent, and totally unintuitive. Where in Debian you run
<code>apt install</code> or in Alpine you run <code>apk add</code>, in
Arch you run... <code>pacman -S</code>. And then to update, instead of
running <code>apt update &amp;&amp; apt upgrade</code> you run
<code>pacman -Syu</code>. The options are literally alphabet soup, and
you could certainly understand pacman with some effort, but when you
compare to the good package managers which don't require any time to
understand <code>pacman</code> leaves something to be desired. Also
<code>pacman</code> is kind of slow, but my standards for speed are
based on xbps/apk now.</p>
<p>On the bright side literally anything you could ever want is in the
AUR. On the not-so-bright side, as nice as some AUR wrappers are, I just
want to manage my dependencies with pacman and I can't. (Well, unless
you use the Chaotic AUR --- but that's a huge mess too for reasons I
won't get into right now.)</p>
<p>Arch is also very DIY, just like pretty much every not-Debian distro.
You have to set up Xorg/Wayland on your own (though a lot of
Systemd-related stuff is just installed and set up for you). Networking
is also annoying, just like on every other distro.</p>
<h2 id="alpine">Alpine</h2>
<p>Alpine is my favorite distro. It doesn't do everything, but for the
people who'll be satisfied with its capabilities it is the best in its
class by far. And its limitations aren't because of technical flaws with
Alpine, but flaws with the programs you want to run. (Namely, companies
who release proprietary binaries only build them against glibc, so if
you use musl libc, you're screwed.)</p>
<p>The main sell of Alpine for me is the <code>apk</code> package
manager, particularly how small and neatly divided each of the packages
are. For instance, package <code>foo</code> usually does not include
docs, and the docs are contained in <code>foo-docs</code>. This is
because if you're on a server you don't need the docs, you should be
reading the manpages on your own system. Granted, docs don't really take
up that much room, so it's not the biggest deal. For your development
environment, you can and should just install the <code>docs</code>
metapackage to get the documentation for each program you install.</p>
<p><code>apk</code> is super intuitive too. If you want to find the
package that contains file <code>foo</code>, simply run
<code>apk search foo</code>. <code>apk</code> is also much faster than
any other package manager, including <code>pacman</code> and
<code>xbps</code>. It's expressive enough to do anything you'd ever want
and I don't know why you'd ever use another package manager at this
point.</p>
<p>Since Alpine uses OpenRC, not systemd, and barely has anything
configured by default, you may have to do some basic hardware
configuration yourself. For instance, in every other distro</p>
<ul>
<li>the brightness value on boot is taken from whatever it was on
shutdown</li>
<li>wifi autoconnects pretty easily</li>
<li>laptops hibernate on close lid</li>
</ul>
<p>yet with Alpine, I had to set all these up on my own.</p>
<p>Alpine does have limitations, but there are ways to get around it.
You can use a chroot of a different operating system (or have Bedrock
handle it for you) or a universal package manager like Flatpak, which
bundles it dependencies as well as the binary. You can choose to use
different software --- and I don't mean to go all FSF "you must never
under any circumstances use proprietary software" here. There are
genuinely good interfaces that still maintain compatibility with the
proprietary backend. For instance, <code>6cord</code> is a good Discord
terminal client that just works and <code>rclone</code> lets you treat
your Dropbox folder as a remote filesystem. Steam not working is a bit
of a pain point, but I grind Spider Solitaire in KPatience all day
anyway so it's OK for me. In fact if you want to focus, Alpine is a
really good distro for a work environment.</p>
<p>Adelie Linux also seems very similar to Alpine Linux (I haven't
personally used it myself). It uses the same package manager (apk), the
same init system (OpenRC), but a different userland (Adelie uses GNU
while Alpine uses BusyBox). I get why Adelie uses GNU coreutils ---
BusyBox does have some problems, like <code>sort</code> not seeing
whitespace as a separator by default when you pass in the
<code>-t</code> flag.<a href="#fn2" class="footnote-ref" id="fnref2"
role="doc-noteref"><sup>2</sup></a> (I do like BusyBox a lot though!
Full disclosure, I use BusyBox on most my systems.) The
<code>gcompat</code> library, a glibc compatibility layer, is also
developed for Adelie, so that is one of the many reasons Adelie might be
worth considering. (<code>gcompat</code> also can be installed on
Alpine, though I've had zero success in getting it to work.)</p>
<h2 id="void">Void</h2>
<p>Void is similar to Alpine but it uses runit (IMO a better init system
since it makes you manually symlink stuff, which is basically what
happens under the hood with <code>systemctl enable</code> but without
any black magic). The package manager is very similar, but unlike
Alpine, Void also lets you build a vast array of packages from source
with <code>xbps-src</code>. Everything under the sun can be found there
(even PolyMC, a Minecraft launcher!) though it does feel a bit clumsy
compared to the AUR.</p>
<p>Void also uses glibc unlike Alpine, so pretty much everything is
compatible with Void. (You can choose to use musl libc if you want, but
to me that eliminates 90% of the benefit of using Void over Alpine.) For
99% of people this is the ideal desktop/laptop distro.</p>
<h2 id="bedrock">Bedrock</h2>
<p>You know how you can make a chroot of one distro in another (usually
done for compatibility purposes)? Bedrock is like that but on steroids.
You can mix and match coreutils, kernel version, package managers,
etc.</p>
<p>However, making a chroot directory for another distro is a reversible
operation, while converting to Bedrock is not. Thus I only suggest it if
you are totally out of options otherwise. (I use it on my desktop
because Gnome/Ubuntu just <em>works</em> with NVIDIA monitors while
everything else is totally pure agony, though if I were to set it up all
over again, I wouldn't.)</p>
<h2 id="verdict">Verdict</h2>
<p>For servers, use Alpine, hands down. The proprietary programs you're
"missing" for Alpine are mostly for personal use, you shouldn't be
running a server with proprietary programs anyway. (That said, if you
want to run Alpine in production you probably should also run it on your
dev machine.)</p>
<p>Personal computers are a bit more complicated. If you want to lean
more heavily into gaming with Steam use Arch or Void. I personally think
that if you're going to install more "random" packages<a href="#fn3"
class="footnote-ref" id="fnref3" role="doc-noteref"><sup>3</sup></a>,
Arch is the better choice, mostly because I hate xbps-src. I run Alpine
on my "work" laptop, but Dropbox, Discord (I use 6cord, a terminal
client for Discord instead on Alpine), and Steam are all major
PITAs.</p>
<p>There's also an argument for installing Bedrock on top of a sane base
like Alpine Linux. It's like chrooting but you don't actually have to
care about building packages yourself, or setting up the environment. It
is a bit bulkier though since you pretty much have most of a distro's
base installed, minus the init parts.</p>
<p>Final note: If you are a soon-to-be new Linux user planning to
install a "user-friendly" distro (usually a Debian-based distro, and
said Debian-based distro is almost always Ubuntu), don't let my
criticism of Ubuntu stop you. For all the flaws of Ubuntu, it is still
bona fide Linux and a thousand times better than Windows/Mac.</p>
<section id="footnotes" class="footnotes footnotes-end-of-document"
role="doc-endnotes">
<hr />
<ol>
<li id="fn1"><p>"So Debian uses <code>apt</code> and you can do
<code>apt install BLAH</code> while Arch uses <code>pacman</code> and
you can do <code>pacman -S BLAH</code>" --- real helpful, buddy. I can
read the manpages myself.<a href="#fnref1" class="footnote-back"
role="doc-backlink">↩︎</a></p></li>
<li id="fn2"><p><a
href="https://git.busybox.net/busybox/commit/?id=00f2a35b835c6f49617f5379073e9063e7e683ce">This
was fixed in Git.</a><a href="#fnref2" class="footnote-back"
role="doc-backlink">↩︎</a></p></li>
<li id="fn3"><p>Mostly proprietary crap that you only use because
everyone else does, and you have enough social sense to not go all RMS
and tell your teacher "But I can't use Zoom, it's proprietary!"<a
href="#fnref3" class="footnote-back" role="doc-backlink">↩︎</a></p></li>
</ol>
</section>]]></description>
	<pubDate>5 Jul 2022</pubDate>
</item>
<item>
	<title>What &quot;Testsolving&quot; Means</title>
	<link>https://dennisc.net/writing/essays/testsolving.md</link>
	<description><![CDATA[<p>Over the past few years I've been asked to
testsolve contests several times, and for some reason or another it
inevitably becomes "please help me write my contest", or worse, "please
write the rest of my contest for me". I suspect there are two reasons
for this:</p>
<ul>
<li>people don't understand what "testsolving" means,</li>
<li>or they are too irresponsible to write their contest
themselves.</li>
</ul>
<p>If I suspect you are the second type of person, I will just flat-out
refuse to help you with your contest. But I suspect there are a lot of
hard-working people who may unintentionally be taking advantage of their
"testsolvers" because of misunderstandings.</p>
<h2 id="how-do-you-write-a-contest">How do you write a contest?</h2>
<ul>
<li><strong>Write problems.</strong> At some point, possibly after
arranging them into a test but no later, you must write full solutions
for each of them.</li>
<li><strong>Arrange problems into a test.</strong> The people who do
this can be the people who write problems, but this is not always the
case.</li>
<li><strong>Verify feel.</strong> Are the problems appropriately
easy/hard for the intended target audience? Is the "intended" target
audience who you will actually get? Are the subjects distributed
reasonably? Are the problems fun to do? Iterate until the answer to all
these question is yes.</li>
<li><strong>Verify correctness.</strong> Make sure every problem is
well-defined, answers are what you think they are, and the solutions are
clear and logically sound.</li>
</ul>
<p>Particularly for verifying correctness, it is imperative that you
have full solutions written. Verifying correctness does not mean finding
the answers to your problems. It does not mean verifying your answer
key, either. It means you verify that absolutely everything is
correct.</p>
<p>You aren't ready to ship a contest until you're ready to release
everything right now, meaning the test itself and the solution manual.
It maybe even means preparing some advertising materials, or the means
of testing (testing venues for in-person, testing portal for
online).</p>
<p>So when do testsolvers come into play? At earliest it is at the third
step, verifying feel. Personally I make a rule for myself not to involve
testsolvers until I think I'm ready to ship a contest. (More precisely,
by "I" I mean Math Advance.) Testsolvers are just there to make sure
that the contest is ready. They are the final correctness
verification.</p>
<p>One-line summary: If you expect your contest to change after
receiving feedback from someone, they are not a testsolver, they are
helping you write your contest.</p>
<h2 id="but-i-need-help-on-my-contest">But I need help on my
contest!</h2>
<p>Fair enough. Testsolving is not the only role non problem writers can
take, and it's perfectly normal to ask for help, even from outsiders to
your group. Just don't tell people you want them to "testsolve" if
you're giving them an obviously flawed product to look at. Testsolving
means that you have made your very best efforts to create a final
version of your contest, and that you are very sorry if anything has to
change at all.</p>
<p>Obviously you won't be able to catch everything, and you may need
slight assistance or want feedback on earlier steps, such as "what about
this new arrangement of problems?" or "is the feel better now?" It is
okay to ask for these things. But remember, the job of a testsolver is
not to help you write your contest. They are just the final verifiers.
Inevitably your mistakes will be revealed, but the thing about mistakes
is you're supposed to put some effort into avoiding them.</p>
<h2 id="dont-ask-me-to-testsolve-until...">Don't ask me to testsolve
until...</h2>
<p>...you have all your solutions written. No exceptions. I don't want
to read a test half-filled with problems that make zero sense. I mean,
you should be careful enough that you don't even put problems on your
test unless you know they are actually comprehensible. Everyone in Math
Advance can do it, it's really not that hard.</p>
<p>But if you know that you've been cursed with the inability to
properly express your mathematical ideas, then one way to make sure it
doesn't affect me is by writing solutions. It'll be really hard to write
clear solutions if the problem isn't clearly stated, so there's
that.</p>
<p>If you often get the feedback "I don't understand this problem", one
thing I haven't tried but recommend is having at least one solution per
problem by someone who isn't the problem author. That way if a problem
is unclear, it becomes apparent quickly.</p>
<h2 id="im-not-ready-for-testsolving-can-you-still-help">I'm not ready
for testsolving, can you still help?</h2>
<p><strong>Do not ask me for help unless you are using mapm.</strong> If
my time is not valuable enough for you to use a totally new tool for
creating your contests, that is totally fair. But my time is worth that
much to me, and I am sick of reading disorganized, carelessly written
Overleaf documents that are not even in sync with each other.</p>
<p>For those of you who are willing to use mapm :) If you want me to
help you write your test, the answer is probably still no. I just don't
write enough problems to do that, period. If you want help with
arranging your test, maybe, with the caveat that I will not take a
leading role. I am pretty opinionated and vocal though, so you will
definitely get lots of feedback.</p>
<p>If you are willing to use mapm but don't know how or want me to help
you set it up, I'd love to do so.</p>
<hr />
<p>If you have any questions about contest-writing, feel free to email
me. If it's a good question, I might just update this article to include
it!</p>
<p>Update (2022-07-27): Please ask your testsolvers to look through your
contest before you publicly announce it! If your contest is
significantly flawed, in 99% of cases the "testsolver" will end up
taking more responsibilities (because anyone who volunteers their free
time to testsolve a contest is probably really nice). You don't want to
force a time crunch on them that they never signed up for.</p>
<p>The alternative is that the testsolver goes "fuck it, I don't care
anymore" and BSes through the rest of the test or just stops commenting.
This happens a lot with contest creators who are either unnecessarily
stubborn or fail to plan ahead, and you don't want this to happen to you
either.</p>]]></description>
	<pubDate>12 Apr 2022</pubDate>
</item>
<item>
	<title>Gemini</title>
	<link>https://dennisc.net/writing/tech/gemini.md</link>
	<description><![CDATA[<p>I now have a Gemini capsule!<a href="#fn1"
class="footnote-ref" id="fnref1" role="doc-noteref"><sup>1</sup></a> The
domain is the same: dennisc.net.</p>
<p>If you don't know what Gemini is, it's an <a
href="gemini.circumlunar.space">internet protocol based on
simplicity</a>. It totally separates content (server responsibility)
from style (client responsibility). So you can read my website however
you want: through a terminal, a GUI, through light mode, etc.</p>
<p>I recommend <a
href="https://github.com/makeworld-the-better-one/amfora">Amfora</a> for
terminal enthusiasts and <a
href="https://github.com/skyjake/lagrange">Lagrange</a> for everyone
else; at least, those are the two I have looked at. I am sure other
Gemini clients are also amazing, I just haven't had the chance to look
at them yet.</p>
<p><img src="lagrange.png" alt="Viewing dennisc.net with Lagrange"></p>
<p><img src="lagrange-outline.png" alt="Lagrange outline"></p>
<p>Reproduced below is my first status update. I don't think I will
mirror this content again, I want to keep some content
gemini-exclusive.</p>
<hr>
<p>I've got a ton of things on my notepad's to-do list that I'd like to
keep in a more permanent medium. (Some of them I have recently checked
off.) So here they are, roughly separated by topic.</p>
<h2 id="writing">Writing</h2>
<p>I've had a couple of thoughts about pedagogy that I've never really
gotten around to writing. One is that group lessons are probably more
valuable than individual lessons, despite the latter costing far more
per hour. I think this is only true in some limited circumstances: you
have to be teaching smart people, they have to be self-motivated, and
they have to be sufficiently extroverted. People tell you the main value
in schools like MIT isn't really in the professors or the classes or
whatever, but in the peer group. Doesn't the same hold true in
general?</p>
<p>Recently I also finished porting over the ARU-Telescoping unit for
MAST, and the solutions all follow the same template:</p>
<blockquote>
<p>Algebraic expression A can be rewritten as B, which obviously
telescopes to value C.</p>
</blockquote>
<p>There's no padding where I explain the motivation of the solution.
There is motivation, obviously, but I have omitted it. I've considered
adding it before, but in the end decided not to.</p>
<p>Whereas in my geometry textbook, I sometimes explain in great detail
where each step comes from, even writing out obvious statements like</p>
<blockquote>
<p>Angle ABC and angle ABD are congruent where B, C, and D are all
collinear.</p>
</blockquote>
<p>Of course, this is in the context of a chain of equalities to show
that some angle is equal to another, so said statement clarifies the
chain of equalities a bit more.</p>
<p>Just like how some books and movies deliver a message more
effectively by implying it, rather than outright stating it, I think
some non-fiction texts might also do the same. Brevity can be good, and
so can omitting details, since it can be used as a tool to magnify the
most important parts of the text.</p>
<p>So there is something that makes it right to omit motivation for
telescoping and makes it wrong to omit it for geometry. What is this
difference? I don't know what it is, and if you have any ideas I'd be
glad to hear them.</p>
<h2 id="glee-the-hypothetical-git-server">Glee, the (hypothetical) Git
server</h2>
<p>=&gt; https://www.dennisc.net/writing/tech/glee-design Design for a
small-scale self-hosted Git service</p>
<p>Recently in my investigations with Gemini, I've heard whispers in the
wind that authentication and primitive read/write access might be
possible with Gemini. I don't have any ideas on how the details would
work, but if all the pieces line up I am interested in writing a Gemini
frontend for Glee in addition to (or possibly in replacement of) a web
frontend.</p>
<p>The graphical frontend would likely just be for read access anyway, I
don't care about giving people a GUI to set permissions or whatever.
That stuff should be done with a command line that works around the API
(even if the graphical read-only frontend is on Gemini, the API exposed
for writing to permissions files would probably be on HTTP). But if too
large a subset of functionality can't be easily created with Gemini, I
think I will just not use Gemini for Glee, period.</p>
<h2 id="math">Math</h2>
<p>I've been telling myself that I should look at the CAMO 2022 for a
while, and maybe now is the time to do it, what with it being two days
away from USAMO.</p>
<p>=&gt; http://cmc.ericshen.net/CMC-2022/CAMO-2022.pdf CAMO 2022</p>
<p>I also need to finish solutions up for the GQU-Triangles MAST unit.
That's sort of been blocking me from porting other over stuff.</p>
<p>Also, sometime after the USAMO, I would like to give a lecture on my
ARU-Telescoping unit to the MAST kids. (I would've done it before the
USAMO had I not qualified.)</p>
<h2 id="latex-lint">latex-lint</h2>
<p>I have a small project called latex-lint which I use with Vim.
Currently all it does is indent through latexindent + move punctuation
outside of math mode. Eventually I want to add functionality to do
this:</p>
<p><code>Git diff replacing double dollar signs in LaTeX -$$1+1=2$$ +\[1+1=2\]</code></p>
<p>=&gt; https://gitlab.com/chennisden/dotfiles/latex-lint</p>
<h2 id="mapm">mapm</h2>
<p>I've been telling myself for a long time that I need a GUI of mapm to
really make adoption widespread across Math Advance. But it seems that
even with just a CLI, adoption is pretty high across the active problem
writers and test compilers. Many thanks to everyone who has begun using
it, particularly Prajith Velicheti, Aprameya Tripathy, and Kelin Zhu,
who have done a lot of work migrating problems to mapm, providing
installation manuals and helping people through the process, and using
it for their own projects. (I am somewhat deliberately obfuscating who
each description is attributed to.)</p>
<p>Of course, I have also been writing my own manuals and maintaining
the documentation for the project. Though mapm is still in an alpha
stage right now, I think it is far better than any other publicly
available alternative. I encourage you give it a try if you want to
compile your own math contests. The (informal) spec is super short (just
like Gemini) and very extensible.</p>
<p>=&gt; https://gitlab.com/mapm/zero-to-mapm From Zero to mapm =&gt;
https://mapm.mathadvance.org Comprehensive mapm documentation</p>
<p>Just like how I recently wrote a "Why latexmk" article on what niche
the latexmk script fills, I should do the same for mapm. A lot of open
source projects have this great, technical description of what it does,
and no two sentence summary on why you would use it. mapm is among that
number and hopefully I can change that soon.</p>
<p>=&gt; /latexmk Why latexmk, mirrored on Gemini =&gt;
https://dennisc.net/writing/tech/latexmk Why latexmk, on the web</p>
<p>As for the GUI: I wonder how much I need to write this utility,
versus just wanting to write it to fully take advantage of our tags and
buckets system. It is still my next major programming project, though I
can already see I am inventing new things to do (like programming the
build script for this gemlog) instead of actually writing the GUI.</p>
<p>If you are interested in using mapm, join us at Zulip. Unfortunately
you are required to make an account, but unless I've screwed up, anyone
should be able to join.</p>
<p>=&gt; https://mapm.zulipchat.com mapm Zulip organization</p>
<h2 id="linux-mostly-sway">Linux (mostly Sway)</h2>
<p>I had planned on switching to Sway on my desktop, but it uses Nvidia
drivers. (I know, sue me, --my-next-driver-wont-be-nvidia.) Nouveau kind
of really sucks and I don't care enough to get it to work properly. But
my laptop, which is a Lenovo IdeaPad, is basically the Linux gods' gift
to humanity. So I do have Sway on my laptop.</p>
<p>Previously my twm was i3, which is largely compatible with Sway, but
there's a couple of little Sway-exclusive things (like the holding tray
for windows) that I hadn't really configured yet. Plus, I'm using
Polybar for desktop but that doesn't exactly work on Sway as far as I
know (at least not without X, which sort of defeats the point).</p>
<p>Also I'm really surprised people recommend Arch so much over Alpine.
I mean, I'm one of them, just because Arch is so much more popular that
chances of you fixing a problem are much higher (everyone and their mom
has a pacman post, the only thing it lags behind in converage is
Ubuntu). But besides bleeding edge + more package coverage, I think
Alpine is just better in a lot of ways. Although no AUR is a dealbreaker
for a lot of people, I'm already using Bedrock, so really no reason not
to have my base running Alpine. I won't deal with that now, but
hopefully in a few months I look back on it and take care of that
then.</p>
<hr>
<p>I hope you will consider installing Gemini and checking out my
gemlog.<a href="#fn2" class="footnote-ref" id="fnref2"
role="doc-noteref"><sup>2</sup></a></p>
<section id="footnotes" class="footnotes footnotes-end-of-document"
role="doc-endnotes">
<hr />
<ol>
<li id="fn1"><p>The equivalent of a website in Gemini is a capsule.<a
href="#fnref1" class="footnote-back" role="doc-backlink">↩︎</a></p></li>
<li id="fn2"><p>Especially if you hate light mode. Because guess what!
You can choose to use a dark mode client for Gemini, unlike in the web
where it's super hacky. If light mode happens to be your cup of tea, you
can use that too.<a href="#fnref2" class="footnote-back"
role="doc-backlink">↩︎</a></p></li>
</ol>
</section>]]></description>
	<pubDate>20 Mar 2022</pubDate>
</item>
<item>
	<title>Does your contest format suck?</title>
	<link>https://dennisc.net/writing/essays/contest-formats.md</link>
	<description><![CDATA[<p>In these past three or four years there has
been a proliferation of new student-run math contests. Most contests
adopt their own format, which means that each new contest is a new
format you have to learn. This alone is reason enough to make your
contest format simple, but not only does your format need to be simple
enough for contestants to understand, it needs to be simple enough for
the organizers to write a good contest.</p>
<p>With that said, here is a litmus test to see if your contest format
sucks: can you explain it in no more than twenty words?</p>
<ul>
<li>AMC 8: 25 MC in 75 minutes. (5 words)</li>
<li>AMC 10/12: 25 MC in 75 minutes with 5 options. 6 points for correct,
1.5 for blank, 0 for incorrect (18 words)</li>
<li>AIME: 15 questions with integer answers 0-999, 3 hours, 1 point for
correct 0 points for wrong (16 words)</li>
<li>USA(J)MO/IMO: 2 days of 3 questions, 4.5 hours each. Proof-based,
responses graded from 0 to 7. (15 words)</li>
<li>MAT: 3 sets of 3 problems with positive integer answers, 30 minutes
each, plus a set of tiebreakers broken on time. (20 words)<a href="#fn1"
class="footnote-ref" id="fnref1"
role="doc-noteref"><sup>1</sup></a></li>
<li>HMMT Nov: 10 questions 50 minutes for general and theme. 10
questions in 60 minutes for team. 12 sets of 3 for Guts, last set is
estimation. (25 words)<a href="#fn2" class="footnote-ref" id="fnref2"
role="doc-noteref"><sup>2</sup></a></li>
<li>HMMT Feb: 10 questions 50 minutes for 3 subject rounds. 60 minutes
for team, proof-based. 12 sets of 4 for Guts, last set is estimation.
(23 words)</li>
</ul>
<p>In all of these cases I didn't even have to try particularly hard to
get it under 20 (except HMMT). I suspect I could've gotten most of these
under 15 if I word-golfed hard enough. If you can't get your format
under 20 words, then you should change it before it comes to bite you
into the ass in the form of a poorly designed test.</p>
<section id="footnotes" class="footnotes footnotes-end-of-document"
role="doc-endnotes">
<hr />
<ol>
<li id="fn1"><p>In an ideal world MAT wouldn't even have tiebreakers.
And in fact, for PMAT --- the beginner version of the MAT --- I'm
inclined to get rid of tiebreakers entirely, which would reduce PMAT to
11 words and make it the simplest format out of all the contests listed
here besides the AMC 8, which is ideal for an introductory contest.<a
href="#fnref1" class="footnote-back" role="doc-backlink">↩︎</a></p></li>
<li id="fn2"><p>Yeah, I think HMMT is a bit convoluted. Could you get it
down to less than 20? Probably, but the amount of work you have to do is
so much that it de facto fails the litmus.<a href="#fnref2"
class="footnote-back" role="doc-backlink">↩︎</a></p></li>
</ol>
</section>]]></description>
	<pubDate>24 Jun 2022</pubDate>
</item>
<item>
	<title>Reread</title>
	<link>https://dennisc.net/writing/essays/reread.md</link>
	<description><![CDATA[<p>You know you've found something good when it's
worth rereading.</p>
<p>It doesn't matter what it is. Even a press release handled well has a
moment that you can't help but revisit. A police interview has that
moment of catharsis that some of us love to watch over and over.</p>
<p>Hitchcock famously said that "suspense is when the spectator knows
more than the characters." And indeed, anything worth reading --- or
watching --- must have that same feeling. Not necessarily of suspense,
mind you, but just the feeling that it's worth seeing the piece through
even when you know its conclusion. After all, there are very few mystery
novels that are stunning the first time around and absolutely boring the
next.</p>
<p>That's not to say that reading something for the first time has no
value --- obviously it does. So a good book, essay, movie, or game needs
to be interesting enough to capture your interest the first time, even
if you don't know or understand everything that's happened.</p>
<p>But there's a separate sort of value you get from rereading
something. I feel that this isn't given as much attention as it really
deserves. Even when it comes to documentation, how often something is
reread tells you a lot. It tends to either be important or have some
fundamental concept it's easy to get confused on.</p>
<p>Consider the <code>mount</code> command: is it
<code># mount /dev/sda2 /mnt</code> or is it
<code># mount /mnt /dev/sda2</code>? Turns out it's the former. And it
has to be the former, because otherwise you can't run <code>mount</code>
with one argument. And this makes mounting USBs without user
intervention so much easier to handle because now you don't have to
worry about where to mount it.</p>
<p>As a writer, I am good enough to make all my essays worth reading the
first time around. But I don't think that's enough. In fact, I have
several essays that I haven't published --- both on my old site and this
one --- that I think were worth reading once. But that's the problem:
it's <em>only</em> worth reading once.</p>
<p>The day before publishing this essay I made a couple of user
interface changes on this site. One of them was removing the boxes with
the links in the writing subpages, but not the <a href="/writing">main
one</a>. Why? Because no one will ever reread the descriptions.<a
href="#fn1" class="footnote-ref" id="fnref1"
role="doc-noteref"><sup>1</sup></a> I might even remove it for the main
writing page, because the sections are honestly pretty
self-explanatory.</p>
<p>This is a new <a href="/writing/essays/framework">idea</a> for me as
well. Only for the last few weeks have I been writing with a focus on
rereadability. The essays on my old site were littered with hyperlinks
everywhere. I didn't notice at the time, but that was a good sign --- it
meant that at least I was interested enough in my writing to reread it
and reference it. And the reason to aggressively prune writing? To
increase the proportion that's worth rereading. I've even started trying
to minimize the number of footnotes in my essays, because often people
don't find them worth reading even once, let alone rereading.<a
href="#fn2" class="footnote-ref" id="fnref2"
role="doc-noteref"><sup>2</sup></a></p>
<p>Rereadability is the one word summary for what makes a good <a
href="/writing/essays/hook">hook</a>. I don't know how rereadble the
rest of this essay is, but I hope at least the hook is.<a href="#fn3"
class="footnote-ref" id="fnref3" role="doc-noteref"><sup>3</sup></a></p>
<section id="footnotes" class="footnotes footnotes-end-of-document"
role="doc-endnotes">
<hr />
<ol>
<li id="fn1"><p>Feel free to let me know if I'm wrong about this and you
actually reread the descriptions. I won't revert the change either way
since I've got enough writing to make the <a href="/writing/all">all
writing section</a> too visually bloated if I use those big boxes.<a
href="#fnref1" class="footnote-back" role="doc-backlink">↩︎</a></p></li>
<li id="fn2"><p>Sometimes I wonder if it was a mistake to add footnote
functionality to this site. I think the answer ends up being no, because
footnotes give me space without breaking the flow of the text. And if
you have more ideas than you have room for (which really should be the
criteria for whether you write an essay or not), footnotes are a very
helpful escape hatch.<a href="#fnref2" class="footnote-back"
role="doc-backlink">↩︎</a></p></li>
<li id="fn3"><p>I get away with bad conclusions because at the end of
the piece there's nothing left to (re)read.<a href="#fnref3"
class="footnote-back" role="doc-backlink">↩︎</a></p></li>
</ol>
</section>]]></description>
	<pubDate>6 Dec 2021</pubDate>
</item>
<item>
	<title>Committing to CMU</title>
	<link>https://dennisc.net/writing/blog/committing.md</link>
	<description><![CDATA[<p>So today I committed to CMU. I was deciding
between UT Austin (Turing Scholars) and CMU. Some details:</p>
<ul>
<li>both CS</li>
<li>UT Austin Turing actually has a higher mean salary than CMU (caveat:
methodology for comparison was questionable)</li>
<li>money isn't a <em>major</em> issue</li>
</ul>
<p>Either way, I don't think I would've made a <em>wrong</em> decision.
But I'm only ~40% sure that I made the <em>better</em> decision, for a
couple of reasons:</p>
<ul>
<li>parents played a big influence in where I'm going. In some
hypothetical world where my choices were MIT vs. Harvard, I'd be like
"ew no I hate Harvard I am definitely going to MIT", and the strength of
my preference would be enough to override any hypothetical parental
desires. If my choice was made totally independent of their influence, I
would almost certainly have chosen UT Austin, but I was barely more sure
that UT was the better choice. Well, at least my mom will get to enjoy
her Asian parent WeChat group.</li>
<li>apparently CMU is really fucking small and that sucks. In some
sense, it's cool that people density is higher, so you can just hang out
with people and not be lost looking for another human soul, but I'd also
be able to explore campus and still find something new even in my fourth
year. With a school only four times the physical size of my high school,
that's just not very likely. At least Pittsburgh is pretty big, so I can
just step off campus and go downtown.</li>
<li>CMU allegedly induces depression. Obviously this is overblown, but
where there's smoke there's fire.</li>
</ul>
<p>But hey, there's lots to be excited about too in CMU. For better or
worse, there's no turning back at this point, so might as well be
optimistic and make the most out of it. Some part of me is thinking of
putting in a transfer application to MIT, but by the time I get there
I'll probably really enjoy CMU and be too lazy to fill it out.</p>
<p>Also one of my friends from school is going to CMU, so that's cool
too.</p>
<h3 id="ucl-rejection">UCL Rejection</h3>
<p>I couldn't really fit this anywhere, but I felt that college talk was
the best place to put it. I got rejected from a British university I
applied to a long time ago, University College London. At this point I
didn't even care enough to have a reaction either way, and almost
decided not to check. (Which I did to Irvine, and I honestly might not
have known they accepted me if they didn't email me about their honors
program.)</p>
<h2 id="roommate-rizz">Roommate rizz</h2>
<p>So a lot of people have asked to room with me, which is pretty cool
because I'll have a roommate for sure and there's a group of people I'll
definitely be able to talk with during orientation (though I want to
meet new people, especially outside of SCS!)</p>
<p>But of course, roommate rizz doesn't count unless you get
<em>rizz</em> rizz. In high school it's always been some combination of
"it's complicated", "circumstances", and "waited too long to take any
actual initiative." But things will never be the same when I get to
college. This will be my life goal that I value even more than that
sweet sweet Jane Street internship 🫡</p>
<p>(To be clear, I'm mostly joking, but I should try and be more
extroverted. Right now I'm this weird mix of extrovert and introvert,
where I'm not afraid to put myself out there and have eyes on me, but at
the same time I might find it difficult to talk to specific people I
want to talk to because of <em>circumstances</em> or any other litany of
excuses. Also at WARP I discovered that I get really tired after doing
stuff with other people and need to hole myself in my room for a few
hours afterwards, so <em>consistency</em> rather than <em>intensity</em>
seems to be the correct approach here.)</p>
<p>And for no reason whatsoever, I feel like the Tepper kids are
probably the most sociable/normal/etc. Which, I guess, is part of the
job description...</p>
<h2 id="track-and-field">Track and Field</h2>
<p>My track season ended with a whimper.</p>
<p>Three weeks ago at Dublin, I nearly fell asleep during warmups and
got a terrible time on the mile.</p>
<p>Two weeks ago at the Amador Valley Spring Fling, I hit a decent PR
and thought, "maybe I can bring this momentum forward and close my last
season with a good-ish time."</p>
<p>A week ago at Granada, I made a few tactical errors in the race and
could only match my PR.</p>
<p>And Thursday, I had a terrible cough and severe allergies. It wasn't
as bad as Dublin, but it was noticeably slower than my PR and I felt
like I was dying the entire race (moreso than usual).</p>
<p>So rather than closing the season with a big PR, or even modest
gains, it was just very meh for reasons entirely out of my control. And
I ended up not being able to run the fun events I wanted to because the
pollen was making me bawl my eyes out and I could barely see the track,
let alone run on it.</p>
<p>So how do I feel? Well, I'd probably care more if I was good at
distance running. It kinda feels the same way as my 3 on USAMO last year
--- pretty embarrassing, but I'm not sure I was really invested in the
result at that point. I enjoyed the process, it taught me some pretty
valuable lessons, and I'm a better person because of running. Or less
fat, at least.<a href="#fn1" class="footnote-ref" id="fnref1"
role="doc-noteref"><sup>1</sup></a> Very much like college applications,
I've come out through the other side and nothing really
<em>terrible</em> happened, but at the same time, nothing great really
happened either, and I'm still a little regretful about the whole
thing.</p>
<p>I do plan to continue running in college. I don't think I'll train as
intensely as before at college, though I'll probably still show up for
summer training when I'm in town this year. It's very possible that I've
run my last 1600m race already, or at least one of my last three if some
one-off miracle occurs and there's a track meet convenient enough that I
can register for. I might try some actual distance races though like
5Ks, 10Ks, etc.</p>
<h2 id="ap-chemistry">AP Chemistry</h2>
<p>Man, AP Chemistry was (is?) such a wild ride. To this day I have
never done a practice MCQ, but based on my performances on FRQs I think
I could probably get a 5. However I do lack some problem-solving
experience, which is expected since I started self-studying literally
less than two weeks ago.</p>
<p>Before I actually made a serious attempt, I was like "I have three
weeks left I'm screwed, why don't I just give up." But then I tried for
a bit, learned pKa/buffers/thermochem/the other stuff I didn't know
pretty quickly, and now I actually think that a 5 is not only within
reach, but honestly should be pretty easy. I'd told myself that you
could learn the entirety of AP Calc BC in 2 months, the entirety of AP
Stat in 2 weeks, etc, and I also <a
href="/writing/essays/competence">wrote about how most people suck at
any given thing</a>, yet I didn't really internalize either of these
things until now.</p>
<p>Right now, I just need to memorize VSEPR and maybe review
thermochemistry. That should be enough to get me a 5, although now I'm
studying chemistry, it actually seems pretty interesting to me again
:)</p>
<h2 id="multivariable-calculus">Multivariable Calculus</h2>
<p>My relationship with vector calculus has been a real doozy. First I
thought, "huh the multidimensional analogs are pretty natural
generalizations." Then I got to the four fundamental theorems of vector
calculus: line integrals, Green's, Stokes, Divergence, and then I went
"what the heck is this physics nonsense, this makes absolutely no sense
and I still don't really know what an integral is why didn't I take real
analysis," but now I'm learning that there's something deeper behind
these four theorems.</p>
<p>Honestly I've been less engaged with the material than I hoped I'd
be, and without a final I really might just check out mentally after the
last unit test. Which is a bit sad, considering multivariable calculus
is still math even if it's gross applied math with the applications
(physics) neutered. But learning real analysis then vector analysis
seems to be a better approach, skipping the non-rigorous calculation
nonsense portion, and also discrete math is good to learn too. The
opportunity cost of evaluating irrelevant integrals is just too high to
justify actively doing it.</p>
<p>But we do have a final <em>project</em>, and it's something I've been
thinking about doing for a long time. I've always wanted to write an
article about numerical computation, history and present day included.
Logs were invented so people could multiply big<a href="#fn2"
class="footnote-ref" id="fnref2" role="doc-noteref"><sup>2</sup></a>
numbers easily, but they did it first with trig tables. And the reason
they did it was to perform calculations with astronomical data, which is
how they derived Kepler's Laws. I think this is really cool stuff and
want to share it with you guys too, and this has finally given me an
excuse to do exactly that. I'm going to write the article, <em>then</em>
actually care about meeting the project requirements, which are not too
demanding anyway and won't compromise the article in any fashion.</p>
<p>Also, have you ever wondered how your computer calculates (well
really, approximates) <span class="math inline">sin 1</span>? It's not
<em>just</em> Taylor Series, there's a lot that goes into it from the
little I've seen. (This is going to be the present-day portion.)</p>
<h2 id="a-trend">A trend</h2>
<p>I've noticed that most of the time, I really don't share a lot of
good news on my blog, and when I do there's always a tone of solemnity.
This isn't too surprising, because nothing purely good <em>and</em>
noteworthy has happened to me recently (life is rapidly getting more
complicated), and even if it did, it probably wouldn't be interesting
enough to write about.</p>
<p>I mean, since my life is about to be consumed by CS, it's very likely
that my website turns into a math/CS blog for real. I don't think I've
written about math without using it as an example for a philosophical
framework --- when I write about math now, it's usually in-depth enough
to be an article of part of a book --- and my CS posts are along the
lines of, "how to use Git", "how to make a non-shitty website", etc.</p>
<p>While my CS posts have actual meat, unlike the "beginner-friendly"
crap most article mills put out, it's often written as a high-level,
cursory overview in order to remain accessible. But when CS occupies a
lot of my headspace, I'll likely have ideas (maybe even rehashes of
lectures) in my head that I'll just speedily put down as a post on this
website. So the ratio of "personal things that happen" that I share is
likely to decrease.<a href="#fn3" class="footnote-ref" id="fnref3"
role="doc-noteref"><sup>3</sup></a></p>
<p>I think as you grow older, you start to realize that Noteworthy Good
Things don't really happen to people that often. Life is usually
complicated, and the only Noteworthy Good Things people generally share
are marriages and the birth of a kid.<a href="#fn4" class="footnote-ref"
id="fnref4" role="doc-noteref"><sup>4</sup></a> Maybe if you're a
celebrity or write books this list is longer, but generally life feels
quiet because you learned to ride the waves. It's a little sad to think
that, now I've mentally checked out of high school, I'll never get to
feel the same highs I did when I first qualified for USAJMO or ran the
1600m under 6:00 in my first <em>real</em> track meet.</p>
<section id="footnotes" class="footnotes footnotes-end-of-document"
role="doc-endnotes">
<hr />
<ol>
<li id="fn1"><p>Over the summer my new goal is just to get a 6-pack. No
reason in particular...<a href="#fnref1" class="footnote-back"
role="doc-backlink">↩︎</a></p></li>
<li id="fn2"><p>Since size is relative (powers of 10 are irrelevant),
what really matters is that these numbers need to be precise. This is
one of the many misconceptions that my article will aim to clear up.<a
href="#fnref2" class="footnote-back" role="doc-backlink">↩︎</a></p></li>
<li id="fn3"><p>Or it'll be an excuse to revive my gemlog. Since I only
have personal stuff to share 4-5 times a month, I'll choose to populate
this site with another article, but as the updates get more personal and
more frequent in college (since more social things will probably happen
there), I might decide to publish some stuff there instead. Precisely
because no one is going to read it, unless they're techy enough to
install a Gemini client (which probably means they installed Linux), and
care enough to visit my gemlog. As far as I know, my readership
consisted of one person until I stopped updating.<a href="#fnref3"
class="footnote-back" role="doc-backlink">↩︎</a></p></li>
<li id="fn4"><p>I guess for me, the successful defense of my Master's
Thesis will come first. Hopefully I stay on track to get a master's
degree, since I don't really intend on doing a PhD and I'd feel bad only
graduating with a bachelor's when the opportunity for a 4-year master's
plan is right in front of me.<a href="#fnref4" class="footnote-back"
role="doc-backlink">↩︎</a></p></li>
</ol>
</section>]]></description>
	<pubDate>22 Apr 2023</pubDate>
</item>
<item>
	<title>Linear Algebra, in a nutshell</title>
	<link>https://dennisc.net/writing/blog/linalg.md</link>
	<description><![CDATA[<h2 id="vectors">Vectors</h2>
<p>There are these things called vectors. They don't exist in isolation.
Rather, they're defined as parts of <em>vector spaces</em>. A vector
space has objects called <em>vectors</em> <span
class="math inline"><em>u</em></span>, <span
class="math inline"><em>v</em></span> and <em>scalars</em> <span
class="math inline"><em>k</em></span> such that <span
class="math inline"><em>u</em> + <em>v</em></span> is a vector and <span
class="math inline"><em>k</em><em>v</em></span> is a scalar. Vector
addition and scalar multiplication behave as you'd expect: it commutes,
associates, distributes, etc. Don't think too hard about what vectors
<em>are</em>, just what they <em>do</em>.</p>
<p>The canonical example of a vector is a list of real or complex
numbers. These vectors exist in <span
class="math inline">ℝ<sup><em>n</em></sup></span> or <span
class="math inline">ℂ<sup><em>n</em></sup></span>. We will be focusing
on these vectors soon, but for now we work with generic vector
spaces.</p>
<p>We say a set of vectors <span
class="math inline">{<em>v</em><sub><em>i</em></sub>}</span> is
<em>linearly independent</em> if the only solution to <span
class="math inline">∑<em>a</em><sub><em>i</em></sub><em>v</em><sub><em>i</em></sub> = 0</span>
is <span class="math inline"><em>a</em><sub><em>i</em></sub> = 0</span>
for all <span
class="math inline"><em>a</em><sub><em>i</em></sub></span>. We say a set
of vectors <em>spans</em> a vector space <span
class="math inline"><em>V</em></span> if for any vector <span
class="math inline"><em>v</em> ∈ <em>V</em></span>, there is some
solution to <span
class="math inline">∑<em>a</em><sub><em>i</em></sub><em>v</em><sub><em>i</em></sub> = <em>v</em></span>.
If <span class="math inline">{<em>v</em><sub><em>i</em></sub>}</span> is
linearly independent and spans <span
class="math inline"><em>V</em></span>, then we say <span
class="math inline">{<em>v</em><sub><em>i</em></sub>}</span> is a
<em>basis</em> of <span class="math inline"><em>V</em></span>.</p>
<p>All bases of a vector have the same length (i.e. the same number of
vectors). Therefore we define the <em>dimension</em> of a vector space
to be the length of the basis.</p>
<p>A <em>subspace</em> <span class="math inline"><em>U</em></span> of a
vector space <span class="math inline"><em>V</em></span> is a vector
space whose elements are all in <span
class="math inline"><em>V</em></span> and whose addition/multiplication
operations are identical. That is, if <span
class="math inline"><em>u</em> + <em>v</em> = <em>w</em></span> under
<span class="math inline"><em>U</em></span>, then <span
class="math inline"><em>u</em> + <em>v</em> = <em>w</em></span> under
<span class="math inline"><em>V</em></span> as well, etc.</p>
<h2 id="linear-maps">Linear Maps</h2>
<p>A linear map <span class="math inline"><em>T</em></span> is a
function <span class="math inline"><em>V</em> → <em>W</em></span> such
that <span
class="math inline"><em>T</em>(<em>u</em> + <em>v</em>) = <em>T</em><em>u</em> + <em>T</em><em>v</em></span>
and <span
class="math inline"><em>T</em>(<em>a</em><em>v</em>) = <em>a</em><em>T</em><em>v</em></span>
for all vectors <span class="math inline"><em>u</em></span>, <span
class="math inline"><em>v</em></span> and all scalars <span
class="math inline"><em>a</em></span>. (<span
class="math inline"><em>V</em></span> and <span
class="math inline"><em>W</em></span> are vector spaces.)</p>
<p>The most boring map is <span class="math inline"><em>I</em></span>,
the identity map. It is the function <span
class="math inline"><em>V</em> → <em>V</em></span> such that <span
class="math inline"><em>T</em><em>v</em> = <em>v</em></span>.</p>
<p>The <em>null space</em> of a linear map is the set of vectors <span
class="math inline"><em>v</em></span> such that <span
class="math inline"><em>T</em><em>v</em> = 0</span>. As the term
implies, the null space is a vector space itself. The <em>range</em> of
a linear map is the set of vectors <span
class="math inline"><em>v</em></span> such that there exists some vector
<span class="math inline"><em>u</em></span> satisfying <span
class="math inline"><em>T</em><em>u</em> = <em>v</em></span>. It is also
a vector space. In other words, the range is the set of outputs possible
from <span class="math inline"><em>T</em></span>. (Take note that <span
class="math inline">null <em>T</em> ⊆ <em>V</em></span> and <span
class="math inline">range <em>T</em> ⊆ <em>W</em></span>.) The
<em>Rank-Nullity Theorem</em> states <span class="math inline">dim null
<em>T</em> + dim range <em>T</em> = dim <em>V</em></span>.</p>
<p>Also, linear maps can be injective, surjective, and invertible. <span
class="math inline"><em>T</em></span> is injective if <span
class="math inline"><em>a</em> = <em>b</em> ⇔ <em>T</em><em>a</em> = <em>T</em><em>b</em></span>.
(<span class="math inline"><em>T</em></span> injective is equivalent to
<span class="math inline">null <em>T</em> = {0}</span>.) <span
class="math inline"><em>T</em></span> is surjective if <span
class="math inline">range <em>T</em> = <em>W</em></span>. <span
class="math inline"><em>T</em></span> is bijective if it is both
injective and surjective. And <span
class="math inline"><em>T</em></span> is invertible if <span
class="math inline"><em>T</em><em>T</em><sup>−1</sup> = <em>T</em><sup>−1</sup><em>T</em> = <em>I</em></span>.
Obviously, <span class="math inline"><em>T</em></span> must be of the
form <span class="math inline"><em>V</em> → <em>V</em></span>, i.e.
<span class="math inline"><em>V</em> = <em>W</em></span>, for <span
class="math inline"><em>T</em></span> to be invertible.</p>
<p>A <em>linear endomorphism</em> is a map of the form <span
class="math inline"><em>V</em> → <em>V</em></span>. In other words, the
domain and codomain are identical; this is the definition of an
endomorphism. In an endomorphism, injectivity, surjectivity, and
invertibility are all identical.</p>
<p>Now we discuss <em>invariant subspaces</em> on linear endomorphisms.
A subspace <span class="math inline"><em>U</em></span> is invariant
under a transformation <span class="math inline"><em>T</em></span> if
<span class="math inline"><em>T</em><em>u</em> ∈ <em>U</em></span> for
all <span class="math inline"><em>u</em> ∈ <em>U</em></span>. You can
decompose a vector space into invariant subspaces.</p>
<p>The most useful kind of invariant subspace is that with dimension
<span class="math inline">1</span>. These subspaces are essentially
equivalent to <em>eigenvectors</em>. We say <span
class="math inline"><em>v</em></span> is an eigenvector if <span
class="math inline"><em>T</em><em>v</em> = <em>λ</em><em>v</em></span>
for some scalar <span class="math inline"><em>v</em></span>. Also, we
call <span class="math inline"><em>λ</em></span> the associated
<em>eigenvalue</em>. If <span class="math inline"><em>v</em></span> is
an eigenvector, then <span
class="math inline">{<em>a</em><em>v</em>}</span> is an invariant
subspace with dimension <span class="math inline">1</span>.</p>
<p>A set of eigenvectors in distinct <span class="math inline">dim
1</span> invariant subspaces is linearly independent.</p>
<p>All complex vector spaces have an eigenvalue. All real vector spaces
with odd dimension have an eigenvalue. The former is essentially
equivalent to the Fundamental Theorem of Algebra, and the latter is
equivalent to the fact that all real polynomials with odd degree have a
root.</p>
<h2 id="inner-product-spaces">Inner-Product Spaces</h2>
<p>Up until now any arbitrary vector space sufficed: the scalars could
come from any field. Now we must specifically deal with either the real
or complex vector spaces <span
class="math inline">ℝ<sup><em>n</em></sup></span> and <span
class="math inline">ℂ<sup><em>n</em></sup></span>.</p>
<p>An inner product <span
class="math inline">⟨<em>u</em>, <em>v</em>⟩</span> satisfies the
following:</p>
<ul>
<li><span class="math inline">⟨<em>v</em>, <em>v</em>⟩ ≥ 0</span>, with
equality iff <span class="math inline"><em>v</em> = 0</span></li>
<li><span
class="math inline">⟨<em>u</em> + <em>v</em>, <em>w</em>⟩ = ⟨<em>u</em>, <em>w</em>⟩ + ⟨<em>v</em>, <em>w</em>⟩</span></li>
<li><span
class="math inline">⟨<em>a</em><em>v</em>, <em>w</em>⟩ = <em>a</em>⟨<em>v</em>, <em>w</em>⟩</span></li>
<li><span class="math inline">$\langle v, w\rangle = \overline{\langle
w, v\rangle}$</span></li>
</ul>
<p>(To clarify, <span class="math inline">$\overline{z}$</span> is the
complex conjugate of <span class="math inline"><em>z</em></span>.)</p>
<p>These are our <em>axioms</em>, but one can also deduce that <span
class="math inline">⟨<em>u</em>, <em>v</em> + <em>w</em>⟩ = ⟨<em>u</em>, <em>v</em>⟩ + ⟨<em>u</em>, <em>w</em>⟩</span>
and <span class="math inline">$\langle v, aw\rangle =
\overline{a}\langle v, w\rangle$</span>.</p>
<p>The standard example of an inner product is the dot product. Note
that the complex dot product is not quite what you'd expect; <span
class="math inline">$\langle (w_i), (z_i)\rangle = \sum
w_i\overline{z_i}$</span>. The motivation is so that <span
class="math inline">$\langle z, z\rangle = \sqrt{\sum
|z_i|^2}$</span>.</p>
<p>Also, the <em>norm</em> <span
class="math inline">||<em>v</em>||</span> of <span
class="math inline"><em>v</em></span> is <span
class="math inline">$\sqrt{\langle v, v\rangle}$</span>.</p>
<p>Some (in)equalities you might expect from dealing with the dot
product:</p>
<ul>
<li>Pythagorean Theorem: If <span
class="math inline">⟨<em>u</em>, <em>v</em>⟩ = 0</span>, then <span
class="math inline">||<em>u</em> + <em>v</em>||<sup>2</sup> = ||<em>u</em>||<sup>2</sup> + ||<em>v</em>||<sup>2</sup></span>.</li>
<li>Cauchy-Schwarz: <span
class="math inline">|⟨<em>u</em>, <em>v</em>⟩| ≤ ||<em>u</em>||||<em>v</em>||</span>,
with equality when one of <span class="math inline"><em>u</em></span>,
<span class="math inline"><em>v</em></span> is a multiple of the
other.</li>
<li>Triangle Inequality: <span
class="math inline">||<em>u</em> + <em>v</em>|| ≤ ||<em>u</em>||+||<em>v</em>||</span>,
with equality when one of <span class="math inline"><em>u</em></span>,
<span class="math inline"><em>v</em></span> is a non-negative multiple
of the other.</li>
</ul>
<p>With the inner product defined, we can construct <em>orthonormal</em>
bases of a vector space. In an orthonormal basis, <span
class="math inline">⟨<em>e</em><sub><em>i</em></sub>, <em>e</em><sub><em>j</em></sub>⟩</span>
is <span class="math inline">1</span> if <span
class="math inline"><em>i</em> = <em>j</em></span> and <span
class="math inline">0</span> if <span
class="math inline"><em>i</em> ≠ <em>j</em></span>. An orthonormal basis
always exists, and can be explicitly constructed given some basis with
the <em>Gram-Schmidt Procedure</em>.</p>
<h2 id="spectral-theorem">Spectral Theorem</h2>
<p>A <em>linear functional</em> is a map from <span
class="math inline"><em>F</em><sup><em>n</em></sup> → <em>F</em></span>.
For all linear functionals <span class="math inline"><em>ϕ</em></span>,
there is a unique vector <span class="math inline"><em>v</em></span>
such that <span
class="math inline"><em>ϕ</em>(<em>u</em>) = ⟨<em>u</em>, <em>v</em>⟩</span>
for all <span class="math inline"><em>u</em> ∈ <em>V</em></span>.</p>
<p>Fix some vector <span
class="math inline"><em>w</em> ∈ <em>V</em></span>. For a linear map
<span class="math inline"><em>T</em>: <em>V</em> → <em>W</em></span>,
observe <span
class="math inline">⟨<em>T</em><em>v</em>, <em>w</em>⟩</span> is a
linear functional from <span
class="math inline"><em>F</em><sup><em>n</em></sup> → <em>F</em></span>,
so there exists some <span
class="math inline"><em>T</em><sup>⋆</sup><em>w</em> ∈ <em>V</em></span>
such that <span
class="math inline">⟨<em>T</em><em>v</em>, <em>w</em>⟩ = ⟨<em>v</em>, <em>T</em><sup>⋆</sup><em>w</em>⟩</span>.
Each <span class="math inline"><em>w</em></span> is associated with a
unique <span
class="math inline"><em>T</em><sup>⋆</sup><em>w</em></span>, so we can
consider <span class="math inline"><em>T</em><sup>⋆</sup></span> a
function from <span class="math inline"><em>W</em> → <em>V</em></span>,
and furthermore, <span class="math inline"><em>T</em><sup>⋆</sup></span>
is a linear map.</p>
<p>Say now that <span class="math inline"><em>T</em></span> is a linear
endomorphism, i.e. <span
class="math inline"><em>T</em>: <em>V</em> → <em>V</em></span>. Then we
say <span class="math inline"><em>T</em></span> is <em>self-adjoint</em>
if <span class="math inline"><em>T</em> = <em>T</em><sup>⋆</sup></span>
and <span class="math inline"><em>T</em></span> is <em>normal</em> if
<span
class="math inline"><em>T</em><em>T</em><sup>⋆</sup> = <em>T</em><sup>⋆</sup><em>T</em></span>.
Obviously all self-adjoint operators are normal.</p>
<p>The Spectral Theorem states that <span
class="math inline"><em>T</em></span> has a diagonal matrix iff</p>
<ul>
<li>In a complex vector space: <span
class="math inline"><em>T</em></span> is normal</li>
<li>In a real vector space: <span class="math inline"><em>T</em></span>
is self-adjoint</li>
</ul>
<p>I've been trying really hard to avoid matrices, but bringing them up
is very natural here. To use terms we have defined before, "has a
diagonal matrix" is equivalent to "has an orthonormal basis of
eigenvectors".</p>
<h2 id="conclusion">Conclusion</h2>
<p>So that's linear algebra! A lot of detail has been left out, and we
haven't even <em>touched</em> matrices, but it's still quite doable
right?</p>]]></description>
	<pubDate>29 Jul 2023</pubDate>
</item>
<item>
	<title>MAST is going on indefinite hiatus</title>
	<link>https://dennisc.net/writing/blog/mast-hiatus.md</link>
	<description><![CDATA[<p>In summary, MAST will no longer be offered.
Applications will not be considered and content will not be
developed.</p>
<p>For existing students: you will be getting a tarball of all the
finished units as well as a separate tarball of all unfinished
units.</p>
<p>A public explanation of why Math Advance has decided to place MAST on
hiatus and what this means for its future is in order. This is said
explanation.</p>
<p>We still stand by the claim that MAST's materials are some of the
most thought-out and comprehensive lecture notes in the math contest
community. However, our standards are not just "offer better material
than everyone else" --- they are offering material that is as close to
perfect as we can get. This even applies to the <em>code</em> that runs
MAST and its content. Part of what makes Math Advance what it is now is
our unrelenting strive for perfection, and these last few months have
shown that we do not currently have the infrastructure or manpower to
meet these high standards. Most math organizations (and organizations in
general) would be content to keep offering a program like MAST under
these conditions, and perhaps we would do more good than harm if we did
so. But my personal philosophy as Math Advance's director is that it is
okay to sacrifice the scope of our organization if it means the things
we keep doing are as close to perfect as possible.</p>
<p>Currently we have our hands fill with the contest side of things:
further developing mapm and its ecosystem (many thanks to <a
href="https://evilmuff.in">EvilMuffinHa</a> for agreeing to help out!)
as well as rewriting the MAT website and its contest portal to align
closer to my web development ethos. Personally, I am also working on a
<a href="/writing/tech/glee-design">Git hosting service</a> because I'm
very picky about my infrastructure. In short, my manpower is limited and
my priorities have shifted.</p>
<p>Teaching has, in part, been a selfish endeavor for me. Of course I
enjoy seeing my students improve, but I also enjoy making my content as
good as possible for its own sake. Since it's not currently my main
interest (outside of my draft of an introductory competition geometry
book), I hope you'll forgive me if I don't pursue it as frequently.
Plus, my teaching philosophy has dramatically changed, so I need some
time to collect myself and reorganize my materials in a way that makes
sense to me.<a href="#fn1" class="footnote-ref" id="fnref1"
role="doc-noteref"><sup>1</sup></a></p>
<p>As for the future of MAST? I don't think we're going to see that
exact progrma back as is, though I am inclined to keep the name (so that
way we can keep the logo too). However, I do hope to continue teaching
with Math Advance in the future! It's more likely these materials will
be used for shorter, more intensive math camps during the holidays. Or I
might use them as bases for private tutoring. We'll see what
happens.</p>
<p>I'm hopeful for the future. Perhaps this hiatus of MAST will not only
represent the closing of a certain chapter for Math Advance but also the
beginning of new opportunities. Putting MAST on hiatus, in a way, is
like returning it to the staging area of a Git repository. Of course,
any staged changes there may never make their way to remote regardless
of how much work has been put into it, and just the same, there's the
real possibility that nothing more will come out of the work we've put
into MAST.</p>
<p>However it goes, I'm grateful to everyone for their support.</p>
<p>The original email sent to MAST students:</p>
<blockquote>
<p>I emailed this to the staff a while ago, and after careful
deliberation I have decided that it is best to indefinitely suspend the
MAST program.</p>
<p>Besides the reasons I have laid out in the original email, one more
stands: we are in tech debt. The MAT website is a complete disaster as
it stands, though I will not elaborate until after a rewrite is complete
for security reasons. I'm also writing Git server software to improve
Math Advance's infrastructure, and Math Advance is undergoing aggressive
expansions on the contest side --- we plan to hold a Winter MAT (more
details on this later).</p>
<p>The long and short of it is, I don't have the time/energy to spend on
MAST, and frankly it is not my first priority anymore. When Math
Advance's tech stack becomes more stable, MAST may come back in some
shape or form!</p>
<p>Forwarded message from Dennis Chen on Thu Jul 7, 2022 at 8:26 PM:</p>
<p>There's a good chance I end up forwarding this verbatim to the
students, so I'm going to directly address them. And to the students, if
you end up seeing this, note that this was originally a staff email ---
so many of the concerns I bring up will be pertinent to them and only
them.</p>
<p>MAST is waning, and though the lecture spree did redeem the end of
Season 4, it is obviously not something sustainable at that level. We've
been on minimum maintenance mode for maybe 10 months at this point, and
it's about time we put a name to the decay that's been going on. Let's
call a spade a spade: MAST has fallen in a state of disrepair because
there is no one willing to work on it, including myself.</p>
<p>Many students may not know the difference between MAST and Math
Advance, or that the latter even exists. So, to clarify: Math Advance is
the parent organization of MAST, and we are also the organizers of the
MAT (mat.mathadvance.org). Math Advance is still alive and well, but our
interest (and our start) has always been with writing math contests,
which is why we have recently put much more attention into it.</p>
<p>Part of this "lack of interest" is largely selfish. I've personally
been more involved in writing programs that do useful things for Math
Advance and the math contest community at large. The culmination of my
last 6 months of work is in programs like mapm (mapm.mathadvance.org),
the Math Advance website (mathadvance.org), the MAST website
(mast.mathadvance.org), the design for the MAT contest PDFs, and so on.
However, this shift to programming has largely whittled away at my
familiarity with the math contest scene since I haven't been practicing
or teaching as often.</p>
<p>I still am doing technical writing, but most of those efforts have
been focused on a geometry book for beginners to contest math (mostly at
the middle school level). As such, I am left with little time and energy
to work on MAST materials, and my familiarity with them has honestly
slipped past the point where I can recover. I still faintly remember the
philosophies I put into Perspectives, but that's about it.</p>
<p>At the same time, I recognize that a lot of people have gotten value
from MAST. I don't want to take too much credit --- but I have noticed
that with the new batch of students, MAST has played a role in their
improvements, however small it may have been. Many USAJMO
qualifications, multiple MATHCOUNTS Nationals qualifiers (and some from
really difficult states, too) --- I don't have the time to name you all
in this email, but I'm proud of every one of you. My only hope is that
you pay back the kindness, generosity, and patience you've encountered
in math contests in some shape or form, even if it's not to the math
community. (You're all really talented, and Math Advance would
appreciate seeing some of that talent here :)</p>
<p>Beyond just winning titles in math contests, I'm glad to see that
MAST has also formed a community. We've competed in a ton of math
contests together under the Math Advance banner, played games together
in voice chat, and had some of the silliest conversations. None of this
is going away. If any staff are still willing next year, we will
continue to organize teams for college math contests.</p>
<p>So here's what's going to happen: I probably will not host another
round of applications, or actively give units to people anymore.
Feedback on submissions definitely will not be happening, not that it
has been consistently happening anyway. I will still be answering
questions in the MAST Discord, whether they are about our
handouts/contests or not.</p>
<p>What I will do is probably send a tarball with all of the MAST
materials, both what has been migrated onto the website and the units
which have not. There is no official guarantee for quality for the units
which have not been vetted, but anecdotally speaking, most of them have
some sort of value, even if they aren't quite up to par. This way I do
not have to respond to any unit requests, which further reduces the
workload I get from this program. (It's not like I really decline any
unit requests anyway.)</p>
<p>If I end up doing this, I request that you do not distribute any of
our materials to the wider math contest community. You guys have been
really good about this, so this is more just to let you know that the
redistribution policy is the same. I want to keep the option of using
these materials for some other purpose open, possibly including the
revival of MAST in some shape or form.</p>
<p>Thanks to everyone who has ever contributed material to our program.
Thanks especially to Prajith, who has expanded our workable content base
by writing solutions for many units. Your work will not go to waste ---
though MAST may not exist the same way it did two years ago, I do have
plans for these materials sometime in the future! One of Math Advance's
primary goals is to teach, and I fully intend to continue doing that in
some shape or form.</p>
<p>Finally, thanks to everyone who's donated the suggested $40 to Math
Advance (no one chose to donate a different amount). Though the program
you donated to, MAST, may not be around anymore, we will still use these
funds to support Math Advance's greater mission of supporting math
education. A couple of things that donations will help cover:</p>
<p>--- Prizes for math contests (which we will be hosting more of, as
MAST's hiatus will provide us with more focused energy in this regard)
--- Server costs &amp; domain costs --- Registration fees for college
contests</p>
<p>I've learned a lot from teaching MAST for the last 2 years. I hope
you learned just as much participating. Thank you to all the students
and staff for supporting me for so long --- it's been a blast.</p>
</blockquote>
<section id="footnotes" class="footnotes footnotes-end-of-document"
role="doc-endnotes">
<hr />
<ol>
<li id="fn1"><p>Personally, I still enjoy teaching, so I might do it in
a lower-stakes environment like tutoring. So if you go to school in my
area, I'd be willing to tutor the AMCs/AIME for $60 an hour. It sounds
like a lot, but considering that <a
href="https://blog.evanchen.cc/2016/02/07/stop-paying-me-per-hour/">this
price takes into account the time I need for lesson plans</a>, plus the
fact that the number of USAMO qualifiers tutoring is probably on the
order of 1e3, I think it's pretty reasonable.</p>
<p>I'm also planning on tutoring the SAT for the same rate, though if
you're on this website you probably know it's more of "make some money"
than "I have a passion for the SAT" (hint: nobody does). I think I'd be
pretty good at it though.<a href="#fnref1" class="footnote-back"
role="doc-backlink">↩︎</a></p></li>
</ol>
</section>]]></description>
	<pubDate>29 Jul 2022</pubDate>
</item>
<item>
	<title>...and so it begins</title>
	<link>https://dennisc.net/writing/blog/so-it-begins.md</link>
	<description><![CDATA[<h2 id="final-day-of-sojourn">Final Day of
Sojourn</h2>
<p>As the title suggests, I spent a good chunk of time in California
watching Alice in Borderland (which, by the way, is much better than
Squid Game). A brief rundown of my summer:</p>
<ul>
<li>Went to China</li>
<li>Actually did stuff in very hot places</li>
<li>Got my wisdom teeth extracted in a place with reasonable
weather</li>
<li>Did not want to live (and did nothing) for two weeks</li>
<li>Got back and got (mildly) sick</li>
<li>Did not want to live (and saw nobody) for 4 or 5 days</li>
<li>Saw people</li>
</ul>
<p>I don't think a listicle of things done makes for interesting
reading, but I'm at college now and barely remember any of it.</p>
<p>Vaguely, the way I remembered <em>feeling</em> was "ok well I just
wanna get this over with and like be on my own". I didn't really have
much to do, although at least on the last few days I started seeing
people (my boy Sword Looting went on a trail run with me). But yeah it
is nice to just, maybe have problematic decisions like staying up till 1
or weird shit like showering twice a day (I will <strong>never</strong>
do the opposite) or even technically irresponsible but more agentic
things like skipping shitty O-week events with friends. (I hate the word
"agentic" with a passion but it actually worked perfectly here.)</p>
<p>Also I just decided "fuck it I ain't seeing anyone" on Thursday, the
day before my flight. Probably a good decision so my social battery
doesn't go to 0 before I even go to college.</p>
<h2 id="day-01-locked-out">Day 0+1 (Locked Out)</h2>
<p>Friday 4:00 AM I woke up for a 7:00 AM flight from Oakland. I don't
know why we left so early.</p>
<p>Anyway, as a result of being lazy last night and my mom being
convinced we had no time for me to do some last minute packing (she was
wrong!) I was left without</p>
<ul>
<li>my Switch</li>
<li>Secret Hitler</li>
<li>Ethernet cables</li>
<li>my passport(!!!)</li>
</ul>
<p>Anyway the point is I am an idiot. And apparently now I am coming
back for Fall Break because I really need some of these things (my
passport) and really want some others (my Switch and Secret Hitler if I
don't just cave and order it on Amazon).</p>
<p>After arriving we did some shopping at Costco, and I was too lazy to
actually go and find a restaurant so we just ate Costco pizza and went
to the hotel. The hotel was literally in the middle of nowhere, and to
make things worse the people next to us were blasting TV really loudly
at 1 AM, which made it hard to sleep. My movein time was 9:45 AM and I
should've woken up around 8:30, but I got woken up at 7:30 ish (I am
guessing here) by the fucking TV and was like "ok I never even fell
asleep I can go back to bed".</p>
<p>Then I wake up at 9:55. At first I think my dad is playing a prank on
me; no way I slept that long. But no, it is 9:55 AM and I am definitely
late for my move-in time. "Well, crap", was not the first thing --- or
even one of the things --- that I thought, because I knew (read:
assumed) move-in times didn't really matter. I was right.</p>
<p>After moving in I kick my dad out because I like having friends. Then
we eventually osmosised into a large ass group and it was really funny
when I ran into him again because I forgot to take my blazer out of some
luggage (and so I would've accidentally shipped it back oops). And I
won't lie I forgot the rest of what happened but I vaguely think it
involved the gym a little? Also I met up with a lot of people that day,
so I didn't do the two things I wanted to:</p>
<ul>
<li>Sleep before 11 PM</li>
<li>Study linalg</li>
</ul>
<p>The one thing I do remember, though, was getting locked out of our
dorm for 2 hours and sitting outside because our door key swiper thing
ran out of battery?? And then watching Axler videos with my roommate
while my other roommate slept through the loud-ass knocking on the door.
Eventually the RA contacted campus police who opened our door and
contacted maintenance to fix the lock for us. So we just permanently
left it open before then.</p>
<p>Also I still owe people money and should pay them back eventually
instead of being a bum.</p>
<h2 id="day-23-bonding-over-o-week-by-hating-o-week">Day 2+3 (Bonding
over O-Week by hating O-week)</h2>
<p>One of my friends asked (rhetorically) "how do you even make friends
during O-Week this shit is so boring". (Because it is. Pro tip if you go
to CMU next year, skip almost everything because it sucks, go explore
Pitt with your friends instead!!) Or maybe I asked it. Anyway, someone
else answered "by shitting on O-week events with the people next to us".
Honestly, he's not wrong.</p>
<p>The actual O-week events are by far the worst part of O-week. The
president's welcoming address was boring and made me play Clash Royale
for the first time in literal months (and my roommates too). The SCS
speech was like, "bro why are you flexing 50% yield and stop I don't
care about the details let me leeeeave." The floor event was like "OK
let us now memorize names" (I don't care). And the Day 3 (everything
before was Day 2) house meeting was like, "ok and now the RAs will
socialize while you sit here and do nothing for two hours".</p>
<p>The worst part isn't that these O-week events are nominally
mandatory. It is that everyone else goes there so you can't actually
plan to hang out then, although thank jesus it is beginning to change.
At least I had a few friends who were sane and didn't go to more house
meetings from 3 to 5 or some bullshit?? And when you get there it's
literally kindergarten. The lunch tables are too reminiscent of high
school, and not in a good way. (Although that's just the atmosphere; the
people I eat lunch with are amazing.) And we literally had to "fill
time" so we could get "properly dismissed for lunch". Like bro I'm not
some high school freshman. I can vote so please just let me stand up and
leave.</p>
<p>We also had a math placement test. I didn't ace but did pretty well
(as far as I know, maybe the best?), so it was ok. Better than I
expected and worse than I hoped for.</p>
<p>I complain a lot here, but by and large the positives outweigh the
negatives by far, especially since I skipped a lot of events (mostly to
recharge before placement test, and because the placement test
overlapped). I like CMU and I like the people here. But the most novel
thing these two days is the O-week events, and also the least
confidential, so it is what I focus on here.</p>
<p>Also my gym ratting + two showers a day regime is going well. I will
probably stay consistent because I still study a LOT. Especially now the
placement test is over.</p>
<h2 id="day-4">Day 4</h2>
<p>I dunno if it was post-test nerves or something, but I could not
sleep the entire night. So around 6 AM, I just gave up and went outside
(and now I am absolutely exhausted). When I got back I just started
doing work and puzzles, which somehow requires the least brainpower
compared to actually socializing and stuff. (Goes to show that I'm still
secretly an introvert despite how hard I try to gaslight myself
otherwise.)</p>
<p>Then we tried to register for whitewater rafting in the outdoors
event:</p>
<blockquote>
<p>Try to register for event</p>
<p>Reg is open from Aug 22, 8 AM - Aug 22, 1 AM</p>
<p>???</p>
</blockquote>
<p>Number 1 CS school for real. Now we just have to camp the
website??</p>
<p>The link then got replaced under our noses and we only realized when
it was too late, so my roommates + our adjacent friend group didn't get
our first choice (water rafting). Plus my second choice (paintballing)
disappeared too, so I went with my third choice, caving. But at that
point you can't really get everyone to compromise on a third choice
(most peoples' second choice was paintballing too), so we all got split
up.</p>
<p>Also I went to the floor meeting (for a few minutes anyway, right as
it ended) this afternoon. That was pretty out of character for me, but I
got a free shirt from it so hooray?</p>
<p>At some point I figured I needed to clean our dorm, do laundry, and
buy eggs (for breakfast). I would've done that but got too busy
socializing (I need to be more responsible) and was going to do it at
midnight but things happened.</p>
<h2 id="day-56">Day 5+6</h2>
<p>After two days of not sleeping and a bunch of things going on, I just
crashed.</p>
<p>Every time I went to a live-in camp, I would be super extroverted for
the first few days, but at some point I'd just go "OK I'm done" and
basically hole myself in my room working on my own stuff. (It could be
worse; I could hole myself in my room doing nothing.) And these two days
are when I went, "I'm done".</p>
<p>Day 5 wasn't too bad --- at least, I didn't realize what I'd done
until Day 6 (which is when I am typing this section up). I did sleep a
lot, eat breakfast in my room (instead of with other people --- my
roommates were either asleep or gone?), skip the pool event I signed up
for, and cut my gym session short because I was so tired, but it wasn't
all going downhill. Yesterday I took the initiative to actually go
grocery shopping and went to the Google field trip (which wasn't quite
what I expected or hoped for it to be).</p>
<p>I did nearly fall asleep on the Google trip because it was a lot of
"sit down and listen to panelists" and I was super sleep deprived.</p>
<p>Now for Day 6... I slept at 10 PM last night and woke up pretty late
(8 AM ish)? I decide to skip CMU breakfast because CMU breakfast is
dogshit. Unfortunately, I am not particularly experienced at cooking
stuff nor particularly intelligent, and by the time I got back from
grocery shopping on Day 5, the aforementioned Google trip was happening
very soon. So in my haste to pack everything into the mini-fridge, I
accidentally put the eggs in the freezer instead of cooling.</p>
<p>The eggs were fucked.</p>
<p>So instead of having something nice for breakfast, I was basically
just subsisting on the bread and fruits I bought a while back. I had to
chuck the eggs out as well. It seems small --- and honestly, it really
is --- but I became irrationally upset for a few hours. I say became,
but right now I'm still holed in my room playing BTD Battles 2.
Orientation events might be a bad use of my time, but the difference
between me skipping earlier and skipping now is that in the former case,
I actively had better things to do. I was hanging out with people or at
least going shopping, but now I am just a bum playing video games
instead of socializing with other people.</p>
<p>The worst thing is, right now I am waiting on external events ---
whether it be lunch, a (hopefully good) MMS result, or other people ---
rather than relying on my own initiative to change anything or improve
my mood. I know what I <em>need</em> to do, but I just can't be assed to
do it. This feeling of learned helplessness is pretty awful.</p>
<p>Ok but whatever who cares right? Apparently I did "quite well" on MMS
and need to "discuss options", which is distinctly different from "oh OK
you can just choose to take 242 or not". Which means WE GETTING OUT AND
WE GETTING CHOICE WOOOO</p>
<p>My roommate also got the same email so there'll be someone I know in
my classes maybe. I dunno though because our choice on what to do next
might differ.</p>
<h2 id="day-7">Day 7</h2>
<p>Yeah, basically everything went as perfectly as it could have. I'm
taking 0 math classes and 2 CS classes this fall which is nice, because
most people take 3 core classes. So I can just chill this semester.</p>
<p>Also Carnegie Cup happened. We did puzzle hunt, the counselors
running it dipped, so we dipped back to my room for a while too. The
logic puzzle round was nice and I solo-solved it in ~10 minutes, the
rest was between difficult to impossible for me.</p>
<p>A thought I had near the end of the night: I think there's a point
where it's better to meet new people, and then past that point it's
better to get to know the people you just met. I think we crossed that
point by Day 4. Orientation should not be nearly this long, and it
really should've just been speeches (I guess, because they're kind of
mandatory) and the fun things like Pittsburgh Connect. (More on that
later!)</p>
<h2 id="day-8">Day 8</h2>
<p>I figured out what my second gen-ed will be today: 80-180 (Nature of
Language). I know a couple of people in that class, and technically I'm
on the waitlist but my advisor told me there were 9 open spots, so I'll
basically be guaranteed to get in the class.</p>
<p>More importantly, today was Pittsburgh Connect. The idea is you
either touch grass (go outside) or see cultural stuff (eg museums) to
create, well, a <em>connection</em> with Pittsburgh. I chose to go
caving and honestly it was so fun. And if you're in disbelief, yes, I
actually went inside a cave. Like, <em>a real one</em>. I was surprised
when I saw the details too.</p>
<p>We went to the upper two levels of the Laurel Caverns, and the actual
caving was about 90 minutes long. (The bus ride was 2 hours each way.) I
got really dirty on the trip, and I also got to experience
<em>genuine</em> pitch black and near-silence in a cave. The highlight
was the spring water though. Holy shit it tasted so good. Like
genuinely, that shit changes lives. I swear I might've almost gotten
high on just how good that water was.</p>
<p>I also started reading up on a little bit of Haskell, since I got
into 15-150 (the functional programming class). I already know some
big-picture things about Haskell and FP because I've just been reading
about these ideas on and off, but it didn't really register that I'd be
actually learning about FP this soon until yesterday. I'd heard about
people on LinkedIn who got an Amazon/Jane Street/etc internship who took
150 in the fall but until now I thought those people were a myth and me
doing the same thing would be a pipe dream. Apparently not.</p>
<h2 id="day-9-last-day">Day 9 (last day)</h2>
<p>Man. I was so tired that I slept at 11 and when I decided it was time
to wake up, it was already 9:30. Today the goal is to actually become
adjusted for classes. Not that I can do that in one day, but I'll be
doing what I can.</p>
<p>Today I decided to figure out my schedule (i.e. what I'd be doing
every day) and also dealt with a bit of MAT logistics. (Sorry it's taken
so long, guys!) And, surprising even myself, I decided to attend the
final floor meeting because it's the last one.</p>
<p>Then I got dinner with some people and we went grocery shopping but
there were no eggs. And so I didn't get anything, because the apples in
Scotty's Market are $2.59. Not per pound. <strong>EACH.</strong> That is
pretty fucked up. Scotty, you are one disaster of a mascot dog. Get your
act together.</p>
<h2 id="and-so-it-begins.">...and so it begins.</h2>
<p>So I've had a couple of days of classes already (literally a couple:
exactly two).</p>
<p>First thing's first: CMU stopped serving their shitty orientation
food and put us on the meal plan proper. Actually, this happened a few
days before (Day 7 if I remember correctly?) but I never thought it was
really worth mentioning. The food is pretty good, I really like Rev
Noodles. Meal blocks are still a scam though and there's no way I finish
them all.</p>
<p>Speaking of eating, I've basically only had time to eat two meals a
day. Part of this is because of scheduling shittiness; sometimes I only
have enough time to eat brunch and dinner. But another part (and
honestly most of it) is self-inflicted. More on that later.</p>
<p>My actual classes were mostly OK. Imperative was a little slow but
surely it'll catch up. Functional programming was pretty interesting and
I liked the first lecture better, but I almost collapsed during the
first lecture. (More on this later, and this is related to my two meals
a day situation too.) I don't want to write anything mean about my
writing class so the less said the better. Hopefully Nature of Language
shapes up to be interesting.</p>
<p>This is what my schedule looks like for this quarter:</p>
<p><img src="real.png" alt = "Real schedule"></p>
<p>This is very chill. As I've said before, testing out means I had no
math classes. But also taking zero math classes is one surefire path to
brain rot, so I decided to sit in on a couple of classes and asked a
friend to join me. Well, something awakened in his mind, and now I am
sitting on three classes. This is my fake schedule (that reflects what I
am actually doing):</p>
<p><img src="fake.png" alt = "Fake schedule (including sit-ins)"></p>
<p>If I have to drop something I'll drop Complex Analysis first. (I
didn't go on Monday and I was already fucked up from four
back-to-backs.) Because Complex is more standard than Formal Logic (e.g.
online resources and friends who know it are more common), it's also
something I can afford to put off for a semester.</p>
<p>My fake classes are by far the most interesting. They aren't large
ass lecture halls and the professors can actually individually see
people (wow).</p>
<p>In Linear Algebra (which is covered with abstract fields and has
multilinear transformations hopefully) we just went over fields in the
first lecture. Mostly just review, but it was funny when Prof.
Schimmerling was making an effort to assume as little prereq knowledge
as possible, got to <span
class="math inline">𝔽<sub><em>p</em></sub></span>, and just thought for
a second and gave up (i.e. he said "the field of integers modulo <span
class="math inline"><em>p</em></span>"). I also am not sure whether he
knows we're not actually registered students or not.</p>
<p>In Basic Logic (remains to be seen whether it will turn out to be
truly basic... my guess is no) we covered "the view from 3000 feet up"
and got a general overview of the difference between syntax and
semantics, Godel's (in)completeness theorem, why the Peano axioms cause
incompleteness, and what the heck induction actually is. He also gave
some supplemental textbook recs for the course, which we later learned
are on the syllabus. (The course uses no text.) And now we are on the
Canvas and Piazza, which is pretty nice.</p>
<p>And this is why I get two meals a day some days... (and probably why
I nearly fell asleep in FP lecture). Oh well!</p>
<p>Also, if you think my fake schedule is fucked up...</p>
<p><img src="sfake.png" alt = "Most fucked up fake schedule"></p>
<p>Yeah I think I really awakened something.</p>
<p>Anyway, I'm still hanging out with friends and having fun. Life is
fine even if I technically have 80 units on my fake
schedule.</p>]]></description>
	<pubDate>30 Aug 2023</pubDate>
</item>
<item>
	<title>My taste in math contests</title>
	<link>https://dennisc.net/writing/essays/taste.md</link>
	<description><![CDATA[<p>After running the 2022 Summer MAT, a contestant
told us (paraphrased):</p>
<blockquote>
<p>Thanks so much for organizing this contest! Usually math contests are
way too fast, leaving no time to think about the problems or check your
answers.</p>
<p>Thus, I really enjoy slower-paced contests like MAT where I can enjoy
the problems.</p>
</blockquote>
<p>I feel the same way, which is why I designed the MAT the way I did.
For posterity and for the sake of my future self, I want to record my
thoughts on what makes a contest format and (briefly) what makes a
contest's problems good.</p>
<p>Contest formats, as I wrote about in a slightly facetious manner
before, should be <a
href="https://dennisc.net/writing/essays/contest-formats">simple</a> so
as to not confuse the contestants or distract from the main thing the
contest is about: math. For this reason, I personally don't like the
convoluted weighting scheme contests like HMMT use. In fact, I don't
think problems should be weighted at all, and every significant US
contest (well, that's just the AMC series and maybe MATHCOUNTS)
agrees.</p>
<p>As the quote implies, contestants should have ample time to solve
problems. The only complaints I see with giving lots of time for each
problem is that it makes the contest take too long or makes the contest
fail to differentiate between contestants. In the next two paragraphs I
will address these criticisms, but I first want to expound on the
benefits of having generous time limits. It makes the contest more
relaxing because it allows people to work without fear of running out of
time. Most of all, it gives people the chance to chew on interesting
problems and struggle with them for a while, which is what math contests
are supposed to promote in the first place. No one wants to sit with a
test of problems they either instantly know how to solve or instantly
give up on, and that is what shorter time limits force. Plus, every
contestant should get a chance to see every problem, and if people run
out of time halfway through the contest then what was the point of the
other half?</p>
<p>Having longer time limits makes the contest take longer, but this can
be offset by having less problems. And I think there should be less
problems on most math contests. How much discussion do you reckon the
average HMMT problem gets? Compare that to the MAT: <a
href="https://artofproblemsolving.com/community/q1h2629920p22736788">Summer
2021/1</a>, <a
href="https://artofproblemsolving.com/community/q1h2629930p22736861">Summer
2021/3</a>, <a
href="https://artofproblemsolving.com/community/q1h2629935p22736980">Summer
2021/7</a>, <a
href="https://artofproblemsolving.com/community/q1h2629935p22736980">Summer
2021/9</a>, <a
href="https://artofproblemsolving.com/community/q1h2629935p22736980">Summer
2022/2</a>, <a
href="https://artofproblemsolving.com/community/q1h2629935p22736980">Summer
2022/3</a>, <a
href="https://artofproblemsolving.com/community/q2h2891032p25723795">Summer
2022/4</a>, <a
href="https://artofproblemsolving.com/community/q2h2891040p25723825">Summer
2022/6</a>, <a
href="https://artofproblemsolving.com/community/q2h2891037p25723811">Summer
2022/8</a>, and <a
href="https://artofproblemsolving.com/community/q2h2891036p25723807">Summer
2022/9</a> all have a good amount of discussion, and you can find past
discussion for the problems I didn't list if you know where to look.
This is 50% of all the main 9 problems across both years. I bet you
every American contest (besides the AMC series) has about a 10% rate of
discussion at most. Contests are largely a social experience, and if you
have so many problems that contestants don't discuss because they
literally forgot about doing them, you lose out on the education
factor.</p>
<p>Maybe this makes MAT worse at distinguishing who the "best"
contestants are, but top contestants really do not care that much about
the competitive aspect. First off, winning an unfun contest is
meaningless, and I believe math contests with less problems and more
time are just more fun. But more directly addressing this criticism,
which is partially correct: it doesn't really matter if a contest isn't
perfect at distinguishing performances because contests are only
nominally competitive. If we really wanted to spot the best 5
contestants out of 100, there'd be no reason to include problems 1, 4,
or 7 in the contest. We could just have 9 really hard problems and put
them together. But we also want the other 95 contestants to learn
something and enjoy the contest, and the top 5 contestants probably
enjoyed solving the easier problems on the contest too.</p>
<p>For a contest to be fun, so must its problems. This means every
problem must be satisfying to solve --- it can't be too tedious, and
there actually has to be some sort of idea behind it so the contestant
gets something out of the problem.<a href="#fn1" class="footnote-ref"
id="fnref1" role="doc-noteref"><sup>1</sup></a> I think pretty much
every MAT problem is a good example of this: in particular, Summer
2021/2, Summer 2021/9, and Summer 2022/TB3 are worth looking at. (You
can find past copies of the MAT at <a
href="https://mat.mathdvance.org">mat.mathadvance.org</a>.) Beyond this,
I won't talk too much about problem-writing philosophy; if you want
more, see <a
href="https://www.dropbox.com/s/kj1m54kpa15lb25/PPPPPP.pdf?dl=0">Ankan's
thoughts</a>.</p>
<section id="footnotes" class="footnotes footnotes-end-of-document"
role="doc-endnotes">
<hr />
<ol>
<li id="fn1"><p>Anti-examples include <a
href="https://mat.mathadvance.org/narml.pdf">NARML 6</a> and pretty much
every early combo problem in CHMMC.<a href="#fnref1"
class="footnote-back" role="doc-backlink">↩︎</a></p></li>
</ol>
</section>]]></description>
	<pubDate>3 Aug 2022</pubDate>
</item>
<item>
	<title>Morality in Mathematics</title>
	<link>https://dennisc.net/writing/essays/morals.md</link>
	<description><![CDATA[<p>Suppose for whatever reason you wanted to visit
me. I could tell you to go to <span
class="math inline">40.4432<sup>∘</sup><em>N</em>, 79.9428<sup>∘</sup><em>W</em></span>
by turning your steering wheel <span
class="math inline">117<sup>∘</sup></span> counterclockwise in 8
seconds. Or I could tell you to go to Carnegie Mellon by taking a left
turn at the next traffic light.</p>
<p>Both these sets of instructions technically convey the same
information. But not all information is made equal. Telling you to turn
left is much more helpful, because it tells you the point of what you
are doing.</p>
<p>Mathematics is much the same. Often, I will describe a mathematical
argument as being "morally (in)correct". My friends think this is a
strange thing to say. Surely mathematical arguments are either correct
or incorrect. What on earth does "morally" mean?</p>
<p>Mathematical arguments can be seen as a series of directions. We
start from a certain point (a collection of assumptions), and we arrive
at a destination (a conclusion). And it very much can be the case that
one set of directions is far clearer than another.</p>
<p>Let me give you a fairly advanced example. Consider Sylow's Theorem.
It is perfectly possible to prove it without using the words "orbit" or
"stabilizer" once. But when you do so, you will inevitably end up saying
"turn <span class="math inline">117<sup>∘</sup></span> counterclockwise"
instead of "turn left" a bunch of times. Here, these left turns are just
the theory of group actions (which include orbits and stabilizers).</p>
<p>Definitions and theorems are much the same. You should not just treat
them as lists of causes and lists of effects.</p>
<p>For instance, I could tell you that the implicit function theorem
says that given real/complex Banach spaces <span
class="math inline"><em>X</em></span>, <span
class="math inline"><em>Y</em></span>, and <span
class="math inline"><em>Z</em></span>...</p>
<p>But your eyes would probably glaze over that. At the very least, mine
did the first time I was learning about it. Why should you care?</p>
<p>But now let me tell you the following. Consider a function like <span
class="math inline"><em>f</em>(<em>x</em>, <em>y</em>) = <em>x</em><sup>2</sup> + 2<em>y</em><sup>2</sup> − 2<em>x</em><em>y</em> + 5<em>x</em> + 7<em>y</em> − 20</span>.</p>
<p>Given some value for <span class="math inline"><em>x</em></span>, we
can find a value for <span class="math inline"><em>y</em></span> such
that the equation <span
class="math inline"><em>f</em>(<em>x</em>, <em>y</em>) = 0</span>. It
turns out that we can do even better; there is some <em>function</em>
<span class="math inline"><em>F</em></span> taking values of <span
class="math inline"><em>x</em></span> into values of <span
class="math inline"><em>y</em></span> such that this equation is
satisfied (more precisely, <span
class="math inline"><em>f</em>(<em>x</em>, <em>F</em>(<em>x</em>)) = 0</span>).
And because <span class="math inline"><em>f</em></span> behaves very
nicely, so does the function <span
class="math inline"><em>F</em></span>. In fact, if <span
class="math inline"><em>f</em></span> is <span
class="math inline"><em>k</em></span> times continuously differentiable,
then so is <span class="math inline"><em>F</em></span>.</p>
<p><em>Now</em> we have a reason to care about the Implicit Function
Theorem. Equations like <span
class="math inline"><em>f</em>(<em>x</em>, <em>y</em>) = 0</span> can be
<em>solved</em>, and the function that carves out the solutions is just
as nice as <span class="math inline"><em>f</em></span> itself.</p>
<h2 id="hygiene">Hygiene</h2>
<p>This is why we care about mathematical hygiene. Picture an
unnecessary proof by contradiction that goes like this:</p>
<blockquote>
<p>Assume for the sake of contradiction that <span
class="math inline"><em>X</em></span> is false. <em>Insert direct proof
that <span class="math inline"><em>X</em></span> is true</em>.
Contradiction.</p>
</blockquote>
<p>This isn't bad because it makes the argument longer; it barely makes
a difference to the length. Rather, it obscures the point of the
argument. The point of this argument is not that we may derive a
contradiction by assuming "not <span
class="math inline"><em>X</em></span>"; the point lies in the direct
proof of <span class="math inline"><em>X</em></span>. But using a proof
by contradiction makes it seem otherwise.</p>
<h2 id="orthogonality">Orthogonality</h2>
<p>Being morally correct and technically correct are separate things. Of
course, they are correlated: if you are egregiously wrong, then you are
likely not morally correct either, and a good portion of correct
arguments are morally correct.</p>
<p>Though it may be rare, you can be morally correct without being
technically correct. Usually it is some technical issue that prevents
you from being fully correct. Take the existence of the algebraic
closure of a field for instance.</p>
<blockquote>
<p><strong>Definition (Field Extension).</strong> We say a field <span
class="math inline"><em>K</em></span> is an <strong>extension</strong>
of <span class="math inline"><em>F</em></span> if <span
class="math inline"><em>F</em> ⊆ <em>K</em></span>.</p>
</blockquote>
<blockquote>
<p><strong>Definition (Algebraic Extension).</strong> Suppose <span
class="math inline"><em>K</em></span> is a field extension of <span
class="math inline"><em>F</em></span>. We say it is
<strong>algebraic</strong> if every element in <span
class="math inline"><em>K</em></span> is a root of some polynomial in
<span class="math inline"><em>F</em></span>.</p>
</blockquote>
<p>For example, <span class="math inline">ℂ</span> is an algebraic
extension of <span class="math inline">ℝ</span> because every complex
number is the root of a real polynomial.</p>
<blockquote>
<p><strong>Definition (Algebraic Closure).</strong> An algebraic
extension <span class="math inline"><em>K</em></span> over a field <span
class="math inline"><em>F</em></span> is an <strong>algebraic
closure</strong> if <span class="math inline"><em>K</em></span> is
algebraically closed.</p>
</blockquote>
<p>Notice that a field is algebraically closed if and only if it has no
(non-trivial) field extensions.</p>
<p>Here is the theorem we are trying to prove: every field <span
class="math inline"><em>F</em></span> has an algebraic closure. The
proof idea is simple: consider the collection of all algebraic
extensions of <span class="math inline"><em>F</em></span> endowed with
the order <span class="math inline">⊆</span>. Then Zorn's Lemma produces
a maximal element <span class="math inline">$\overline{F}$</span>, which
is algebraically closed because it has no non-trivial field
extensions.</p>
<p>This argument isn't technically correct: the collection of algebraic
extensions of <span class="math inline"><em>F</em></span> is not
actually a set. But you and I ought to agree this is morally correct.
Telling you this will make it much easier to understand the actual
proof; in fact, reading this <em>and</em> the proof will be much faster
than just reading the proof.</p>]]></description>
	<pubDate>7 Jul 2025</pubDate>
</item>
<item>
	<title>Web dev and insanity</title>
	<link>https://dennisc.net/writing/tech/web-dev-insane.md</link>
	<description><![CDATA[<p>Recently I got assigned web dev work and came
to a conclusion: either I am insane or everyone who uses any Javascript
framework (e.g. React) or component library (e.g. MUI or Bootstrap)
is.<a href="#fn1" class="footnote-ref" id="fnref1"
role="doc-noteref"><sup>1</sup></a><a href="#fn2" class="footnote-ref"
id="fnref2" role="doc-noteref"><sup>2</sup></a></p>
<p>There are a lot of otherwise really smart people who swear by React.
And using two completely different languages and frameworks to write a
website and an API that the website calls. And using component libraries
that to me just seem completely useless.</p>
<p>I suppose I ought to include a disclaimer: it is almost certainly not
the case that React is <em>always</em> a bad idea. In fact sometimes it
may be the <em>best</em> idea. My point here is that often (but not
necessarily always) it does turn out to be a bad idea.</p>
<h2 id="react">React</h2>
<p>Let's start with React. Why on earth am I writing
<code>className</code> instead of <code>class</code>? Why should I write
<code>&lt;Link&gt;</code> instead of <code>&lt;a&gt;</code>? So on and
so forth. There are technical reasons for this. I know what they are,
thank you very much. But if we are going to depart from standards and
muddle up the 1-to-1 relation between "what I write" and "what is
rendered", there better be really big benefits to doing so.</p>
<p>Using <code>&lt;Link&gt;</code> as an example, does making your
website a single-page client-side-rendered application actually help
anyone?</p>
<p><strong>No!</strong> You are not making the next Google Docs. Most
websites with a backend are some selectively rendered text, a few
images, and a bunch of HTML forms. Websites with significant client
interactivity are a different story and not one I know anything about.
But if your website is literally just a blog (which doesn't behave any
differently for different clients, by the way), you really should not be
writing it in React. It's just complexity for no reason most of the
time. Oh and by the way, this isn't just "React is unnecessary most of
the time", it's "Javascript is unnecessary most of the time". React is
much more complicated than plain Javascript, and so the bar for its
inclusion ought to be much higher.</p>
<h2 id="component-libraries">Component libraries</h2>
<p>Component libraries are also hard to justify most of the time. Let's
take one of the more popular libraries, <strong>React</strong> Bootstrap
(to be clear, Bootstrap CSS itself seems fine), and look at the first
component they have: the <a
href="https://react-bootstrap.netlify.app/docs/components/accordion">Accordion</a>.
Here is the HTML code that gets generated.</p>
<div class="sourceCode" id="cb1"><pre
class="sourceCode html"><code class="sourceCode html"><span id="cb1-1"><a href="#cb1-1" aria-hidden="true" tabindex="-1"></a><span class="dt">&lt;</span><span class="kw">h3</span><span class="ot"> class</span><span class="op">=</span><span class="st">&quot;anchor anchorWithStickyNavbar_LWe7&quot;</span><span class="ot"> id</span><span class="op">=</span><span class="st">&quot;basic-example&quot;</span><span class="dt">&gt;</span></span>
<span id="cb1-2"><a href="#cb1-2" aria-hidden="true" tabindex="-1"></a>    Basic Example</span>
<span id="cb1-3"><a href="#cb1-3" aria-hidden="true" tabindex="-1"></a>    <span class="dt">&lt;</span><span class="kw">a</span><span class="ot"> href</span><span class="op">=</span><span class="st">&quot;#basic-example&quot;</span></span>
<span id="cb1-4"><a href="#cb1-4" aria-hidden="true" tabindex="-1"></a><span class="ot">        class</span><span class="op">=</span><span class="st">&quot;hash-link&quot;</span></span>
<span id="cb1-5"><a href="#cb1-5" aria-hidden="true" tabindex="-1"></a><span class="ot">        aria-label</span><span class="op">=</span><span class="st">&quot;Direct link to Basic Example&quot;</span></span>
<span id="cb1-6"><a href="#cb1-6" aria-hidden="true" tabindex="-1"></a><span class="ot">        title</span><span class="op">=</span><span class="st">&quot;Direct link to Basic Example&quot;</span><span class="dt">&gt;</span></span>
<span id="cb1-7"><a href="#cb1-7" aria-hidden="true" tabindex="-1"></a>    <span class="dt">&lt;/</span><span class="kw">a</span><span class="dt">&gt;</span></span>
<span id="cb1-8"><a href="#cb1-8" aria-hidden="true" tabindex="-1"></a><span class="dt">&lt;/</span><span class="kw">h3</span><span class="dt">&gt;</span></span>
<span id="cb1-9"><a href="#cb1-9" aria-hidden="true" tabindex="-1"></a><span class="dt">&lt;</span><span class="kw">div</span><span class="ot"> class</span><span class="op">=</span><span class="st">&quot;playgroundContainer_TGbA&quot;</span><span class="dt">&gt;</span></span>
<span id="cb1-10"><a href="#cb1-10" aria-hidden="true" tabindex="-1"></a><span class="dt">&lt;</span><span class="kw">div</span><span class="ot"> class</span><span class="op">=</span><span class="st">&quot;playgroundHeader_qwyd&quot;</span><span class="dt">&gt;</span>Result<span class="dt">&lt;/</span><span class="kw">div</span><span class="dt">&gt;</span></span>
<span id="cb1-11"><a href="#cb1-11" aria-hidden="true" tabindex="-1"></a><span class="dt">&lt;</span><span class="kw">div</span><span class="ot"> class</span><span class="op">=</span><span class="st">&quot;playgroundPreview_bb8I&quot;</span><span class="dt">&gt;</span></span>
<span id="cb1-12"><a href="#cb1-12" aria-hidden="true" tabindex="-1"></a>  <span class="dt">&lt;</span><span class="kw">div</span><span class="dt">&gt;</span></span>
<span id="cb1-13"><a href="#cb1-13" aria-hidden="true" tabindex="-1"></a>    <span class="dt">&lt;</span><span class="kw">div</span><span class="ot"> class</span><span class="op">=</span><span class="st">&quot;bs-example&quot;</span><span class="dt">&gt;</span></span>
<span id="cb1-14"><a href="#cb1-14" aria-hidden="true" tabindex="-1"></a>      <span class="dt">&lt;</span><span class="kw">div</span><span class="ot"> class</span><span class="op">=</span><span class="st">&quot;accordion&quot;</span><span class="dt">&gt;</span></span>
<span id="cb1-15"><a href="#cb1-15" aria-hidden="true" tabindex="-1"></a>        <span class="dt">&lt;</span><span class="kw">div</span><span class="ot"> class</span><span class="op">=</span><span class="st">&quot;accordion-item&quot;</span><span class="dt">&gt;</span></span>
<span id="cb1-16"><a href="#cb1-16" aria-hidden="true" tabindex="-1"></a>          <span class="dt">&lt;</span><span class="kw">h2</span><span class="ot"> class</span><span class="op">=</span><span class="st">&quot;accordion-header&quot;</span><span class="dt">&gt;</span></span>
<span id="cb1-17"><a href="#cb1-17" aria-hidden="true" tabindex="-1"></a>            <span class="dt">&lt;</span><span class="kw">button</span><span class="ot"> type</span><span class="op">=</span><span class="st">&quot;button&quot;</span><span class="ot"> aria-expanded</span><span class="op">=</span><span class="st">&quot;true&quot;</span><span class="ot"> class</span><span class="op">=</span><span class="st">&quot;accordion-button&quot;</span><span class="dt">&gt;</span></span>
<span id="cb1-18"><a href="#cb1-18" aria-hidden="true" tabindex="-1"></a>              Accordion Item #1</span>
<span id="cb1-19"><a href="#cb1-19" aria-hidden="true" tabindex="-1"></a>            <span class="dt">&lt;/</span><span class="kw">button</span><span class="dt">&gt;</span></span>
<span id="cb1-20"><a href="#cb1-20" aria-hidden="true" tabindex="-1"></a>          <span class="dt">&lt;/</span><span class="kw">h2</span><span class="dt">&gt;</span></span>
<span id="cb1-21"><a href="#cb1-21" aria-hidden="true" tabindex="-1"></a>          <span class="dt">&lt;</span><span class="kw">div</span><span class="ot"> class</span><span class="op">=</span><span class="st">&quot;accordion-collapse collapse show&quot;</span><span class="ot"> style</span><span class="op">=</span><span class="st">&quot;&quot;</span><span class="dt">&gt;</span></span>
<span id="cb1-22"><a href="#cb1-22" aria-hidden="true" tabindex="-1"></a>            <span class="dt">&lt;</span><span class="kw">div</span><span class="ot"> class</span><span class="op">=</span><span class="st">&quot;accordion-body&quot;</span><span class="dt">&gt;</span></span>
<span id="cb1-23"><a href="#cb1-23" aria-hidden="true" tabindex="-1"></a>              Body text #1</span>
<span id="cb1-24"><a href="#cb1-24" aria-hidden="true" tabindex="-1"></a>            <span class="dt">&lt;/</span><span class="kw">div</span><span class="dt">&gt;</span></span>
<span id="cb1-25"><a href="#cb1-25" aria-hidden="true" tabindex="-1"></a>          <span class="dt">&lt;/</span><span class="kw">div</span><span class="dt">&gt;</span></span>
<span id="cb1-26"><a href="#cb1-26" aria-hidden="true" tabindex="-1"></a>        <span class="dt">&lt;/</span><span class="kw">div</span><span class="dt">&gt;</span></span>
<span id="cb1-27"><a href="#cb1-27" aria-hidden="true" tabindex="-1"></a>        <span class="dt">&lt;</span><span class="kw">div</span><span class="ot"> class</span><span class="op">=</span><span class="st">&quot;accordion-item&quot;</span><span class="dt">&gt;</span></span>
<span id="cb1-28"><a href="#cb1-28" aria-hidden="true" tabindex="-1"></a>          <span class="dt">&lt;</span><span class="kw">h2</span><span class="ot"> class</span><span class="op">=</span><span class="st">&quot;accordion-header&quot;</span><span class="dt">&gt;</span></span>
<span id="cb1-29"><a href="#cb1-29" aria-hidden="true" tabindex="-1"></a>            <span class="dt">&lt;</span><span class="kw">button</span><span class="ot"> type</span><span class="op">=</span><span class="st">&quot;button&quot;</span><span class="ot"> aria-expanded</span><span class="op">=</span><span class="st">&quot;false&quot;</span><span class="ot"> class</span><span class="op">=</span><span class="st">&quot;accordion-button collapsed&quot;</span><span class="dt">&gt;</span></span>
<span id="cb1-30"><a href="#cb1-30" aria-hidden="true" tabindex="-1"></a>              Accordion Item #2</span>
<span id="cb1-31"><a href="#cb1-31" aria-hidden="true" tabindex="-1"></a>            <span class="dt">&lt;/</span><span class="kw">button</span><span class="dt">&gt;</span></span>
<span id="cb1-32"><a href="#cb1-32" aria-hidden="true" tabindex="-1"></a>          <span class="dt">&lt;/</span><span class="kw">h2</span><span class="dt">&gt;</span></span>
<span id="cb1-33"><a href="#cb1-33" aria-hidden="true" tabindex="-1"></a>          <span class="dt">&lt;</span><span class="kw">div</span><span class="ot"> class</span><span class="op">=</span><span class="st">&quot;accordion-collapse collapse&quot;</span><span class="dt">&gt;</span></span>
<span id="cb1-34"><a href="#cb1-34" aria-hidden="true" tabindex="-1"></a>            <span class="dt">&lt;</span><span class="kw">div</span><span class="ot"> class</span><span class="op">=</span><span class="st">&quot;accordion-body&quot;</span><span class="dt">&gt;</span></span>
<span id="cb1-35"><a href="#cb1-35" aria-hidden="true" tabindex="-1"></a>              Body text #2</span>
<span id="cb1-36"><a href="#cb1-36" aria-hidden="true" tabindex="-1"></a>            <span class="dt">&lt;/</span><span class="kw">div</span><span class="dt">&gt;</span></span>
<span id="cb1-37"><a href="#cb1-37" aria-hidden="true" tabindex="-1"></a>          <span class="dt">&lt;/</span><span class="kw">div</span><span class="dt">&gt;</span></span>
<span id="cb1-38"><a href="#cb1-38" aria-hidden="true" tabindex="-1"></a>        <span class="dt">&lt;/</span><span class="kw">div</span><span class="dt">&gt;</span></span>
<span id="cb1-39"><a href="#cb1-39" aria-hidden="true" tabindex="-1"></a>      <span class="dt">&lt;/</span><span class="kw">div</span><span class="dt">&gt;</span></span>
<span id="cb1-40"><a href="#cb1-40" aria-hidden="true" tabindex="-1"></a>    <span class="dt">&lt;/</span><span class="kw">div</span><span class="dt">&gt;</span></span>
<span id="cb1-41"><a href="#cb1-41" aria-hidden="true" tabindex="-1"></a>  <span class="dt">&lt;/</span><span class="kw">div</span><span class="dt">&gt;</span></span>
<span id="cb1-42"><a href="#cb1-42" aria-hidden="true" tabindex="-1"></a><span class="dt">&lt;/</span><span class="kw">div</span><span class="dt">&gt;</span></span></code></pre></div>
<p>Yikes. Why is the title of a collapsible item an
<code>&lt;h2&gt;</code>? This is not good from an accessibility
standpoint. This collapsible item is organized under the
<code>&lt;h3&gt;</code> with the title of "Basic Examples" for Pete's
sake. So clearly, it and its title should semantically be a part of the
<code>&lt;h3&gt;</code> header. But the HTML code indicates otherwise.
And <em>any programmatic tool which relies on the semantics of the
HTML</em> (which by the way, includes accessibility software) is not
going to work well if you generate semantically incorrect HTML. And no
amount of aria tags will make up for the fact that your HTML is
terrible.</p>
<p>Also, a button? It's not the worst thing you can do, I guess. At
least <code>aria-expanded=true</code> is properly set. But you can do so
much better for a dropdown.</p>
<details>
<summary>
<strong>Dropdown code</strong>
</summary>
<div>
<div class="sourceCode" id="cb2"><pre
class="sourceCode html"><code class="sourceCode html"><span id="cb2-1"><a href="#cb2-1" aria-hidden="true" tabindex="-1"></a><span class="dt">&lt;</span><span class="kw">details</span><span class="dt">&gt;</span></span>
<span id="cb2-2"><a href="#cb2-2" aria-hidden="true" tabindex="-1"></a>    <span class="dt">&lt;</span><span class="kw">summary</span><span class="dt">&gt;</span></span>
<span id="cb2-3"><a href="#cb2-3" aria-hidden="true" tabindex="-1"></a>        Dropdown code</span>
<span id="cb2-4"><a href="#cb2-4" aria-hidden="true" tabindex="-1"></a>    <span class="dt">&lt;/</span><span class="kw">summary</span><span class="dt">&gt;</span></span>
<span id="cb2-5"><a href="#cb2-5" aria-hidden="true" tabindex="-1"></a>    <span class="dt">&lt;</span><span class="kw">div</span><span class="dt">&gt;</span></span>
<span id="cb2-6"><a href="#cb2-6" aria-hidden="true" tabindex="-1"></a>        Pretend there is some code here.</span>
<span id="cb2-7"><a href="#cb2-7" aria-hidden="true" tabindex="-1"></a>    <span class="dt">&lt;/</span><span class="kw">div</span><span class="dt">&gt;</span></span>
<span id="cb2-8"><a href="#cb2-8" aria-hidden="true" tabindex="-1"></a><span class="dt">&lt;/</span><span class="kw">details</span><span class="dt">&gt;</span></span></code></pre></div>
</div>
</details>
<p>Given how simple this is, why would you ever write this code?</p>
<div class="sourceCode" id="cb3"><pre
class="sourceCode html"><code class="sourceCode html"><span id="cb3-1"><a href="#cb3-1" aria-hidden="true" tabindex="-1"></a>import Accordion from &#39;react-bootstrap/Accordion&#39;;</span>
<span id="cb3-2"><a href="#cb3-2" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb3-3"><a href="#cb3-3" aria-hidden="true" tabindex="-1"></a>function BasicExample() {</span>
<span id="cb3-4"><a href="#cb3-4" aria-hidden="true" tabindex="-1"></a>  return (</span>
<span id="cb3-5"><a href="#cb3-5" aria-hidden="true" tabindex="-1"></a>    <span class="dt">&lt;</span><span class="kw">Accordion</span><span class="ot"> defaultActiveKey</span><span class="op">=</span><span class="st">&quot;0&quot;</span><span class="dt">&gt;</span></span>
<span id="cb3-6"><a href="#cb3-6" aria-hidden="true" tabindex="-1"></a>      <span class="dt">&lt;</span><span class="kw">Accordion.Item</span><span class="ot"> eventKey</span><span class="op">=</span><span class="st">&quot;0&quot;</span><span class="dt">&gt;</span></span>
<span id="cb3-7"><a href="#cb3-7" aria-hidden="true" tabindex="-1"></a>        <span class="dt">&lt;</span><span class="kw">Accordion.Header</span><span class="dt">&gt;</span>Accordion Item #1<span class="dt">&lt;/</span><span class="kw">Accordion.Header</span><span class="dt">&gt;</span></span>
<span id="cb3-8"><a href="#cb3-8" aria-hidden="true" tabindex="-1"></a>        <span class="dt">&lt;</span><span class="kw">Accordion.Body</span><span class="dt">&gt;</span></span>
<span id="cb3-9"><a href="#cb3-9" aria-hidden="true" tabindex="-1"></a>          Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do</span>
<span id="cb3-10"><a href="#cb3-10" aria-hidden="true" tabindex="-1"></a>          eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad</span>
<span id="cb3-11"><a href="#cb3-11" aria-hidden="true" tabindex="-1"></a>          minim veniam, quis nostrud exercitation ullamco laboris nisi ut</span>
<span id="cb3-12"><a href="#cb3-12" aria-hidden="true" tabindex="-1"></a>          aliquip ex ea commodo consequat. Duis aute irure dolor in</span>
<span id="cb3-13"><a href="#cb3-13" aria-hidden="true" tabindex="-1"></a>          reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla</span>
<span id="cb3-14"><a href="#cb3-14" aria-hidden="true" tabindex="-1"></a>          pariatur. Excepteur sint occaecat cupidatat non proident, sunt in</span>
<span id="cb3-15"><a href="#cb3-15" aria-hidden="true" tabindex="-1"></a>          culpa qui officia deserunt mollit anim id est laborum.</span>
<span id="cb3-16"><a href="#cb3-16" aria-hidden="true" tabindex="-1"></a>        <span class="dt">&lt;/</span><span class="kw">Accordion.Body</span><span class="dt">&gt;</span></span>
<span id="cb3-17"><a href="#cb3-17" aria-hidden="true" tabindex="-1"></a>      <span class="dt">&lt;/</span><span class="kw">Accordion.Item</span><span class="dt">&gt;</span></span>
<span id="cb3-18"><a href="#cb3-18" aria-hidden="true" tabindex="-1"></a>      <span class="dt">&lt;</span><span class="kw">Accordion.Item</span><span class="ot"> eventKey</span><span class="op">=</span><span class="st">&quot;1&quot;</span><span class="dt">&gt;</span></span>
<span id="cb3-19"><a href="#cb3-19" aria-hidden="true" tabindex="-1"></a>        <span class="dt">&lt;</span><span class="kw">Accordion.Header</span><span class="dt">&gt;</span>Accordion Item #2<span class="dt">&lt;/</span><span class="kw">Accordion.Header</span><span class="dt">&gt;</span></span>
<span id="cb3-20"><a href="#cb3-20" aria-hidden="true" tabindex="-1"></a>        <span class="dt">&lt;</span><span class="kw">Accordion.Body</span><span class="dt">&gt;</span></span>
<span id="cb3-21"><a href="#cb3-21" aria-hidden="true" tabindex="-1"></a>          Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do</span>
<span id="cb3-22"><a href="#cb3-22" aria-hidden="true" tabindex="-1"></a>          eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad</span>
<span id="cb3-23"><a href="#cb3-23" aria-hidden="true" tabindex="-1"></a>          minim veniam, quis nostrud exercitation ullamco laboris nisi ut</span>
<span id="cb3-24"><a href="#cb3-24" aria-hidden="true" tabindex="-1"></a>          aliquip ex ea commodo consequat. Duis aute irure dolor in</span>
<span id="cb3-25"><a href="#cb3-25" aria-hidden="true" tabindex="-1"></a>          reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla</span>
<span id="cb3-26"><a href="#cb3-26" aria-hidden="true" tabindex="-1"></a>          pariatur. Excepteur sint occaecat cupidatat non proident, sunt in</span>
<span id="cb3-27"><a href="#cb3-27" aria-hidden="true" tabindex="-1"></a>          culpa qui officia deserunt mollit anim id est laborum.</span>
<span id="cb3-28"><a href="#cb3-28" aria-hidden="true" tabindex="-1"></a>        <span class="dt">&lt;/</span><span class="kw">Accordion.Body</span><span class="dt">&gt;</span></span>
<span id="cb3-29"><a href="#cb3-29" aria-hidden="true" tabindex="-1"></a>      <span class="dt">&lt;/</span><span class="kw">Accordion.Item</span><span class="dt">&gt;</span></span>
<span id="cb3-30"><a href="#cb3-30" aria-hidden="true" tabindex="-1"></a>    <span class="dt">&lt;/</span><span class="kw">Accordion</span><span class="dt">&gt;</span></span>
<span id="cb3-31"><a href="#cb3-31" aria-hidden="true" tabindex="-1"></a>  );</span>
<span id="cb3-32"><a href="#cb3-32" aria-hidden="true" tabindex="-1"></a>}</span>
<span id="cb3-33"><a href="#cb3-33" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb3-34"><a href="#cb3-34" aria-hidden="true" tabindex="-1"></a>export default BasicExample;</span></code></pre></div>
<p>The <code>&lt;details&gt;</code> tag is more accessible and easier to
style to boot. There is literally no downside.<a href="#fn3"
class="footnote-ref" id="fnref3" role="doc-noteref"><sup>3</sup></a></p>
<p>And the worst thing is that frameworks like React Bootstrap pass
automated tests like Google's Lighthouse with flying colors. But look
for a couple of seconds and you can already see issues. (I don't know if
Accordion titles are <em>always</em> <code>&lt;h2&gt;</code> elements,
but I suspect the answer is yes. Regardless, it's not the greatest sign
if the title is a header on their official website.) And React Bootstrap
is doing quite well for itself, actually. Just look at <a
href="https://github.com/mui/material-ui/issues?q=accessibility">MUI's
accessibility issues on GitHub</a>.</p>
<p>But this isn't supposed to be an expose about accessibility.<a
href="#fn4" class="footnote-ref" id="fnref4"
role="doc-noteref"><sup>4</sup></a> The main point here is that using a
custom "Accordion" component is moronic if <code>&lt;details&gt;</code>
is already available to you at no cost. Accessibility just happens to be
one of the big reasons it is stupid.</p>
<h2 id="a-potpurri-of-unnecessary-uses">A potpurri of unnecessary
uses</h2>
<p>There are a lot of reasons people have to use React, component
libraries, and other similar things. Let's run through them:</p>
<ul>
<li>"It is more accessible." Making all of your code (including your
rendered HTML) more complicated and error-prone is not accessible.</li>
<li>"It resizes well on different devices like phones." Only if you
apply different styles based on screen width, which is much simpler to
do with plain CSS and media queries.</li>
<li>"It makes my website look nicer." No. Everything is reproducible
with plain HTML and CSS. It all compiles down into (semantically poor)
HTML and CSS. And using plain HTML and CSS ends up being simpler. It is
hard to grok dozens of 2,000 line minified Bootstrap CSS files whose
default values are a mystery to all of mankind. It is much easier to
understand a small CSS file</li>
<li>"It is necessary to connect my frontend to my backend and create a
full-stack website." Factually false. There are simpler and more robust
ways to do this. Rust frameworks like Actix-web, Rocket, etc are much
more robust . And it is simpler because there are less layers in the
client-to-server connection: browser-website-server as opposed to
browser-website-api-server. And only having one middleman is important
because it allows you to <em>guarantee</em> consistent datatypes to
represent your SQL tables (or whatever your database uses).</li>
</ul>
<p>Now I am not going to go as far as to claim React is totally useless.
This is very likely untrue. But it is the case that a lot of the reasons
people <em>think</em> React is useful are total hogwash, at least for
their specific use cases.</p>
<h2 id="what-do-you-do">What do you do?</h2>
<p>So how <em>should</em> you write a website, particularly a full-stack
website? <a href="/writing/tech/static-website">Two years ago</a><a
href="#fn5" class="footnote-ref" id="fnref5"
role="doc-noteref"><sup>5</sup></a> I teased an answer to this
question:</p>
<blockquote>
<p>I hope this post was helpful! A post on full-stack websites will be
coming soon :)</p>
</blockquote>
<p>Two years later and I will tease it a bit more. I am planning to
write a total of three entries, one of which is already done:</p>
<ol type="1">
<li>I will start with an abstract, simplified explanation of the
principles of client-server communication. We will start with
username-password authentication, then dive into cookies, and finally we
will discuss why encryption is necessary.</li>
<li>We will add more detail to the abstract client-server model. The
client is usually just the browser; the server can be divided into the
API and the database. Furthermore, there are many other types of clients
that work. For instance, you could use the terminal to interface with a
CLI, which sends a request to a programmatic API that queries the
database. <strong>The important point is, anything on the server can
interact however it wants with anything else on the server</strong>, and
with a few exceptions, <strong>the same is true for the
client</strong>.</li>
<li>We end off the series by looking at web frameworks, discussing what
a "tech stack" is, and some of my recommendations for what tools to use
for creating a website.<a href="#fn6" class="footnote-ref" id="fnref6"
role="doc-noteref"><sup>6</sup></a></li>
</ol>
<p>I plan to write the first two entries fairly soon. The last entry
will be written eventually, likely when I have finished Glee.</p>
<section id="footnotes" class="footnotes footnotes-end-of-document"
role="doc-endnotes">
<hr />
<ol>
<li id="fn1"><p>Those who have followed this blog know what I think the
answer is :)<a href="#fnref1" class="footnote-back"
role="doc-backlink">↩︎</a></p></li>
<li id="fn2"><p>There are some <a
href="https://www.timr.co/server-side-rendering-is-a-thiel-truth/">oases
of sanity</a> out there.<a href="#fnref2" class="footnote-back"
role="doc-backlink">↩︎</a></p></li>
<li id="fn3"><p>Technically a simple dropdown doesn't match the function
of an accordion, since accordions enforce that only one item is open at
once. Putting aside how terrible of a feature this would be in most
cases, it is quite easy to implement with just HTML and CSS.<a
href="#fnref3" class="footnote-back" role="doc-backlink">↩︎</a></p></li>
<li id="fn4"><p>I am not the right person to write about this, and I'm
sure people who create components are trying their very hardest to make
components accessible.<a href="#fnref4" class="footnote-back"
role="doc-backlink">↩︎</a></p></li>
<li id="fn5"><p>How time flies!<a href="#fnref5" class="footnote-back"
role="doc-backlink">↩︎</a></p></li>
<li id="fn6"><p>You can probably guess what they are. Avoid React,
<em>make the website (one of) your APIs</em> (though this does not
preclude you from creating a REST API that, say, a CLI could interface
with). Write your backend and frontend in the same language, ideally in
the same project so that <strong>your backend types agree with your
frontend types</strong>. (For example, you can use a Rust framework like
Axum to both query the database when appropriate and generate HTML.)<a
href="#fnref6" class="footnote-back" role="doc-backlink">↩︎</a></p></li>
</ol>
</section>]]></description>
	<pubDate>1 Jun 2024</pubDate>
</item>
<item>
	<title>Opinions</title>
	<link>https://dennisc.net/writing/essays/opinions.md</link>
	<description><![CDATA[<p>It's okay to have opinions about things you
aren't skilled at. Good, even, because having fervently held,
<em>correct</em> opinions is how you become skilled at something.</p>
<p>Without opinions all you have are a set of facts. Opinions are the
backbone of a <a href="/writing/essays/framework">framework</a>.</p>
<p>We've all seen those side-by-side factual comparisons of GitHub vs.
GitLab, Postgres vs. Mongo, React vs. Angular, so on and so forth. And
they are <em>boring</em>. It's like it was written by a person without a
soul, because rarely is an actual opinion presented. And just as
importantly, these comparisons are completely unhelpful.</p>
<p>If you search up "GitHub vs. GitLab" and click on the first
comparison article you see, chances are <strong>it won't even mention
the nested directory structure</strong>, let alone emphasize it as the
main sell. Even <a
href="https://about.gitlab.com/why-gitlab/">GitLab</a> cannot articulate
the main feature it has --- you know, the one that GitHub will
<em>never</em> be able to replicate --- and instead chooses to populate
their page with marketing nonsense. You can even go on Reddit, which for
all its flaws at least has sentient human beings with opinions, and not
a single person mentions this crucial difference.</p>
<p>And you're telling me the first person to realize this and write
about it was <a href="/writing/tech/gitlab">a high school
freshman</a>.</p>
<p>Opinions like these, fervently held and correct, lead to a better
command of the facts. Pushing the idea that "Git hosts should store
repositories like my filesystem" further led to me drafting the design
of my own Git host (something I should actually finish). My geometry
students learned the <a
href="/writing/essays/write-smart/area-chart.png">area formulae</a> in
twenty minutes rather than two months because I had <em>really strong
opinions</em> on how they should be presented.</p>
<p>You're unlikely to fervently hold an opinion if it's uncontroversial.
You might believe that Minecraft is an awesome game, but this is also
deeply obvious to the rest of the world. It's not exactly the kind of
thing you need to convince someone else of. So the balance of opinions
you strongly hold will be <em>controversial</em>.</p>
<p>To be clear, by "controversial" I merely mean that it is not a widely
held belief. It does not necessarily mean people are actively
disagreeing with it. For instance, I believe that hand-crafted puzzles
are incomparably better than computer-generated ones. No one who has
seriously thought about logic puzzles would disagree with that
statement. But the average reaction is still along the lines of "does it
really matter that much?" In other words, it's not the kind of belief
that people take for granted.</p>
<p>So if you have strong opinions and act on them, you are going to
disagree with other people. And some of them will have more experience
in the relevant field than you do. (Or at the very least, it will be
something that a lot of experienced people have overlooked.) And I don't
mean a milquetoast sense of disagreement like "Professor, I think you
wrote a plus here when you meant to write a minus". I mean something far
more fundamental.</p>
<p>Fortunately, this doesn't mean you are necessarily wrong. There are
plenty of <em>gaps</em> in the world.<a href="#fn1" class="footnote-ref"
id="fnref1" role="doc-noteref"><sup>1</sup></a> Sure, on the balance,
people who have more experience in a field are typically more likely to
be right. But all you have to do is be right <em>once</em>, confirm you
indeed are right where everyone else is wrong, and then patch that gap
to the benefit of yourself and those around you. Boom. All the sudden,
having strong opinions --- even if they conflict with other people's ---
no longer becomes a bad idea.</p>
<hr />
<p>Sure. If you are young, you cannot possibly have fifty years of
experience building websites, by virtue of not having fifty years of
experience <em>being alive</em>. And to address the elephant in the
room, just so neither of us ignore the fact: I am not even twenty. I
write about puzzles even though I haven't been constructing for very
long, I write about math even though I don't have my bachelor's degree,
and I write about programming even though I've never even held a
full-time programming job. I am just some kid on the internet, screaming
my thoughts into the void and hoping that someone comes out better for
it.</p>
<p>In the grand scheme of things, I don't have a single clue what I am
doing. There is a very good argument to be made that I should shut up,
put my head down, and just listen to the experts. On the surface this
would be a commendable display of humility. But the price is not
thinking for yourself, and that cost cannot possibly be worth it.</p>
<p>But just between the two of us: I have a sneaking suspicion that even
the older people have less of a clue than we might expect. I won't know
for sure until I become older and hopefully wiser, if ever, but there
are a lot of signs that often the "experts<a href="#fn2"
class="footnote-ref" id="fnref2" role="doc-noteref"><sup>2</sup></a>"
are clueless too.</p>
<ul>
<li>Who thought standardized testing was a good idea? You put a bunch of
guys in a room who've been doing this their whole lives, and this is the
best they can come up with? Seriously? You could not find a <em>single
better way</em> to make sure kids were learning?</li>
<li>AP Computer Science is still in Java, and I hope everyone involved
in this decision drops a 45-pound weight on their foot.</li>
<li>Why on earth are single-page applications still a thing?</li>
<li>"You don't need a gym membership to get in shape." Thanks, mister
health guru. You also don't <em>need</em> to ever read a book, you
nitwit. But you don't go around telling people they don't need to read,
now do you?</li>
<li>Why are all you monsters still doing NYT Sudokus. You sick
freaks.</li>
</ul>
<p>Fundamentally, most people <a href="/writing/essays/competence">are
clueless about most things</a>. And I'm not convinced this changes just
because people get older. And it's almost certainly not the case that it
changes <em>so fast</em> that <em>all your opinions</em> as a
20-something year old or whatever become <em>entirely worthless</em>,
because everyone else has gotten it figured out already. I refuse to
believe that, because there is no way that is true.</p>
<hr />
<p>At this point, you might be guessing the takeaway is to start
thinking for yourself and form your own opinions. But that'd just be
preaching to the choir. Rather, the real takeaway is <em>not to be
ashamed of having strong opinions</em>, even when they are in deep
contrast with everyone else's, so long as you've done some reasonable
amount of due diligence. In other words, take your own ideas seriously,
even if (or perhaps especially if) no one else is saying the same
thing.</p>
<p>It is okay to be wrong. And it is okay not to be ashamed of being
wrong, much less just the <em>possibility</em> of being wrong. So long
as you take proper care to not unduly harm or burden other people with
them, holding strong opinions serves as an outlet for tremendous growth,
even if you are wrong in the end. Because all it takes is being right
<em>once</em>.</p>
<section id="footnotes" class="footnotes footnotes-end-of-document"
role="doc-endnotes">
<hr />
<ol>
<li id="fn1"><p>Startups are great evidence that these gaps exist,
because people are willing to invest millions in the mere possibility
that there is a gap to fill in, that the founders have identified it,
and are able to execute so successfully that the investment pays off.
For this to make sense, there better be a <em>lot</em> of gaps to
fill.<a href="#fnref1" class="footnote-back"
role="doc-backlink">↩︎</a></p></li>
<li id="fn2"><p>Sometimes the "experts" are completely full of it. But
it can be hard to tell the professionals apart from the grifters at a
distance, especially in very noisy fields like programming and personal
health.<a href="#fnref2" class="footnote-back"
role="doc-backlink">↩︎</a></p></li>
</ol>
</section>]]></description>
	<pubDate>19 Jul 2024</pubDate>
</item>
<item>
	<title>Math vs. Computer Science</title>
	<link>https://dennisc.net/writing/essays/math-vs-cs.md</link>
	<description><![CDATA[<p>What actually separates math from computer
science? Obviously there is a large intersection between the two, but
each of them has a distinctive feel. Is it just a "you know it when you
see it" kind of distinction?</p>
<p>I don't think so. And I think knowing what characterizes the two
actually helps you become better at both, in particular because you know
what broad class of techniques you should be focusing on.</p>
<p>Math and computer science, broadly speaking, both ask questions about
the solutions to a certain problem. "What are the objects <span
class="math inline"><em>X</em></span> that satisfy some property <span
class="math inline"><em>P</em></span>?"</p>
<ol type="1">
<li>Math is focused on studying the space of solutions, without
necessarily providing a way to construct or explicitly understand
individual instances of solutions.</li>
<li>Computer science is focused on studying procedures to construct
solutions, without necessarily providing you with a broad understanding
of the space of solutions.</li>
</ol>
<p>I think this is best explained through example.</p>
<h2 id="math-borsuk-ulam">Math: Borsuk-Ulam</h2>
<blockquote>
<p>Assume the Earth is a perfect sphere and temperature/air pressure
vary continuously across its surface. There exist two diametrically
opposed points with identical temperature and air pressure.</p>
</blockquote>
<p>We will prove a simpler theorem. Consider the circle <span
class="math inline"><em>S</em><sup>1</sup></span> of radius <span
class="math inline">1</span> in <span class="math inline">ℂ</span> and a
continuous function <span
class="math inline"><em>f</em> : <em>S</em><sup>1</sup>− &gt; ℝ</span>.
Then there is a point <span
class="math inline"><em>x</em> ∈ <em>S</em><sup>1</sup></span> such that
<span
class="math inline"><em>f</em>(<em>x</em>) = <em>f</em>(−<em>x</em>)</span>.</p>
<p><strong>Proof</strong>: Consider the function <span
class="math inline"><em>g</em>(<em>x</em>) = <em>f</em>(<em>x</em>) − <em>f</em>(−<em>x</em>)</span>.
Observe <span
class="math inline"><em>g</em>(−<em>x</em>) = −<em>g</em>(<em>x</em>)</span>.
Pick any <span class="math inline"><em>x</em></span>; either <span
class="math inline"><em>g</em>(<em>x</em>) = 0</span>, in which case we
are done, or not, in which case the Intermediate Value Theorem provides
us with some <span class="math inline"><em>y</em></span> between <span
class="math inline"><em>x</em></span> and <span
class="math inline">−<em>x</em></span> such that <span
class="math inline"><em>g</em>(<em>y</em>) = 0</span>.</p>
<p>(Note the zeroes of <span class="math inline"><em>g</em></span> are
precisely the points which <span
class="math inline"><em>f</em>(<em>x</em>) = <em>f</em>(−<em>x</em>)</span>.)</p>
<p>The Borsuk-Ulam theorem gives us insight into the solution space
(i.e. that it is non-empty). This is a typical example of a
"non-constructive proof", where we learn that a solution exists, but the
proof is no use for actually finding the solution.</p>
<h2 id="computer-science-the-non-decreasing-multiples-of-n">Computer
Science: The non-decreasing multiples of <span
class="math inline"><em>N</em></span></h2>
<p><em>The source is <a
href="https://atcoder.jp/contests/abc443/tasks/abc443_f">AtCoder ABC 443
Task F</a>.</em></p>
<blockquote>
<p>A number is called <strong>non-decreasing</strong> if its digits
don't decrease, e.g. <span class="math inline">1123</span>. What is the
smallest non-decreasing multiple of <span
class="math inline"><em>N</em></span>?</p>
</blockquote>
<details>
<summary>
Solution
</summary>
<p>Perform BFS on the digits (only that we are allowed to revisit the
same vertex multiple times), only going from a digit <span
class="math inline"><em>d</em></span> to digits that are <span
class="math inline"> ≥ <em>d</em></span>. Keep track of the remainder
modulo <span class="math inline"><em>N</em></span> by going from
remainder <span class="math inline"><em>r</em></span> to remainder <span
class="math inline">(10<em>r</em> + <em>d</em>)%<em>N</em></span>
whenever you visit digit <span
class="math inline"><em>d</em></span>.</p>
Terminate the BFS when we reach a remainder of <span
class="math inline">0</span>. The path we took corresponds to the
smallest non-decreasing multiple of <span
class="math inline"><em>N</em></span>.
</details>
<p>We can easily modify this solution to yield all non-decreasing
multiples of <span class="math inline"><em>N</em></span> (just don't
terminate) in increasing order. So we have a reasonably fast way to
generate all such multiples of <span
class="math inline"><em>N</em></span>.</p>
<p>Yet this solution provides no insight into what properties these
non-decreasing multiples of <span class="math inline"><em>N</em></span>
have. How many of them are there? How quickly do they grow? We have no
idea.</p>]]></description>
	<pubDate>15 Mar 2026</pubDate>
</item>
<item>
	<title>To move fast, move slow</title>
	<link>https://dennisc.net/writing/essays/to-move-fast-move-slow.md</link>
	<description><![CDATA[<p>There are some incrediblly fast programmers who
can complete a large rewrite of a medium-sized codebase and drop a
thousand-line diff in five or six hours. A quick</p>
<pre><code>git add .
git commit -m &quot;backend refactor&quot;
git push</code></pre>
<p>later and the entire codebase has been upended. It's impressive,
really, and I say this without a hint of irony. To immediately start
executing massive changes without faffing around for weeks is genuinely
a skill worth emulating.</p>
<p>Unfortunately, that is the only part worth emulating. Because when
you drop that many changes all in one commit, any semblance of thought
that went into them is completely lost to time. And it really was just a
semblance of thought to begin with, because there is just no way to
write code that fast while thinking deeply about what you are doing.
There are no explanations, only bugs and bad UX choices.</p>
<p>The consequences are obvious. You wake up the next morning,
everything is broken, and it takes the next few days just to fix things
up. And if there are a few parts that you want to revert later for
whatever reason, you have to trudge back through the codebase, figure
out what does what, and manually undo the changes one by one. After all,
<code>git revert</code> will do you no good if you are only nominally
using Git in the first place.</p>
<p>I can't help but think: if only you took the time to properly think
your changes through and make good commits, we wouldn't be in this mess
in the first place.</p>
<h2 id="the-pitfall">The pitfall</h2>
<p>But this is not just an essay about Git. Rather, it is about a common
pitfall that people fall in: trying to do things quick rather than doing
them right.</p>
<p>Picture this. You're taking a calculus class, you don't understand
differentiation, and there's a test on it tomorrow. So instead of
sitting down for a week, asking yourself "what is differentiation
really?" and shoring up your understanding, you memorize the derivative
of <span class="math inline"><em>x</em><sup><em>n</em></sup></span> and
<span class="math inline">sin <em>x</em></span>. And that is enough to
pass, so you rinse and repeat.</p>
<p>If I lay it out like this, the problem becomes obvious. If you never
take the time to understand even the most basic of concepts in calculus,
of course it seems impossible no matter how much effort you put in. Yet
what a pernicuous trap it is.</p>
<p>You need to put in some effort to do anything meaningful. That is
just a fact. But we extrapolate too far. In our heads, hard work looks
like staring at a textbook for six hours a day and grinding derivative
exercises, rather than sitting on a couch and vaguely wondering "it's a
little weird that I don't actually know how we get from rational numbers
to real numbers". It looks like writing thousands of lines of code in
one night rather than taking a walk and asking why access control in
every Git host sucks so much. But <em>working hard</em> and actually
<em>getting something done</em> are not the same.</p>
<p>Of course you need to do exercises in order to understand calculus.
And yes, I know that all my brilliant ideas for a Git hosting service
won't do me any good until it exists. But you also need to ask the
fundamental questions: what is really going on here? How can I make
these complicated ideas as simple as possible? And how would I explain
it to another person?</p>
<h2 id="category-theory">Category theory</h2>
<p>The right thing to do when you don't understand something is to take
a step back and ask: "What underlying idea am I actually missing?
<em>Why don't I understand this?</em>" This much is obvious. Yet knowing
this does not make you immune to falling in the pitfall. At the very
least, it didn't save me.</p>
<p>A few months ago, my algebra professor gave a very fast presentation
of category theory. If you understand the universal mapping property of
the free group, you can easily guess how it went. First we discussed
categories, then functors, then natural transformations, and finally
adjunctions. As a homework exercise, we were asked to prove that some
pair of functors were adjoint, and I knew it was a really trivial
verification.</p>
<p>Yet I could not for the life of me understand what an adjunction was.
So I look at the Hom-set definition and I am immediately greeted by more
confusion. What is a Hom-set? And how on earth do you get a natural
transformation between two Hom-sets, I thought you needed a functor for
that? And what is a natural transformation, actually?</p>
<p>So I kept spinning in circles. I stared at the definition of an
adjunction, digged through the terms that I didn't understand, realized
I still had no clue what an adjunction is, and went back to staring at
its definition. A few days later I push some symbols with the
counit-unit definition and hack together a solution. In the process I
gained very little understanding of what was happening.</p>
<p>Now fast forward to a few weeks ago, when I decide to bite the bullet
and write a category theory section for my algebra primer. Now I have to
step back and think: what is a category, really, and how do I explain
it? How do I build up to a functor? A natural transformation? And an
adjunction?</p>
<p>A week later and the concept of an adjunction is crystal clear to
me.</p>
<p>In the process I realize that many of the things I wrote were pointed
out by my professor in class. So really, if I had taken fifteen minutes
to think "why did he talk so long about reversing this arrow, and how do
I use that fact to update my mental framework of category theory", I
would have understood the hom-bifunctor (and by extension adjunctions)
half a year earlier.</p>
<h2 id="burnout">Burnout</h2>
<p>I have a confession to make. Officially I should be re-implementing
email-password authentication for work. But I'll be honest with you,
this is probably the fourth or fifth time we are doing this, and I've
gotten really sick of it. (In fact, this is the reason I thought to
write this essay to begin with.)</p>
<p>But I'm not here to complain. My point is that you and I are both
smart enough to tell when we are running in circles. Re-doing something
because you didn't think it through the first time is a sure-fire recipe
to burnout.<a href="#fn1" class="footnote-ref" id="fnref1"
role="doc-noteref"><sup>1</sup></a> And the worst thing about this kind
of burnout is, when you feel the work you've done before is pointless,
<em>you're right</em>.</p>
<p>So how do you avoid this? I confess I do not have all the answers,
but here is what I think. Sitting back on a couch and thinking for half
the day is nice. It is relaxing. It doesn't carry much risk of burnout.
So it is tempting to conclude that you have to trade all of these
comforts away to do real, hard work. I admit you have to make this
sacrifice sometimes. But I am becoming increasingly convinced that most
of the important work gets done in the shower, on a train, or by nature,
rather than at a desk.</p>
<section id="footnotes" class="footnotes footnotes-end-of-document"
role="doc-endnotes">
<hr />
<ol>
<li id="fn1"><p>Especially when it's due to circumstances out of your
control, but that's a story for another time.<a href="#fnref1"
class="footnote-back" role="doc-backlink">↩︎</a></p></li>
</ol>
</section>]]></description>
	<pubDate>8 Aug 2024</pubDate>
</item>
<item>
	<title>The many worlds interpretation of mathematics</title>
	<link>https://dennisc.net/writing/blog/many-worlds.md</link>
	<description><![CDATA[<p><em>This is the first in a series of posts
about model theory.</em></p>
<p>I've talked about this stuff before when writing about <a
href="/writing/essays/why-i-study-math">why I do math</a>, but I wanted
to write a standalone piece to emphasize the ideas I'll discuss
here.</p>
<h2 id="prerequisites">Prerequisites</h2>
<p>Basic familiarity with sets, logic. Familiarity with "different sizes
of infinity" is also helpful (for instance, that <span
class="math inline">ℕ</span> is smaller than <span
class="math inline">ℝ</span> since no function from <span
class="math inline">ℕ</span> to <span class="math inline">ℝ</span>
covers all the elements of <span class="math inline">ℝ</span>).</p>
<h2 id="what-is-independence">What is independence?</h2>
<p>As alluded to in the prerequisites, you may know from Cantor's
Diagonalization Theorem that <span
class="math inline">|ℕ| &lt; |ℝ|</span>. But is there some set <span
class="math inline"><em>S</em></span> whose size is strictly in between,
i.e. <span class="math inline">|ℕ| &lt; |<em>S</em>| &lt; ℝ|</span>?
This question is known as the <strong>Continuum Hypothesis</strong>.</p>
<p>You may have heard that the Continuum Hypothesis is "independent of
ZFC". So what does that actually mean?</p>
<h3 id="what-is-zfc">What is ZFC?</h3>
<p>It turns out mathematics is governed by a set of rules which we call
"axioms", and the language of mathematics is really the language of
sets. For instance, we can encode the natural numbers as sets. And ZFC
does two things:</p>
<ol type="1">
<li>It gives us certain sets to work with, such as the empty set and the
set of natural numbers<a href="#fn1" class="footnote-ref" id="fnref1"
role="doc-noteref"><sup>1</sup></a>.</li>
<li>Given a collection of sets, we can perform operations on them to get
new sets. For instance, given two sets <span
class="math inline"><em>A</em></span> and <span
class="math inline"><em>B</em></span>, we may find their union <span
class="math inline"><em>A</em> ∪ <em>B</em></span>.</li>
</ol>
<p>This is a very imprecise picture, but it will do good enough.</p>
<p>At the same time, mathematics may be considered the study of whether
things are true or false. And formally, a proof is a <em>syntactic
object</em> which starts from a list of assumptions and derive a
conclusion. For instance, if we start with <span
class="math inline"><em>a</em> ⟹ <em>b</em></span> and <span
class="math inline"><em>b</em> ⟹ <em>c</em></span>, we may conclude
<span class="math inline"><em>a</em> ⟹ <em>c</em></span>. And so on. The
point is, we are given a list of rules which tell us how we may combine
assumptions to reach conclusions. As another example, we are allowed to
combine <span class="math inline"><em>a</em> ∧ <em>b</em></span> with
<span class="math inline"><em>a</em> ∧ ¬<em>b</em></span> to derive
<span class="math inline"><em>a</em></span>. These syntactic
considerations are what we will refer to as "first-order logic".</p>
<p>The point is, ZFC (along with first-order logic) describes how
mathematics ought to behave.</p>
<h3 id="many-worlds">Many worlds</h3>
<p>I'll give you the punchline up front: <strong>there are multiple
worlds of mathematics</strong> satisfying the rules of ZFC, and they are
genuinely distinct.</p>
<p>We've just established that "mathematics" is "anything satisfying the
rules of ZFC." Let me give you an analogy: When we study linear algebra,
we study "vector spaces", which is "anything satisfying the rules of a
vector space". Importantly, we are <em>not</em> studying just one
particular vector space: when we create definitions such as "linearly
independent", or prove theorems such as "all linearly independent
spanning sets of a vector space have the same size" (this is the
definition of dimension), we are doing this for <em>every</em> vector
space, because we are only using the language and axioms of vector
spaces.</p>
<p>The same holds for mathematics. Who says that ZFC only describes one
world of mathematics?</p>
<h3 id="common-misconceptions">Common misconceptions</h3>
<p>If you're anything like me, you may have watched certain YouTube
videos that say "we cannot prove whether the Continuum Hypothesis is
true or false." This is technically true, but it is some very misleading
phrasing.</p>
<p>In particular, if you were to explicitly unpack your assumptions
about what this means, they might look something like this:</p>
<ol type="1">
<li>There is one world of mathematics.</li>
<li>There is no proof that the Continuum Hypothesis is true. There is
also no proof that it is false.</li>
<li>Furthermore, we somehow know that we can <em>never</em> produce such
a proof.</li>
<li>So I guess we'll just never know whether the Continuum Hypothesis is
true or false, and we can never know.</li>
</ol>
<p>This is completely wrong. Here's what's actually going on:
<em>assuming there is a world of mathematics satisfying the rules of
ZFC</em>, there is some world of mathematics where the Continuum
Hypothesis is true, and another world of mathematics where the Continuum
Hypothesis is false.</p>
<h3 id="godels-completeness-theorem">Godel's Completeness Theorem</h3>
<p><em>From now on we abbreviate the Continuum Hypothesis as
CH.</em></p>
<p>So why does "CH is independent of ZFC" imply that there is a world of
ZFC mathematics where CH is true, and another world where CH is false?
On the surface, "there is no proof of CH or (not CH)" is a statement
about <em>proof manipulations</em> (<strong>syntactics</strong>) while
the statement about multiple worlds is about <em>actual worlds of
mathematics obeying the rules of ZFC</em> (<strong>semantics</strong>).
But as we will soon see, our system of syntactics and semantics are
carefully designed to be tightly connected.</p>
<p>This shows itself in Godel's Completeness Theorem:</p>
<blockquote>
<p>Suppose a set of rules does not lead to any contradictions; we call
such a system <strong>consistent</strong>. Then there is an object
satisfying those rules. (The converse also holds.)</p>
</blockquote>
<p>A few other related facts:</p>
<ol type="1">
<li>If I can prove something given a set of rules, then it is true for
every object satisfying those rules. (For instance, if I prove "every
basis in a vector space has the same dimension", then it is actually
true of every vector space.)</li>
<li>And importantly, if I <em>can't</em> prove a statement given a set
of rules, then there is an object that <em>doesn't</em> satisfy that
statement. (For instance, since I cannot prove "every vector space is
finite-dimensional", then there exists an infinite-dimensional vector
space.)</li>
</ol>
<p>Given these rules, here is how you prove that CH is independent of
ZFC. Start with some universe of ZFC. Use it to construct a universe of
ZFC that satisfies CH and a universe of ZFC that does not satisfy CH.
Now we can't prove CH <em>or</em> not CH, since there is a universe of
ZFC that breaks each of these statements. Voila! We have
independence.</p>
<h3 id="godels-incompleteness-theorem">Godel's Incompleteness
Theorem</h3>
<p>But this isn't actually the end of the story. So far, the impression
I've been giving is that "there is a universe where CH is true and one
where CH is false." But this isn't really the correct picture.</p>
<p>Instead, it would be more accurate to say the following:</p>
<blockquote>
<p>There either exists <strong>no</strong> universe of mathematics
satisfying ZFC, <strong>OR</strong> there exists a universe where CH
holds <em>and</em> a universe where CH does not hold.</p>
</blockquote>
<p>Furthermore, we have no idea whether there exists a universe of
mathematics satisfying the rules of ZFC. Now, why would we bother
studying a system of rules if <em>we can't even show there's a universe
of mathematics satisfying these rules</em>?</p>
<p>The short answer: we have to. Godel's Second Incompleteness Theorem<a
href="#fn2" class="footnote-ref" id="fnref2"
role="doc-noteref"><sup>2</sup></a> says</p>
<blockquote>
<p>No system of mathematics can prove its own consistency.</p>
</blockquote>
<p>In short, we cannot prove any system of mathematics is consistent
without working in a stronger system of mathematics, which we then need
an even stronger system of mathematics to show the consistency of, and
so forth...</p>
<p>This means that, at some point, we just need to take the consistency
of our system for granted. We can rely on heuristic arguments such as
"we've tried really hard and haven't found a contradiction" and "the
rules of ZFC seem simple enough." But we can never know for sure...
<strong>unless</strong> we find a contradiction. (For example, naive set
theory has a contradiction in Russell's Paradox, so we know for sure it
is not consistent and need to toss it out.)</p>
<p>Finally, we should talk about why inconsistency results <em>must</em>
exist, regardless of which system of mathematics we work in. This is a
consequence of Godel's First Incompleteness Theorem, which says</p>
<blockquote>
<p>Given any system of mathematics, there exist statements that can
neither be proven nor disproven.</p>
</blockquote>
<p>This necessarily implies that there exists a world where the
statement is true and another where the statement is false. Why? Because
if there were no world where the statement were true, then it would be
false in every world, which means we can disprove it by Godel's
Completeness Theorem. Similarly, if there were no world where the
statement is false, then it would be true in every world, which means we
can prove it.</p>
<p>What does all of this mean? If we have a system of mathematical
rules, we don't know and <em>can't</em> know how many worlds satisfying
these rules exist (unless we derive a contradiction in these rules).
However, we know that there <em>cannot</em> be exactly one such
world.</p>
<h3 id="independence-is-a-good-thing-actually">Independence is a good
thing, actually</h3>
<p>We know that no matter how many rules we tack on, we will never get a
collection of rules that carves out <em>exactly</em> one universe of
mathematics. But we can at least try to patch up our theory. For
instance, if we know CH is independent of ZFC, why not just assume that
CH holds? That could make proving certain things simpler. After all, we
literally have <em>more</em> assumptions to prove theorems with. So why
don't we?</p>
<p>The core of mathematics is to <em>prove things in as much generality
as (reasonably possible)</em>. We could, for instance, study linear
algebra only in the vector space <span
class="math inline">ℝ<sup>3</sup></span> and prove theorems such as
"every basis of <span class="math inline">ℝ<sup>3</sup></span> has the
same size". That certainly would make things easier, but we would be
losing a lot of insight. And sometimes we want to focus on specific
vector spaces, such as finite-dimensional vector spaces. Then it makes
sense to tack on an extra assumption. But if we don't need it, we really
shouldn't use it.</p>
<p>Studying ZFC mathematics is much the same. For instance, all of real
analysis still holds whether CH holds or not. So when we are proving,
for example, that "<span class="math inline">ℚ</span> is dense in <span
class="math inline">ℝ</span>", we aren't just pointing to a specific
world of mathematics and saying <span class="math inline">ℚ</span> is
dense there. Rather, we are making a statement about the entire
<em>multiverse</em> of mathematics.</p>
<p>Isn't that neat?</p>
<section id="footnotes" class="footnotes footnotes-end-of-document"
role="doc-endnotes">
<hr />
<ol>
<li id="fn1"><p>Okay, I am telling you a bit of a white lie here. I am
referring to the Axiom of Infinity. It just gives us a set that behaves
<em>like</em> the set of natural numbers, but we can derive the
existence of the natural numbers from it.<a href="#fnref1"
class="footnote-back" role="doc-backlink">↩︎</a></p></li>
<li id="fn2"><p>I am really lying to you here. There are many more
technical subtleties at play here, none of which I will go over here.<a
href="#fnref2" class="footnote-back" role="doc-backlink">↩︎</a></p></li>
</ol>
</section>]]></description>
	<pubDate>26 May 2025</pubDate>
</item>
<item>
	<title>A plan of attack for Glee</title>
	<link>https://dennisc.net/writing/tech/a-plan-of-attack.md</link>
	<description><![CDATA[<p>As of a few hours ago, my understanding of
trees in Postgres has shot up a lot, thanks to <a
href="https://leonardqmarcq.com/posts/modeling-hierarchical-tree-data">a
blog post by Leonard Marc</a>. The approach we will be using is #2, i.e.
storing the parent directory as a foreign key. (More details soon.)
Suffice to say that I feel very stupid and enlightened at the same time,
because now I believe I have a perfectly sound model of Glee. In fact,
it is sound enough that I am confident that I can begin programming ---
and I am so averse to programming that my mailserver has not been able
to send emails for the last eight months.</p>
<h2 id="storytime-skippable">Storytime (skippable)</h2>
<p>Previously I had a hare-brained idea to store the metadata of a
repository (who has permissions to act in this repository?) as an actual
file in the filepath. It suffices to say this is a terrible idea, but it
would have worked just fine with my previous design.</p>
<p>Then I started thinking about the goals of Glee. At the start, Glee
was meant to be a host that didn't need to scale, but now my goal is for
Glee to scale towards large single-organization hosts. (Because
otherwise it is utterly useless and you can just use <code>cgit</code>.)
The underlying complexity, however, will still remain very low,
somewhere between <code>cgit</code> and <code>sourcehut</code>. It is
the goal that</p>
<ul>
<li>all of the design decisions can be explained in a single
medium-sized document,</li>
<li>understanding the design is sufficient to use the software
proficiently.</li>
</ul>
<p>But this post is not meant to be that document. I will hold off on
that until I have Glee in a somewhat usable state.</p>
<p>Now, if we want large single organizations to use this for
enterprise-ish stuff, we really don't want random people creating
accounts. (I also cannot be bothered to implement a "send registration
email" feature.) The logical flow is that if you are an admin of a
directory or repository (which we will henceforth call a <em>path</em>),
then you may give an email address (say <code>dchen@dennisc.net</code>)
permissions to (say) write to the path. If
<code>dchen@dennisc.net</code> is already associated with an account,
then that account will now have permissions to write to said path.</p>
<p>If not, an email will be sent containing an invite link, with which
<code>dchen@dennisc.net</code> can use to register. In the database, we
will note that this invite link should also give the new account
permissions to the path (say) <code>a/b/c.git</code>. So we will store
the permission <code>write: a/b/c.git</code> in the associated database
entry for that invite link, and when the invite link is used, that
permission will be added for the new user.</p>
<p>Now what if <code>a/b/c.git</code> moves to <code>a/e.git</code>
after the invite link is created but before it is used?</p>
<p>Oh.</p>
<p>The correct way to deal with this issue is to instead point to a
unique id representing the path, one that doesn't change. Which calls
for storing information about paths in the database.</p>
<h2 id="directories-and-repositories">Directories and Repositories</h2>
<p>To motivate this section, I will say what I have said before in many
of my previous Glee posts. Glee is about storing your Git repositories
as a filesystem.</p>
<p>We are going to use a standard tree structure in Postgres. We will
have a table <code>Directories</code> and <code>Repositories</code>. The
fields of each are going to be</p>
<ul>
<li>id: a uuid</li>
<li>public: whether the directory or repository is publicly viewable, an
optional boolean (no value means "inherit")</li>
<li>name: the name of the directory or repository, for example
<code>c.git</code></li>
<li>parent: a <em>nullable</em> foreign key pointing to the uuid of a
directory</li>
<li>permissions: a list of read/write/admin with user ids, e.g.
<code>[read, b3994226-6761-456d-879c-7b18facbbd81]</code></li>
</ul>
<p>Of course, the parent of the root directory <code>/</code> will have
no parent. It will be the <em>sole</em> path with no parent. It also
will be the sole path we cannot move.</p>
<p>For now I'm thinking the struct representing this unified model in
Rust should be <code>DirRepo</code> in <code>backend.rs</code>. Or maybe
just <code>Path</code>, but that is not the most ideal name because it
conflicts with a filesystem path, and <code>Path</code> implies a
complete path rather than just one step (i.e. current file plus
parent).</p>
<p>We will index the column <code>id</code> in the table
<code>Directories</code>. That way we can emulate <code>ls</code> for
the directory <code>b3994226-6761-456d-879c-7b18facbbd81</code> by
simply searching for anything with a parent id of
<code>b3994226-6761-456d-879c-7b18facbbd81</code> and have this query be
efficient.</p>
<p>We will have to validate that <code>name</code> does not contain any
<code>/</code> characters upon any client POST request for obvious
reasons.</p>
<h2 id="handling-redirects">Handling redirects</h2>
<p>Now handling redirects is trivial, which means we will do it. We will
have a table of <code>Redirects</code> which store</p>
<ul>
<li>parent</li>
<li>name</li>
<li>link: which ID the redirect goes to.</li>
</ul>
<p>Let me give you a concrete example to explain how resolving redirects
will work. Suppose we rename
<code>a/b/c.git -&gt;</code>a/d.git<code>. As expected, we look at the entry for</code>c.git`,</p>
<ul>
<li>change its name to <code>d.git</code>,</li>
<li>change its parent to <code>a</code> (more accurately the id of
<code>a</code>).</li>
</ul>
<p>Furthemore, we create a Redirect with</p>
<ul>
<li>parent: whatever the id of <code>b</code> is (this is the parent of
<code>c.git</code> before rename)</li>
<li>name: <code>c.git</code></li>
<li>link: whatever the id of <code>c.git</code> was, i.e. the id of the
new <code>d.git</code>.</li>
</ul>
<p>Note that the path <code>a/b</code> still exists, we just moved
<code>c.git</code>. Here is what happens when we try to navigate to
<code>a/b/c.git</code>:</p>
<ul>
<li>There is a directory named <code>a</code> with parent
<code>/</code>.</li>
<li>There is a directory named <code>b</code> with parent
<code>a</code>.</li>
<li>There is no directory or file named <code>c.git</code> with parent
<code>b</code>. But there is a <em>Redirect</em> with the name
<code>c.git</code> with parent <code>b</code> that points to
<code>d.git</code>. So now we look at <code>d.git</code> and get a
repository.</li>
</ul>
<p>To be clear, when we say "with parent <code>/</code>", we really mean
that its parent is the id of the root directory, etc.</p>
<p>(Basically this is the idea I had with symlinks, but it solves the
problem of changing identifiers because we use a static id.)</p>
<p>To demonstrate the robustness of this idea, suppose we now move
<code>a/b</code> to <code>a/e</code>. We still want
<code>a/b/c.git</code> to go to the correct repository. What
happens?</p>
<ul>
<li>There is a directory named <code>a</code> with parent
<code>/</code>.</li>
<li>There is no directory named <code>b</code> with parent
<code>a</code>. However, there is a redirect with name <code>b</code>
and parent <code>a</code> that goes to <code>e</code> (which has path
<code>a/e</code>).</li>
<li>There is no directory or file named <code>c.git</code> with parent
<code>e</code> (remember that when we do parent checks, it is with the
id; saying "with parent <code>e</code>" is merely a shorthand). However,
there is a redirect with name <code>c.git</code> with parent
<code>e</code> that points to <code>d.git</code>. So now we get the same
<code>d.git</code>, precisely as desired!</li>
</ul>
<p>In fact, <code>a/b/c.git</code> will <em>always</em> redirect to that
same repository until a new directory or repository is made at that same
path.</p>
<p>And these redirects persist until they are "overwritten" by a new
path at the same location. When the overwrite occurs, we will delete the
redirect. The leading principle here is very simple:</p>
<blockquote>
<p>The combination of name and parent id must be unique among all
directories, repositories, and redirects.</p>
</blockquote>
<p>That means there are no unused redirects lying around, meaning that
<strong>we never have to prune redirects</strong>. So our analogy of a
filesystem with repositories and directories can be extended with
redirects. Now we just have two types of files: redirects and
repositories, and directories.</p>
<p>What do we do when we try to create a new directory/repository and
there is a conflict?</p>
<ul>
<li>If the conflict is with a redirect, simply delete the redirect.</li>
<li>If the conflict is with another directory/repository, forbid the
operation.</li>
</ul>
<h2 id="how-are-we-concretely-storing-repositories">How are we
concretely storing repositories?</h2>
<p>Now it would be stupid to actually perform a filesystem move every
time we do a "virtual" move in the database. The correct answer is very
obvious: we store the repository with uuid
<code>b3994226-6761-456d-879c-7b18facbbd81</code> in the path
<code>b3994226-6761-456d-879c-7b18facbbd81.git</code>.<a href="#fn1"
class="footnote-ref" id="fnref1" role="doc-noteref"><sup>1</sup></a>
That way when we resolve a path to a repository, we merely need to look
at <code>uuid.git</code> in the filesystem. Furthermore, because we
never move repositories in the actual filesystem and never change uuids,
any bug with filepath resolution is fixable. This means we will never
corrupt our data with moves, because <em>we are never changing the
underlying data</em>; bugs will only appear due to incorrect filepath
resolution.</p>
<h2 id="user-permissions-again">User permissions, again</h2>
<p>Specifically we will talk about</p>
<ul>
<li>how users ought to be invited</li>
<li>how permissions will be managed on the frontend</li>
</ul>
<p>because those are the only things which I have changed the design
of.</p>
<p>A link to a special page to "manage permisisons" for a
directory/repository will appear if you have admin access. We will not
be modifying a raw TOML file because that is a bad idea. Here is our new
approach:</p>
<p>When resolving whether a user is an admin, we should also determine
whether they have directly been defined to be admin (i.e. in the current
directory or repository) or whether they have inheritd admin from a
parent directory. We will say an admin is an <strong>Inherit
Admin</strong> if they have inherited and a <strong>Direct
Admin</strong> if they have been directly defined as an admin.</p>
<p>An inherit admin will be stronger than a direct admin. So if we have
determined a user is a direct admin, we also must check whether they
inherit admin as well, since making someone a direct admin on top of
being an inherit admin should not reduce their permissions.</p>
<p>A direct admin cannot delete admins in the current
directory/repository. An inherit admin can delete direct admins in the
current directory/repository.</p>
<p>Regardless of what permisisons you have (read/write/admin), the main
page of the repo will tell you what permissions you have upfront. (Many
other sites are awful at doing this.)</p>
<p>Admins, whether inherit or direct, can see both who has
<em>direct</em> permissions on the "manage permissions" page. You may
think that resolving who has inherited permissions might be complex, and
you would be right, but we already do this work when determining whether
to show the permissions page. Instead of just resolving permissions for
one user, we will create a list of all users and the permissions they
have. For example, we might say</p>
<ul>
<li>Alice is an admin of the repository</li>
<li>Bob inherits admin from <code>/gym</code></li>
<li>Charles inherits write from <code>/gym</code></li>
</ul>
<p>However, it might be privileged information that Dean is an admin of
<code>/</code>, and it would be bad if a low-level admin saw "Dean
inherits admin from <code>/</code>". Suppose the highest parent
directory we inherit admin from is <code>/path</code>. Then we only want
to show users who inherit permissions from <code>/path</code> or lower.
So when we traverse the tree to resolve permissions, we will be keeping
track of</p>
<ul>
<li>the highest parent directory you inherit admin from,</li>
<li>and the lowest parent directory every other user inherits their
<em>strongest</em> permission from,</li>
</ul>
<p>where "high" means "less deep" and "low" means "deeper".</p>
<p>If your highest inheriting directory is higher than a user's lowest
inheriting directory, then you will see that the user inherits their
permissions from said lowest inheriting directory.</p>
<p>Also, there will be a special "manage permissions" page on
<code>/</code> which allows admins of <code>/</code> to delete any user
who is not an admin of <code>/</code>.</p>
<h2 id="displaying-the-git-log-as-a-graph">Displaying the git log as a
graph</h2>
<p>Here's a tip that will change your life: try using
<code>git log --graph</code>. GitHub, GitLab, and SourceHut's log views
are all linear, meaning they do not show the commit graph. BitBucket of
all places does. We show the commit graph as well because that is the
right thing to do, although we will shamelessly fail on unreasonably
large octopus merges.</p>
<p>This will require a good understanding of <code>libgit2</code>'s
<code>rev-walk</code> function and significant thought into the frontend
design of the Git log. Of all the things I want to implement in Glee,
this seems like it will be the hardest.</p>
<h2 id="plan-of-action">Plan of action</h2>
<p>Having finally fleshed out the design, here is the plan of action.
<em>In this order</em>, here is how I plan to implement Glee:</p>
<ul>
<li>Revamp the user model.
<ul>
<li>Remove admin, because we are now handling permissions on the
filesystem in a more sophisticated manner.</li>
<li>Maybe start using Redis (well really ValKey now). Because while
scalability was not a goal before, the whole point now of several new
ideations is that scalability is actually important. We want big
organizations to be able to use this, at least in theory, so Postgres
authentication might become a bottleneck. (But I will have to do
research onto whether this is actually worth doing, though my gut says
using Redis is the right thing to do.)</li>
</ul></li>
<li>Create Directory/Repository tables.
<ul>
<li>Use foreign key pointer approach.</li>
<li>Make an index on the parent id and set up scaffolding for
initializing indices.</li>
</ul></li>
<li>Revamp Invite Token model
<ul>
<li>Invites should be associated with "what do you want to invite user
to", so path + permission (read/write/admin).</li>
<li>Said invites will also modify the appropriate directory/repository
entry.</li>
</ul></li>
<li>Implement permissions page for each directory/repository.</li>
<li>Implement directory main page view.</li>
<li>Implement repository main page view</li>
<li>Implement log/trunk view, etc for repositories.
<ul>
<li>Need to figure out how to emulate <code>git log --graph</code>, but
with a web UI.</li>
</ul></li>
<li>Figure out SSH interceptors to implement write access.</li>
</ul>
<p>When all this is done, we will have a reasonably complete product. I
feel that I finally have the requisite understanding of Postgres to
implement the database-side stuff, though I will have to spend some more
time understanding Git better. But at the very least, I can implement
everything up to the repository main page view without understanding Git
one bit more. So the goal will be to get to that point soon.</p>
<section id="footnotes" class="footnotes footnotes-end-of-document"
role="doc-endnotes">
<hr />
<ol>
<li id="fn1"><p>Really, we store this repository in the data directory
of Glee.<a href="#fnref1" class="footnote-back"
role="doc-backlink">↩︎</a></p></li>
</ol>
</section>]]></description>
	<pubDate>9 Aug 2024</pubDate>
</item>
<item>
	<title>English class is intellectually dishonest</title>
	<link>https://dennisc.net/writing/essays/english-is-dishonest.md</link>
	<description><![CDATA[<p>There's a general consensus that you should
only write about what you know. The threshold for "knowing" differs from
person to person. There are plenty of tech bloggers using Medium that
pretty much admit to not knowing what they are doing, whereas there are
some people who will never write in fear of being wrong. Where in the
middle you should lie is up to personal taste, but I <em>hope</em> that
there is at least agreement that we should all strive not to
deliberately write on things we don't know about.</p>
<p>English class breaks this expectation in the most spectacular of
ways. The most important skills in writing are finding what you know
enough to write about (both because you want what you're writing to
interest you and for the sake of intellectual honesty), and knowing when
to retreat. Particularly the latter. Out of the essays I've discarded or
left unpublished, there are drafts with anywhere between 10 and 1,000
words. (Typically not more, because I learn to give up on dead ends
pretty fast.)</p>
<p>In English class it is never a choice to just stop writing an essay.
And if we accept that writing can do harm to other people (it is not
hard to think of some examples), why can't it do harm to yourself? You
are not just writing about things you don't know about, you are writing
about things you don't even care enough to learn. Just as using the
wrong running stance can give you bad muscle memory which will hurt you
later down the road, writing about the wrong topics can make
bullshitting a habit. Bullshitting is a useful skill to have, but few
people besides car dealers want it to be their only skill. Yet that is
what English promotes for 12 straight years of your life (and possibly
more, depending on what college you go to if any).</p>
<p>There is a question of audience. Because your English papers are
terrible and you never wanted to write them in the first place, the only
people who will ever read your papers are your teacher and a couple of
classmates. But just as what you write about can become a habit, <a
href="/writing/essays/write-smart">who you write it for</a> can as well.
You are not writing an exploratory essay which you explicitly
acknowledge has a high chance of being wrong. You are trying to pass off
the knowledge you gained or pulled out of your ass in the last hour as
genuine, deep, etc. Which it is not. So your only choice in English
class is to write for stupid people, <em>even if your audience doesn't
happen to be</em>, because that's your only hope for successfully
bullshitting your essay past them.</p>
<p>English class is a perverse cycle: your intelligence gets insulted,
and in the process, all you can do is insult the intelligence of other
people by lying and misrepresenting the knowledge you have. I'm not
saying you shouldn't explore new ideas in your writing. But you should
not, for even a second, take on the role of some omniscient being
evaluating a book about things you have never experienced, or weighing
policies you have never bothered to study. You have a limited
perspective, and if you ever want to expand it, you have to acknowledge
that.</p>
<p><a href="/writing/essays/modifiers">Write "I think" when it
appropriately reflects the confidence you have.</a> Be honest about your
biases, undermine your own credibility when it makes sense, and above
all, don't try to pass off bullshit just because your underpaid public
school teacher couldn't be bothered to stop you.</p>]]></description>
	<pubDate>31 Mar 2022</pubDate>
</item>
<item>
	<title>so it ends</title>
	<link>https://dennisc.net/writing/blog/so-it-ends.md</link>
	<description><![CDATA[<p>well, I've graduated.</p>
<h2 id="may-30-last-day-of-school">may 30: last day of school</h2>
<p>May 30th was a Tuesday. Incidentally, it also was the last day I came
to school.<a href="#fn1" class="footnote-ref" id="fnref1"
role="doc-noteref"><sup>1</sup></a> We have finals on Wednesday,
Thursday, and Friday, but I don't have anything going on in any of my
classes (I don't even have classes on Friday), and my <em>teachers</em>
aren't even showing up (mostly), so I might as well not show up
either.</p>
<p>A lot of my senior friends are leaving for vacation right as the
school year ends, which really sucks since I decided to leave July
instead since I didn't want to leave immediately. So realistically the
last time I'll see them until winter break is graduation.</p>
<p>But honestly, sitting in a classroom and doing nothing for two hours
would be a bit sad, and I don't actually care enough to come to school
just to talk to my classmates.</p>
<p>The noteworthy part is that no one really got hit by the fact it was
all about to end. It's similar to college apps: you expect to be super
nervous about it the entire time, but in the end you just can't be
bothered to care anymore. Sure, there probably are people who really
loved high school and don't want to leave, but for me it was just <a
href="https://guya.cubari.moe/read/manga/Oshi-no-Ko/39/9/">a slightly
enjoyable job</a>.</p>
<p>There still are a couple of things left to do, like graduation, grad
night, and my friend's grad party. (As I actually type this up all three
have happened. They were fun, but as I expected, there was no sense of
finality.) But now that I've finished every assignment from high school,
I can "start fresh". I don't have to worry about stupid assignments or
checking my high school email or truancy letters (which I have 3 of) or
whatever. There's a lot of things I plan to start doing using the
momentum of the transition from high school to college, some of which
I'll declare publicly even though I know I'll fail most of them:</p>
<ul>
<li>Set a strict sleep schedule at like 10:00 PM or something. It'll get
really bad at college so I'm giving it room to get worse to like, 11:30
PM which is still not <em>horrible</em>.</li>
<li>Set an instructionless puzzle by the end of the summer. (This'll be
hard if the only ideas I get are Fillomino Chaos Constructions. They
<em>could</em> work as instructionless, but if I set another puzzle with
squares and circles and the example just <em>so happens to align with
FCC</em>, then it'll be really obvious.)</li>
<li>Finish my Git host (or at least have the MVP done)</li>
<li>Pretend to take some MIT/Harvard courses at an accelerated rate. I
want to get through the undergrad math curriculum (should've started a
LOT earlier) and probably be a little ahead in CS too. I might be in
SCS, but I'm really a fake CS major. Being good at math is much more
important to me, though obviously I'll also be a tryhard when it comes
to CS.</li>
<li>Stop being a Rust one-trick (i.e. stop sucking at C and learn
Haskell, everything else kinda sucks)</li>
<li>Hit the gym every day and get that 6 pack (and non-stickman arms).
This is unironically the most important</li>
</ul>
<p>Summer represents a time with minimal obligations, which means
maximal freedom for self-improvement. I already feel far behind of where
I could've been and should've been if I was more aggressive in learning
before, so I gotta play catchup now.</p>
<p>On that note, I should probably get the logistics ball for Summer MAT
2023 rolling, both sponsorship and web-hosting wise.</p>
<p>I'm not so concerned about looking back at the past right now. Yeah,
I missed a lot of opportunities and experiences in high school (some of
which is my fault, and some of which is due to external circumstances),
but the future looks so promising that I don't really care anymore.</p>
<h2 id="may-31-so-it-all-comes-crashing-down">may 31: so it all comes
crashing down</h2>
<p>Only on the Dennis Chen blog will you get a tech support story in my
graduation post. Alas, when my server fries itself and my websites are
all down, everything else kinda has to take a back seat for a bit.</p>
<p>Context: A week ago, I bought a Raspberry Pi 4 Model B to host a
Minecraft server for the cross country guys, and when I was done with it
I was going to bring it to CMU for it to act as our webserver.</p>
<p>So as I was finishing my last ever high school assignment and messing
around, I noticed that puzz.dennisc.net was not connecting. Huh, weird.
I was upstairs and didn't want to move downstairs to where the server
was, so I just tried SSHing into the server to check it was up. No dice.
How about pinging it?</p>
<blockquote>
<p>Route unreachable</p>
</blockquote>
<p>Well FUCK. That means my server doesn't just have connectivity
issues, it's literally powered off. So I quickly redirect my DNS servers
to my cloud server for now and investigate in the meanwhile.</p>
<p>The red LED on the Pi (the one that denotes power) is on. The RPI
doesn't have a way to force a graceful shutdown, so after confirming the
device wasn't booted with an HDMI cable and a monitor, I just unplugged
the power.</p>
<p>Then, I kept experimenting with reboots, using different SD cards
with different operating systems just to rule out the SD card as a
potential problem. No matter what, it wouldn't boot --- not even into a
bootloader to tell you, "you fucked up man". This was really bad. I
didn't want to spent the first day of vacation doing sysadmin stuff, but
it looked like this problem wasn't going to resolve itself so
easily.</p>
<p>Then I started looking stuff up. Maybe the bootloader killed itself
for no reason. The forums say that if the Pi can't boot, the green LED
<em>should</em> flash 4 times in a metronomic rhythm. So I remove the SD
card, connect the power, and got just one quick flash --- which meant
the bootloader was dead. So the last thing I try is running the repair
OS --- for a potential problem that is incredibly rare and has no reason
to happen --- and again, no dice.</p>
<p>At this point the machine is probably totaled. Irredeemable. (Note
from the future: it was. I returned it.) Fortunately, Best Buy has a 15
day return policy, and the Pi decided to kill itself for no reason much
before the deadline. So I'm returning it tomorrow and hopefully I get a
refund.</p>
<p>In the meantime, I learn that CMU gives a public address to every
machine connected via Ethernet (how do they have so many public IPs, one
wonders?) Also, when we're not running any time-sensitive events like
the MAT, it'd probably be OK if something messed up and the server
needed to be taken down for a couple of hours.</p>
<p>The original plan (after using the Pi as a Minecraft server with the
cross country kids) was to have one machine at home and another at CMU.
But I just discovered that A records don't allow for fallbacks, so there
wouldn't be a ton of point in maintaining a far away machine. So,
possibly contingent on getting Alpine Linux to run on my Orange Pi 3
LTS, I'm probably not going to buy another single-board chip. I just
don't see the need for it.</p>
<p>Speaking of trying to get the Orange Pi to run Alpine: by god it is
such an annoying, difficult, confusing, and under-documented process.
The guides for getting <em>any</em> Allwinner<a href="#fn2"
class="footnote-ref" id="fnref2" role="doc-noteref"><sup>2</sup></a>
board to run Alpine are at least 5 years old, and none are specific to
both Alpine and the 3 LTS. I've tried a few times before and no dice.
The process I'm roughly trying is:</p>
<ul>
<li>compile u-boot and burn it to a micro SD card's first 1024
bytes</li>
<li>create a boot partition of filetype ext4, toggle bootable, run
mkfs.ext4</li>
<li>extract the tarball of Alpine for Generic ARM into that partition
(using mount)</li>
</ul>
<p>The Pi refuses to boot when I insert such an SD Card, or sometimes in
the past it would just boot the built-in Android ROM. I have fuckall
idea what's happening, because I don't own a USB to TTL serial cable,
but (note from the future) hopefully it'll come soon.</p>
<p>Fortunately there is an Orange Pi Discord, and three months ago
someone tried to do the exact same thing I'm doing right now. So
hopefully they succeeded and I can ask them what they did, install
Alpine myself, and actually document the goddamn process.</p>
<p>Miscellaneous events today:</p>
<ul>
<li>Asian moms pulled up to our house and I sequestered myself in my
room</li>
<li>I solved KNT's ridiculous 25 letter ciphered Japanese Sums
puzzles</li>
<li>recently I felt kinda chubby and that's really bad (I can't
<em>see</em> the difference in the mirror but I can <em>feel</em> it).
<strong>Note from the future:</strong> I started running and swimming
with the cross country guys so now this problem is fixed.</li>
</ul>
<p>Well, hopefully I resolve my stupid self-hosting issues by tomorrow
and actually start working on stuff I care about. (Note from the future:
Hahahahahahahahahaha no. That did not happen.)</p>
<h2 id="june-1-the-final-ditch">june 1: the final ditch</h2>
<p>This is the last day I ever get to ditch high school. And of course,
that is exactly what I did.</p>
<p>I was planning on working on personal CS Projects, but this morning,
CMU's Discrete Math Primer summer course came out. So instead, I spent
much of the morning working through the DMP, and got through about 1/3
of it before grad rehearsal.</p>
<p>Grad rehearsal was so pointless. I don't know why I even came; it's
not like anyone checked. Guys, please don't drag us into the sweltering
heat just to ramble on about stuff you could've just sent in an
email.</p>
<p>After I came back, I did some more DMP and went on a run. Then, I had
an idea for my new puzzle site: I could add optional <code>hints</code>
and <code>example</code> tags to the puzzle struct (note from the
future: <code>example</code> became one of the potential links), so I
could display hints and examples like in my old puzzle site.</p>
<p>Then I went to bed around 11:30 tonight. Not as early as I'd like,
but tomorrow is grad night and it's going to get so much worse then.
(Technically, I won't even go to bed tomorrow since I get back at 1:00
AM!)</p>
<h2 id="june-2-so-it-ends">june 2: so it ends</h2>
<p>This morning, the CS placement exams came out. So I finished DMP then
did both of the exams. While I unfortunately failed to ace both the
exams (note from the future: the one problem I missed probably has an
incorrect answer since <strong>no one</strong> has aced this really easy
10 question exam yet), I did do good enough to not get thrown out of
Imperative, which I have the AP credit for anyway.</p>
<p>Today, we also finally went to Best Buy to return the broken RPI.
Unfortunately Best Buy doesn't carry USB to TTL serial cables, a niche
debugging tool for stuff that has exposed GPIO pins (basically just
single-board chips like the Pi) that I need to figure out how to run
Alpine on the Orange Pi 3 LTS. Then I went to TJMaxx and bought some
black shorts, because I desperately need more. (Yes, my fit is all
black. No, you do not get to laugh.) Nothing of note happened after that
until graduation.</p>
<p>Graduation, to put it bluntly, was a mess. We stood around doing
nothing for two hours, and I hate crowds and enclosed spaces because you
have to pretend the 3 things you can even do are interesting as you
cycle between them.</p>
<p>During the grad speeches, I was thinking, "shut up about COVID please
I've heard about it 5 other times", "wow you are a disaster child", and
"Zzzz". The final one isn't entirely true: during the valedictorian
speech my brain was working on overdrive. Not only did I find the
ruleset I wanted to use for Fillomino Chaos Construction #2, but I even
thought of a breakin. So as the speaker was talking, I was thinking
"please let the wifi just connect so I can set the breakin with Penpa
before I forget." (I got the wifi.)</p>
<p>Then after awards (for god-knows what) were presented, it was time to
read the names of all. 700. seniors. It took way too long, but it
honestly wasn't bad because I had a lot of friends to cheer on
throughout the whole ceremony. Not that there's anything cheerworthy
about walking on a stage and receiving a participation trophy --- well,
not even that, because the diploma itself wasn't even there on time,
just the diploma <em>cases</em> --- but for a brief moment, it was fun
to pretend otherwise. Celebrating each other, even if it's for stupid
stuff, is honestly not that bad. Especially because when someone does
something genuinely impressive, most of the time no one else understands
what they actually did. So the silver lining of the pointless and
ridiculously long graduation ceremony was that at least we got to
celebrate each other and fully understand <em>why</em>.</p>
<p>That still doesn't mean I think graduation isn't stupid, and I still
wish I got to skip it. But since I had to be there anyway, I made sure
to enjoy it a little.</p>
<p>It was only during the afterparty that it really hit home: I'm not
seeing these people ever again. It's not like I'm crying about it or
super depressed, but it did strike a reflective chord in me. The people
I was really close to, I'll meet them one way or another in college or
further in the future. Some people I straight up had no idea existed, so
I honestly don't care that much. It's the people in between that leave
me torn: it was nice knowing them, but we're not nearly close enough to
meet up in the summer or in college.</p>
<p>Some part of me regrets not getting to know these people better. I
genuinely like these people, and vice versa. But come on, a fake
extrovert like me only has enough energy to be social every so often,
and I'm not going to sacrifice my uninterrupted 8-hour puzzle writing
streaks just to go <em>partying</em> or something.</p>
<p>I do care about these people. Just not enough to go out of my way to
find their contact info and invite them to something, especially since I
can already fill my schedule with the people I know and the things I
want to get done this summer. And that's kind of a sobering thought.</p>
<p>But of course far more important than anything else today, I figured
out what the next few puzzles I'm going to set are going to be like, and
I can't wait to actually set them. I'm going to continue the Fillomino
Chaos Construction series and I already have ideas for three total
puzzles. (Note from the future: I finished writing FCC #2.) So if you
liked FCC #1, boy I got some good news for you.</p>
<h2 id="aftermath">aftermath</h2>
<p>As I predicted, I didn't really care about graduation. Instead my
priorities were:</p>
<ul>
<li>CMU (both summerwork and getting to know people)</li>
<li>writing puzzles (I somehow managed to drag myself away from the
Penpa tab when it was time to meet up with the guys)</li>
<li>meeting up with the cross country guys</li>
</ul>
<p>Also algebraic data types and Haskell. I really need to learn Haskell
and FP.</p>
<p>Out of my priorities, I did a lot more hanging out than I expected,
and less math/<em>strength</em> exercises than I should've.</p>
<p>I finished up Fillomino Chaos Construction #2 and sent it to KNT, and
as he testsolved I discovered 2 errors, which is an entirely new record.
I only fucked up twice when I was setting the puzzles, and even better,
it was actually pretty easy to fix the logical leaps I made and make the
steps actually rigorous. Man I am such a genius, maybe someday I'll even
figure out how to not send broken puzzles in the first place.</p>
<p>I also went to a graduation party of a friend who goes to a different
school. The host had a Kahoot about herself (only God knows why), and
there were questions like "what is my favorite flower". And everyone
else is getting these right, and I'm thinking "how the fuck am I
supposed to know what <em>your</em> favorite color is, I don't even know
what <em>mine</em> is". Needless to say, I placed dead last. Also I need
more meat, but it was super fun despite there being basically no meat in
the menu.</p>
<p>OK, now it's midnight and technically June 7, so I should really head
to bed. Schedule for tomorrow is aggressively do math, make the build
script for dennisc.net <em>much</em> faster, send some sponsorship
emails, and maybe find a CS course to study.</p>
<section id="footnotes" class="footnotes footnotes-end-of-document"
role="doc-endnotes">
<hr />
<ol>
<li id="fn1"><p>The only reason I came at all was because there were
multivariable presentations (including my own on that day). The only
reason I attended these presentations at all was because I didn't want
to do 24 project reviews.<a href="#fnref1" class="footnote-back"
role="doc-backlink">↩︎</a></p></li>
<li id="fn2"><p>This is the Orange Pi 3 LTS's processor.<a
href="#fnref2" class="footnote-back" role="doc-backlink">↩︎</a></p></li>
</ol>
</section>]]></description>
	<pubDate>7 Jun 2023</pubDate>
</item>
<item>
	<title>Computer analysis on Consecutive Neighbors</title>
	<link>https://dennisc.net/writing/tech/consec-neighbors-computer.md</link>
	<description><![CDATA[<p>A quick recap of what "Consecutive Neighbors"
is: I've been writing sudoku puzzles and invented a variant with a
global restriction.</p>
<blockquote>
<p>Every number must share a side with at least one other consecutive
number. For example, 2 must share a side with either a 1 or a 3
(possibly both).</p>
</blockquote>
<p>This is a very limiting restriction, and the grid is very sensitive
to initial conditions (i.e. initial digits placed). Placing just
<em>one</em> digit can break the puzzle 30 steps later, so I have to
know early when things don't work out. I'd like to programmatically
check that a solution is valid, and moreover, when I've hit a dead end
and need to backtrack or slightly adjust the structure of the
puzzle.</p>
<p>Obviously, there's intention behind the puzzles: the initial clues I
set up usually include 1/2's or 8/9's to use the condition, and after
the initial setup I typically have an idea what the rest of the 12 and
89 pairs will look like. But I'd like to know what givens work and where
stuff would break, in order to get <em>a</em> working solution (which is
really, really hard). But this sort of computer analysis helps to get
through dead ends much quicker.</p>
<p>Anyway, here's the code I wrote to check 81 digits (inputted as
chars, cast as ints):</p>
<div class="sourceCode" id="cb1"><pre
class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb1-1"><a href="#cb1-1" aria-hidden="true" tabindex="-1"></a><span class="pp">#include </span><span class="im">&lt;iostream&gt;</span></span>
<span id="cb1-2"><a href="#cb1-2" aria-hidden="true" tabindex="-1"></a><span class="kw">using</span> <span class="kw">namespace</span> std<span class="op">;</span></span>
<span id="cb1-3"><a href="#cb1-3" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb1-4"><a href="#cb1-4" aria-hidden="true" tabindex="-1"></a><span class="dt">int</span> main<span class="op">()</span> <span class="op">{</span></span>
<span id="cb1-5"><a href="#cb1-5" aria-hidden="true" tabindex="-1"></a>    <span class="dt">char</span> input<span class="op">[</span><span class="dv">81</span><span class="op">];</span></span>
<span id="cb1-6"><a href="#cb1-6" aria-hidden="true" tabindex="-1"></a>    <span class="cf">for</span> <span class="op">(</span><span class="dt">int</span> i<span class="op">=</span><span class="dv">0</span><span class="op">;</span> i<span class="op">&lt;</span><span class="dv">81</span><span class="op">;</span> <span class="op">++</span>i<span class="op">)</span> <span class="op">{</span></span>
<span id="cb1-7"><a href="#cb1-7" aria-hidden="true" tabindex="-1"></a>        cin <span class="op">&gt;&gt;</span> input<span class="op">[</span>i<span class="op">];</span></span>
<span id="cb1-8"><a href="#cb1-8" aria-hidden="true" tabindex="-1"></a>    <span class="op">}</span></span>
<span id="cb1-9"><a href="#cb1-9" aria-hidden="true" tabindex="-1"></a>    <span class="dt">int</span> grid<span class="op">[</span><span class="dv">9</span><span class="op">][</span><span class="dv">9</span><span class="op">];</span></span>
<span id="cb1-10"><a href="#cb1-10" aria-hidden="true" tabindex="-1"></a>    <span class="cf">for</span> <span class="op">(</span><span class="dt">int</span> i<span class="op">=</span><span class="dv">0</span><span class="op">;</span> i<span class="op">&lt;</span><span class="dv">9</span><span class="op">;</span> <span class="op">++</span>i<span class="op">)</span> <span class="op">{</span></span>
<span id="cb1-11"><a href="#cb1-11" aria-hidden="true" tabindex="-1"></a>        <span class="cf">for</span> <span class="op">(</span><span class="dt">int</span> j<span class="op">=</span><span class="dv">0</span><span class="op">;</span> j<span class="op">&lt;</span><span class="dv">9</span><span class="op">;</span> <span class="op">++</span>j<span class="op">)</span> <span class="op">{</span></span>
<span id="cb1-12"><a href="#cb1-12" aria-hidden="true" tabindex="-1"></a>            grid<span class="op">[</span>i<span class="op">][</span>j<span class="op">]</span> <span class="op">=</span> input<span class="op">[</span><span class="dv">9</span><span class="op">*</span>i<span class="op">+</span>j<span class="op">]</span> <span class="op">-</span> <span class="dv">48</span><span class="op">;</span></span>
<span id="cb1-13"><a href="#cb1-13" aria-hidden="true" tabindex="-1"></a>        <span class="op">}</span></span>
<span id="cb1-14"><a href="#cb1-14" aria-hidden="true" tabindex="-1"></a>    <span class="op">}</span></span>
<span id="cb1-15"><a href="#cb1-15" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb1-16"><a href="#cb1-16" aria-hidden="true" tabindex="-1"></a>    <span class="co">// Perform neighbor check on each cell</span></span>
<span id="cb1-17"><a href="#cb1-17" aria-hidden="true" tabindex="-1"></a>    <span class="cf">for</span> <span class="op">(</span><span class="dt">int</span> i<span class="op">=</span><span class="dv">0</span><span class="op">;</span> i<span class="op">&lt;</span><span class="dv">9</span><span class="op">;</span> <span class="op">++</span>i<span class="op">)</span> <span class="op">{</span></span>
<span id="cb1-18"><a href="#cb1-18" aria-hidden="true" tabindex="-1"></a>        <span class="cf">for</span> <span class="op">(</span><span class="dt">int</span> j<span class="op">=</span><span class="dv">0</span><span class="op">;</span> j<span class="op">&lt;</span><span class="dv">9</span><span class="op">;</span> <span class="op">++</span>j<span class="op">)</span> <span class="op">{</span></span>
<span id="cb1-19"><a href="#cb1-19" aria-hidden="true" tabindex="-1"></a>            <span class="co">// We set to true as soon as there is a neighbor.</span></span>
<span id="cb1-20"><a href="#cb1-20" aria-hidden="true" tabindex="-1"></a>            <span class="dt">bool</span> has_neighbor <span class="op">=</span> <span class="kw">false</span><span class="op">;</span></span>
<span id="cb1-21"><a href="#cb1-21" aria-hidden="true" tabindex="-1"></a>            <span class="cf">for</span> <span class="op">(</span><span class="dt">int</span> x<span class="op">=</span>max<span class="op">(</span><span class="dv">0</span><span class="op">,</span>i<span class="op">-</span><span class="dv">1</span><span class="op">);</span> x<span class="op">&lt;=</span>min<span class="op">(</span><span class="dv">8</span><span class="op">,</span>i<span class="op">+</span><span class="dv">1</span><span class="op">);</span> <span class="op">++</span>x<span class="op">)</span> <span class="op">{</span></span>
<span id="cb1-22"><a href="#cb1-22" aria-hidden="true" tabindex="-1"></a>                <span class="cf">for</span> <span class="op">(</span><span class="dt">int</span> y<span class="op">=</span>max<span class="op">(</span><span class="dv">0</span><span class="op">,</span>j<span class="op">-</span><span class="dv">1</span><span class="op">);</span> y<span class="op">&lt;=</span>min<span class="op">(</span><span class="dv">8</span><span class="op">,</span>j<span class="op">+</span><span class="dv">1</span><span class="op">);</span> <span class="op">++</span>y<span class="op">)</span> <span class="op">{</span></span>
<span id="cb1-23"><a href="#cb1-23" aria-hidden="true" tabindex="-1"></a>                    <span class="cf">if</span> <span class="op">((</span>x <span class="op">==</span> i <span class="op">||</span> y <span class="op">==</span> j<span class="op">)</span> <span class="op">&amp;&amp;</span> <span class="op">(</span>grid<span class="op">[</span>x<span class="op">][</span>y<span class="op">]</span> <span class="op">-</span> grid<span class="op">[</span>i<span class="op">][</span>j<span class="op">]</span> <span class="op">==</span> <span class="op">-</span><span class="dv">1</span> <span class="op">||</span> grid<span class="op">[</span>x<span class="op">][</span>y<span class="op">]</span> <span class="op">-</span> grid<span class="op">[</span>i<span class="op">][</span>j<span class="op">]</span> <span class="op">==</span> <span class="dv">1</span><span class="op">))</span> <span class="op">{</span></span>
<span id="cb1-24"><a href="#cb1-24" aria-hidden="true" tabindex="-1"></a>                        has_neighbor <span class="op">=</span> <span class="kw">true</span><span class="op">;</span></span>
<span id="cb1-25"><a href="#cb1-25" aria-hidden="true" tabindex="-1"></a>                    <span class="op">}</span></span>
<span id="cb1-26"><a href="#cb1-26" aria-hidden="true" tabindex="-1"></a>                <span class="op">}</span></span>
<span id="cb1-27"><a href="#cb1-27" aria-hidden="true" tabindex="-1"></a>            <span class="op">}</span></span>
<span id="cb1-28"><a href="#cb1-28" aria-hidden="true" tabindex="-1"></a>            <span class="cf">if</span> <span class="op">(!</span>has_neighbor<span class="op">)</span> <span class="op">{</span></span>
<span id="cb1-29"><a href="#cb1-29" aria-hidden="true" tabindex="-1"></a>                <span class="cf">return</span> <span class="dv">0</span><span class="op">;</span></span>
<span id="cb1-30"><a href="#cb1-30" aria-hidden="true" tabindex="-1"></a>            <span class="op">}</span></span>
<span id="cb1-31"><a href="#cb1-31" aria-hidden="true" tabindex="-1"></a>        <span class="op">}</span></span>
<span id="cb1-32"><a href="#cb1-32" aria-hidden="true" tabindex="-1"></a>    <span class="op">}</span></span>
<span id="cb1-33"><a href="#cb1-33" aria-hidden="true" tabindex="-1"></a>    </span>
<span id="cb1-34"><a href="#cb1-34" aria-hidden="true" tabindex="-1"></a>    <span class="co">// Spit the grid back out; we&#39;re going to be doing this in batch</span></span>
<span id="cb1-35"><a href="#cb1-35" aria-hidden="true" tabindex="-1"></a>    <span class="cf">for</span> <span class="op">(</span><span class="dt">int</span> i<span class="op">=</span><span class="dv">0</span><span class="op">;</span> i<span class="op">&lt;</span><span class="dv">9</span><span class="op">;</span> <span class="op">++</span>i<span class="op">)</span> <span class="op">{</span></span>
<span id="cb1-36"><a href="#cb1-36" aria-hidden="true" tabindex="-1"></a>        <span class="cf">for</span> <span class="op">(</span><span class="dt">int</span> j<span class="op">=</span><span class="dv">0</span><span class="op">;</span> j<span class="op">&lt;</span><span class="dv">9</span><span class="op">;</span> <span class="op">++</span>j<span class="op">)</span> <span class="op">{</span></span>
<span id="cb1-37"><a href="#cb1-37" aria-hidden="true" tabindex="-1"></a>            cout <span class="op">&lt;&lt;</span> grid<span class="op">[</span>i<span class="op">][</span>j<span class="op">];</span></span>
<span id="cb1-38"><a href="#cb1-38" aria-hidden="true" tabindex="-1"></a>        <span class="op">}</span></span>
<span id="cb1-39"><a href="#cb1-39" aria-hidden="true" tabindex="-1"></a>        cout <span class="op">&lt;&lt;</span> <span class="ch">&#39;</span><span class="sc">\n</span><span class="ch">&#39;</span><span class="op">;</span></span>
<span id="cb1-40"><a href="#cb1-40" aria-hidden="true" tabindex="-1"></a>    <span class="op">}</span></span>
<span id="cb1-41"><a href="#cb1-41" aria-hidden="true" tabindex="-1"></a>    <span class="cf">return</span> <span class="dv">0</span><span class="op">;</span></span>
<span id="cb1-42"><a href="#cb1-42" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code></pre></div>
<p>This helps to confirm a solution is correct. But if I want to
<em>find</em> a solution given some set of givens, there's a somewhat
hacky way:</p>
<ul>
<li>after doing an initial analysis, input the digits I know for sure
into <a
href="https://sudoku-solutions.com">sudoku-solutions.com</a>,</li>
<li>use the "Check" option (which will definitely fail) and download all
the possible solutions as a text file</li>
<li>use <code>sed</code> to fix newlines (<code>rn</code> looks like the
script was meant for Windows)</li>
<li>read line-by-line and input each solution into the constraint
checker (code shown above)</li>
<li>see outputted solutions, if any, and either use it or
backtrack.</li>
</ul>
<p>This is the code I used to pipe every solution into the constraint
checker:</p>
<div class="sourceCode" id="cb2"><pre
class="sourceCode bash"><code class="sourceCode bash"><span id="cb2-1"><a href="#cb2-1" aria-hidden="true" tabindex="-1"></a><span class="cf">while</span> <span class="va">IFS</span><span class="op">=</span> <span class="bu">read</span> <span class="at">-r</span> <span class="va">line</span><span class="kw">;</span> <span class="cf">do</span></span>
<span id="cb2-2"><a href="#cb2-2" aria-hidden="true" tabindex="-1"></a>    <span class="bu">echo</span> <span class="va">$line</span> <span class="kw">|</span> <span class="ex">./close-checker</span></span>
<span id="cb2-3"><a href="#cb2-3" aria-hidden="true" tabindex="-1"></a><span class="cf">done</span> <span class="op">&lt;</span> close-solutions</span></code></pre></div>
<p>(<code>close-solutions</code> is the file which I move the downloaded
solutions into. <code>close-checker</code> is the file the constraint
checker is stored in.)</p>
<p>I plan to improve it later by actually programming a solver that uses
this condition to narrow things down much faster, but for now, this was
the quickest thing to hack up.</p>
<p>This is easily generalizable to Dutch Neighbors, and it will be
really helpful for writing my <a href="puzzle-book">puzzle book</a>.
Though this variant is still difficult to set, at least it will be a
little <em>quicker</em>.</p>]]></description>
	<pubDate>14 Jan 2023</pubDate>
</item>
<item>
	<title>Creating</title>
	<link>https://dennisc.net/writing/essays/creating.md</link>
	<description><![CDATA[<p>Creating things is very difficult and
frustrating. It's not a skill that can be taught. But it is a skill you
can be <em>primed to develop</em>. This is the goal of this essay: to
prime you to start building something that requires creativity.<a
href="#fn1" class="footnote-ref" id="fnref1"
role="doc-noteref"><sup>1</sup></a></p>
<p>I personally write puzzles and math contests, so that is what I will
use as my primary examples.</p>
<h2 id="have-an-idea-you-want-to-share">Have an idea you want to
share</h2>
<p>The way you create something is by having a vague idea you want to
share, and then continuing to make it more specific until you have a
finished product.</p>
<p>What that means is, while wanting to create something is commendable,
it is not enough. Instead of hyperfixating on a specific <em>goal</em>,
like "I want to write a mock AIME", it is better to let it happen
organically. Write problems based on ideas you are thinking about, and
once you have amassed enough, then you can look at what you have and
decide whether a mock AIME fits the ideas you've been exploring or
not.</p>
<p>Conversely, if you have a specific idea, like "<a
href="https://artofproblemsolving.com/wiki/index.php/2016_USAJMO_Problems/Problem_2">how
many consecutive zeroes can I get in a power of 5</a>", then quit
reading this post or looking at general advice until you are done making
whatever you want to make. It will still be here when you're done ---
your idea, however, will probably disappear soon unless you flesh it out
<em>now</em>.</p>
<h2 id="empathy">Empathy</h2>
<p>When you are creating something, you need empathy for whoever is
going to be experiencing it. This means when you are setting a puzzle,
you cannot randomly spam Kropki dots until you stumble into something
uniquely determined. You have to place each Kropki dot with intention:
<em>what does this dot imply, and what will a solver make of it?</em>
You can be a bit generous here, because not every solver will notice the
logic you are trying to set, but an ideal solver should reasonably be
able to solve it logically without too many layers of indirection in
their deductions.</p>
<p>The same is true for writing: how will a reader interpret these
words? Is the pacing alright? And the same is also true for math
contests. For each problem, is there a logical, succinct, clean way to
solve it? For the contest as a whole, can an inexperienced solver be
engaged for the entire time? And can veteran math competitors still find
value and joy in doing your contest?</p>
<p>You cannot just consider your goal to be "find something that
<em>technically</em> works", whether it be a math problem that
technically has a solution or a Sudoku puzzle that happens to be
uniquely determined. You also need reason to believe that at least some
of the people you're showing your puzzle to will discover the idea you
were thinking about when you set the puzzle.</p>
<p>In a nutshell: how do you expect whoever's consuming your content to
react?</p>
<h2 id="surplus">Surplus</h2>
<p>Some people <a href="https://artisanalsudoku.substack.com">can write
5 puzzles a week every week</a>, while other people (and this is
everyone when they start setting their first sudoku) have no idea how to
even start. Or, how some people can solo write mock AMCs, while other
people think math problems come out of thin air. So, what's the
difference between someone who doesn't create anything and someone who
can consistently create stuff?</p>
<p>In my view, not much. It's not really habit or experience, because I
can consistently program or write math problems or whatever for 6 months
straight, but if I stop for two weeks to write my college essays<a
href="#fn2" class="footnote-ref" id="fnref2"
role="doc-noteref"><sup>2</sup></a>, I'm kind of back to square one.</p>
<p>I think the difference is just that <em>people who consistently
create have a surplus of ideas</em>. What I mean is that, as I am
setting a puzzle, or writing an essay, or programming a project, I have
the next 5 things I plan to create roughly laid out. And then it will
become 10 things, then 20 things, which I plan to do, and I will have to
put many of them on the "I may get to this eventually" back-burner. If
you need an idea to create something, then the way to consistently
create things is to have ideas in reserve.<a href="#fn3"
class="footnote-ref" id="fnref3" role="doc-noteref"><sup>3</sup></a></p>
<p>Notably, this surplus being the differences means <em>you have to
keep your momentum going</em>. Consistency is largely not a product of
experience, or even of any trait inherent to <em>you</em>, but a product
of your previous ideas leading into your next ones. If at any point the
ball stops rolling, you will have to get it started again. How
experience helps is by making it easier to get started (again): when I
first wrote math problems, it took me half a year to start writing good
stuff, but now I think it'd only take a month or so to get back into the
groove.<a href="#fn4" class="footnote-ref" id="fnref4"
role="doc-noteref"><sup>4</sup></a></p>
<h2 id="the-difference-between-creating-and-solving">The difference
between creating and solving</h2>
<p>When you're doing a math test or solving a puzzle, you know for sure
that there is some reasonable set of steps you can take to find the
solution. But when you are (say) setting a puzzle, by default you have
no idea whether there is a solution or not. You can develop intuition
and tools to give you an indication, typically a negative one. Knowing
that there are no solutions (i.e. your puzzle is overconstrained) is
helpful, but it does not directly give you a solution.</p>
<p>This is important because it changes when you should give up. When
you are doing a math test, the only reason to give up is if you don't
know something. In other words, giving up indicates that there is a
problem <em>that eventually should be fixed</em>. Giving up on
<em>solving</em> a sudoku puzzle means you can improve your depth, or
your consistency, or a variety of other things. But giving up on
<em>setting</em> a puzzle means <em>there is a problem not worth
fixing</em>.</p>
<p>Puzzles are inherently broken until you finish setting them; it's
just a question of degree. So you have to ask yourself, how much work do
I have to do to finish this puzzle, <a href="two-kinds-of-bad">is it
easier to just start over</a>, and how good could the end result
realistically be? And when you give up, the information it gives you is
not always "you should focus on X". Often, it can be, "you should ignore
idea Y because it turned out to be worthless in the end". Oh well.<a
href="#fn5" class="footnote-ref" id="fnref5"
role="doc-noteref"><sup>5</sup></a></p>
<section id="footnotes" class="footnotes footnotes-end-of-document"
role="doc-endnotes">
<hr />
<ol>
<li id="fn1"><p>Well, really, this essay is priming you to be primed.
Wanting to create something in general is not going to directly work,
you have to have a specific idea. Which is why, if I wanted to be more
accurate, I'd have to add another layer of indirection.<a href="#fnref1"
class="footnote-back" role="doc-backlink">↩︎</a></p></li>
<li id="fn2"><p>And this is why I hate college essays: they completely
kill the momentum of high school seniors for a semester. No wonder
everyone has senioritis second semester, sheesh.<a href="#fnref2"
class="footnote-back" role="doc-backlink">↩︎</a></p></li>
<li id="fn3"><p>This is why it's important to log your ideas. Secure
your reserves!!<a href="#fnref3" class="footnote-back"
role="doc-backlink">↩︎</a></p></li>
<li id="fn4"><p>I have been writing problems on and off (like once every
2 or 3 months), but that is a far cry from consistency. I am not
consistently writing problems write now, because, well, there is <a
href="https://puzz.dennisc.net">something else</a> I am consistently
writing.<a href="#fnref4" class="footnote-back"
role="doc-backlink">↩︎</a></p></li>
<li id="fn5"><p>It's possible to just botch up execution of an idea! I
tried (for about 10 or so minutes) to set a Kakuro Sudoku with a
different layout before I started setting the one on my <a
href="https://puzz.dennisc.net/#kakuro-sudoku">puzzle page</a>, and the
puzzle I was trying to set would probably have been terrible, but that
doesn't mean Kakuro Sudoku is a bad idea! It just meant that my layout
was a bad idea. So when you are trying to figure out what you should do
differently after giving up, think about the reason you gave up.<a
href="#fnref5" class="footnote-back" role="doc-backlink">↩︎</a></p></li>
</ol>
</section>]]></description>
	<pubDate>15 Jan 2023</pubDate>
</item>
<item>
	<title>Unique Readability</title>
	<link>https://dennisc.net/writing/blog/unique-readability.md</link>
	<description><![CDATA[<p><a href="inductive-structures">Last time</a> we
established the concept of an <strong>inductive structure</strong>.
Before we get to what unique readability, we'll have to talk a little
more about inductive structures.</p>
<p>We will use <span class="math inline">dom <em>f</em></span> to refer
to the domain of <span class="math inline"><em>f</em></span> in these
notes.</p>
<p>Also, from now on, when we say "the closure of <span
class="math inline">(<em>X</em>, <em>F</em>)</span>", we mean the
<strong>minimal</strong> set <span
class="math inline"><em>Y</em> ⊃ <em>X</em></span> such that <span
class="math inline"><em>Y</em></span> is closed under <span
class="math inline"><em>F</em></span>.</p>
<h2 id="arity">Arity</h2>
<p>Before, we were dealing with functions <span
class="math inline"><em>f</em></span> that possibly had tuples of
different sizes in its domain. For instance, maybe <span
class="math inline"><em>f</em></span> can take <span
class="math inline">2</span> arguments sometimes, and <span
class="math inline">3</span> arguments at other times. For the purposes
of an inductive structure, we can decompose such a function into <span
class="math inline"><em>f</em><sub>2</sub></span> and <span
class="math inline"><em>f</em><sub>3</sub></span>, the subsets of the
functions that take <span class="math inline">2</span> and <span
class="math inline">3</span> functions respectively. This would not
alter the closure whatsoever, so for the remainder of these notes we
will make that simplification.</p>
<p>If a function <span class="math inline"><em>f</em></span> takes <span
class="math inline"><em>n</em></span> inputs, then we say it is <span
class="math inline"><em>n</em></span>-ary. Alternatively, we say that
<span class="math inline"><em>n</em></span> is its arity. Both terms are
synonymous.</p>
<h2 id="induction">Induction</h2>
<blockquote>
<p><strong>Theorem.</strong> Let <span
class="math inline"><em>P</em></span> be some property and <span
class="math inline">(<em>X</em>, <em>F</em>)</span> be an inductive
structure. If <span class="math inline"><em>P</em></span> is a property
such that</p>
<ul>
<li>all <span class="math inline"><em>a</em> ∈ <em>X</em></span> satisfy
<span class="math inline"><em>P</em></span></li>
<li>for all <span class="math inline"><em>f</em> ∈ <em>F</em></span> and
all tuples <span
class="math inline">(<em>a</em><sub>0</sub>, …, <em>a</em><sub><em>n</em> − 1</sub>) ∈ dom(<em>f</em>)</span>,
if all <span class="math inline"><em>a</em><sub><em>i</em></sub></span>
satisfy <span class="math inline"><em>P</em></span> then <span
class="math inline"><em>f</em>(<em>a</em><sub>0</sub>, …, <em>a</em><sub><em>n</em> − 1</sub>)</span>
does too.</li>
</ul>
<p>then all elements in the closure of <span
class="math inline">(<em>X</em>, <em>F</em>)</span> satisfy <span
class="math inline"><em>P</em></span> as well.</p>
</blockquote>
<p>This is what a proof by induction looks like. First we prove the base
case: all <span class="math inline"><em>a</em> ∈ <em>X</em></span>
satisfy <span class="math inline"><em>P</em></span>. Then we prove the
inductive step: applying a function <span
class="math inline"><em>f</em></span> to a tuple of stuff that satisfies
<span class="math inline"><em>P</em></span> spits out something that
also satisfies <span class="math inline"><em>P</em></span>.</p>
<p>Consider the inductive structure <span
class="math inline">({0}, {+1})</span> that generates the natural
numbers. Whenever we do a standard proof by induction, this is the
closure we are implicitly using. But hopefully you see just how powerful
this theorem is.</p>
<blockquote>
<p><strong>Outline of proof.</strong> Recall how we constructed sets
<span class="math inline"><em>X</em><sub><em>n</em></sub></span> to show
that <span class="math inline">(<em>X</em>, <em>F</em>)</span> has a
closure. Now we can inductively prove that every <span
class="math inline"><em>a</em> ∈ <em>X</em><sub><em>n</em></sub></span>
satisfies <span class="math inline"><em>P</em></span>.</p>
</blockquote>
<h2 id="motivating-example-propositional-logic">Motivating example:
propositional logic</h2>
<p>These notes will assume a little bit of CS knowledge and no knowledge
of propositional logic. If you know the latter, you can probably skim or
even entirely skip this section.</p>
<p>So perhaps you are familiar with boolean operators such as</p>
<pre><code>(a &amp;&amp; (!b)) || c</code></pre>
<p>Propositional logic works a similar way: we have formulae composed of
propositional letters --- like <span
class="math inline"><em>a</em></span>, <span
class="math inline"><em>b</em></span>, and <span
class="math inline"><em>c</em></span> are in the example above, though
they can be anything --- and operators like <code>&amp;&amp;</code>,
<code>||</code>, and <code>!</code> that act on some number of
propositional letters. However, in classical logic (the form of
propositional logic we usually study) we use different symbols to
represent the AND, OR, and NOT operators: they are <span
class="math inline">∧</span>, <span class="math inline">∨</span>, and
<span class="math inline">¬</span>, respectively.</p>
<p>Well, the formulae in a propositional logic can also be represented
as a closure of an inductive structure! For example, consider an
inductive structure <span
class="math inline">({<em>a</em>, <em>b</em>, <em>c</em>}, {∧, ∨})</span>
such that <span
class="math inline">∧(<em>a</em>, <em>b</em>) = (<em>a</em> ∧ <em>b</em>)</span>.
Note that there is an <span class="math inline">∧</span> function that
returns a string with an <span class="math inline">∧</span> symbol, and
the two are not the same. Furthermore, note that the <span
class="math inline">(</span> and <span class="math inline">)</span>
characters are part of the outputted string. We can similarly define
<span class="math inline">∨(<em>a</em>, <em>b</em>)</span>.</p>
<p>Here's why we need the parentheses: ignore for a second what you know
about operator precedence. Consider a formula like <span
class="math inline"><em>a</em> ∧ <em>b</em> ∨ <em>c</em></span>. Should
it represent <span
class="math inline">(<em>a</em> ∧ <em>b</em>) ∨ <em>c</em></span>, or
should it represent <span
class="math inline"><em>a</em> ∧ (<em>b</em> ∨ <em>c</em>)</span>?
Another way to think of it is, without the parentheses, how was this
propositional formula inductively generated: as <span
class="math inline">∧(<em>a</em>, ∨(<em>b</em>, <em>c</em>))</span>, or
as <span
class="math inline">∨((<em>a</em> ∧ <em>b</em>), <em>c</em>)</span>?
Thus it is useful for formulae to be generated in one unique way. It is
useful for propositional formulae to be <strong>uniquely
readable</strong> (which they are, solely because of the
parentheses).</p>
<h2 id="unique-readability">Unique readability</h2>
<blockquote>
<p><strong>Definition (Unique Readability).</strong> An inductive
structure <span class="math inline">(<em>X</em>, <em>F</em>)</span> is
uniquely readable if and only if for every <span
class="math inline"><em>y</em></span> in its closure <span
class="math inline"><em>Y</em></span>, <em>exactly</em> one of the
following conditions hold:</p>
<ul>
<li><span class="math inline"><em>y</em> ∈ <em>X</em></span></li>
<li>there is exactly one <span
class="math inline"><em>f</em> ∈ <em>F</em></span> and exactly one tuple
<span
class="math inline">(<em>a</em><sub>0</sub>, …, <em>a</em><sub><em>n</em> − 1</sub>) ∈ 
dom <em>f</em></span>. such that <span
class="math inline"><em>f</em>(<em>a</em><sub>0</sub>, …, <em>a</em><sub><em>n</em> − 1</sub>) = <em>y</em></span>
and <span
class="math inline"><em>a</em><sub><em>i</em></sub> ∈ <em>Y</em></span>
for <span
class="math inline">0 ≤ <em>i</em> &lt; <em>n</em></span>.</li>
</ul>
</blockquote>
<p>Note that the inductive structure <span
class="math inline">({0}, {+1})</span> is uniquely readable. Try proving
this yourself if you don't understand why this is true!</p>
<p>This notion of unique readability leads to the concept of defining a
function recursively. We will first explore the properties we generally
want a definition by recursion to have, then establish a theorem that
formalizes all of these concepts.</p>
<p>First, note that a definition by recursion does not always go off
without a hitch. Consider some inductive structure <span
class="math inline">(<em>X</em>, <em>F</em>)</span> with <span
class="math inline"><em>a</em></span>, <span
class="math inline"><em>b</em></span>, <span
class="math inline"><em>c</em> ∈ <em>X</em></span> and <span
class="math inline"><em>f</em></span>, <span
class="math inline"><em>g</em> ∈ <em>F</em></span>. Then if <span
class="math inline"><em>f</em>(<em>a</em>) = <em>c</em></span> and <span
class="math inline"><em>g</em>(<em>b</em>) = <em>c</em></span>, a
recursive definition based on <span
class="math inline"><em>f</em></span> and <span
class="math inline"><em>g</em></span> might run into issues --- what if
<span
class="math inline"><em>f</em>(<em>a</em>) ≠ <em>g</em>(<em>b</em>)</span>?
Guaranteeing this is true in general is hard, so instead we want there
to be one unique set of inputs that generates this output. In other
words, we want <em>injectivity</em>, which comes from <em>unique
readability</em>.</p>
<p>Here is our wishlist for a definition by recursion. For our starting
set <span class="math inline"><em>X</em></span> in <span
class="math inline">(<em>X</em>, <em>F</em>)</span> with closure <span
class="math inline"><em>Y</em></span>, we want to specify:</p>
<ul>
<li>a subset of a function <span class="math inline"><em>G</em></span>
on <span class="math inline"><em>X</em></span></li>
<li>specify how to compute <span
class="math inline"><em>G</em>(<em>y</em>)</span> for <span
class="math inline"><em>y</em> ∈ <em>X</em> \ <em>Y</em></span> by
taking the unique <span class="math inline"><em>f</em></span> and unique
tuple <span
class="math inline">(<em>a</em><sub>0</sub>, …, <em>a</em><sub><em>n</em> − 1</sub>)</span>,
and then defining <span
class="math inline"><em>G</em>(<em>y</em>)</span> using <span
class="math inline"><em>f</em></span>, <span
class="math inline"><em>a</em><sub>0</sub></span>, <span
class="math inline">…</span>, <span
class="math inline"><em>a</em><sub><em>n</em> − 1</sub></span>, <span
class="math inline"><em>G</em>(<em>a</em><sub>0</sub>)</span>, <span
class="math inline">…</span>, <span
class="math inline"><em>G</em>(<em>a</em><sub><em>n</em> − 1</sub>)</span>.</li>
</ul>
<p>More broadly, we can define a function <span
class="math inline"><em>G</em></span> on a closure <span
class="math inline"><em>Y</em></span> just by looking at the starting
set <span class="math inline"><em>X</em></span> and a set of
compositions on elements in the starting set <span
class="math inline"><em>X</em></span> to define <span
class="math inline"><em>G</em>(<em>y</em> ∈ <em>Y</em> \ <em>X</em>)</span>.</p>
<p>Of course, for the reasons we have just established, <span
class="math inline">(<em>X</em>, <em>F</em>)</span> should be uniquely
readable.</p>
<p>Now we're ready to formalize this idea.</p>
<blockquote>
<p><strong>Theorem (Definition by recursion).</strong> Consider a
uniquely readable inductive structure <span
class="math inline">(<em>X</em>, <em>F</em>)</span> with closure <span
class="math inline"><em>Y</em></span>. If</p>
<ul>
<li>we are given a function <span
class="math inline"><em>G</em><sub>0</sub></span> with <span
class="math inline"><em>G</em><sub>0</sub>: <em>X</em> → <em>Z</em></span></li>
<li>for every <span class="math inline"><em>f</em> ∈ <em>F</em></span>,
if <span class="math inline"><em>f</em></span> is <span
class="math inline"><em>n</em></span>-ary, we are given a <span
class="math inline">2<em>n</em></span>-ary function <span
class="math inline"><em>H</em><sub><em>f</em></sub></span> where <span
class="math inline">dom
<em>H</em><sub><em>f</em></sub> = <em>Y</em><sup><em>n</em></sup> × <em>Z</em><sup><em>n</em></sup></span>,</li>
</ul>
<p>then there is a unique function <span
class="math inline"><em>G</em></span> such that</p>
<ul>
<li><span class="math inline">dom <em>G</em> = <em>Y</em></span></li>
<li>for all <span class="math inline"><em>x</em> ∈ <em>X</em></span>, we
have <span
class="math inline"><em>G</em>(<em>x</em>) = <em>G</em><sub>0</sub>(<em>x</em>)</span></li>
<li>for all <span class="math inline"><em>f</em> ∈ <em>F</em></span> and
all <span
class="math inline">(<em>a</em><sub>0</sub>, <em>a</em><sub>1</sub>, …, <em>a</em><sub><em>n</em> − 1</sub>) ∈ <em>Y</em><sup><em>n</em></sup></span>
and <span
class="math inline">(<em>a</em><sub>0</sub>, <em>a</em><sub>1</sub>, …, <em>a</em><sub><em>n</em> − 1</sub>) ∈ dom
<em>f</em></span>, we have <span
class="math inline"><em>G</em>(<em>f</em>(<em>a</em><sub>0</sub>, …, <em>a</em><sub><em>n</em> − 1</sub>)) = <em>H</em><sub><em>f</em></sub>(<em>a</em><sub>0</sub>, …, <em>a</em><sub><em>n</em> − 1</sub>, <em>G</em>(<em>a</em><sub>0</sub>), …, <em>G</em><sub><em>a</em><sub><em>n</em> − 1</sub></sub>)</span>.</li>
</ul>
</blockquote>
<p>This specifies a unique way to extend <span
class="math inline"><em>G</em><sub>0</sub></span> given an inductive
structure and <span
class="math inline"><em>H</em><sub><em>f</em></sub></span> for each
<span class="math inline"><em>f</em> ∈ <em>F</em></span>.</p>
<blockquote>
<p><strong>Outline of proof</strong>: Recall the definition of <span
class="math inline"><em>X</em><sub><em>n</em></sub></span> when we
showed the existence of a closure. We show by inducting on <span
class="math inline"><em>n</em></span> that there exists only one
possible extension of <span
class="math inline"><em>G</em><sub><em>n</em> − 1</sub></span>, whose
domain is <span
class="math inline"><em>X</em><sub><em>n</em> − 1</sub></span>, onto
<span class="math inline"><em>G</em><sub><em>n</em></sub></span>, whose
domain is <span
class="math inline"><em>X</em><sub><em>n</em></sub></span>.</p>
</blockquote>
<p>Here is an example of a definition by recursion on the Fibonacci
sequence. Our inductive structure is <span
class="math inline">({0, 1}, {<em>f</em>})</span> where <span
class="math inline"><em>f</em>(<em>n</em>, <em>n</em> + 1) = <em>n</em> + 2</span>
for <span class="math inline"><em>n</em> ≥ 0</span>, and its domain is
only pairs of the form <span
class="math inline">(<em>n</em>, <em>n</em> + 1)</span> for <span
class="math inline"><em>n</em> ≥ 0</span>.</p>
<p>Now we define an initial function <span
class="math inline"><em>G</em><sub>0</sub></span> such that <span
class="math inline"><em>G</em><sub>0</sub>(0) = 0</span> and <span
class="math inline"><em>G</em><sub>0</sub>(1) = 1</span>. Define <span
class="math inline"><em>H</em><sub><em>f</em></sub>(<em>n</em>, <em>n</em> + 1, <em>G</em>(<em>n</em>), <em>G</em>(<em>n</em> + 1)) = <em>G</em>(<em>n</em>) + <em>G</em>(<em>n</em> + 1)</span>,
and note <span
class="math inline"><em>G</em>(<em>n</em> + 2) = <em>G</em>(<em>f</em>(<em>n</em>, <em>n</em> + 1)) = <em>H</em><sub><em>f</em></sub>(<em>n</em>, <em>n</em> + 1, <em>G</em>(<em>n</em>), <em>G</em>(<em>n</em> + 1)) = <em>G</em>(<em>n</em>) + <em>G</em>(<em>n</em> + 1)</span>.
Yay! Our idea of unique readability and a definition of recursion makes
sense on a simple function like the Fibonacci sequence, even if it is a
little convoluted.</p>
<p>Though it is convoluted and we will not usually need to construct
recursive functions like this, it is good to know what is happening
under the hood. And it is good to understand why the Fibonacci sequence
gives you a well-defined, unique value of <span
class="math inline"><em>f</em>(<em>x</em>)</span> for all <span
class="math inline"><em>x</em> ∈ ℕ</span>. It is because the Fibonacci
sequence is equivalent to a function <span
class="math inline"><em>G</em></span> on a uniquely readable closure
<span class="math inline">(<em>X</em>, <em>F</em>)</span>, as we have
just shown.</p>]]></description>
	<pubDate>8 Sep 2023</pubDate>
</item>
<item>
	<title>How to construct a puzzle</title>
	<link>https://dennisc.net/writing/essays/how-to-construct-a-puzzle.md</link>
	<description><![CDATA[<p>After publishing <a
href="/writing/essays/puzzle-construction">some musings</a> on puzzle
construction and outlining the process in private to a few people, I
thought I might as well write down the process in one place. The one
thing I will omit is what software to use because I have already written
about that before.</p>
<p>Before reading past the first section ("Solve puzzles") you should
solve <a href="https://puzz.dennisc.net/#hedge-maze">Hedge Maze</a>. If
you are having trouble with it I recommend trying <a
href="https://puzz.dennisc.net/#wings">Wings</a> first.</p>
<h2 id="getting-started-solve-puzzles">Getting started: solve
puzzles</h2>
<blockquote>
<p>Solve a lot of puzzles. And learn something from them.</p>
</blockquote>
<p>Puzzles are about communicating and showcasing logical ideas. So the
first step is to learn some logical ideas. And the only way to do that
is by solving puzzles. Lots of them.</p>
<p>But you can't be solving any old puzzles. The puzzles you solve
should be teaching you things --- the <em>right</em> things --- so they
need to be good. And you need to be able to tell which ones are good. In
other words, you need to develop a taste in puzzles.</p>
<p>This means you need to get off of sudoku.com (or any other similar
site). These puzzles are computer generated. You are solving puzzles to
study ideas. <em>Computers can't have ideas.</em><a href="#fn1"
class="footnote-ref" id="fnref1" role="doc-noteref"><sup>1</sup></a></p>
<p>So where do you find good puzzles? If you are newer to
puzzle-solving, I recommend checking out <a
href="https://gmpuzzles.com">gmpuzzles.com</a> and some shorter videos
on <a href="https://www.youtube.com/c/CrackingTheCryptic">Cracking the
Cryptic</a>. If you have a little more experience, try longer Cracking
the Cryptic videos or <a
href="https://logic-masters.de/Raetselportal/?chlang=en">Logic Masters
Germany</a>.</p>
<p>I also have my own <a href="/puzz-rec">recommendations for
beginners</a>. Furthermore I recommend</p>
<ul>
<li><a href="https://puzz.dennisc.net/#equations">Equations</a></li>
<li><a href="https://puzz.dennisc.net/#thats-what-i-mean">That's What I
Mean</a></li>
<li><a href="https://puzz.dennisc.net/#wings">Wings</a></li>
</ul>
<p>for beginners, in that order.</p>
<h2 id="the-break-in-logical-ideas-interact">The break-in: logical ideas
interact</h2>
<blockquote>
<p>With some logical ideas under your belt, ask yourself: how do I force
them to interact in an interesting way?</p>
</blockquote>
<p>At the start there are a lot of things you can do. The vast majority
of them lead to nothing useful. Your job is to restrict the search space
so that it is feasible to find an interesting break-in. This means it is
acceptable, and even encouraged, to set some almost arbitrary
constraints on yourself.</p>
<p>By way of analogy, imagine you were designing a logo for a company.
You would much rather have a set of reasonable requirements than nothing
despite the fact it shrinks the space of good logos to choose from.
Because while a set of requirements may rule out some logos that would
work perfectly well for the company, it rules out far more logos that
would not work well. The important fact is that the <em>proportion</em>
of good logos in the search space increases. The same goes for puzzles.
This is why even <em>stupid</em> inspirations can work: as idiotic as
they are, they still considerably shrink the search space.</p>
<p>Now I will use my puzzle <a
href="https://puzz.dennisc.net/#hedge-maze">Hedge Maze</a> as a case
study. (If you haven't solved it yet, now is the time!)</p>
<p>The break-in for the puzzle uses two ideas. As far as I know they do
not have formal names, so I will call them "Push" and "Square
restriction". (By the way, <a
href="https://puzz.dennisc.net/#wins">Wings</a> is a good example of
"Push". That is why I recommended you solve it if you were having
trouble with Hedge Maze.)</p>
<h3 id="push">Push</h3>
<p>If we restrict the digit 1 to the green cells in boxes 1 and 3 as
shown, then 1 must appear in one of the red cells in box 2.</p>
<p><img src="/writing/essays/how-to-construct-a-puzzle/push.svg"></p>
<p>This is because there already are two 1's in rows 1 and 2. Thus rows
1 and 2 cannot have any more 1's, forcing the 1 in box 2 to appear in
row 3.</p>
<h3 id="square-restriction">Square restriction</h3>
<p>If we restrict the digit 9 from the red squares in boxes 1, 3, 7, 9,
then the digit 9 must appear somewhere in the indicated green squares in
boxes 1, 3, 7, 9. Furthermore, the digit 9 is restricted from the yellow
squares in boxes 2, 4, 6, 8 as a consequence.</p>
<p><img src="/writing/essays/how-to-construct-a-puzzle/square-restriction.svg"></p>
<h3 id="the-interaction">The interaction</h3>
<p>So if we put cages with sufficiently small sums in the following
arrangement:</p>
<p><img src="/writing/essays/how-to-construct-a-puzzle/init.svg"></p>
<ul>
<li>the low digits in the cages will be pushed</li>
<li>the high digits will perform a square restriction</li>
</ul>
<h3 id="applying-more-pressure-with-arrows">Applying more pressure with
arrows</h3>
<p><em>Square restriction</em> was applying fairly strong pressure to
the puzzle and <em>Push</em> was not doing much as of the moment. I
wanted to force large digits for two reasons:</p>
<ul>
<li>push the <em>Square restriction</em> on 8 to its limits,</li>
<li>and make <em>Push</em> behave interestingly by forcing some cages to
only have two digits in common (because their common digits are pushed
to the row with the arrow bulb).</li>
</ul>
<p>To that effect I used a common arrow trick: the sum of the digits on
the bulbs must equal the sum of the digits on the arrows. The sum of the
digits on the bulb is at most 15. The sum of 5 digits in the same box is
at least 15.</p>
<h3 id="motivation-and-takeaways">Motivation and takeaways</h3>
<p>So how did I come up with this break-in to begin with? It was not by
explicitly saying, "I will make <em>Push</em> and <em>Square
restriction</em> interact in exactly this fashion".<a href="#fn2"
class="footnote-ref" id="fnref2" role="doc-noteref"><sup>2</sup></a>
Rather, I decided to put down small-sum cages because my intuition told
me they would apply pressure to each other in an interesting way. Of
course, my intuition also did recognize the <em>Push</em> and <em>Square
restriction</em> implication immediately after; that's why I decided to
keep pushing the idea rather than dismissing it as a boring arrangement
of random clues.</p>
<p>This process with the cages took no more than 10 seconds in my head.
After working out the implications with the cages, it took me at most a
minute to decide on adding arrows. This doesn't mean that I can bust out
a break-in to a puzzle that quickly. But it does mean that I can
recognize a good idea and discard bad ideas very fast. And in a creative
process, being able to iterate fast is vital.</p>
<p>This is why it is so important to solve puzzles and learn from them.
Otherwise I would not have honed my intuition to recognize this
arrangement would apply just enough pressure to draw interesting
conclusions without breaking the puzzle outright.</p>
<h2 id="finishing-the-puzzle-perseverance">Finishing the puzzle:
perseverance</h2>
<blockquote>
<p>Just do it.</p>
</blockquote>
<p>After applying a sufficient amount of pressure on the puzzle through
the break-in, you are no longer <em>inventing</em> a good puzzle.
Instead you are <em>discovering</em> one of the few good sequences of
clues to finish it. At the start there are a lot of interesting things
you can do. Now at each step, you need to discover the one of the few
things you can do to advance the puzzle forward yet still be
interesting.</p>
<p>Though I say you are "finishing" the puzzle, the length of this stage
can vary wildly. Sometimes you can be almost done after setting the
break-in. At other times you might have 90% of the puzzle left to set.
An example of the latter: the break-in of <a
href="https://puzz.dennisc.net/#fillomino-cc">Fillomino Chaos
Construction</a> consisted of the clues in the bottom-right 5x5
corner.</p>
<p><img src="https://puzz.dennisc.net/fillomino-cc.svg"></p>
<p>After setting that 5x5 corner, the puzzle was only around 10% done.
But after that, the puzzle was leading me. Each clue would leave an
interesting little interaction somewhere else, and so the process
continued until the puzzle was finished.</p>
<p>Sometimes the "interesting thing" to do is really complex, almost as
complex as the break-in itself. These are the kinds of things that are
hard to think of all at once, so you need to be willing to try things
out, even if they are not obviously promising at first. Another example
from Hedge Maze:</p>
<p><img src="/writing/essays/how-to-construct-a-puzzle/subtle.svg"></p>
<p>Look at the clues highlighted in green. They don't really do much on
their own, but putting them all together they do a <em>lot</em>, and in
very subtle ways. Because it is so subtle --- unlike the break-in, which
screams "I am sledgehammering this puzzle into submission" --- it is not
the kind of thing that is easy to come up with, all at once.</p>
<p>So one tip is not to blindly follow the greedy algorithm. Though it
is <em>often</em> the right thing to do, it is not <em>always</em>.
Sometimes setting up clues that don't do a lot on their own but feel
like they have the potential to set up subtle interactions later is the
right thing to do.</p>
<section id="footnotes" class="footnotes footnotes-end-of-document"
role="doc-endnotes">
<hr />
<ol>
<li id="fn1"><p>Why can't computers --- or more specifically, ML models
--- generate even mediocre logic puzzles, despite being able to write
and produce art at a decent level? Though I'm no ML expert, here are my
guesses:</p>
<ul>
<li><p>Nobody has really tried. Logic puzzles are just not popular
enough to justify the effort required to train a model in generating
them. Plus, there isn't even enough data to do anything besides generate
really bad classic and killer sudokus, something which can already be
done by brute force.</p></li>
<li><p>More fundamentally, ML is based on gradient descent, which
requires differentiablity and thus continuity.</p>
<p>Image generation, for example, is a quite continuous process. If I
change one pixel's RGB values by a little, the resulting imaes is
virtually the same. And if I replace one word of a story with a
near-synonym, the meaning is virtually the same as well.</p>
<p>But in a puzzle, if I change a given 1 to a 2, chances are that I
have completely broken the puzzle. Puzzles are a chaotic environment:
small changes in input lead to big changes in the outcome. So I suspect
training an ML model to even <em>recognize</em> good puzzles is well
beyond our current capabilities, let alone <em>construct</em>
them.</p></li>
</ul>
<a href="#fnref1" class="footnote-back" role="doc-backlink">↩︎</a></li>
<li id="fn2"><p>To be clear, you <em>can</em> set puzzles by explicitly
trying to make logical ideas interact. I just didn't this time.<a
href="#fnref2" class="footnote-back" role="doc-backlink">↩︎</a></p></li>
</ol>
</section>]]></description>
	<pubDate>13 Jun 2024</pubDate>
</item>
<item>
	<title>the semester in review</title>
	<link>https://dennisc.net/writing/blog/f24.md</link>
	<description><![CDATA[<p>What a crazy semester it's been! I've had some
ups, and I've certainly had some downs, but all in all I've had a really
fun time. I wanted to take some time to celebrate the wins I've taken,
learn from the opportunities that slipped by, and reflect on the
semester.</p>
<h2 id="academics">academics</h2>
<p>Man, this might be the first semester I've experienced such a
profound level of burnout.</p>
<p>Objectively, the courseload I took on was similar to last
semester:</p>
<ul>
<li>Math Studies Analysis (this semester) was about as difficult as
Vector Analysis (last semester) for me.</li>
<li>15210 (Algos) was maybe a little bit harder than 15251 (Theoretical
CS) for me. (Well, the exams went a lot worse in the former, but the
effort I put in and the final grade I should be getting out are the
same.)</li>
<li>Model Theory was noticeably harder than Graduate Algebra,
particularly because the material came less naturally to me.</li>
<li>Randomized Algorithms was really chill, probably easier than even
Probability in Computing.</li>
<li>My gened this semester was a bit easier than the combination of the
two geneds I took last semester.</li>
</ul>
<p>But I found this schedule much more exhausting, and frankly, I didn't
really learn much outside of my classes this year; I simply did not have
the energy to care about much else. Maybe a large part of this is due to
living off-campus, with the commute time being quite non-trivial and
all. But I think that's not all there is to it, and maybe this is a
symptom of a fundamental shift in myself as a person.</p>
<p>I also think it is quite unfortunate that I did not learn as much as
I could have from all my classes. In particular, I've never stopped to
reflect about analysis, although in part this is due to its breakneck
pace. Unfortunately many of the definitions and proofs in Model Theory
don't really make sense to me (in the sense that I don't understand why
I should care), although reviewing Morley's Theorem has made things
start to tie together. And I really detested the algorithms course for
the entire semester, though after the final my opinion of it improved
drastically.</p>
<p>However, I have an entire month to reflect academically on the
courses I took, as well as learning a bit of algebraic geometry to
prepare for the spring. I hope that, academically, this semester does
not turn out wasted, and I am optimistic that I can make more out of it
in the coming month.</p>
<h2 id="social">social</h2>
<p>I think my social life really improved this semester! I had a lot of
good times, and while there were a few dry weeks in the semester where
nothing happened (which unfortunately dampened my mood), the rest of the
semester was packed with exciting events.</p>
<p>In no particular order, I</p>
<ul>
<li>went to frat parties,</li>
<li>went to a few houseparties hosted by friends,</li>
<li>hosted some parties myself,</li>
<li>went rock climbing with the boys after Sunday office hours,</li>
<li>went to the SCS ball,</li>
<li>helped<a href="#fn1" class="footnote-ref" id="fnref1"
role="doc-noteref"><sup>1</sup></a> host the first in a decade CS251
puzzlehunt!</li>
<li>bantered during grading/staff meeting/house parties/banquet with the
CS251 staff,</li>
<li>and got lots of froyo with my friends who live on Squirrel
Hill.</li>
</ul>
<p>Overall I had a lot of fun. I found myself in situations where I
wouldn't have been in last year (or earlier in my life), became a big
party person much to my own surprise, and made a few mistakes that I am
hopefully growing past.</p>
<h3 id="overanalyzing-different-kinds-of-parties">overanalyzing
different kinds of parties</h3>
<p>At the start of the semester, I thought that frat parties and
clubbing were more fun compared to the chiller houseparties that I'd go
to. But upon further reflection, I realized that my preferences had
flipped, and I think for good reason.</p>
<p>See, when you go clubbing or to a frat party, pretty much everyone
there is a stranger and inhibitions are lowered. This makes it a lot
easier to either walk up to people and talk to them (if you're actually
proactive) or be like me and hope that someone will come up to you if
you dance hard enough to the music (which has been surprisingly
effective for a shy guy like me :]). And there is a lot of fun in
chatting with random strangers and letting loose on the dance floor.
Because I don't drink, I don't wake up the next day with a hangover
which is really nice --- I can still plan events on Sunday morning with
my friends who don't party while the partygoers are recovering from what
I can only imagine is true agony. So from one perspective, parties are a
good way to let loose with no consequence.</p>
<p>But this is also the greatest weaknesses of frat parties/clubbing,
and what in my eyes makes houseparties so much more fun. While frat
parties are filled with random people, houseparties are chock full of
second degree connections, the "friends of friends". And as Po-Shen Loh
says, "the best way to approach socialization is with a BFS". There are
plenty of interesting people at these parties, and unlike frat parties,
it's much easier to form and strengthen connections with people
there.</p>
<p>Additionally, I think there are maybe three main barriers to overcome
when getting to be close with someone:</p>
<ol type="1">
<li><p>You literally have no idea who this person is/haven't formally
introduced yourselves. This one I think is actually a bit easier to
close (provided you do it at the right timing). If you are trying to
learn the names of your classmates, just try and make conversation with
them before the start of class in the first week. Especially in times
like orientation week, it is easy to get "name/major/where you're
from".</p>
<p>Unfortunately, I find this is usually not enough to form the start of
a friendship with someone. At least personally, I think the most
effective way is to actually have shared experiences together. Maybe
you're playing Smash in the dorm lounge and someone asks to join in. Or
you bond over your shared interest in algebraic geometry<a href="#fn2"
class="footnote-ref" id="fnref2" role="doc-noteref"><sup>2</sup></a> or
your favorite K-Pop group.<a href="#fn3" class="footnote-ref"
id="fnref3" role="doc-noteref"><sup>3</sup></a> For a lot of the people
I've gotten close to this way, I find that I don't even ask for their
name until it comes up naturally or when one of us is about to
leave.</p></li>
<li><p>You'll wave or say hi to them when you see them but you won't
actually have a conversation.</p></li>
<li><p>You'll talk to each other when you come across each other but you
don't actively make plans to hang out together.</p></li>
</ol>
<p>At a frat party, you often use the conversation starters of "What's
your name? What year/major? Where are you from?" And unsurprisingly, I
don't usually end up texting the people I meet at a frat party for long.
This is in stark contrast to a houseparty, where you can often break
past the second barrier for people who you know exist and think are cool
but haven't really had a chance to talk to yet. And if you've never met
a person before but they turn out to be a friend of a friend, you can at
least get to the "waving at each other" stage and potentially break the
second barrier at a later time (perhaps another houseparty).</p>
<p>Of course, there are times when you just know everyone at a house
party and it's more of catching up with friends and doing stupid stuff
together rather than meeting new people. But those are good times too,
even if they won't really advance your social life as much.</p>
<p>By the way, given that I think houseparties are such a good form of
socialization, it should come as no surprise that I attribute a lot of
my improved social life to all of my friends and I getting houses this
year. (After all, it would not be really possible to throw a houseparty
in a dorm...)</p>
<h3 id="opportunities-that-passed-me-by">opportunities that passed me
by</h3>
<p>I'm not the type to make the first move. This is a statement that is
usually applied to romance, but for me it applies much more broadly. For
example --- especially in freshman year --- I wouldn't wave at people I
"sort of knew but didn't know if I knew well enough to say hi to" unless
they waved at me first. And even then I'd check behind me to make sure
they weren't waving at anyone else.</p>
<p>My point is, I was the type of person who would wait for someone else
to first express friendliness or interest. When people were looking for
roommates, I pretty much let other people come to me rather than
proactively looking for a roommate. This may have been a good way to
feel wanted or popular, but it was not actually a good way to ensure my
roommates had similar interests, compatible personalities, and similar
living standards as myself.</p>
<p>In retrospect, this hesitation may have caused me to lose out on a
lot of opportunities, both with meeting individual people but moreso
with clubs/internships. Part of why I didn't try so hard to join a club
was because I feared looking stupid (if only to myself) if I tried to
join one and it ended up not panning out for some reason. Even still I
have this problem with just deciding to try new things, though I am
taking steps to have this break help me grow past that.</p>
<p>In the future, I would like to be part of some clubs and
organizations --- I will elaborate more on this when talking about my
goals over this break and the next semester.</p>
<p>Finally, I should probably reflect on why I was this way for so long.
A big part of it is that I am inherently just a somewhat shy person, and
also someone who maybe finds it hard to invest effort into new things.
For instance, there have been times when I very well could've manuevered
myself into starting a conversation with someone I ran into, but ended
up only just waving at them because I didn't feel like putting in that
emotional investment and energy. While I don't think I can ever be like
a business major and just talk to everyone I ever have the opportunity
to (it's really impressive how they manage to pull it off), I think I
could stand to proactively talk to more people more often.</p>
<h2 id="change-and-the-past">change and the past</h2>
<blockquote>
<p>if I lose it all</p>
<p>slip and fall</p>
<p>will you laugh at me?</p>
</blockquote>
<p>Having looked back at some of my older "social" posts, particularly
my graduation post, I've changed a lot. Comparing myself to senior year,
it almost feels as if I might as well have been a completely different
person back then.</p>
<p>I got a sense of fashion (thank god), my music tastes changed (from
almost 0% K-Pop to almost 100%), and I became a lot more extroverted. If
I talked to myself in high school, even senior year but especially
freshman or sophomore year, I think high school me would be shocked as
to who I've become. But at the same time there is a good bit of
continuity. I still am a massive nerd (obviously), enjoy puzzles (okay
maybe that's an extension of being a nerd), enjoy reading
manga/webtoons, and probably more I'm forgetting at the moment.</p>
<p>It's definitely a "two steps forward, one step back" kind of
situation though. I haven't been reading books or going on runs as
often, and I've become <a href="/writing/blog/exhaustion">more tired</a>
than I used to be. Another thing is that I get distracted more easily.
When I'm out, I'm listening to music on Spotify; when I'm at home, I'll
be rotting on YouTube or Instagram or playing Minecraft. It makes sense
why I'm academically fried now, because I used to lock in and study math
when I had nothing else to do. So part of what I hope to accomplish this
break is re-establish these good habits.</p>
<p>I have also fell out of touch with some old friends, even some who I
was close with during freshman year. I would like to be proactive in
getting back in touch with some of them at the start of the next
semester! But at the same time, as we diverge from our common interests
and lose shared connections, it sometimes makes sense for both of us to
move on in our lives, even if we both regard each other fondly. (I
watched <a href="https://www.youtube.com/watch?v=1e1n683_hc4">this
video</a> recently and it really resonated with me.) Still, it's not as
if I am spending 24/7 socializing, and I basically should be. There is
plenty of time to catch up with people, and I intend to be more
proactive about this at the start of the next semester.</p>
<p>Though when I'm back in my hometown with my high school friends, even
though all of us have changed (so many glowups, and so many former
academic weapons turning into bums), we can still harness that same
(degenerate) energy we had in the past when we're together. After
college ends, it won't be nearly as convenient to organize reunions, so
I want to make the most of the time that we have during the winter
(since so many people are working internships during the summer).</p>
<h2 id="goals-and-the-future">goals and the future</h2>
<p>I'm really looking forward to the future! Things I would like to get
into or get better at:</p>
<ul>
<li>Putting together some new fits. All of my stuff is from MUSINSA and
the range of styles I have right now is fairly narrow. I also want to
put together some more elaborate fits together too.</li>
<li>Relatedly, skincare and hairstyling; I've put a little bit of effort
into both and it's already paid such dividends, so I can only imagine
how much it'll pay off if I actively try for both of them.</li>
<li>Take vocal/hip-hop dance classes and just generally get better at
both.</li>
<li>Learn some algebraic geometry.</li>
<li>Start running/going to the gym/climbing again! (All of these stopped
because finals started rolling in...)</li>
<li>Cook more food!</li>
<li>Construct at least one logic puzzle during this break, and plan out
the logic puzzle course I am teaching in the spring.</li>
<li>Sleep more! And earlier!</li>
</ul>
<section id="footnotes" class="footnotes footnotes-end-of-document"
role="doc-endnotes">
<hr />
<ol>
<li id="fn1"><p>Okay, maybe "helped" is a bit generous of a descriptor
here...<a href="#fnref1" class="footnote-back"
role="doc-backlink">↩︎</a></p></li>
<li id="fn2"><p>Yeah at core I am still a nerd.<a href="#fnref2"
class="footnote-back" role="doc-backlink">↩︎</a></p></li>
<li id="fn3"><p>Which presently is ATEEZ but TXT and Stray Kids are up
there too.<a href="#fnref3" class="footnote-back"
role="doc-backlink">↩︎</a></p></li>
</ol>
</section>]]></description>
	<pubDate>16 Dec 2024</pubDate>
</item>
<item>
	<title>Two Kinds of Bad</title>
	<link>https://dennisc.net/writing/essays/two-kinds-of-bad.md</link>
	<description><![CDATA[<p>Let's say Alice and Bob are doing a competitive
programming contest like USACO, and they happen to be stuck on the same
problem that requires an <span
class="math inline"><em>O</em>(<em>n</em>log <em>n</em>)</span>
solution. Alice has an algorithm with <span
class="math inline"><em>O</em>(<em>n</em>log <em>n</em>)</span> time
complexity, but her implementation doesn't even compile. Perhaps she
doesn't know how to use C++ and thus the arrows in her <code>cin</code>s
and <code>cout</code>s are all in the wrong direction, or maybe the
indices in her for loops are off by one. Meanwhile, Bob can't get the
last few test cases because he has a perfectly working implementation of
an <span class="math inline"><em>O</em>(<em>n</em><sup>2</sup>)</span>
algorithm.</p>
<p>Which situation would you rather be in?</p>
<h2 id="against-local-optimizations">Against local optimizations</h2>
<p>In most situations you'd rather in Alice's situation: even if what
you have doesn't work at all, with a bit of debugging your code will do
exactly what you want. In contrast, no matter how much Bob improves his
code, whether he improves the constant factor by <span
class="math inline">10%</span> or <span class="math inline">100×</span>,
he'll be no closer to really solving the problem, besides whatever
intuition his <span
class="math inline"><em>O</em>(<em>n</em><sup>2</sup>)</span> algorithm
has given him.</p>
<p>The difference between Alice's code and Bob's code is that hers is
reparably bad while his is irreparably bad. With Alice, you can give
specific pointers to fix the code: line 11 is missing a semicolon, for
loops must be scoped by braces, etc. With Bob, all you can say is, "your
algorithm is <span
class="math inline"><em>O</em>(<em>n</em><sup>2</sup>)</span> where this
problem requires an <span
class="math inline"><em>O</em>(<em>n</em>log <em>n</em>)</span>
solution, start over".</p>
<p>If you accept that Alice's code is better than Bob's, then you accept
that it is possible for 0 points to be, at some intermediate point in
time, better than 200 points. And this is when you strictly define
"better" as "will get me more points in the end"! In other words, there
are cases where <strong>your score now is not the best predictor for
your final score</strong>.</p>
<p>I used competitive programming as my primary example because it's the
most precise: your optimizations can get you something tangible
(points). But a good non-technical analogue, though not as precise, is
writing.</p>
<p>When you revise your essays there are two things you can do: make
local optimizations, like fixing spelling or replacing awkward syntax,
or fundamentally expanding on and changing the ideas in your writing.<a
href="#fn1" class="footnote-ref" id="fnref1"
role="doc-noteref"><sup>1</sup></a></p>
<p>With writing, I find that it's easy to get stuck in the trap of local
optimizations. You can spend forever fixing up sentences while still
feeling doubtful about the whole essay. Conversely, I find that any
essay I end up publishing is one I like from the get-go, polished or
not.</p>
<p>When I say "writing" I don't just mean my essays. It took me a year
to write my first draft of my geometry textbook and I wasted the better
part of the next two years making local optimizations. I ended up
starting over when I realized that most of my exposition didn't really
have a core --- it was just a collection of shoddy notes.</p>
<h2 id="reparable-vs.-irreparable">Reparable vs. Irreparable</h2>
<p>The "two kinds of bad" I alluded to in the title are the reparably
bad and the irreparably bad, and you really don't want the latter (it's
not fixable, by <em>definition</em>). Given this, I think people don't
think enough about the difference between the reparably and irreparably
bad. Because for the former, the best thing to do is to find and stamp
out the flaws, whereas for the latter you should just give up and start
over.</p>
<p>So what does irreparably bad mean? The pedantic might point out that
technically, anything can be repaired if you try hard enough. But that's
not a particularly useful definition. Instead, I think something is
irreparably bad if it takes less effort to start from scratch than to
fix it.</p>
<p>In elementary school (and television<a href="#fn2"
class="footnote-ref" id="fnref2" role="doc-noteref"><sup>2</sup></a> for
elementary schoolers) you get told to never give up. This advice is
terrible, because presumably the reason you don't give up is because you
can make things better or accomplish your goal or whatever it is. But
unlike Attack on Titan<a href="#fn3" class="footnote-ref" id="fnref3"
role="doc-noteref"><sup>3</sup></a>, in real life you will rarely solve
your problems just by approaching them headstrong without thinking. If
your goal is "I want to solve this USAMO geo" you don't just commit
yourself to bashing it, you have to learn to give up when it doesn't pan
out. And when I say "when it doesn't pan out", I really mean "when you
notice bashing is an irreparably bad approach."</p>
<p>But when you're working on something and a part of it is
fundamentally flawed, the situation isn't as bleak as "you wasted all of
your time, now start over". Take math contests as an example: there are
multiple ways a contest draft can be fundamentally flawed. It might be
the case that all the problems are bad, which is the worst case scenario
since writing problems is the bulk of the difficulty in compiling a good
contest. But it could also be a bad contest format, or a bad
subject/difficulty distribution.<a href="#fn4" class="footnote-ref"
id="fnref4" role="doc-noteref"><sup>4</sup></a> Even if you have to
start over, like I did with my geometry textbook, you will still have
learned something through the process.</p>
<p>Even on the scale of individual problems there are reparable flaws
and irreparable flaws. A reparable problem might have typoes, a bad
answer extract, or a stupid formulation, whereas an irreparable problem
just does not have an interesting idea.</p>
<p>It's not entirely accurate for me to say "fundamental flaws",
emphasis on "flaws". More often than not, something is irreparably bad
if it's <em>missing</em> something, rather than having something
extra.<a href="#fn5" class="footnote-ref" id="fnref5"
role="doc-noteref"><sup>5</sup></a> This is mostly semantics, though,
and you can probably just substitute "fundamentally flawed" with
"irreparably bad."</p>
<p>Ideally whatever you make isn't flawed in any way, fundamentally or
not. But especially for first attempts (e.g. first drafts of a novel),
it's usually not possible to make sure everything is perfect as you're
coming up with it. Your time, energy, and abilities are all limited.</p>
<p>When people tell you the first thing you write will be bad they're
usually right. In general, even if it isn't your first rodeo, what you
make is going to be flawed in some way. But you can control, to some
extent, what flaws you catch and how quickly you catch them. <strong>You
can control what kind of bad it is.</strong> So when you're writing
something, whether it be a program, a novel, an essay, or a textbook,
spend more time making sure there aren't any irreparable flaws. The
reparable flaws are just that: <em>reparable</em>. You can always deal
with them later.<a href="#fn6" class="footnote-ref" id="fnref6"
role="doc-noteref"><sup>6</sup></a></p>
<section id="footnotes" class="footnotes footnotes-end-of-document"
role="doc-endnotes">
<hr />
<ol>
<li id="fn1"><p>On that note, I think English class totally misses the
point of writing because it focuses on minuta like not starting your
sentences with "and" or MLA citations, instead of letting people
discover, "What kind of writing am I good at, what do I want to write,
and how do I want to go about it?"</p>
<p>I'm pretty pessimistic about English classes because you can't teach
coming up with ideas. You can learn it and get better at it the same way
you can get better at running, but it's something that comes mostly with
practice and experience.<a href="#fnref1" class="footnote-back"
role="doc-backlink">↩︎</a></p></li>
<li id="fn2"><p>When I was that age anime was the worst offender. Maybe
it's different now.<a href="#fnref2" class="footnote-back"
role="doc-backlink">↩︎</a></p></li>
<li id="fn3"><p>(Spoiler alert, although at the time of writing anyone
who's watched the anime knows this already.) When I say "Attack on
Titan" I mean "Eren screaming that he'll kill the titans." And hell,
when the existence of Marley is revealed, Eren realizes "I can't just
kill Titans, my way of thinking is <strong>fundamentally flawed</strong>
because Titans are Eldians and Marley is going to invade the crap out of
us". So even in anime, you can't just decide you want to solve X really
really badly without being willing to give up and take completely
different approaches.<a href="#fnref3" class="footnote-back"
role="doc-backlink">↩︎</a></p></li>
<li id="fn4"><p>Depending on how bad the subject/difficulty distribution
is, it might even fall in the "reparable" category.<a href="#fnref4"
class="footnote-back" role="doc-backlink">↩︎</a></p></li>
<li id="fn5"><p>Not always, though. Writing lecture materials in
Microsoft Word (Google Docs counts, since it uses the same file format)
would make them irreparably bad, and here the word "flaw" would apply.<a
href="#fnref5" class="footnote-back" role="doc-backlink">↩︎</a></p></li>
<li id="fn6"><p>Another way you can look at this is: how much will the
problem compound if I leave it alone? You can probably use big-<span
class="math inline"><em>O</em></span> as a framework to think about it
(exercise left to reader).<a href="#fnref6" class="footnote-back"
role="doc-backlink">↩︎</a></p></li>
</ol>
</section>]]></description>
	<pubDate>23 Apr 2022</pubDate>
</item>
<item>
	<title>WARP 2023: preliminary thoughts</title>
	<link>https://dennisc.net/writing/blog/warp.md</link>
	<description><![CDATA[<p>WARP is an applied <a
href="https://www.lesswrong.com/tag/rationalist-movement">rationality</a>
camp from March 5-15. For reasons I will explain later, I am not a
rationalist: I didn't come into the camp as one, and I will not be
leaving the camp as one. This is the penultimate day of WARP and my
introversion has reached a critical mass. So instead of participating in
activities, I'll try to retroactively write about what happened in the
last weekish.</p>
<h2 id="day-by-day">Day-by-day</h2>
<h3 id="day--1-mar.-4">Day -1 (Mar. 4)</h3>
<p>The day before the camp started, I was supposed to run the 1600m/800m
at the Dan Gabor Invitational. Then I got pretty sick and didn't want it
to get worse because of the rain... which really sucks, because now I
have to run a 3200m when I get back. Yay!</p>
<p>I did not do any of my homework, but I started writing two puzzles
during the night: <a href="/puzzles/cars/ctc">Cars</a> and <a
href="https://logic-masters.de/Raetselportal/Raetsel/zeigen.php?id=000D9A">Monster
Without A Name</a>. This was despite the fact I basically needed to wake
up at 4 the next day because my flight was really early.</p>
<h3 id="day-0-mar.-5">Day 0 (Mar. 5)</h3>
<p>On the plane, I finished constructing the Cars puzzle and put a bit
more work into Monster Without A Name. When I got off the plane and
found the other WARP people, they started a conversation about robots
doing surgery and other nerdy/interesting topics.<a href="#fn1"
class="footnote-ref" id="fnref1" role="doc-noteref"><sup>1</sup></a>
When we got to the campsite --- which is <em>really cool</em>, they had
archery/a pool/rock climbing (more on that later!) --- we immediately
started chucking around a frisbee for 20 minutes standing right outside
our dorms.</p>
<p>After some trivial banter/dinner/other stuff I forgot, the opening
ceremony began. The only noteworthy part was "due to past events", there
was a policy against romance. Not just student/staff (which obviously
held true for every camp), but also between student/student. It didn't
affect me personally, but I'm including this because one of the quotes
was, "There's obviously nuance as to what constitutes 'romantic', but if
you hug for more than 8 seconds we'll send you back home."<a href="#fn2"
class="footnote-ref" id="fnref2" role="doc-noteref"><sup>2</sup></a> I
don't know why the director felt the need to elaborate on what
constituted romance, but regardless, "8 seconds" immediately became a
meme.</p>
<p>I forgot what happened the rest of the day, but there were no classes
or anything of that sort. Since I don't remember, probably nothing much
happened.</p>
<h3 id="day-1-mar.-6">Day 1 (Mar. 6)</h3>
<p>Some context: the WARP schedule is divided into three sections, the
morning, afternoon, and dinner. In the morning there are semi-structured
classes, in the afternoon people announce/hold activities on the spot,
and after dinner there is usually some staff-run event.</p>
<p>I see the schedule and immediately notice: "(8:00 - 9:00) Breakfast"
as the first event. I think, "huh, this seems pretty late!" And
surprisingly, there are very few things actually firmly scheduled
throughout the day (and as I would soon learn, even the classes
scheduled in the morning were ditchable). Of course, a late start just
means more room for people to stay up until 2 AM, so a couple of times I
almost miss breakfast and once I actually did miss breakfast.</p>
<p>Classes:</p>
<ul>
<li>The first class I had was <em>Map and Territory</em>, and the lesson
can basically be summed up into one sentence: "The map (models) do not
completely capture the territory (reality)".</li>
<li>The second class was <em>Philosophy of Therapy</em>. Somewhat
contrary to what the name suggests, it just explored modalities of
therapy (the instructor, Damon --- who is also the director --- is a
therapist). Much of this I knew from AP Psychology, but it was very
interesting to have an actual psychologist go over what I learned in
school.</li>
<li>The third and last class was Bayes' Theorem. It was just meant to
establish that everyone knew Bayes' Theorem (and get the outliers caught
up), but
<ul>
<li>no other class really used Bayes' Theorem,</li>
<li>and I'm pretty sure everyone knew Bayes' Theorem.</li>
</ul></li>
</ul>
<p>Going into the camp I had an expectation that the classes would be
more technical. The website said</p>
<blockquote>
<p>The curriculum covers a wide range of topics, <strong>from game
theory, cryptography, and mathematical logic,</strong> to AI safety,
styles of communication, and cognitive science.</p>
</blockquote>
<p>which I took as meaning "about half of this is technical and the
other half is either nonsense (like AI safety) or soft skills (which are
very much not nonsense)". But I already noticed a couple of trends in
the first few classes, some of which I hoped would not continue:</p>
<ul>
<li>There was a strong emphasis on soft stuff, like rationalist
philosophies.</li>
<li>The content density was relatively low. The technical class (Bayes')
was pretty simple<a href="#fn3" class="footnote-ref" id="fnref3"
role="doc-noteref"><sup>3</sup></a>, and a lot of classes were at least
partially interactive/discussion-based, which by definition lowers
content density.</li>
</ul>
<p>In the afternoon, there are typically three 1-hour time slots for
events, starting at 3:30, 4:30, and 5:30.</p>
<ul>
<li>I was already really tired after three back-to-back classes, so I
decided not to show up to any of the 3:30 events.</li>
<li>At 4:30 Jason led a talk about "math that blows minds" and basically
ended up converging the lesson on Lob's Theorem (very interesting, and
would end up becoming a theme for his talks). I went to this one.</li>
<li>At 5:30 I gave a talk on how to write (sudoku) puzzles, which at
some point I hope to record and turn into a video.</li>
</ul>
<p>The after-dinner event this day was two scheduled 1-on-1's, which is
the official term for "deep conversations between two people". I ended
up not really buying into 1-on-1's, and eventually I figured out that
1-on-1's weren't something I actually wanted to seek out, it was just
something I felt like I was supposed to do.<a href="#fn4"
class="footnote-ref" id="fnref4" role="doc-noteref"><sup>4</sup></a></p>
<ul>
<li>The first one was with Jason, who had a lot of interesting math
problems to share (examples include, "The Kolmogorov complexity of a
string is the length of the shortest program that prints that string,
what fraction of all strings have provable Kolmogorov complexity?"<a
href="#fn5" class="footnote-ref" id="fnref5"
role="doc-noteref"><sup>5</sup></a>)</li>
<li>The second one I had was with Srijon, a math olympiad student from
Kolkata I kind of knew through OTIS. We talked a lot, both about math
and about culture ("how to assimilate into American culture?" My answer
was, "don't bother, I think the biggest divide here isn't even
nationality, it's interests.<a href="#fn6" class="footnote-ref"
id="fnref6" role="doc-noteref"><sup>6</sup></a> You have a unique
perspective and can provide a lot of value through that instead").
Eventually we realized it was time to go to Max's "Get Stronger" talk,
which was obviously the most important thing this entire camp. (I'm not
joking.)</li>
</ul>
<p>After the "Get Stronger" presentation (which was mostly in
lowercase), we went to apply our knowledge by hitting the gym. I'd end
up hitting the gym every day, where in cross country/track we only hit
the weight room twice a week. I haven't dedicated a whole lot of space
to this, since it's pretty simple (eat more protein, sbd, etc --- hit me
up if you want more details about exercise!) but I want to emphasize
again that this was the most important thing for me that happened in the
entirety of camp, it made me actually love going to the gym.</p>
<h3 id="day-2-mar.-7">Day 2 (Mar. 7)</h3>
<p>Classes:</p>
<ul>
<li><strong>Math That Blows Minds: Unifying Frames</strong> was about
category theory. I think I understood at most 40 percent of this class,
but it was really cool to learn about something I have never seen
before. Now I am kind of inspired to learn category theory in the
summer.</li>
<li><strong>Emotions Make Sense</strong> was about how emotions inform
us of our wants, and how to accurately figure out what we want (as
opposed to what we think we want, what we want to want, etc).</li>
<li><strong>Entropy and Agency</strong> started off with something
concrete (entropy) and then turned into how "agents" (whatever that
means --- you can treat it as humans) basically reduce their own entropy
while increasing the entropy of their environment, and how agents
interact. I did not understand the second half and do not know how much
of it is actually real, as opposed to LessWrong speak.</li>
</ul>
<p>Activities: I did none of them since I had an idea for
<strong>Monster Without A Name</strong> and holed myself up in my room
finishing it. (I ended up making mistakes on the puzzle by overlooking
possibilities multiple times, so I would hole myself up later trying to
patch these mistakes, but never for as long as on Day 2.)</p>
<p>Dinner: I hit the gym after dinner and then arrived in the middle of
storytime. (Or I arrived in the middle of storytime for some reason and
then hit the gym, I honestly don't remember in what order.) There were a
lot of very personal stories, and because they were very personal I will
not share any of them even though I remember most of them.</p>
<h3 id="day-3-mar.-8">Day 3 (Mar. 8)</h3>
<p>We got our first covid case and all classes were moved outside. The
camp premises had two gazebos, which we used for classes that day. Damon
(I think) pointed towards one gazebo and said "Andis will be teaching at
this gazebo and Jason will be teaching at that gazebo". In typical WARP
fashion, the gazebos were forever named "This Gazebo" and "That Gazebo".
Wind would end up being very annoying, since it would blow over the
easels all the damn time.</p>
<p>Classes:</p>
<ul>
<li><p><strong>Thingspace</strong>: Basically the theory of categories
(but this was a soft class and not category theory, lol). Basically it
was about how relating concepts like "brown", "tall", "made of wood",
etc to each other is an <span
class="math inline"><em>O</em>(<em>n</em><sup>2</sup>)</span> operation
where relating concepts to a central, artificial node like "tree" was
<span class="math inline"><em>O</em>(<em>n</em>)</span>. (Also the time
complexity for reaching equilibrium in the first case could be
exponential in the case of contradictory signals.) Andis went over how
our models of categories were a (useful) simplification, and how we
could resolve confusion by thinking about things more "purely".</p>
<p>As a concrete example, for the debate "are hot dogs sandwiches?" he
established that a potential core disagreement could be whether there is
a continuous clump of sandwich-like things from the prototypical
sandwich to a hot dog (when graphed on the hyperspace of relevant
traits), or whether hot dogs and sandwiches were two separate
clumps.</p>
<p>This all sounds super abstract but it is because I am communicating
the idea poorly. This was really an interesting class and one of the
more useful ones to me.</p></li>
<li><p><strong>Technical Agency</strong>: Basically a lot of decision
theory I didn't understand (and am not actually sure is real). Newcomb's
paradox is basically trivial unless the prediction is super accurate
(implying determinism and a God-like intelligence) or your future
actions influence the past (presupposes a simulation or something).
Neither of these axioms seem reasonable.</p></li>
<li><p><strong>How to Train a Dog</strong>: Behavioral conditioning
works on animals and maybe people too (in some circumstances). Use
positive rather than negative reinforcement. (Most of this I was
familiar with because of AP Psych.)</p></li>
</ul>
<p>Activities: Again I did none due to a combination of working out and
holing myself in my room to write <strong>Monster Without A
Name</strong>.</p>
<p>Dinner: We had a very long talk by Bryan Caplan about how EAs should
support open borders. While I think the reasoning is somewhat sketch,
especially since I am not an EA, I agreed with the premise of his
argument: more immigration, even of low-skilled workers, is probably a
good thing.</p>
<p>Since that went on for very long, I slept pretty late and my sleep
schedule got slightly fucked.</p>
<h3 id="day-4-mar.-9">Day 4 (Mar. 9)</h3>
<p>Classes:</p>
<ul>
<li><strong>How to Change</strong>: Sicong used an example from his own
life to explain how present problems (e.g. procrastination) can be tied
to past trauma, and how to overcome it. I think the source material was
a book but I cannot remember the title of that book. I haven't noticed
this really happening in my own life, but the key word is
<strong>haven't noticed</strong>. I'll keep this as a tool in my belt:
hopefully I won't need it, but if I do, I will know how to use it.</li>
<li><strong>Leadership</strong>: The instructor said nothing the entire
class and had students basically do whatever with the class. I'm pretty
sure the class was trying to make some meta point, but honestly, I
walked away with the feeling "it is easy to be clever and hard to be
actually helpful." This is one of the few classes I think I should've
skipped; the message did not really resonate with me.</li>
<li><strong>Uncertainty</strong>: If you've seen Evan Chen's post on the
interval guessing game + how we are way too confident in our intervals
and need to make them embarrassingly wide, that's what this class is
about! We filled in the blank "Washington was born before X" with
predictions that we were 80, 95, and 99 percent confident in.</li>
</ul>
<p>Activities:</p>
<ul>
<li>At 3:30-4:30 there was a scavenger hunt with a lot of running around
that was pretty fun! We (Aname, my new favorite meme team name) got 3rd
out of 4th, which is pretty bad but whatever.</li>
</ul>
<p>I didn't participate in the other activities for the same reasons as
before: working out, writing a puzzle.</p>
<p>After dinner we did Lightning Talks, which are three-minute talks on
literally anything. Fionn and Zdenek wrote each others' talks, and
Zdenek's<a href="#fn7" class="footnote-ref" id="fnref7"
role="doc-noteref"><sup>7</sup></a> talk (which Fionn wrote) was about
proving that <span class="math inline">2<em>n</em></span> was even via
induction. I gave two talks: one about why Woodrow Wilson was the worst
president (I forgot the Spanish Flu in my talk, which Hugh added in the
penultimate talk), and another on the solution to the WARP geometry
application question.</p>
<h3 id="day-5-the-interregnum-mar.-10">Day 5, the interregnum (Mar.
10)</h3>
<p>This was a "break day", which meant way too much physical activity.
There was a high ropes course, archery, wall climbing, and the pool was
opened. I did all of these things, in addition to the gym. Thank god the
track workout was speed development that day, if it was anything harder
I might have actually died of exhaustion.</p>
<p>I also did a bit of work on <strong>Monster Without A
Name</strong>.</p>
<h3 id="day-6-mar.-11">Day 6 (Mar. 11)</h3>
<p>This was two days ago? It feels like an eternity.</p>
<p>Classes:</p>
<ul>
<li><strong>Language and Logic</strong>: A brief history of the
philosophy of language. Very interesting, and the only class I came in
with literally 0 information beforehand.</li>
<li><strong>Information Hygiene</strong>: Be careful about the info you
receive, fact-check anything you spread, and curate a good circle of
information. I honestly thought most of this was too much for everyday
life, since there are a lot of fun facts I don't actually care about
(i.e. there is no difference in my life whether it is true or not). But
one point Damon made really resonated with me: <strong>communicate your
level of confidence when you say something</strong>. I wrote about this
<a href="/writing/essays/modifiers">more than a year ago, while I was
still in junior year</a>, and this is one of my essays I strongly agree
with even now.</li>
<li><strong>Inadequate Equilibria</strong>: Efficient market hypothesis
is false. Most people don't know most things and arbitrage is not always
possible, whether it's due to transaction costs or some other reason.
Also the Prisoner's Dilemma has a suboptimal equilibrium.</li>
</ul>
<p>I unfucked up <strong>Monster Without A Name</strong> and finally
made a reasonable, solvable version. I don't actually know what events
happened that day, but I think it's plausible that I didn't do any of
them to finish <strong>Monster Without A Name</strong> and work out.</p>
<p>After dinner:</p>
<ul>
<li>There was a Fermithon and due to technical difficulties we were
basically robbed out of our win &gt;:(</li>
<li>We had a lot of epic freestyle rap battles where I shit on applied
math<a href="#fn8" class="footnote-ref" id="fnref8"
role="doc-noteref"><sup>8</sup></a> and Texas<a href="#fn9"
class="footnote-ref" id="fnref9" role="doc-noteref"><sup>9</sup></a>,
among other things.</li>
<li>We played Secret Hitler.</li>
<li>I did a midnight tempo run (<span class="math inline">6 × 6</span>
minutes with 1 minute running recovery).</li>
</ul>
<h3 id="day-7-mar.-12">Day 7 (Mar. 12)</h3>
<p>I was going to write a journal this day but got super busy.</p>
<p>Classes: Probably because of lowering participation rates, every
class was offered once instead of splitting into three cycles. Also
these classes were more focused on practicality, and were called
"workshops" instead.</p>
<ul>
<li><strong>Premortem</strong>: I was pretty familiar with this concept
and it seems like a fancy way of saying "be aware of what might go
wrong". But the act of actually visualizing the failure modes probably
makes it more effective.</li>
<li><strong>Resolve Cycles</strong>: You basically decide to do
something for the next 5 minutes and pray momentum carries you. I have
no idea how useful this actually is and want to find out by trying it.
(I ended up writing an email I'd been putting off for the practical
part, and let me just say it's kind of pissing me off right now...)</li>
<li><strong>Double Crux</strong>: Instead of arguing, try to understand
what shapes the core of your beliefs. Then if you can find a core belief
that contradicts the other person's (a double crux), you can either work
from there or realize you have a fundamental facts/values disagreement
that cannot be resolved. Alternatively, maybe it's a factual
disagreement that can easily be resolved.</li>
</ul>
<p>I skipped Afternoon Meta to lift weights. This isn't the first time I
skipped for this reason, but it's the only day I remember skipping for
gym for sure. This time, I showed up to two activities: Logic (this was
actually math, which was quite exciting and refreshing after a ton of
days with no math), and Physics Intuition (where we guess what happens
for physics experiments). I forgot that rotational inertia was inversely
proportional rather than directly proportional to acceleration like an
idiot, and then the rest of the questions were just super hard (but
still very interesting).</p>
<p>After dinner, there was the second edition of lightning talks, in
which people had to give hot takes (i.e. at least half of people had to
disagree for you to give your talk). Predictably, the number of
reasonable hot takes people had was pretty low, because most people
agreed on most things --- that's what happens when you select from
people with similar backgrounds and shared experiences (including but
not limited to the 10 days at camp). Max used the Cobbs-Douglass
function to explain why people should be at the gym instead, a bunch of
people changed their minds, then everyone realized the logical
implication: if you changed your mind you should go to the gym. So half
the people left for the gym and Lighting Talks quickly died.</p>
<p>Then I ostensibly solved puzzles in the Lodge and went on a short
recovery run to finish my Sunday minutes. I honestly forget why I slept
so late.</p>
<h3 id="day-8-mar.-13">Day 8 (Mar. 13)</h3>
<p>The final day of classes, and the penultimate day of camp. I attended
every class today, which means that I am one of two people with a
perfect attendance record (for classes at least --- I don't count the
metas because they are mostly useless).</p>
<ul>
<li><strong>DADA</strong>: How people can use "Dark Arts" to emotionally
manipulate you and how to protect yourself from these appeals. Included
Secret Hitler references.</li>
<li><strong>Visible/Invisible Curriculum</strong>: How explicit and
implicit messaging can either synergize or contradict each other.</li>
<li><strong>Why Everything WARP teaches is wrong</strong>: I attended at
least 40 percent because I wanted the perfect attendance record, but
honestly this was preaching to the choir for me. I was already taking in
this camp with skepticism and moderation, so "be skeptical and
understand our biases and wait to make drastic changes" was something I
already was planning on doing. Also it ended up just being a discussion
which is never great for content density.</li>
</ul>
<p>I went to lift and almost decided to skip afternoon meta but went
because I wanted to learn about Quest Day. It turns out people were
looking for us. It also turns out that it was a bad idea to go to
Afternoon Meta, because that shit lasted forever and I was no longer
warmed up when I went back to the gym. I technically hit a PR on bench
(3 x 35 on each side) but definitely can one-rep max more, and hit a
one-rep max of 70 (on each side) for deadlift. I still want to work on
squat, because I just started squatting (we don't do squat in XC), and
work my way up to what is probably my current limit.</p>
<p>I then went to my room to journal and ended up writing a puzzle
instead (<a href="/puzzles/zoom/ctc">Zoom</a>). The timezone on my
computer was wrong so dinner almost ended by the time I was pinged for
Hamming Circles, and I sped my way to get some food. Thank goodness
dinner was still open. I missed Hamming Circles, though I never planned
on going because I honestly didn't have problems I thought WARP would
help with ("no sleep and no rizz"). I also don't like talking about my
problems when I've made no real effort to solve them because that just
feels counterproductive.</p>
<p>And here I am, in the Lodge, writing this journal post with no one
around. Seriously, where the hell is everyone else? (I also need to go
for a run but honestly might just skip today's workout and do it
tomorrow. But it's short so I guess I'll do it today?)</p>
<h2 id="general-thoughts">General thoughts</h2>
<p>I expected this camp to be half soft skills and half hard skills. In
some sense, I didn't get what I wanted out of this camp: significantly
more technical abilities or knowledge. But at the same time I learned a
lot of cool stuff, although I will take all of it with many grains of
salt.</p>
<p>The content density in the classes was kind of lacking. I feel like
all of the content could have been compressed in two days, and it's only
two days because we did start out with some more technical
lectures.Fortunately, activities were a lot better in this regard (when
learning technical stuff was the intent of an activity).</p>
<p>I met a lot of cool people, many of whom touch grass (i.e. are not
EAs). I respect the intelligence and character of the rationalists too,
even though their lifestyle and worldview is very different from mine. I
don't know if I regret not interacting with them more, because on one
hand they are very smart people and I could've at least been rational
(hah) and learned math from them<a href="#fn10" class="footnote-ref"
id="fnref10" role="doc-noteref"><sup>10</sup></a>, but on the other hand
the tradeoff would have been working out less which was unacceptable for
me.</p>
<p>But overall I think this camp was a success in my books. I worked out
a lot, learned cool stuff, and had fun. Also it was free and I missed
school, so the opportunity cost was basically 0.</p>
<h2 id="why-not-rationalityea">Why not rationality/EA?</h2>
<p>I'm not going to think about this too hard because I think jumping
into that rabbithole is a total waste of time.</p>
<p>I had a 1-on-1 (I know, surprising) and one of the topics that came
up was the following:</p>
<blockquote>
<p>Why are you not a rationalist?</p>
</blockquote>
<blockquote>
<p>Me: <em>gives very "rational"/logical reasoning</em></p>
</blockquote>
<blockquote>
<p>Sounds pretty rational to me bub</p>
</blockquote>
<p>On one hand I actually agree with rationalists on a lot of stuff,
particularly when it comes to more difficult problems.<a href="#fn11"
class="footnote-ref" id="fnref11" role="doc-noteref"><sup>11</sup></a> I
also approach some proper subset of my life using reasoning and logic,
just as every other person with more than 3 brain cells does. But on the
other hand, I do not think that this set of worldviews or abilities
makes for a particularly interesting definition of a rationalist.</p>
<p>I don't make logical reasoning/math the deciding factor of important
decisions because I believe the error bars of my calculations would be
too wide, whether it's because of faulty observations or faulty logic.
Yeah, this sounds pretty Rational with a capital R, but I genuinely just
do not approach most of this life with my mindset, particularly because
I believe it's not worth thinking about all this extra stuff just for
marginal benefit. But rationalists (like Slate Star Codex) are right
about a lot of things --- most of them are just things I do not care
that deeply about.</p>
<p>But some subset of rationalists (and I argue, the prototypical
rationalist) think stupid shit like AI safety or whatever is the most
important problem and that the rest of human suffering doesn't matter in
comparison because "according to my (shitty) EV calculations".<a
href="#fn12" class="footnote-ref" id="fnref12"
role="doc-noteref"><sup>12</sup></a></p>
<section id="footnotes" class="footnotes footnotes-end-of-document"
role="doc-endnotes">
<hr />
<ol>
<li id="fn1"><p>I promise we all touch grass; my theory is that some
subset of the students were like "oh my god I can openly be nerdy" and
then they did that.<a href="#fnref1" class="footnote-back"
role="doc-backlink">↩︎</a></p></li>
<li id="fn2"><p>I'm putting this as a footnote for reasons of
length/clarity, but the <em>actual</em> thing the director said was even
funnier: it was only after the <em>second</em> time that you'd be sent
home. The first time, you'd just be warned.<a href="#fnref2"
class="footnote-back" role="doc-backlink">↩︎</a></p></li>
<li id="fn3"><p>In retrospect the Bayes' class was a blessing:
especially after Jason (a guest instructor who taught a math class)
left, the number of technical classes was basically 0.<a href="#fnref3"
class="footnote-back" role="doc-backlink">↩︎</a></p></li>
<li id="fn4"><p>Which doesn't mean I did it, just the opposite. If I'm
told I should do something (or it's implicitly stated) and I don't
believe it, I often and easily decide not to do that thing. I was one of
a small minority of people who felt this way. More power to the people
who were able to extract value from 1-on-1's, I just wasn't one of
them.<a href="#fnref4" class="footnote-back"
role="doc-backlink">↩︎</a></p></li>
<li id="fn5"><p>Finitely many, because consider a program with length L
that searches for proofs of the form "String <strong>s</strong> has
Kolmogorov complexity greater than L" and halts/outputs
<strong>s</strong> when such a proof is found. The Kolmogorov complexity
of this string is at most L since your program of length L generated
this string, yet you have a proof that its Kolmogorov complexity is more
than L, contradiction. So the length of a string with provable
Kolmogorov complexity is bounded.<a href="#fnref5" class="footnote-back"
role="doc-backlink">↩︎</a></p></li>
<li id="fn6"><p>Namely, math and not Keeping Up With the Kardashians or
whatever. And if this is your cultural disconnect, I think that's a good
thing.<a href="#fnref6" class="footnote-back"
role="doc-backlink">↩︎</a></p></li>
<li id="fn7"><p>Speaking of Zdenek, since his second e has an accent or
something, the nametag printer printed "ZDEN K". I would frequently
"remove letters" from his name for arbitrary reasons, and at one point
he was down to "ZD K". (I gave him his letters back near the end.)<a
href="#fnref7" class="footnote-back" role="doc-backlink">↩︎</a></p></li>
<li id="fn8"><p>I applied for Applied Math in UCB and UCLA...<a
href="#fnref8" class="footnote-back" role="doc-backlink">↩︎</a></p></li>
<li id="fn9"><p>Where I very likely will be going to college...<a
href="#fnref9" class="footnote-back" role="doc-backlink">↩︎</a></p></li>
<li id="fn10"><p>If you guys are reading this, it's because I didn't
have the time or energy after being a gym rat, not because I don't think
you're very cool people. Maybe next WARP/SPARC/etc I'll get the chance
to talk to more of you guys!<a href="#fnref10" class="footnote-back"
role="doc-backlink">↩︎</a></p></li>
<li id="fn11"><p>For one I believe life extension, alternatively the
fight to stop death/aging/etc, is a very important problem. I also think
that anyone who says "death gives life meaning" is full of shit, even
more full of shit than the extreme rationalist/EA community. And I think
those guys are pretty full of shit.<a href="#fnref11"
class="footnote-back" role="doc-backlink">↩︎</a></p></li>
<li id="fn12"><p>When your axioms are so sketchy and theoretical, I
really think you should consider that your error bars should be really
fucking wide and make "according to my calculations" worthless.<a
href="#fnref12" class="footnote-back" role="doc-backlink">↩︎</a></p></li>
</ol>
</section>]]></description>
	<pubDate>13 Mar 2023</pubDate>
</item>
<item>
	<title>Idea Density</title>
	<link>https://dennisc.net/writing/essays/idea-density.md</link>
	<description><![CDATA[<p>The reason you can watch TikTok for 6 hours
straight but can barely get through 2 pages of your real analysis
textbook is because they have different idea densities. In other words,
there's much more substance behind real analysis than an average
TikTok.<a href="#fn1" class="footnote-ref" id="fnref1"
role="doc-noteref"><sup>1</sup></a></p>
<p>This is obvious, but I think the framework of idea density is pretty
useful, especially since it'll help you compare apples to apples. Let me
explain why.</p>
<h2 id="attention-spans">Attention spans</h2>
<p>The common refrain is that "kids these days have no attention span",
and this is a bad approximation of what is actually happening --- why
else do people keep tabs on what Brittney sent on SnapChat, and oh my
god did you hear Samantha got accepted to Harvard? Arguably people are
better at paying attention now (or predatory companies are better at
getting it now). It's clearly just <em>sometimes</em> that people can't
pay attention.</p>
<p>What's actually happening is that the idea density people default to
has drastically decreased. For instance, people used to use phonebooks
and actual paper maps, instead of a Contacts list and Google Maps. Most
of us zoomers (myself included) would start sobbing hysterically if
asked to do the former. We've also gotten accustomed to rapid context
switching, such as looking at your phone every 5 seconds while doing
work.</p>
<p>Most people would quickly categorize both these phenomenons as "bad".
I'm not so keen on agreeing with that; my opinion is mostly neutral, in
that I believe "this is just a thing that's happening" rather than "this
is inherently good or bad". But the bad effects it does have are
undeniable, and crucially, I think they can be somewhat mitigated.</p>
<p>The most obvious and most important mitigation is to expose yourself
to a wider range of idea densities. Since the average person spends most
their time with low density media, <em>in general</em>, people should
try to increase their time with high density media. On the flipside, if
you're the guy always reading stuff like Slate Star Codex or Scott
Aaronson, maybe try watching Cocaine Bear or something too.</p>
<p>Let me take a step back and actually explain why this balance is
important. If you only engage with low idea density media, you won't
actually learn much or use your brain often. And if you only engage with
high density media, you'll miss out on a lot of "softer" value, like pop
culture, much of the humanities, and socialization<a href="#fn2"
class="footnote-ref" id="fnref2" role="doc-noteref"><sup>2</sup></a>
too.</p>
<p>With that said, here are some ways to increase your propensity
towards high idea density (and crucially not just a list of high idea
density things to expose yourself towards):</p>
<ul>
<li>Make smart friends who you can talk about interesting stuff with,
and ideally, work with. This won't make you do more idea-dense stuff,
but it will increase your threshold for what idea-dense means.</li>
<li>Learn more math. This is the most real, easily-understandable, and
information dense subject. At the same time, it is convenient. You do
not need to do any hands-on work or buy equipment or whatever: the
activation energy is low. And, most importantly, when you can understand
the world through the lens of math, it will be easier to observe and
process higher density information. (For instance, actually knowing
calculus makes statistics much clearer.)</li>
<li>Read general non-fiction (i.e. not textbooks), specifically
history/psychology books.</li>
<li>Improve the hygiene of your low-density activities (this deserves
its own section)</li>
</ul>
<p>There's no list for low density, because there's only one thing you
need to do: talk to people more often, <strong>especially those who'll
drag you into quality, low-idea density experiences</strong>. (More on
quality later.) Walk under bridges at 12 AM, watch Hamilton, lift
weights together. Do stupid shit together and have fun.</p>
<h3 id="addendum-meditation">Addendum: meditation</h3>
<p>Meditation is interesting because you're trying to clear your head,
which means that the idea density should approach 0. I haven't tried it
yet, but thinking of meditation as a tool to increase the range of idea
densities you're exposed to might just be the push I need.</p>
<h2 id="junk-food">Junk food</h2>
<p>People shit on sugar because their model of sugar is "high fructose
corn syrup" and not "group of macronutrients you need to survive".
Similarly, as I alluded to earlier, people shit on low-idea density
media because their model is "TikTok" and not "humanities + actually
talking to people". Just as a rich diet consists of eating a ton of
fruits and veggies (many of which contain a good amount of sugar), a
rich life consists of a lot of high quality low-density activities, like
watching movies with friends, going out to eat, and casual conversations
(bonus points if you are running together while talking).</p>
<p>It's somewhat unhealthy that studying is viewed as "the right thing
to do" while socializing is viewed as "the wrong thing to do", just
because the prototypical high idea density thing is good and the
prototype for low density is bad.<a href="#fn3" class="footnote-ref"
id="fnref3" role="doc-noteref"><sup>3</sup></a> (Though these days
there's a much better emphasis on balance --- perhaps too much, since
people are really shying away from making high school students
<em>read</em> these days.)</p>
<p>So when you're on your phone scrolling through TikTok for the 6th
hour, the correct impulse is probably not "I should open the damn
textbook", because you will be too pooped to get anything done. Instead,
call up a friend and ask if they want to hang out. Chances are, they are
<em>also</em> scrolling on TikTok and need someone to break them out of
it.</p>
<section id="footnotes" class="footnotes footnotes-end-of-document"
role="doc-endnotes">
<hr />
<ol>
<li id="fn1"><p>One important caveat to make: the <em>actual</em> idea
density of, say, some guy doing a trickshot is probably really high:
there's a lot of knowledge you need to actually land it. But the
<em>communicated</em> idea density, which is what really matters here,
is low.<a href="#fnref1" class="footnote-back"
role="doc-backlink">↩︎</a></p></li>
<li id="fn2"><p>Which I now think is really important, maybe even more
important than knowing math.<a href="#fnref2" class="footnote-back"
role="doc-backlink">↩︎</a></p></li>
<li id="fn3"><p>And these same people aren't consciously aware of idea
density. For instance, tiger parents will replace social media with
studying rather than getting their kid to do a real sport (i.e. not
marching band), which quickly leads to burnout.<a href="#fnref3"
class="footnote-back" role="doc-backlink">↩︎</a></p></li>
</ol>
</section>]]></description>
	<pubDate>27 Mar 2023</pubDate>
</item>
<item>
	<title>User permissions for Glee</title>
	<link>https://dennisc.net/writing/tech/glee-permissions.md</link>
	<description><![CDATA[<p>The previous user permission system for Glee
that I had in mind was dead simple: you are either unauthenticated, a
user, or an admin, and each repository was configured to have certain
permissions (read/write) for users and admins. Unfortunately, upon
further reflection I have concluded that this system is utterly useless
for anything besides systems with a very small number of people (usually
1), and at that point you may as well run cgit. So I am revamping the
design <strong>with the explicit goal of refining access control even
for large organizations</strong>, though the primary target audience of
small groups will not change.</p>
<p>There is a question of whether we ought to store the permission
information with users (each user has a list of paths they have
permissions to), or with paths (each repository lists out the users that
are allowed to read/write/admin it). The answer is dead obvious in
retrospect: <strong>store permissions with paths</strong> because files
can/will be frequently moved around. Looking through every user and
editing their permissions to point to the new path names is massively
inconvenient. So when I say "this user has permission to write to this
repository", the permission-giver is the repository.</p>
<p>So what does each path store? Dead simple:</p>
<ul>
<li>a list of people who can read the path;</li>
<li>a list of people who can write to the path;</li>
<li>a list of people who can administrate the path.</li>
</ul>
<p>With that out of the way, let's flesh out the permissions system by
considering an example. We will work with the following Glee
filesystem:</p>
<pre><code>gym/
    squat.git
    bench.git
    deadlift.git
running.git</code></pre>
<p>(For clarity, the <code>.git</code> suffix is how Git stores bare
repositories by default and is what we will use to differentiate git
repositories from directories. Using the filesystem as an analogy, the
repositories are "files" and the directories are... directories.)</p>
<p>Suppose I have administrative privileges over the entire system, i.e.
I have <code>admin</code> permissions in <code>/</code>. I invite my
friend Carl as an <code>admin</code> of <code>gym/</code>. Carl can now
write to every repository in <code>gym/</code>, because being an
<code>admin</code> necessarily means you can do that. Furthermore, Carl
can invite Alice to <code>gym/</code> and give her whatever permissions
in <code>gym/</code> he wants, including making her an administrator of
<code>gym/</code> as well. However, Carl cannot step outside the bounds
of <code>gym/</code> and give her <em>any</em> permissions over
<code>running.git</code>. Furthermore, unless I <em>explicitly</em>
state otherwise, Carl has <em>no permissions</em> in
<code>running.git</code>.</p>
<p>This way we can have maintainers of entire subsystems without giving
them any permissions out of their scope.</p>
<h2 id="no-negative-permissions">No negative permissions</h2>
<p>I cannot specify that Carl can administrate all of <code>gym/</code>
except <code>gym/bench.git</code>. This would make life far too complex,
and if you want to give Carl access to all of <code>gym/</code> except
<code>gym/bench.git</code>, that's a sign that semantically,
<code>gym/bench.git</code> should be moved to a different path.</p>
<h2 id="unauthenticated-read-access">Unauthenticated read access</h2>
<p>We still want people who are not logged in to the Glee instance, i.e.
the general public, to be able to publicly see some repositories. Here,
we do want negative permissions to exist; we may want the general public
to be able to see everything except <code>running.git</code>, which is a
highly private repository.</p>
<p>For this, we <em>will</em> use the ideas in the <a
href="/writing/tech/glee-design">initial design post</a>. To rehash,
here is how it will work:</p>
<ul>
<li>For each path, we will store a value
<code>unauthenticated_read: Option&lt;boolean&gt;</code>. For those not
familiar with Rust or functional languages, it means either
<code>unauthenticated_read</code> will be set to <code>true</code>,
<code>false</code>, or not set at all.</li>
<li>To determine whether a repository can be read, we will look at the
value of <code>unauthenticated_read</code>. If it is unset, we will
<strong>recursively</strong> traverse up one directory and look at
<code>unauthenticated_read</code>, stopping when we see that
<code>unauthenticated_read</code> is set or when we reach
<code>/</code>, whichever comes first.</li>
<li>For example, take a path like <code>gym/squat.git</code>. Say
<code>unauthenticated_read</code> is not set, then we will look at
<code>gym/</code>. If <code>gym/</code> has
<code>unauthenticated_read</code> set to <code>false</code>, then we
make <code>gym/squat.git</code> unreadable. If it was set to
<code>true</code>, then <code>gym/squat.git</code> would be
readable.</li>
<li>If <code>gym/squat.git</code>, <code>gym/</code>, and <code>/</code>
all do not have <code>unauthenticated_read</code> set, i.e. we do not
find any <code>unauthenticated_read</code> value, we default to making
the path unreadable for the sake of security.</li>
</ul>
<p>So whether a <strong>repository</strong> is readable follows a simple
algorithm: if the first <code>unauthenticated_read</code> value we find
is <code>true</code> when traversing up the directory structure, then
the repository is readable. Otherwise, the repository is not
readable.</p>
<p>Now what happens if we stumble upon a <strong>path</strong> where
<code>unauthenticated_read</code> resolves to false (as according to the
recursive algorithm mentioned above)? The answer is <strong>not</strong>
"make the path unreadable": what if it has readable children?
Instead,</p>
<ul>
<li>if the path has any readable children, we will list all of said
readable children;</li>
<li>if the path has no readable children, then the path will not be
readable; in other words, it will return a 404.</li>
</ul>
<p>Consider the following example:</p>
<pre><code>a/              UNREADABLE
    b/          READABLE
        c.git   UNREADABLE</code></pre>
<p>When we read <code>a/</code>, since <code>b/</code> is readable, we
will display</p>
<pre><code>a/
    b/</code></pre>
<p>This is <strong>despite</strong> the fact that <code>b/</code> has no
readable repositories as children!</p>
<h2 id="the-frontend">The frontend</h2>
<h3 id="user-registration">User registration</h3>
<p>Before this, when permissions were much simpler (so simple that they
were essentially useless), the only way to make a user would be for an
administrator to invite them directly. Now we will allow any user to
make an account. However, instead of allowing a user to create an
account and then verify their email (a stupid decision given that a
malicious actor could steal your email address without much effort), the
way someone who owns <code>abc@def.xyz</code> will register is</p>
<ul>
<li>they will visit <code>https://git.dennisc.net/register</code> and
send themselves a registration email, which contains the registration
link <code>https://git.dennisc.net/register?code=abcd</code>;</li>
<li>they visit <code>https://git.dennisc.net/register?code=abcd</code>,
and since they have a valid registration code, they will register on
that page. Note the registration code <code>abcd</code> is tied to the
email <code>abc@def.xyz</code>.</li>
</ul>
<h3 id="changing-permissions-for-a-path">Changing permissions for a
path</h3>
<p>Suppose you want to change the permissions for <code>gym/</code> and
you are an <code>admin</code> for <code>gym/</code>. Then
<code>https://git.dennisc.net/gym</code> will display a "Manage
permissions" link, which will take you to
<code>https://git.dennisc.net/gym?permissions</code>. Then there will be
a TOML file structured like</p>
<div class="sourceCode" id="cb4"><pre
class="sourceCode toml"><code class="sourceCode toml"><span id="cb4-1"><a href="#cb4-1" aria-hidden="true" tabindex="-1"></a><span class="dt">read</span> <span class="op">=</span> <span class="op">[</span><span class="st">&quot;somereader@gmail.com&quot;</span><span class="op">]</span></span>
<span id="cb4-2"><a href="#cb4-2" aria-hidden="true" tabindex="-1"></a><span class="dt">write</span> <span class="op">=</span> <span class="op">[</span><span class="st">&quot;somewriter@outlook.com&quot;</span><span class="op">]</span></span>
<span id="cb4-3"><a href="#cb4-3" aria-hidden="true" tabindex="-1"></a><span class="dt">admin</span> <span class="op">=</span> <span class="op">[</span><span class="st">&quot;abc@def.xyz&quot;</span><span class="op">]</span></span></code></pre></div>
<p>i.e. there is a list of readers, writers, and admins for each path.
You will be able to edit this path in a <code>&lt;textarea&gt;</code>
and submit the new values in an HTML form.</p>
<p>It goes without saying, but you will not be able to do any of this if
you are not an <code>admin</code> for <code>gym/</code>.</p>
<details>
<summary>
How are permissions stored?
</summary>
<div>
<p>They are stored in the filesystem. You are literally (indirectly)
reading/writing to the filesystem, though of course the latter step only
happens after validating your input. Also relevant: the default TOML
file will be</p>
<div class="sourceCode" id="cb5"><pre
class="sourceCode toml"><code class="sourceCode toml"><span id="cb5-1"><a href="#cb5-1" aria-hidden="true" tabindex="-1"></a><span class="dt">read</span> <span class="op">=</span> <span class="op">[]</span></span>
<span id="cb5-2"><a href="#cb5-2" aria-hidden="true" tabindex="-1"></a><span class="dt">write</span> <span class="op">=</span> <span class="op">[]</span></span>
<span id="cb5-3"><a href="#cb5-3" aria-hidden="true" tabindex="-1"></a><span class="dt">admin</span> <span class="op">=</span> <span class="op">[]</span></span></code></pre></div>
<p>This TOML file will be populated immediately upon creation of the
path.</p>
</div>
</details>
<details>
<summary>
Handling query strings (implementation details)
</summary>
<div>
<p>In axum, the way to handle a query string with no value is to make
the datatype</p>
<div class="sourceCode" id="cb6"><pre
class="sourceCode rust"><code class="sourceCode rust"><span id="cb6-1"><a href="#cb6-1" aria-hidden="true" tabindex="-1"></a><span class="at">#[</span>derive<span class="at">(</span>Deserialize<span class="at">)]</span></span>
<span id="cb6-2"><a href="#cb6-2" aria-hidden="true" tabindex="-1"></a><span class="kw">pub</span> <span class="kw">struct</span> Permissions <span class="op">{</span></span>
<span id="cb6-3"><a href="#cb6-3" aria-hidden="true" tabindex="-1"></a>    permissions<span class="op">:</span> <span class="dt">Option</span><span class="op">&lt;</span>()<span class="op">&gt;,</span></span>
<span id="cb6-4"><a href="#cb6-4" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code></pre></div>
<p>and then function for the <code>get</code> API route would be</p>
<div class="sourceCode" id="cb7"><pre
class="sourceCode rust"><code class="sourceCode rust"><span id="cb7-1"><a href="#cb7-1" aria-hidden="true" tabindex="-1"></a><span class="kw">pub</span> <span class="kw">async</span> <span class="kw">fn</span> get(</span>
<span id="cb7-2"><a href="#cb7-2" aria-hidden="true" tabindex="-1"></a>    Query(Permissions <span class="op">{</span> permissions <span class="op">}</span>)<span class="op">:</span> Query<span class="op">&lt;</span>Permissions<span class="op">&gt;,</span></span>
<span id="cb7-3"><a href="#cb7-3" aria-hidden="true" tabindex="-1"></a>) <span class="op">-&gt;</span> Response <span class="op">{</span></span>
<span id="cb7-4"><a href="#cb7-4" aria-hidden="true" tabindex="-1"></a>    <span class="op">...</span></span>
<span id="cb7-5"><a href="#cb7-5" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code></pre></div>
<p>where we can parse <code>permissions</code> in order to determine
whether the query string <code>?permissions</code> is present.</p>
<p>I haven't tested this but it should be right in principle, at
least.</p>
</div>
</details>
<h2 id="caching-permissions">Caching permissions</h2>
<p>This is now getting down to implementation details, so the design
here is much more uncertain. (After all, I can't know if an
implementation detail is a good idea until I get down to implementing
it, unlike high-level designs.)</p>
<p>Perhaps it would be a good idea to cache permissions so that, instead
of resolving permissions for <code>a/b/c.git</code> by recursively
looking through the permissions of <code>a/b/</code>, <code>a/</code>,
and <code>/</code>, we can instead resolve "who has permissions to
<code>a/b/c.git</code>?" every time we edit the permissions of
<code>a/b/c.git</code> or any of its parents. And any time we edit the
permissions of a path, we update the cache for it and all of its
children.</p>
<p>The argument against doing this is that it increases the complexity
of the code, and you'd have to be kind of a monster to have deep enough
paths for this kind of thing to matter.</p>
<h2 id="a-small-note-about-redirects-for-renamed-repositories">A small
note about redirects for renamed repositories</h2>
<p>This has nothing to do with the rest of this note, but it is
something I was thinking about when re-reading the <a
href="/writing/tech/glee-design">original design post</a> and thinking
about my old solution for redirects. I realize now there is a better
solution and will write it down before I forget.</p>
<p>There is a dead simple solution: symlinks. If you rename
<code>old.git</code> to <code>new.git</code> then</p>
<ul>
<li><code>mv old.git new.git</code></li>
<li><code>ln -s new.git old.git</code></li>
</ul>
<p>And whenever we try to create either the directory <code>new/</code>
or the repository <code>new.git</code>, we</p>
<ul>
<li>check whether <code>new/</code> or <code>new.git</code> already
exists: <code>new.git</code> does;</li>
<li>then check whether <code>new.git</code> is a symlink: it is;</li>
<li>since it is a symlink, we may remove it without worries and create
the directory <code>new/</code> or repository <code>new.git</code> as
desired.</li>
</ul>
<h3 id="addendum-20240724">Addendum (2024/07/24)</h3>
<p>The problem is not as simple as I made it out to be. Suppose you make
repository <code>a.git</code>, and then rename it to <code>b.git</code>
and then to <code>c.git</code>. You initially would have</p>
<pre><code>a.git -&gt; b.git -&gt; c.git</code></pre>
<p>But what happens if you replace b.git? Now you have</p>
<pre><code>a.git -&gt; b.git (NEW)
c.git</code></pre>
<p>Now <code>a.git</code> points to <code>b.git</code>. If the whole
point of redirects is to introduce stability, then this defeats the
whole purpose.</p>
<p>In principle, it is possible to hunt down <em>every</em> symlink for
<em>every</em> rename. My original solution of a history array would
have the same problem. Plus, if you were to rename a directory, that
would be a lot of work to do. And what if your redirect
<code>/foo/bar.git</code> was stored in the directory <code>foo</code>,
and then you moved <code>/foo</code> to <code>/baz</code>? How would you
even keep track of that?</p>
<p>So for the sake of simplicity and predictability, I am inclined to
drop redirects entirely. If I think of a really good solution, I will
use it, but based on the flexibility of moving files in a filesystem,
the difficulty of keeping redirects consistent while still keeping
renames performant seems quite hard. GitHub can do redirects easily
because they have fixed depth; we do not.</p>]]></description>
	<pubDate>29 Jun 2024</pubDate>
</item>
<item>
	<title>Ideas and Mechanics</title>
	<link>https://dennisc.net/writing/essays/ideas-and-words.md</link>
	<description><![CDATA[<p>Teachers love to tell you that "your ideas are
good, you just need to improve on your style" even though they're just
saying it to be nice most of the time. But I do agree that there are two
orthogonal components in writing.</p>
<p>I don't think the orthogonal components are ideas and style because
so much of what falls under "style" really belongs to ideas. Rather, I
think it's closer to ideas and mechanics.</p>
<p>Ideas are the core of the essay. I believe that a lot of the time
choosing the right words falls into ideas. Often <a
href="write-smart#importing">you just need to choose the right words or
concept for your readers to understand what you mean</a>. A good
heuristic for whether something falls into ideas is whether you have to
concentrate and think about it. Ideas are things you can only come up
with when you're in a flow state.</p>
<p>Mechanics, as the name suggests, is a more rigid process with less
room for interpretation. You can improve the mechanics of an essay at
just about any time. Often times when I am rereading my old writing I'll
pull up my website and fix any mechanical mistakes I happen to come
across. Sometimes it is as superficial as just fixing typoes or
substituting one word for another.</p>
<p>Because writing is so broad --- you can write textbooks, essays,
journal, and even text<a href="#fn1" class="footnote-ref" id="fnref1"
role="doc-noteref"><sup>1</sup></a> --- I'll limit this essay to writing
meant for the general public. So I'm talking about biographies, pop
science, and essays (like this one) but not journals or textbooks.</p>
<p>This is how I think about my writing and what I do to get better.
Maybe it will help you as well.</p>
<h2 id="ideas">Ideas</h2>
<p>You can easily think of an idea to write about: what you did during
school, had for lunch, or how the last sports meet went down. The
problem is nobody cares what you had for lunch including yourself.<a
href="#fn2" class="footnote-ref" id="fnref2"
role="doc-noteref"><sup>2</sup></a> What really takes effort is
developing the meat of an idea, especially once you get in the habit of
thinking and writing. Coming up with plausible ideas stops being the
bottleneck pretty fast.</p>
<p>Some ideas are not going to go anywhere.<a href="#fn3"
class="footnote-ref" id="fnref3" role="doc-noteref"><sup>3</sup></a> The
main skill you need to develop with ideas is discernment, not coming up
with them. Not only do you need to avoid pursuing unpromising ideas, but
you also need the discernment to seize ideas worth writing about as
well, especially since ordinary conversations and events can be really
good catalysts for writing.<a href="#fn4" class="footnote-ref"
id="fnref4" role="doc-noteref"><sup>4</sup></a></p>
<p>I can't tell you what ideas to think about, but I can offer a few
heuristics.</p>
<p>The most obvious is that you have time to think, whether it's in the
moments before you fall asleep, commuting to school, et cetera. If you
find that you don't have time to think then make it. People waste an
inordinate amount of time going through their phones or playing games.
If you occasionally make an effort not to indulge in these distractions,
you'll find that your mind will naturally wander to <a
href="http://www.paulgraham.com/top.html">whatever interests you most
right now</a>.</p>
<p>Sometimes I don't write my essays immediately when I think of them,
but I just write up an outline with a pencil and leave it to be finished
in a couple of days. This is mostly out of laziness but I find it serves
as a good filter. You want to care and know enough about whatever you're
writing on to be able to remember it for a few days.</p>
<p>I find that I can't actually think of many of the details of an essay
even after I've thought of the idea. Most of the time the details I do
write up are true enough to my initial idea, but sometimes the essay
veers off into a whole different direction. At those times, I have to
think about what the main idea actually is. At those times I tend to put
the writing on pause, maybe browse the internet for a bit, and after
about 40 minutes I come back with a renewed sense of purpose.</p>
<p>Above all, if you haven't written in a while or really need to write
your college essays<a href="#fn5" class="footnote-ref" id="fnref5"
role="doc-noteref"><sup>5</sup></a>, just write. You only need to have a
vague idea on what you're writing about, because writing is the process
of roughly translating your thoughts to words. It's like deciphering an
encoded message: even if you know how to translate it, you won't know
what it means until you've done so.</p>
<p>If you want to develop your ability to think of ideas, you have to
develop your ideas. The reason we write is because we don't have a good
gauge of what we're thinking. How many times have you thought you had an
idea for an essay, whether it be for school, college, or something else,
only for it to fizzle out into nothing? But if you have all your ideas
in front of you, it is really easy to <a href="reread">go back and make
connections</a>.</p>
<h2 id="mechanics">Mechanics</h2>
<p>Knowing which words to pick or how to structure sentences is a more
mechanical process. It's a little bit like programming: it requires
creativity from you, but outside of a couple of key situations you do
not need to actively be creative.</p>
<p>There's obvious things like making sure your sentences are
grammatically correct or varying your choice of words. Strive for
readability as well: make sure your sentences and <a
href="/writing/blog/paragraphs">paragraphs</a> aren't too long and <a
href="http://www.paulgraham.com/simply.html">don't use bigger words than
you have to</a>.</p>
<p>My personal philosophy for paragraph breaks is pretty simple: insert
one whenever it makes sense. It's fine if you have really short
paragraphs because of this.</p>
<p>For individual sentences, there's a main idea I want to convey and
then <a href="modifiers">modifiers</a> I want to add to make my
statement as accurate as possible. Let's take the following sentence in
this essay:</p>
<blockquote>
<p>People waste an inordinate amount of time going through their phones
or playing games.</p>
</blockquote>
<p>I originally was writing</p>
<blockquote>
<p>The amount of time people waste going through their phones is
inordinate.</p>
</blockquote>
<p>I say "was writing" because I never actually finished typing the
sentence out; I immediately knew the wording was awkward. But I want to
touch on why it's awkward: it's because the sentence builds towards the
modifier as a conclusion. You want to either place the main observation
or conclusion at the end of the sentence. Of course you can choose to
style your sentences differently. But I believe that the best way to
think about them is "how do I best fit my idea and modifiers
together?"</p>
<p>If you look at really good writers, you'll notice they don't try to
present ideas as something more than they really are. Modifiers are
supposed to clarify your points, not hide your lack of knowledge.<a
href="#fn6" class="footnote-ref" id="fnref6"
role="doc-noteref"><sup>6</sup></a> This is why choosing the right
modifiers is often a question of ideas rather than words. I think skill
with words and presentation is largely mechanical: you have an idea and
its nuances, what's the best way to fit them together into a sentence? A
paragraph? An essay?</p>
<p>This is veering into the territory of ideas --- mechanics is just
about fitting them together. So back to mechanics.</p>
<p>Surprisingly, the way you do mechanics doesn't really change from
essay to essay. It doesn't even matter if it's your own writing. In
English class I would edit at least half a dozen paper for each essay we
were assigned (I got a reputation for being good at writing, though I
don't really see how since I didn't show anyone my actual writing). Any
mechanical changes I made to other people's essays would all fit the
same style. Where ideas are supposed to be flexible, mechanics should be
universal: your taste in mechanics should apply to your writing, my
writing, and everyone else's writing. Is there any wording or syntax you
disagree with in this essay? Why? And how can you apply the answer to
improve your own writing?</p>
<p>Most people feel it's "inappropriate" to judge mechanics, partially
because they vary from person to person and partially because they don't
usually read with a critical lens. That's why the best way to improve
your mechanics fast is to get friends who also write, proofread each
other's work, and offer suggestions: it makes it appropriate and
expected that you've got an eye out for mechanics because the only
specific advice you can offer is on mechanics anyway.<a href="#fn7"
class="footnote-ref" id="fnref7" role="doc-noteref"><sup>7</sup></a></p>
<section id="footnotes" class="footnotes footnotes-end-of-document"
role="doc-endnotes">
<hr />
<ol>
<li id="fn1"><p>Texting isn't always similar to writing (in fact most of
the time it is not), but the thing I like about it is you can really
easily shift to writing (mostly on accident). Textbooks explain concepts
and I don't think explaining how to solve question 5 on the homework is
significantly different. If you tell a story to a friend, is that really
different from blogging or journaling either? True, texting is low focus
and has low information density, but I still think it kinda counts
sometimes.</p>
<p>I don't think conversations are ever like writing (though
conversations can spur good writing) because you don't really have the
ability to refer to past bits of your conversation, whereas when texting
you can reference a specific message.<a href="#fnref1"
class="footnote-back" role="doc-backlink">↩︎</a></p></li>
<li id="fn2"><p>If we exclude journaling, which this essay does.<a
href="#fnref2" class="footnote-back" role="doc-backlink">↩︎</a></p></li>
<li id="fn3"><p>I wish I kept track of them because I'd have provided
some examples if I did.<a href="#fnref3" class="footnote-back"
role="doc-backlink">↩︎</a></p></li>
<li id="fn4"><p>I came up with the crux of this essay in a conversation
with my friends from Math Advance.<a href="#fnref4"
class="footnote-back" role="doc-backlink">↩︎</a></p></li>
<li id="fn5"><p>I'd do well to take my own advice here.<a href="#fnref5"
class="footnote-back" role="doc-backlink">↩︎</a></p></li>
<li id="fn6"><p>People misusing modifiers this way is probably why
English teachers tell you to avoid them. But they sometimes shun
modifiers so hard that they forget modifiers can enhance and clarify
your writing rather than muddle it.<a href="#fnref6"
class="footnote-back" role="doc-backlink">↩︎</a></p></li>
<li id="fn7"><p>See <a href="two-kinds-of-bad">Two Kinds of Bad</a>:
usually, fixable flaws are in the mechanics and unfixable flaws are in
the ideas.<a href="#fnref7" class="footnote-back"
role="doc-backlink">↩︎</a></p></li>
</ol>
</section>]]></description>
	<pubDate>5 Aug 2022</pubDate>
</item>
<item>
	<title>Force Multipliers</title>
	<link>https://dennisc.net/writing/essays/force-multipliers.md</link>
	<description><![CDATA[<p>In the military, a force multiplier refers to
something that makes something else more effective. A tool like GPS, on
its own, will do absolutely nothing. But give this functionality to
drones and you can <a
href="https://www.cnn.com/2021/06/28/politics/us-airstrikes-new-iran-drone-attacks-avoid-surveillance/index.html">wreak
havoc</a>.</p>
<p>No one is disputing the utility of the GPS. But for some reason, the
effect of force multipliers on us, in a non-military context, is
completely ignored.</p>
<p>Let's give a functional definition of a force multiplier first. A
force multiplier is a tool that does not automaticlaly create anything
of value, but can be used to create something of value with greater
efficiency.</p>
<p>Take text editors, for instance. Text editors will not write code for
you, but they will help you write code. There's a common refrain that
text editors are just tools and they don't make you a better programmer.
"Not everyone wants to set up a local TeX compiler!" they say. "Online
editors just work." I've heard the same for programming languages and
operating systems. Textbooks and studying strategies. It's all just
personal preference. Hell, I've even heard people use this to justify
typesetting books in Sans Serif fonts.</p>
<p>Of course you can write the same code with different text editors or
the same program with a different language. Learn the same thing from a
different textbook. Read the same book despite the differences in font
selection. But these differences can make the experience more efficient
or more cumbersome, in subtle or drastic ways.</p>
<p>Force multipliers have an effect that is incomparable to raw
increases. Not better or worse, just not comparable --- at least, not in
a general sense. This is the thing people tend to forget or just don't
realize. You can't ask, "Will learning Vim or Python be more useful in
general?" Because if you already know seven different programming
languages, the eighth won't make as much of a difference, whereas if you
don't even know how to program the whole point of Vim will be lost on
you anyway.</p>
<p>You can still evaluate whether adding a force multiplier or raw
ability is the better option in a specific scenario. This makes
improvement somewhat of an optimization problem. Just be aware the
answer can change based on the initial conditions.</p>
<h2 id="force-multipliers-all-the-way-down">Force multipliers all the
way down</h2>
<p>Everything is a force multiplier, whose effectiveness can be
increased or decreased like the others. Just the same as your fancy
keyboard is useless if you can't even type fast, your fast typing
abilities are useless if you don't have a keyboard.</p>
<p>Force multipliers can be categorized in a number of ways, but the
most useful by far is mutual exclusivity. You can only type on one
keyboard at a time. You can only use one text editor at a time. You can
only read one book at a time. Now, this exclusivity is not literal; any
smart-aleck could take two keyboards and begin slamming the keys. But it
is effectively true; you won't type very fast on two different
keyboards. Let's call such a group of force multipliers a
<em>stratum</em>.</p>
<p>There are two types of tradeoffs that can be evaluated: intrastratum
and interstratum. In English, that means within a stratum and between
strata, respectively.</p>
<p>Intrastratum force multipliers can be compared in a more general
sense. Vim or Emacs? A valid (though contentious) question, because you
can't use both. Two spaces or four? Clearly the answer is two, but at
least the options are in the same stratum. Replit or VSCode? What in
tarnation are you talking about? One is an online editor+compiler suite
and the other is just a local editor --- the two aren't even
comparable.</p>
<p>The effectiveness of these force multipliers will vary from person to
person. Someone might be very familiar with Vim and not know how Emacs
works, or vice versa. Such a variance can lead to the misconception that
there is no way to determine if a text editor is better than another,
since everything is subjective.</p>
<p>As a thought experiment, consider any text editing program with the
ability to save completely removed. Not only is it inferior to the
original text editing program, it is inferior to practically
<em>every</em> text editing program. The ability to save is absolutely
crucial, and an editor without it is worthless.<a href="#fn1"
class="footnote-ref" id="fnref1" role="doc-noteref"><sup>1</sup></a></p>
<p>Is it so hard to believe, then, that the ability to programmatically
modify their text editor might be seen as essential for some people?
Saving is part of what makes a text editor powerful --- without it, a
text editor would have no power. Text editors can still have some power
without configurable macros, but it certainly is less. And for some
people, that's enough. But it would be wrong to say Vim is just as
powerful than GEdit.</p>
<p>When making a general comparison between which force multiplier is
more effective, you should almost always compare the maximum efficiency
across people, not the minimum. Maybe the 90th percentile, because you
should take into consideration how hard it is to use. There's a bit of
nuance here because the users of powerful tools end up being
self-selecting, but you should never use the average effectiveness over
everyone, particularly not people who don't even use said tool.</p>
<p>Interstratum force multipliers have to be compared on a case-by-case
basis. An example from math contests is the age-old debate between
learning by reading books (theory) and working through contests or
problem-sets (practice). Theory is the foundation for problems, and
experience is crucial to do problems "in the wild." The people who
stress the importance of doing books and those who focus on problems are
both right.<a href="#fn2" class="footnote-ref" id="fnref2"
role="doc-noteref"><sup>2</sup></a></p>
<p>Such a division between intrastratum and interstratum is not perfect.
Judgements between any force multipliers will have to include some level
of generality and some level of specificity, and they will never be
perfect. And debates, both intrastratum and interstratum, both specific
and general, can get ridiculous. But to argue that all intrastratum
comparisons are subjective or that every interstratum question has a
good answer is just as ridiculous.</p>
<h2 id="organizations">Organizations</h2>
<p>Up until now I've been discussing force multipliers as having varying
positive effects. But make no mistake: force multipliers can have a
coefficient of less than 1.</p>
<p>I know a lot of people who refuse to work in groups because they
think it's bullshit. To a large extent, they are right: most groups are
astoundingly inefficient.</p>
<p>But how inefficient does a group need to be to make it not worth
working in? There's a lot of things that are nice about it: being with
other people<a href="#fn3" class="footnote-ref" id="fnref3"
role="doc-noteref"><sup>3</sup></a> and being able to increase your
scope is nice. But you also lose some control in exchange for it. This
threshold will vary person by person, but I'd approximate my answer to
be about <span class="math inline">1.1</span>, maybe even <span
class="math inline">1.2</span>, because I'm sort of a control freak when
it comes to my work.</p>
<p>So what can you do to increase the coefficient of the force
multiplier? It really depends on what kind of group you are. There are
some groups that are essentially just brand names for a specific person,
made in order to standardize both internal procedures and outward
expectations. Single-person tutoring centers come to mind. Then there
are groups that serve as a brand name multiple people can borrow from,
each person adopting their own style on top of the established standard.
(Again, tutoring centers).</p>
<p>What both of these groups have in common is that their value --- or
potentially, their lack thereof --- is derived from their standards and
procedures. Contrary to some beliefs, a bit of bureaucracy can be a good
thing: it ensures a certain quality and consistency. Bad standards,
however, are much more dangerous --- not only do they waste time, but
they can individually force what could've been good products to become
worse.</p>
<p>The people who do the best work are the ones that take pride in it.
And if the force multiplier for the quality of work in an organization
is less than 1, its efficiency be damned, the organization is completely
screwed. So above all, you have to make sure people can do good work in
such an organization, and only then should you focus on speed.<a
href="#fn4" class="footnote-ref" id="fnref4"
role="doc-noteref"><sup>4</sup></a></p>
<p>But there's a final type of group: one that exists because this
amassing of people is necessary to do something at all. By and large,
math contest-writing groups fall into this category. It's very rare that
one person has the technical, mathematical, logistical, and
presentational skills to run the whole operation. These groups are a
little more tricky to evaluate, because not having a force multiplier is
not an alternative. Here the default coefficient isn't 1 --- it's 0.</p>
<p>But zero is clearly not the threshold. People still get annoyed with
inefficient, mangled bureaucracies, even when there is no other
alternative. The force multiplier still needs to have a coefficient
greater than 1 for the organization to be healthy, because people can
still tell if their work <em>could</em> be better.</p>
<p>In fact, that gives a good definition for the coefficient of 1: as
good as you feel you could've done on your own.<a href="#fn5"
class="footnote-ref" id="fnref5" role="doc-noteref"><sup>5</sup></a></p>
<section id="footnotes" class="footnotes footnotes-end-of-document"
role="doc-endnotes">
<hr />
<ol>
<li id="fn1"><p>This example is simplified, because part of the value of
a broken object is how easily it could be fixed. If you wrote the
world's best novel but accidentally substituted every capital O with a
0, it would still be worth a lot because you can easily find and replace
these 0's.<a href="#fnref1" class="footnote-back"
role="doc-backlink">↩︎</a></p></li>
<li id="fn2"><p>There is one group that is decidedly wrong, however: the
people who are proud of never working through a book. It's one thing to
never optimize a certain force multiplier; perhaps circumstances may
have even made it the correct move. But it is another thing to wantonly
ignore an entire class of force multipliers and suggest to other people
they do the same.<a href="#fnref2" class="footnote-back"
role="doc-backlink">↩︎</a></p></li>
<li id="fn3"><p>On the flipside, if you're very inefficient, people will
get mad at each other and it won't be very pleasant.<a href="#fnref3"
class="footnote-back" role="doc-backlink">↩︎</a></p></li>
<li id="fn4"><p>For math organizations in particular, make sure you
provide good tooling. For instance, MAST's website, LaTeX structure, and
build script are all integrated, which makes it easier to write and
update solutions. This encourages a high quality of solutions, which
means that speed and quality are really not orthogonal.<a href="#fnref4"
class="footnote-back" role="doc-backlink">↩︎</a></p></li>
<li id="fn5"><p>Up until now, coefficients have been arbitrary, not in
the least because some strata of force multipliers are necessary. You
can't write text without a text editor, so what has a coefficient of 1?
A text editor with no tools, like Notepad (Windows), TextEdit (Mac), or
Nano/GEdit (Linux). This is because most people feel their base
productivity is on a text editor with no tooling, and that any extra
tools would increase productivity, rather than prevent its decrease.<a
href="#fnref5" class="footnote-back" role="doc-backlink">↩︎</a></p></li>
</ol>
</section>]]></description>
	<pubDate>6 Jan 2022</pubDate>
</item>
<item>
	<title>What the heck is a function?</title>
	<link>https://dennisc.net/writing/tech/functions.md</link>
	<description><![CDATA[<p>What is a function? Well, it's a thing that
takes things to things. That's not very specific. But it turns out this
very non-specific understanding is precisely what we need. Cast aside
your preconceptions that functions have to return things that "behave
well", like integers or reals. They can return anything: even
functions.</p>
<p>Why is this the case? Well, functions are <strong>things</strong>
themselves. So they can be the input of another function or the
output.</p>
<p>As an example, the derivative is certainly a function. It takes
things to things. But its input is a function, and its output is too.
Consider <span
class="math inline"><em>f</em>(<em>x</em>) = <em>x</em><sup>2</sup></span>
and its derivative <span
class="math inline"><em>f</em><sup>′</sup>(<em>x</em>) = 2<em>x</em></span>.
Here we input the <em>function</em> <span
class="math inline"><em>x</em><sup>2</sup></span> and get an output of
the <em>function</em> <span class="math inline">2<em>x</em></span>.</p>
<h2 id="a-detour-into-set-theory">A detour into set theory</h2>
<p>OK, so functions are things. But mathematically, what are these
things really? As with many other foundational questions, we must turn
to set theory.</p>
<p>Say we have a function whose domain is <span
class="math inline"><em>D</em></span> and whose codomain is <span
class="math inline"><em>R</em></span>. Then a function <span
class="math inline"><em>f</em></span> is just a subset of <span
class="math inline"><em>D</em> × <em>R</em></span> such that for every
<span class="math inline"><em>x</em> ∈ <em>D</em></span>, there is
exactly one <span class="math inline"><em>y</em> ∈ <em>R</em></span>
such that <span
class="math inline">(<em>x</em>, <em>y</em>) ∈ <em>f</em></span>. We
typically say <span
class="math inline"><em>f</em>(<em>x</em>) = <em>y</em></span> to denote
that <span
class="math inline">(<em>x</em>, <em>y</em>) ∈ <em>f</em></span>.</p>
<p>OK, so functions are Cartesian products. Cartesian products are also
sets, so there's no reason you couldn't take a Cartesian product of
Cartesian products. The point here is, it should feel very
<em>mathematically</em> natural to consider functions of functions.</p>
<p>There are many unquestioned assumptions here. What is an ordered pair
<span class="math inline">(<em>x</em>, <em>y</em>)</span>? It's a set of
the form <span
class="math inline">{<em>x</em>, {<em>x</em>, <em>y</em>}}</span>. And
what even is a set? Well... there's a long answer involving naive set
theory, Russel's paradox, and ZFC... and really <a
href="/writing/essays/properties">sets aren't some intrinsic
<em>thing</em>, they just are objects that satisfy some set of
properties</a>. Anyway, if you want to know more about this, I recommend
Dr. Schimmerling's <em>A course in set theory</em> (which I have gotten
through a small chunk of). He also has notes on formal logic, which is
necessary to fully understand the axioms of ZFC (i.e. what are
<em>properties</em>, with respect to the comprehension scheme
axiom?)</p>
<h2 id="functional-programming">Functional programming</h2>
<p>A slogan of of functional programming is that <em>functions are
values</em>. In the beginning I wasn't very specific with what a
function is:</p>
<blockquote>
<p>A function is a <strong>thing</strong> that takes things and returns
things.</p>
</blockquote>
<p>"Thing" is a little more well-defined in functional programming:
roughly, we say any piece of data that doesn't cause an
exception/infinite loop/other flavor of disaster is a <em>value</em>.
Integers are values, strings are values, booleans are values... and
functions are values.</p>
<p>So let's revise:</p>
<blockquote>
<p>A function is a value that takes values and returns values.</p>
</blockquote>
<h3 id="higher-order-functions">Higher-order functions</h3>
<p>But our naive functions, the ones that do basic things like take and
return integers, are still useful to reason about. That's why we have a
special term for these functions that take functions: a <em>higher-order
function</em> (HOF).</p>
<blockquote>
<p>A higher-order function (HOF) is a function that either takes in
functions or returns functions.</p>
</blockquote>
<p>Okay, here's an example of how higher order functions might help with
a (made-up) case study. <em>All code is written in Standard ML. You
don't really need to know SML to understand what is going on.</em></p>
<p>Suppose you want to have a function that allows Alice to input her
favorite color to return a sentence that returns her favorite color.</p>
<div class="sourceCode" id="cb1"><pre
class="sourceCode sml"><code class="sourceCode sml"><span id="cb1-1"><a href="#cb1-1" aria-hidden="true" tabindex="-1"></a><span class="kw">fun</span> aliceColor (color : <span class="dt">string</span>) : <span class="dt">string</span> =</span>
<span id="cb1-2"><a href="#cb1-2" aria-hidden="true" tabindex="-1"></a>    <span class="st">&quot;Alice&#39;s favorite color is &quot;</span> ^ color</span></code></pre></div>
<p><em>Note that the ^ operator performs string addition.</em></p>
<p>Now Bob wants in on the party. Okay, we'll write him a function
too.</p>
<div class="sourceCode" id="cb2"><pre
class="sourceCode sml"><code class="sourceCode sml"><span id="cb2-1"><a href="#cb2-1" aria-hidden="true" tabindex="-1"></a><span class="kw">fun</span> bobColor (color : <span class="dt">string</span>) : <span class="dt">string</span> =</span>
<span id="cb2-2"><a href="#cb2-2" aria-hidden="true" tabindex="-1"></a>    <span class="st">&quot;Bob&#39;s favorite color is &quot;</span> ^ color</span></code></pre></div>
<p>Okay... seems a little redundant. I mean, it's basically the same
function as <code>aliceColor</code>.</p>
<p>And now Charles, Darla, Ethan, and Frank want in on the party. At
this point, it might make sense to write a function that takes in a name
and returns a function that allows people to express their favorite
color. Let's do just that!</p>
<div class="sourceCode" id="cb3"><pre
class="sourceCode sml"><code class="sourceCode sml"><span id="cb3-1"><a href="#cb3-1" aria-hidden="true" tabindex="-1"></a><span class="kw">fun</span> colorQuery (name : <span class="dt">string</span>) : (<span class="dt">string</span> -&gt; <span class="dt">string</span>) =</span>
<span id="cb3-2"><a href="#cb3-2" aria-hidden="true" tabindex="-1"></a>    (<span class="kw">fn</span> color =&gt; name ^ <span class="st">&quot;&#39;s favorite color is &quot;</span> ^ color)</span></code></pre></div>
<p>If we write</p>
<div class="sourceCode" id="cb4"><pre
class="sourceCode sml"><code class="sourceCode sml"><span id="cb4-1"><a href="#cb4-1" aria-hidden="true" tabindex="-1"></a><span class="kw">val</span> aliceColor = colorQuery <span class="st">&quot;Alice&quot;</span></span></code></pre></div>
<p>then hooray, we have our function that allows Alice to input her own
favorite color.</p>
<h3 id="currying">Currying</h3>
<p>But what if I lied to you, the unassuming user, and told you that
<code>colorQuery</code> took two inputs? Unless you messed around and
found out, you'd believe me: <code>colorQuery</code> is a function that
takes in a name and a favorite color, and says NAME's favorite color is
COLOR. But you, who has seen and analyzed the code for
<code>colorQuery</code>, would go "no, you're just applying functions
twice."</p>
<p>This is the same for our favorite functions. Consider the
<code>max</code> function in Haskell. <em>We switch to Haskell because
in Haskell, every function is curried: that is, all functions secretly
only take one input. This is not the case in SML.</em> Open up
<code>ghci</code> and type</p>
<div class="sourceCode" id="cb5"><pre
class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb5-1"><a href="#cb5-1" aria-hidden="true" tabindex="-1"></a><span class="fu">max</span> <span class="dv">4</span> <span class="dv">5</span></span></code></pre></div>
<p>You get 5, as you expect.</p>
<p>But now... try</p>
<div class="sourceCode" id="cb6"><pre
class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb6-1"><a href="#cb6-1" aria-hidden="true" tabindex="-1"></a>max4 <span class="ot">=</span> <span class="fu">max</span> <span class="dv">4</span></span>
<span id="cb6-2"><a href="#cb6-2" aria-hidden="true" tabindex="-1"></a>max4 <span class="dv">3</span></span>
<span id="cb6-3"><a href="#cb6-3" aria-hidden="true" tabindex="-1"></a>max4 <span class="dv">5</span></span></code></pre></div>
<p><em>Note <code>max4</code> is a function value.</em></p>
<p>We get a function <code>max4</code> that compares integers to 4 and
returns the larger one.</p>
<p>Okay, let's return to SML code, and write our own max function that
is curried:</p>
<div class="sourceCode" id="cb7"><pre
class="sourceCode sml"><code class="sourceCode sml"><span id="cb7-1"><a href="#cb7-1" aria-hidden="true" tabindex="-1"></a><span class="kw">fun</span> max (x : <span class="dt">int</span>) : (<span class="dt">int</span> -&gt; <span class="dt">int</span>) =</span>
<span id="cb7-2"><a href="#cb7-2" aria-hidden="true" tabindex="-1"></a>    (<span class="kw">fn</span> y =&gt; <span class="kw">if</span> x &lt; y <span class="kw">then</span> y <span class="kw">else</span> x)</span></code></pre></div>
<p>If you ran</p>
<div class="sourceCode" id="cb8"><pre
class="sourceCode sml"><code class="sourceCode sml"><span id="cb8-1"><a href="#cb8-1" aria-hidden="true" tabindex="-1"></a><span class="kw">val</span> bigger = max <span class="dv">4</span> <span class="dv">5</span></span></code></pre></div>
<p>then great, bigger is just 5. But if you run</p>
<div class="sourceCode" id="cb9"><pre
class="sourceCode sml"><code class="sourceCode sml"><span id="cb9-1"><a href="#cb9-1" aria-hidden="true" tabindex="-1"></a><span class="kw">val</span> max4 = max <span class="dv">4</span></span></code></pre></div>
<p>then the code evaluates to</p>
<div class="sourceCode" id="cb10"><pre
class="sourceCode sml"><code class="sourceCode sml"><span id="cb10-1"><a href="#cb10-1" aria-hidden="true" tabindex="-1"></a><span class="kw">val</span> max4 =</span>
<span id="cb10-2"><a href="#cb10-2" aria-hidden="true" tabindex="-1"></a>    (<span class="kw">fn</span> y =&gt; <span class="kw">if</span> <span class="dv">4</span> &lt; y <span class="kw">then</span> y <span class="kw">else</span> <span class="dv">4</span>)</span></code></pre></div>
<p>This shouldn't be surprising: it's how we defined the
<code>max</code> function to begin with.</p>
<p>Currying functions like <code>max</code> isn't very useful, but when
you get to polymorphic higher-order functions, partial application can
become very useful.</p>
<h2 id="conclusion">Conclusion</h2>
<p>Here I presented several perspectives that all led to the same
conclusion: functions can take in/spit out other functions. First
consider the naive idea of a function as something that takes in things
and outputs things. Well, functions are things. Then consider that
functions are really subsets of Cartesian products, which are sets, so
you can take a function (a subset of a Cartesian product) of a function
(another subset of a Cartesian product, which is crucially a set!)
Finally, consider that programatically, it is useful to return functions
in order to remove redundant code. (That's what Rust does for
implementations of Traits!)</p>
<p>Maybe functions taking functions is old news to some of you. But
hopefully a few of you came away with a new perspective on
functions.</p>
<p>Further reading:</p>
<ul>
<li><em>A Course in Set Theory</em> by Ernest Schimmerling</li>
<li><a
href="http://learnyouahaskell.com/higher-order-functions"><em>Learn You
a Haskell for Great Good!</em></a></li>
<li>Learn OCaml/Haskell/etc...</li>
</ul>]]></description>
	<pubDate>27 Sep 2023</pubDate>
</item>
<item>
	<title>Mathematical objects are their properties</title>
	<link>https://dennisc.net/writing/essays/properties.md</link>
	<description><![CDATA[<p>In elementary school you probably thought of
multiplication as repeated addition, which works well for things like
<span class="math inline">41 ⋅ 17</span>.</p>
<p>But what about <span class="math inline">4.1 ⋅ 1.7</span>? Ok, so
multiplication is repeated addiition, <em>but</em> you can also do this
weird decimal shifting operation.</p>
<p>Well, what about <span class="math inline">3 ⋅ 0.333…</span>? Ok, so
multiplication also must have an inverse, so multiplication is repeated
addition <em>but</em> you also have to define a bunch of other stuff so
that multiplication stays closed in the rationals. Okay: that is still
kind of acceptable.</p>
<p>So where the hell is <span class="math inline">$\sqrt{2}\cdot
\sqrt{2}$</span> supposed to fit in with this model? In fact, what even
is <span class="math inline">$\sqrt{2}$</span>? Once you've properly
defined this, any analogy of "if I have 4 rows of 5 apples" has long
since flown out the window.</p>
<h2 id="what-is-multiplication">What is multiplication?</h2>
<p>Okay, so it's clearly absurd to continue thinking of multiplication
so simplistically. At the same time, "4 rows of 5" is a good analogy to
get kids to learn how to multiply; telling them what a Cauchy sequence
is or how you construct the real numbers is kind of silly.</p>
<p>But let's think more abstractly: what is multiplication? In our whole
number multiplication example, multiplication is a function that takes
two natural numbers to another natural numbers. It also is distributive
over another operation called <em>addition</em>...</p>
<blockquote>
<p>A <strong>field</strong> is a set of elements <span
class="math inline"><em>F</em></span> with two binary operations (i.e.
<span class="math inline"><em>F</em> × <em>F</em> → <em>F</em></span>,
taking two elements of <span class="math inline"><em>F</em></span> to
another element of <span class="math inline"><em>F</em></span>): <span
class="math inline">+</span> and <span class="math inline">⋅</span>.</p>
<p>Addition (<span class="math inline">+</span>) is associative and
commutative.</p>
<p>Multiplication is distributive and commutative.</p>
</blockquote>
<p>Also, there is an additive identity <span
class="math inline">0</span> and a multiplicative identity <span
class="math inline">1</span> with <span
class="math inline">0 ≠ 1</span>, every element has an additive inverse
(i.e. <span class="math inline"><em>a</em> + (−<em>a</em>) = 0</span>),
and every non-zero element has a multiplicative inverse (i.e. <span
class="math inline"><em>a</em> ⋅ <em>a</em><sup>−1</sup> = 0</span>).
But these properties are not too relevant, so we gloss over them for the
rest of this essay.</p>
<p>Looking at this definition, <strong>multiplication is just a binary
operator that distributes over addition</strong>.</p>
<p>This still doesn't really answer what multiplication is. OK,
multiplication does this distributive thing, but there's no general
physical meaning or anything tethering it to reality. All we have are
some nice little specific examples that don't really entirely encompass
what multiplication is. But that's kind of the point: there's no real
answer to what multiplication <em>is</em>.</p>
<p>However, you know what multiplication does: it distributes. And
sometimes we want to study specific instances of multiplication, like in
the rationals or the reals. In these specific cases multiplication will
take on more properties, and in some cases (like the rationals) there is
an easily understood analogy that almost makes you think,
"multiplication is just an extension of this apples analogy".</p>
<p>But ultimately, when you are generally studying multiplication, you
are studying <em>everything with a distributive property</em>. This
makes it easy to apply general results to a specific multiplicative
operator, like the multiplicative operator over the rationals or reals.
In general, <strong>when you study things based on their properties, you
get the most general results possible</strong>. That's why you should
reason about objects based on their properties.</p>
<h2 id="another-example-linear-algebra">Another example: Linear
Algebra</h2>
<p>Unless your first treatment of linear algebra is very theoretical,
you will likely be introduced to a vector like this:</p>
<blockquote>
<p>A vector is a list of elements <span
class="math inline">⟨<em>v</em><sub>1</sub>, …, <em>v</em><sub><em>n</em></sub>⟩</span>.</p>
</blockquote>
<p>This is a great example of how vectors behave: you can visualize the
independent components and you have an obvious basis you can work with:
the aptly-named <strong>standard basis</strong>. In the <span
class="math inline">2<em>D</em></span> plane and <span
class="math inline">3<em>D</em></span> space, you even have an obvious
physical analogy: unit vectors are literally perpendicular.</p>
<p>But this is just a convenient model for working with vectors. Things
like polynomials are vectors too, as well as other things that we may
not even be able to explicitly represent. Especially for objects like
the latter, how do we reason about them with linear algebra if we
<strong>don't even know what they are</strong>?</p>
<p>Well, here's how: you know what they do. Let's look at what a vector
really is, or more accurately, what a <strong>vector space</strong>
is:</p>
<blockquote>
<p>A vector space <span class="math inline"><em>V</em></span> over a
field <span class="math inline"><em>F</em></span> is a set of elements
with two binary operations:</p>
<ul>
<li>Addition: Given two objects <span
class="math inline"><em>v</em></span> and <span
class="math inline"><em>w</em></span> in <span
class="math inline"><em>V</em></span>, <span
class="math inline"><em>v</em> + <em>w</em></span> is also an element in
<span class="math inline"><em>V</em></span>.</li>
<li>Multiplication: Given a scalar <span
class="math inline"><em>a</em> ∈ <em>F</em></span> and a vector <span
class="math inline"><em>v</em></span>, <span
class="math inline"><em>a</em><em>v</em></span> is also an element in
<span class="math inline"><em>V</em></span>.</li>
</ul>
</blockquote>
<p>Of course, there are also axioms about associativity, commutativity,
distributivity, and identity/inverse elements, just like in a field. If
you want the full details, <a
href="https://en.wikipedia.org/wiki/Vector_space">the Wikipedia page on
vector spaces</a> should suffice.</p>
<p>Here is the main point: we <em>expect</em> vector addition and
multiplication to behave in certain ways --- many revolving around size
or magnitude --- because we are used to real numbers or complex numbers.
But fields where such notions do not exist can also form vector spaces.
Under these fields, we don't really understand what addition or
multiplication are. We can't even guarantee that every element in <span
class="math inline"><em>V</em></span> is in <span
class="math inline"><em>F</em><sup><em>n</em></sup></span>,
<strong>because we don't need to</strong>. Just because we no longer can
"multiply every element <span
class="math inline"><em>v</em><sub><em>i</em></sub></span> by a scalar
<span class="math inline"><em>a</em></span>" explicitly, and just
because we don't necessarily know what this multiplication operation is,
doesn't mean we still can't reason about it so long as it's distributive
(and some other stuff).</p>
<p>Especially because some of the properties of a vector space are so
abstract, you can't really reason about what a vector space <em>is</em>.
Sure, there are some good examples like <span
class="math inline">ℝ<sup>3</sup></span>. But in the end those are just
illustrative examples.</p>
<p>Let's look at what a linear map is.</p>
<blockquote>
<p>A linear map satisfies</p>
<ul>
<li><span
class="math inline"><em>T</em>(<em>u</em> + <em>v</em>) = <em>T</em>(<em>u</em>) + <em>T</em>(<em>v</em>)</span></li>
<li><span
class="math inline"><em>T</em>(<em>a</em><em>v</em>) = <em>a</em><em>T</em>(<em>v</em>)</span></li>
</ul>
</blockquote>
<p>Notice how neither of these properties rely on vectors being
explicitly representable, say, as a list. We don't actually know what
vectors are or what these linear maps are, just how they behave. And yet
algebra still works fine even if we don't explicitly write out vectors
as <span
class="math inline">⟨<em>v</em><sub>1</sub>, …, <em>v</em><sub><em>n</em></sub>⟩</span>
and explicitly write out linear transforms as matrices, because
everything still works even if we can't write them out explicitly.</p>
<p>In fact, linear algebra isn't the study of these <span
class="math inline">⟨<em>v</em><sub>1</sub>, …, <em>v</em><sub><em>n</em></sub>⟩</span>
things or these weird arrays of numbers. It's not about lists or
matrices. At its core, we are studying <em>every set of objects and
functions that satisfies linearity, all at the same time</em>. We're not
studying vectors or linear maps as if they are some concrete thing, but
as properties: we are studying objects that behave linearly.</p>
<h2 id="conclusion">Conclusion</h2>
<p>Multiplication as repeated addition and vectors as lists serve as
very good examples for how multiplication and vectors behave. Much would
be lost if we stopped using these analogies.</p>
<p>However, much would also be lost if we don't focus on the
fundamentals as well. For instance, many linear algebra courses focus so
much on the fields <span class="math inline">ℝ</span> and <span
class="math inline">ℂ</span> that we often lose the ability to think
abstractly about vector spaces over <em>all</em> fields, even when many
of the results proved in <span class="math inline">ℂ</span> still hold
true for any field <span class="math inline"><em>F</em></span>.</p>
<p>Objects are their properties. That's all they are. Any other
descriptor is just a motivated example.</p>
<h2 id="addendum">Addendum</h2>
<p>One reason to study vector spaces abstractly is that non-trivial
vector spaces can be finite. If you only reason about the fields <span
class="math inline">ℝ</span> and <span class="math inline">ℂ</span>, it
might be a little difficult to reason about the field <span
class="math inline">𝔽<sub><em>p</em></sub></span> (the field of integers
modulo <span class="math inline"><em>p</em></span>). Yet many results
that hold on <span class="math inline">ℝ</span> and <span
class="math inline">ℂ</span> hold true on <span
class="math inline">𝔽<sub><em>p</em></sub></span> and indeed a vector
space over any other field.</p>
<p>This is why, whenever possible, we should prove theorems using
properties as fundamental as possible. That way, instead of using some
cursed characteristic polynomial argument to prove something just for
the field <span class="math inline">ℂ</span>, we can use a more elegant
argument to prove it for vector spaces over any
field.</p>]]></description>
	<pubDate>3 Jul 2023</pubDate>
</item>
<item>
	<title>How to make a static website</title>
	<link>https://dennisc.net/writing/tech/static-website.md</link>
	<description><![CDATA[<p>Making a static website has been a solved
problem for a long time, yet people still manage to fuck it up in the
most spectacular of ways. Google is not helpful either, since it gives
you the next shitty version of Wix.</p>
<p>Let's start from the top. This is how you make a static website.<a
href="#fn1" class="footnote-ref" id="fnref1"
role="doc-noteref"><sup>1</sup></a></p>
<h2 id="what-is-a-static-website-anyways">What is a static website,
anyways?</h2>
<p>A static website is one that serves the same content to everyone. A
site like Facebook is not a static website because depending on who
you're signed in as, you'll have permission to see different things. How
that's done is beyond the scope of this article, though.</p>
<p>This site is a static website. Your personal website (if that is what
you are making) will likely be one too.</p>
<h2 id="specs">Specs</h2>
<p>Before you write a website, you should know how HTML and CSS work.
(You do not need to learn how Javascript works, because you should never
use it anyway.) Be willing to Google, but know that most resources are
counterproductive when it comes to web development.</p>
<p>General principles to keep in mind are avoid Javascript at all
costs<a href="#fn2" class="footnote-ref" id="fnref2"
role="doc-noteref"><sup>2</sup></a>, generally don't trust Medium or
Dev.to articles, and prefer MDN over W3Schools (in some cases, W3Schools
is acceptable).</p>
<h3 id="html">HTML</h3>
<p>The key idea is that HTML is marked up with tags, some of which
contain semantic information. Here's am example of a valid HTML
document:</p>
<div class="sourceCode" id="cb1"><pre
class="sourceCode html"><code class="sourceCode html"><span id="cb1-1"><a href="#cb1-1" aria-hidden="true" tabindex="-1"></a><span class="dt">&lt;!DOCTYPE</span> html<span class="dt">&gt;</span></span>
<span id="cb1-2"><a href="#cb1-2" aria-hidden="true" tabindex="-1"></a><span class="dt">&lt;</span><span class="kw">html</span><span class="ot"> lang</span><span class="op">=</span><span class="st">&quot;en&quot;</span><span class="dt">&gt;</span></span>
<span id="cb1-3"><a href="#cb1-3" aria-hidden="true" tabindex="-1"></a>    <span class="dt">&lt;</span><span class="kw">head</span><span class="dt">&gt;</span></span>
<span id="cb1-4"><a href="#cb1-4" aria-hidden="true" tabindex="-1"></a>        <span class="dt">&lt;</span><span class="kw">title</span><span class="dt">&gt;</span>Dennis Chen&#39;s Web Page<span class="dt">&lt;/</span><span class="kw">title</span><span class="dt">&gt;</span></span>
<span id="cb1-5"><a href="#cb1-5" aria-hidden="true" tabindex="-1"></a>        <span class="dt">&lt;</span><span class="kw">meta</span><span class="ot"> name</span><span class="op">=</span><span class="st">&quot;viewport&quot;</span><span class="ot"> content</span><span class="op">=</span><span class="st">&quot;width=device-width, initial-scale=1.0&quot;</span><span class="dt">&gt;</span></span>
<span id="cb1-6"><a href="#cb1-6" aria-hidden="true" tabindex="-1"></a>        <span class="dt">&lt;</span><span class="kw">meta</span><span class="ot"> name</span><span class="op">=</span><span class="st">&quot;description&quot;</span><span class="ot"> content</span><span class="op">=</span><span class="st">&quot;This is a description.&quot;</span><span class="dt">&gt;</span></span>
<span id="cb1-7"><a href="#cb1-7" aria-hidden="true" tabindex="-1"></a>    <span class="dt">&lt;/</span><span class="kw">head</span><span class="dt">&gt;</span></span>
<span id="cb1-8"><a href="#cb1-8" aria-hidden="true" tabindex="-1"></a>    <span class="dt">&lt;</span><span class="kw">body</span><span class="dt">&gt;</span></span>
<span id="cb1-9"><a href="#cb1-9" aria-hidden="true" tabindex="-1"></a>        <span class="dt">&lt;</span><span class="kw">main</span><span class="dt">&gt;</span></span>
<span id="cb1-10"><a href="#cb1-10" aria-hidden="true" tabindex="-1"></a>            <span class="dt">&lt;</span><span class="kw">h1</span><span class="dt">&gt;</span>Dennis Chen&#39;s Web Page<span class="dt">&lt;/</span><span class="kw">h1</span><span class="dt">&gt;</span></span>
<span id="cb1-11"><a href="#cb1-11" aria-hidden="true" tabindex="-1"></a>            <span class="dt">&lt;</span><span class="kw">p</span><span class="dt">&gt;</span>Welcome to my webpage!<span class="dt">&lt;/</span><span class="kw">p</span><span class="dt">&gt;</span></span>
<span id="cb1-12"><a href="#cb1-12" aria-hidden="true" tabindex="-1"></a>        <span class="dt">&lt;/</span><span class="kw">main</span><span class="dt">&gt;</span></span>
<span id="cb1-13"><a href="#cb1-13" aria-hidden="true" tabindex="-1"></a>    <span class="dt">&lt;/</span><span class="kw">body</span><span class="dt">&gt;</span></span>
<span id="cb1-14"><a href="#cb1-14" aria-hidden="true" tabindex="-1"></a><span class="dt">&lt;/</span><span class="kw">html</span><span class="dt">&gt;</span></span></code></pre></div>
<p>HTML should be considered a tree: each element can have children, and
most elements belong to a parent (the only exceptions are the outermost
html tag and the DOCTYPE tag).</p>
<p>Let's break each of these tags down one by one and explain why all of
them are necessary:</p>
<ul>
<li><code>&lt;!DOCTYPE html&gt;</code>: It declares to the browser that
you're using valid HTML 5. Otherwise, it will assume that you're in the
90s and display the website using <a
href="https://developer.mozilla.org/en-US/docs/Web/HTML/Quirks_Mode_and_Standards_Mode">Quirks
Mode</a>.</li>
<li><code>&lt;html lang="en"&gt;</code>: Specifying <code>en</code> is
helpful for the purposes of SEO (search engine optimization) and also
tells screenreaders what language your site is in, which helps with
pronunciation.</li>
<li><code>&lt;head&gt;</code>: It contains metadata.</li>
<li><code>&lt;title&gt;</code>: It sets the tab title in your browser
and is also used for SEO.</li>
<li><code>&lt;desc&gt;</code>: This is the description that's displayed
in your search engine.</li>
<li><code>&lt;meta name="viewport"...&gt;</code>: It makes your website
not suck on mobile browsers. See <a
href="https://stackoverflow.com/questions/61238548/side-effects-of-removing-width-device-width-from-viewport-meta-tag-when-initi">Stack
Overflow</a> for a more complete explanation. This tag should be
included verbatim and should not be changed for any reason
whatsoever.</li>
<li><code>&lt;body&gt;</code>: Delineates where content starts.</li>
<li><code>&lt;main&gt;</code>: Delineates where the main content is.
(Stuff like the navbar and footer would not be placed in here, but would
be placed in <code>body</code>.)</li>
</ul>
<p>You <strong>must</strong> include all of these tags in your HTML
document. If you have a navbar (you probably should), put it inside
<code>&lt;nav&gt;</code>. Same for footers: use
<code>&lt;footer&gt;</code>.</p>
<p>If you use the right tags, the document will semantically make sense
without ARIA roles. (If you don't know what ARIA tags are, that's fine.
Only Javascript soydevs, including myself once upon a time, who can't be
assed to read the docs or Google will need them anyway.) If you are
using ARIA tags, you are probably doing something wrong. Even <a
href="https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA">Mozilla
agrees with me</a>:</p>
<blockquote>
<p>Many of these widgets were later incorporated into HTML5, and
developers should prefer using the correct semantic HTML element over
using ARIA, if such an element exists. For instance, native elements
have built-in keyboard accessibility, roles and states. However, if you
choose to use ARIA, you are responsible for mimicking the equivalent
browser behavior in script.</p>
</blockquote>
<p><a
href="https://drewdevault.com/2021/06/27/You-cant-capture-the-nuance.html">Just
don't use custom form fields, buttons, etc and you will be fine.</a> If
you don't know what I'm talking about: good. Keep it that way. A button
should obviously be a <code>&lt;button&gt;</code> and not a
<code>&lt;div onclick=&gt;</code>, anyone that tells you otherwise is
wrong.</p>
<h3 id="css">CSS</h3>
<p>CSS is how documents are styled. Some people have different
perspectives on how much of the document should be styled with CSS
versus inline with HTML. Should everything be styled in a
<code>main.css</code> stylesheet? Or should some styling be done with
HTML, a la Tailwind? I am personally of the opinion that most styling
belongs in CSS stylesheets, but other perspectives exist and may be
worth considering.</p>
<p>CSS is also a total nightmare. Okay, not really, it's just kind of
hard for beginners to implement some useful things. In this section
we're going to discuss how to accomplish some more tricky things, like
having a navbar where the "Home" link is on the left and the other stuff
is all on the right. (We skip over the easy stuff like changing colors
because any idiot can do that.)</p>
<p>The two CSS classes you should know about and are least likely to are
<a
href="https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Flexible_Box_Layout/Basic_Concepts_of_Flexbox">flex-boxes</a>
and <a
href="https://developer.mozilla.org/en-US/docs/Web/CSS/grid">grids</a>.
For flex-boxes, you should know that <code>justify</code> controls
alignment of elements across the main axis and <code>align</code>
controls alignments of elements on the cross axis (perpendicular to the
main axis). In conjunction with <code>margin: auto</code>, or perhaps a
directional <code>margin-right: auto</code>, the flex-box can be very
powerful.</p>
<p>With regards to fonts, prefer to use general font families rather
than specific fonts. I know the default sans serif is ugly, so at the
very least, fall back to a general font family if you must specify a
font.</p>
<p>Here is a rudimentary example of a navbar with a "Home" link
left-justified and the other links right-justified.</p>
<p>HTML:</p>
<div class="sourceCode" id="cb2"><pre
class="sourceCode html"><code class="sourceCode html"><span id="cb2-1"><a href="#cb2-1" aria-hidden="true" tabindex="-1"></a><span class="dt">&lt;</span><span class="kw">nav</span><span class="dt">&gt;</span></span>
<span id="cb2-2"><a href="#cb2-2" aria-hidden="true" tabindex="-1"></a>    <span class="dt">&lt;</span><span class="kw">a</span><span class="ot"> class</span><span class="op">=</span><span class="st">&quot;nav-home&quot;</span><span class="ot"> href</span><span class="op">=</span><span class="st">&quot;/&quot;</span><span class="dt">&gt;</span>Home<span class="dt">&lt;/</span><span class="kw">a</span><span class="dt">&gt;</span></span>
<span id="cb2-3"><a href="#cb2-3" aria-hidden="true" tabindex="-1"></a>    <span class="dt">&lt;</span><span class="kw">a</span><span class="ot"> href</span><span class="op">=</span><span class="st">&quot;/link1&quot;</span><span class="dt">&gt;</span>Link 1<span class="dt">&lt;/</span><span class="kw">a</span><span class="dt">&gt;</span></span>
<span id="cb2-4"><a href="#cb2-4" aria-hidden="true" tabindex="-1"></a>    <span class="dt">&lt;</span><span class="kw">a</span><span class="ot"> href</span><span class="op">=</span><span class="st">&quot;/link2&quot;</span><span class="dt">&gt;</span>Link 2<span class="dt">&lt;/</span><span class="kw">a</span><span class="dt">&gt;</span></span>
<span id="cb2-5"><a href="#cb2-5" aria-hidden="true" tabindex="-1"></a><span class="dt">&lt;/</span><span class="kw">nav</span><span class="dt">&gt;</span></span></code></pre></div>
<p>Note that the class <code>nav-home</code> doesn't mean anything yet,
it's only when we apply CSS styling that it makes a difference.</p>
<p>CSS:</p>
<div class="sourceCode" id="cb3"><pre
class="sourceCode css"><code class="sourceCode css"><span id="cb3-1"><a href="#cb3-1" aria-hidden="true" tabindex="-1"></a>a<span class="fu">.nav-home</span> {</span>
<span id="cb3-2"><a href="#cb3-2" aria-hidden="true" tabindex="-1"></a>    <span class="kw">margin-right</span><span class="ch">:</span> <span class="bu">auto</span><span class="op">;</span></span>
<span id="cb3-3"><a href="#cb3-3" aria-hidden="true" tabindex="-1"></a>}</span></code></pre></div>
<p>In general, I recommend putting the following directive in your CSS
stylesheet:</p>
<div class="sourceCode" id="cb4"><pre
class="sourceCode css"><code class="sourceCode css"><span id="cb4-1"><a href="#cb4-1" aria-hidden="true" tabindex="-1"></a>html {</span>
<span id="cb4-2"><a href="#cb4-2" aria-hidden="true" tabindex="-1"></a>    <span class="kw">font-family</span><span class="ch">:</span> <span class="dv">sans-serif</span><span class="op">;</span></span>
<span id="cb4-3"><a href="#cb4-3" aria-hidden="true" tabindex="-1"></a>    <span class="kw">max-width</span><span class="ch">:</span> <span class="dv">800</span><span class="dt">px</span><span class="op">;</span></span>
<span id="cb4-4"><a href="#cb4-4" aria-hidden="true" tabindex="-1"></a>    <span class="kw">margin</span><span class="ch">:</span> <span class="bu">auto</span><span class="op">;</span></span>
<span id="cb4-5"><a href="#cb4-5" aria-hidden="true" tabindex="-1"></a>}</span></code></pre></div>
<p>You can change <code>max-width</code> if you want. What's important
is that, based on whatever fontsize you choose, there are around 60-80
characters in each line of text. Anything more is unreasonable.
<code>margin: auto</code> just automatically uses the remaining space
and divides it to create equal margins on the left and right, which has
the effect of centering it.</p>
<h2 id="math">Math</h2>
<p><strong>Update: MathML is supported in Chrome now! All you have to do
is pass the <code>--mathml</code> flag to pandoc now.</strong></p>
<p>If you're reading this website, you probably have some interest in
getting math to render properly on your website. If you're using pandoc,
there are a variety of flag combinations you can pass to get embedded
math equations. Unfortunately, each of them have their traedoffs (read:
they all suck).</p>
<ul>
<li>WebTeX (<code>--webtex --self-contained</code><a href="#fn3"
class="footnote-ref" id="fnref3" role="doc-noteref"><sup>3</sup></a>):
You are serving a lot of images to the client and worse, pandoc has the
gall to add shitty inline styles to your document. However, you can use
a custom pandoc template that doesn't contain any of the crap you don't
need, such as the inlined styles. I recommend you not let Pandoc handle
the hard work and just have your template be <code>$body$</code>.</li>
<li>MathML (<code>--mathml</code>): This is the best solution from a
standards standpoint... but MathML isn't implemented in Chromium or any
of its derivatives, which makes it unusable for the vast majority of
your visitors. Check back in a few years though, <a
href="https://www.igalia.com/2022/06/22/Intent-to-Ship-MathML.html">promising
progress is being made</a>.</li>
<li>MathJax/KaTeX (<code>--mathjax</code>/<code>--katex</code>): This is
the most popular solution, and if you asked anyone else, this is what
they would recommend. If I had more non-trivial math equations to
render, I'd use KaTeX, but I'm really hellbent about keeping Javascript
off of this site. If you're going to use a Javascript library though,
use KaTeX.</li>
</ul>
<p>With regards to styling, <em>only</em> MathML works as you'd want it
to. KaTeX is slightly hacky, you have to modify the <code>fill</code>
and <code>stroke</code> attributes because you're working with SVGs, and
WebTeX is <em>really hacky</em> because you have to invert all images
with class <code>math</code>.</p>
<p>I personally use MathML because I don't have a lot of complex
equations to render, that's not what my writing is usually about. If you
<em>must</em> have everyone see your math rendered and <em>must not</em>
use Javascript (a rare combination!) then use WebTeX. For everyone else,
KaTeX is the best choice. But MathML has made some promising progress,
so I'd check back in mid-2023. (That's when the people spearheading the
inclusion of MathML in Chrome hope to have it upstreamed.)</p>
<h2 id="code">Code</h2>
<p>Pandoc also solves the problem of displaying code snippets. Just use
code blocks and annotate a language, as thus:</p>
<pre><code>```c
printf(&quot;Hello, world!&quot;);
```</code></pre>
<p>This will get you</p>
<div class="sourceCode" id="cb6"><pre class="sourceCode c"><code class="sourceCode c"><span id="cb6-1"><a href="#cb6-1" aria-hidden="true" tabindex="-1"></a>printf<span class="op">(</span><span class="st">&quot;Hello, world!&quot;</span><span class="op">);</span></span></code></pre></div>
<p>Pandoc uses Skylighting to semantically mark up each of the
characters with an HTML class. Therefore, you can apply a stylesheet for
syntax highlighting. See this <a
href="https://raw.githubusercontent.com/runxel/skylighting-theme/master/mylighting.css">example
stylesheet</a>.</p>
<p>If you want, you can explicitly number lines as such:</p>
<pre><code>```{.c .numberLines}
printf(&quot;Hello, world&quot;!);
```</code></pre>
<p>However, I anti-recommend this approach. If you're displaying more
than one line of code in a code block, you should always be annotating
line numbers if only for consistency. This is what I do on this
website.</p>
<p>Pandoc will apply the <em>semantic</em> classes for you, but it is
still up to you to apply CSS styling for it. Here's a shell script I
copied off the internet that will give you a CSS stylesheet for your
code:</p>
<div class="sourceCode" id="cb8"><pre
class="sourceCode bash"><code class="sourceCode bash"><span id="cb8-1"><a href="#cb8-1" aria-hidden="true" tabindex="-1"></a><span class="va">style</span><span class="op">=</span><span class="va">${1</span><span class="op">:-</span>pygments<span class="va">}</span></span>
<span id="cb8-2"><a href="#cb8-2" aria-hidden="true" tabindex="-1"></a><span class="va">tmp</span><span class="op">=</span></span>
<span id="cb8-3"><a href="#cb8-3" aria-hidden="true" tabindex="-1"></a><span class="bu">trap</span> <span class="st">&#39;rm -f &quot;$tmp&quot;&#39;</span> EXIT</span>
<span id="cb8-4"><a href="#cb8-4" aria-hidden="true" tabindex="-1"></a><span class="va">tmp</span><span class="op">=</span><span class="va">$(</span><span class="fu">mktemp</span><span class="va">)</span></span>
<span id="cb8-5"><a href="#cb8-5" aria-hidden="true" tabindex="-1"></a><span class="bu">echo</span> <span class="st">&#39;$highlighting-css$&#39;</span> <span class="op">&gt;</span> <span class="st">&quot;</span><span class="va">$tmp</span><span class="st">&quot;</span></span>
<span id="cb8-6"><a href="#cb8-6" aria-hidden="true" tabindex="-1"></a><span class="bu">echo</span> <span class="st">&#39;`test`{.c}&#39;</span> <span class="kw">|</span> <span class="ex">pandoc</span> <span class="at">--highlight-style</span><span class="op">=</span><span class="va">$style</span> <span class="at">--template</span><span class="op">=</span><span class="va">$tmp</span></span></code></pre></div>
<p>If you want a list of the valid highlighting styles you can pass into
this script, run <code>pandoc --list-highlight-styles</code>.</p>
<p>I've made some modifications with regards to spacing in my <a
href="/code.css">CSS stylesheet</a> and removed the background, because
I think the defaults generated by pandoc kind of suck.</p>
<h2 id="editability-and-the-build-process">Editability and the build
process</h2>
<p>Just because you need to serve HTML doesn't mean you need to write
all of it. Typically what a beginner will do is manually write HTML for
each page, with some judicious copy-pasting. Instead, the correct
approach is to write content in an easy to edit format. The most popular
format is <a
href="https://www.markdownguide.org/basic-syntax/">Markdown</a>, and
it's what I personally use.</p>
<p>This is where you need to start learning how to the command line. You
need to be able to build your website using commands on a Unix-based
operating system because that's where it'll be hosted. Windows users,
take note: This means you need to get off of that shitty operating
system, at least for development purposes. Spin up an instance of Linux
(I recommend Alpine) using qemu. See <a
href="https://drewdevault.com/2018/09/10/Getting-started-with-qemu.html">Drew
Devault's qemu post</a> for help setting that up.<a href="#fn4"
class="footnote-ref" id="fnref4" role="doc-noteref"><sup>4</sup></a></p>
<p>The way your build script will look depends largely on the file
structure of your website. However, you will almost certainly be using
<code>pandoc</code> to convert HTML to Markdown, <code>jq</code> to
parse the metadata from your Markdown files, and probably sed/awk to
insert your generated HTML into your base templates.</p>
<h2 id="hosting">Hosting</h2>
<p>Hosting is largely beyond the scope of this article. However, I will
briefly overview the two approaches you can take:</p>
<ul>
<li>Have someone else host it for you. Typically people do this through
GitHub Pages, but in my opinion, there is no excuse to use anything
besides <a href="https://srht.site/">sourcehut pages</a>.<a href="#fn5"
class="footnote-ref" id="fnref5"
role="doc-noteref"><sup>5</sup></a></li>
<li>Host it on your own. If this is the approach you're taking, I
recommend NGINX as your server software. (If you haven't gotten a server
yet and need to pick an OS, I suggest Alpine Linux or one of the
BSDs.)</li>
</ul>
<p>For the latter you need your own domain, and even if you aren't
hosting on your own server, you still can use one as well. You can get
one through a variety of domain registries, but make sure that whatever
you choose has a good API.</p>
<h2 id="summary">Summary</h2>
<ul>
<li>Static websites serve the same content to everyone, so you don't
need a backend.</li>
<li><strong>Never use Javascript.</strong> Whatever you want to do,
there's probably an HTML element for it.</li>
<li>Whenever possible, use semantically correct tags for HTML. One
probably exists for whatever use-case you have.</li>
<li>Learn about flex-boxes and grids for CSS.</li>
<li>Pandoc, with some effort, supports math equations and code
blocks.</li>
<li>Use well-known and battle-tested command-line utilities to compose
your build scripts.</li>
<li>Host with <a href="https://srht.site">srht.site</a> if you don't
have your own server.</li>
</ul>
<p>I am a very opinionated developer, so you may find yourself
disagreeing with some of my points. However, please make sure your
websites are accessible and design with speed, longevity, and empathy in
mind. Ultimately your users will not care if you built your site with
Hugo or a series of bash scripts, but hopefully this post has convinced
you that you do not need or want the latest Javascript framework for a
simple, static site that doesn't need to provide an interactive
experience anyway.</p>
<p>I hope this post was helpful! A post on full-stack websites will be
coming soon :)</p>
<section id="footnotes" class="footnotes footnotes-end-of-document"
role="doc-endnotes">
<hr />
<ol>
<li id="fn1"><p>If you would like an example of a good website, see <a
href="https://mathadvance.org">mathadvance.org</a>. My <a
href="https://gitlab.com/chennisden/dennisc.net">personal website</a> is
a bit more complex, but it shows you how to auto-generate the <a
href="/writing">writing page</a> as well.<a href="#fnref1"
class="footnote-back" role="doc-backlink">↩︎</a></p></li>
<li id="fn2"><p>The only exception I can think of is interactive timers,
and maybe autosubmit once time runs out, which is all the Javascript I
intend to put on the MAT website --- speaking of which, one day it will
be fixed...</p>
<p>Not that any of this is relevant to this post, since MAT is not a
static website.<a href="#fnref2" class="footnote-back"
role="doc-backlink">↩︎</a></p></li>
<li id="fn3"><p>The <code>--self-contained</code> flag generates the
images and stores them as base64 in the HTML files, which means that at
least you aren't calling an external website for your images.</p>
<p>But if you have non-inlined CSS styles, it won't be self-contained...
god, what a fucking mess!<a href="#fnref3" class="footnote-back"
role="doc-backlink">↩︎</a></p></li>
<li id="fn4"><p>I don't recommend using a virtual machine for Linux,
however. In the long term you will learn so much more if you just
daily-drive it.<a href="#fnref4" class="footnote-back"
role="doc-backlink">↩︎</a></p></li>
<li id="fn5"><p>I'll elaborate a bit on why SourceHut Pages is the
correct choice. Basically, it's because you can "push" to SourceHut
pages by just sending a tarball instead of using a Git repository as an
extra layer of indirection.</p>
<p>This makes it really easy to make publishing just a <a
href="https://git-scm.com/book/en/v2/Customizing-Git-Git-Hooks">post-push
Git hook</a>.<a href="#fnref5" class="footnote-back"
role="doc-backlink">↩︎</a></p></li>
</ol>
</section>]]></description>
	<pubDate>26 Jun 2022</pubDate>
</item>
<item>
	<title>Write for Smart People</title>
	<link>https://dennisc.net/writing/essays/write-smart.md</link>
	<description><![CDATA[<p>Writing can help you sort out your thoughts,
some of which you may not have even known you were thinking. Yet writing
can also be expository, like in a textbook. In this regard, it is
important to consider your audience --- if you make an unreasonable
assumption about what they know or how they think, your writing will fly
over their heads.<a href="#fn1" class="footnote-ref" id="fnref1"
role="doc-noteref"><sup>1</sup></a></p>
<p>Traditionally these two goals of writing have been divorced. You are
either writing for yourself, or for someone else. Diaries for you,
articles and textbooks for other people. This results in writing that is
nearly incomprehensible: think high school math textbooks. I doubt that
many high schoolers have thought about their ideal math textbook, but if
they did I bet it would look nothing like what we have now.</p>
<p>The only idea you can express properly is one you yourself have. So
the closer you can get to writing for yourself, the better. And when it
comes down to it, the closest you can get is writing for smart
people.</p>
<h2 id="first-principles">First Principles</h2>
<p>In the fictional SCP Foundation there are a series of stories about
<a
href="https://scp-wiki.wikidot.com/antimemetics-division-hub">antimemetics</a>,
entities that make you lose your memories. And the way the characters
combat these <em>antimemetics</em> is by preparing notes or clues such
that they can rederive everything they knew, as quickly as possible.</p>
<p>And that's what writing is. You don't forget things nearly as quickly
as in the SCP stories, but memory is still unreliable. Your working
memory can hold maybe seven distinct pieces of information at a time.
That's barely enough to keep a sentence or two in your head at once. In
fact, when I write these essays, I typically write one phrase at a time,
or even just a couple of words. That's because I can go back and retrace
my stream of thought, in a way that I can't when I'm just thinking.</p>
<p>But writing is not merely a recording of thought. From a standpoint
of artistry and efficiency, you are trying to move through <em>as fast
as possible</em>, without leaving anything out. This implies that not
all writing is equal: if one piece can express a point more clearly and
succinctly than another, it is better, at least in that regard.</p>
<p>Fast doesn't mean short though. Fast means easy for whoever's
reading. Think about code: ninety-nine times out of a hundred, you
prefer the straightforward solution over the clever one-liner, even if
it's a bit longer and runs slower. Because what you write shouldn't just
make sense to yourself now --- it has to make sense to you five years in
the future too. That's why it's useful to write for prosperity and to
have an audience: you won't get caught up by any assumptions of any
specific knowledge you have or your state of mind at the moment if you
don't make them to begin with.</p>
<p>Information isn't only contained in the facts themselves; it's also
contained in how they are arranged. And it is much easier for someone to
process information through structure than isolated facts. Try to think
of every formula for the area of a triangle that you can. You probably
listed some subset of the following:</p>
<ul>
<li><span class="math inline">$\frac{bh}{2}$</span></li>
<li><span class="math inline"><em>r</em><em>s</em></span></li>
<li><span class="math inline">$\frac{1}{2}ab\sin C$</span></li>
<li><span class="math inline">$\frac{abc}{4R}$</span></li>
<li><span class="math inline">$\sqrt{s(s-a)(s-b)(s-c)}$</span></li>
</ul>
<p>This is the way every textbook teaches the area formulae and the way
most students learn it. You'd be fortunate if a textbook even provided
you such a list; all the textbooks I've seen separate them into separate
<em>chapters</em>, if it even includes all five.<a href="#fn2"
class="footnote-ref" id="fnref2" role="doc-noteref"><sup>2</sup></a></p>
<p>Thinking about the area formulae this way is not correct. Instead
consider the following chart, excerpted from the draft of my
introductory geometry textbook:</p>
<p><img src="/writing/essays/write-smart/area-chart.png" alt="Chart of area formulae"></p>
<p>If you already knew the proofs, their connections are self-evident
through the chart. And if you didn't, now you know what to expect. In
any case, memorization is wholly unnecessary, because the proofs suggest
themselves.<a href="#fn3" class="footnote-ref" id="fnref3"
role="doc-noteref"><sup>3</sup></a></p>
<h2 id="importing">Importing</h2>
<p>You don't want to explain every concept you use from scratch or it's
going to distract from the point you're trying to make. And not all
words are created equal: certain words and concepts are more
<em>expressive</em>.<a href="#fn4" class="footnote-ref" id="fnref4"
role="doc-noteref"><sup>4</sup></a></p>
<p>Think about importing a library in a program. In theory, you could
reimplement it all on your own, but you have no reason to, and in any
serious application that would be completely infeasible. So the same
goes for writing. You couldn't possibly hope to explain every concept in
purely theoretical terms, devoid of any context from the outside world.
So we use examples, analogies, and shared knowledge in order to
communicate our ideas.</p>
<p>See what I did there? By taking something familiar and comparing it
to my idea, I was able to explain it more concretely.</p>
<p>All of this is contingent on the reader understanding the basics of
programming, or at the least, being willing to look it up. This
assumption precludes at least ninety percent of the world from reading
my essays. That's okay, because I'm not writing for those ninety
percent.</p>
<p>But the title of this essay isn't "Assume Your Audience Knows
Everything You Do". For some readers, a couple of points in an essay
might not land. Maybe even an entire essay. You want to write for smart
people because you have reason to believe this will change.</p>
<p>This is why rereading is so important. You might not have gotten all
the information or understood all of the examples the first time
through. And if you're smart, you can expect to see something new with
each reread. <strong>This is true even if you're the one who
<em>wrote</em> the essay.</strong><a href="#fn5" class="footnote-ref"
id="fnref5" role="doc-noteref"><sup>5</sup></a> It follows that <a
href="/writing/essays/reread">any good writing is worth rereading</a>,
because if a reader can absorb everything in one go, then it must not be
very information-dense.</p>
<p>You can trick yourself into getting very far even if you don't have
anything to say when you're writing for stupid people. Think 99% of
notes from private tutors (if you've ever had one): when you are alone
and reviewing them, you realize they are just unintelligible
chicken-scratch and you're better off just reading a textbook. You can't
get away with this when you're teaching, say, math olympiad kids,
because they're literally some of the best high schoolers in the nation.
And nor do I think you would want to. There is a sense of respect you
have when writing for smart people, and that alone makes your writing so
much better. If you respect the time of your readers, you will respect
your own time when writing.</p>
<section id="footnotes" class="footnotes footnotes-end-of-document"
role="doc-endnotes">
<hr />
<ol>
<li id="fn1"><p>This is why I am a little skeptical of claims like <a
href="https://web.evanchen.cc/geombook.html">"this text has no
prerequisites"</a>. It may technically be true, but if you have never
done something intensive like olympiad geometry before you will get lost
very fast.</p>
<p>Although I think with EGMO, the qualifiers "written for competitive
students", "any student with proof experience", etc are sufficient. Many
people smarter than me have been able to start learning olympiad
geometry through it first try. This textbook is written for smart
people, and I think that's a good thing, even if "smart" precludes
me.</p>
<p>For an example of textbooks that aren't written for smart people,
take any AoPS textbook besides Volumes 1/2, especially Introduction to
Geometry. It assumes that people don't know what a point/line/angle is,
or how to label/read a polygon, so it spends 50 pages on this. Nuances
like <span
class="math inline"><em>A</em><em>B</em><em>C</em><em>D</em></span> and
<span
class="math inline"><em>A</em><em>C</em><em>B</em><em>D</em></span>
being different polygons are important, but these can be covered in a
tenth of the space if you just state them straight out.<a href="#fnref1"
class="footnote-back" role="doc-backlink">↩︎</a></p></li>
<li id="fn2"><p>AoPS Introduction to Geometry is really bad in this
regard. Evan Chen's EGMO helpfully lists them all out and proves them
(though I think its proof to Heron's is one of the more complex ones),
but due to its target audience said section is quite terse.<a
href="#fnref2" class="footnote-back" role="doc-backlink">↩︎</a></p></li>
<li id="fn3"><p>In writing this section of the essay I had to list out
the five area formulae. I only succeeded in remembering them all when I
pictured the chart in my head.<a href="#fnref3" class="footnote-back"
role="doc-backlink">↩︎</a></p></li>
<li id="fn4"><p>It is no coincidence that <em>expressiveness</em> is
also used to describe programming languages.<a href="#fnref4"
class="footnote-back" role="doc-backlink">↩︎</a></p></li>
<li id="fn5"><p><a
href="https://gitlab.com/chennisden/dennisc.net/-/commit/8c5ab2aa36f1cf3cd130a5cb4826225bda4464e3">Case
in point.</a><a href="#fnref5" class="footnote-back"
role="doc-backlink">↩︎</a></p></li>
</ol>
</section>]]></description>
	<pubDate>24 Feb 2022</pubDate>
</item>
<item>
	<title>Notes</title>
	<link>https://dennisc.net/writing/essays/notes.md</link>
	<description><![CDATA[<p>In high school many of your teachers will force
you to takes notes.<a href="#fn1" class="footnote-ref" id="fnref1"
role="doc-noteref"><sup>1</sup></a> They seem like ridiculous wastes of
time, and the notes you take in high school typically are. But if done
right notes can be very valuable.</p>
<p>Obviously the most effective way of taking notes will differ from
person to person. This is just the way I think about mine.</p>
<h2 id="value">Value</h2>
<p>The whole point of notes is that they become the central authority
for you on a certain topic. It's not supposed to be the Spark Notes of a
certain topic. Otherwise, why not just skim or read the textbook again?
It might work for a test<a href="#fn2" class="footnote-ref" id="fnref2"
role="doc-noteref"><sup>2</sup></a>, but you won't gain much else by
summarizing.</p>
<p>Making your notes on a subject better than any existing material
seems like a tall order. And a tall order it is indeed. But it's not
impossible!</p>
<p>Your notes just need to be the best for you. Sometimes no good
reference material exists: consider the lack of an introductory geometry
textbook, or up until <a
href="https://web.evanchen.cc/geombook.html">EGMO</a>, an olympiad
geometry textbook. Other topics are more complex and not as linear:
Linear Algebra Done Right and Linear Algebra Done Wrong present topics
in different orders and choose to emphasize different connections.</p>
<p>Some texts are just unparalleled and can't be feasibly improved on.<a
href="#fn3" class="footnote-ref" id="fnref3"
role="doc-noteref"><sup>3</sup></a> In these circumstances, I don't
think there's much of a point to taking notes. But most topics are
either complex enough that different textbooks fill different niches, or
otherwise textbooks don't exist/are terrible. Sometimes both. For
neither of these statements to be true is very rare.</p>
<h2 id="structure">Structure</h2>
<ul>
<li>You want to have semantic separation of content line up with visual
separation of content.</li>
<li>You can't always arrange information linearly, or sometimes it just
doesn't make sense to. An example from my upcoming geometry textbook:
when it comes to angle chasing and similar triangles, sometimes there
are questions that use <span class="math inline">$\frac{bh}{2}$</span>
even though it makes sense for area techniques to be introduced later.
Just try to be explicit about when information isn't or can't be
presented linearly, especially when two sections both reference each
other.<a href="#fn4" class="footnote-ref" id="fnref4"
role="doc-noteref"><sup>4</sup></a> A broader example in math is Linear
Algebra and Multivariable Calculus --- each subject relies on knowledge
from the other to some extent.</li>
</ul>
<ul>
<li><p>Follow through. If A implies B then you should put B close after
A. For example, most introductory geometry textbooks include Power of a
Point as <span
class="math inline"><em>P</em><em>A</em> ⋅ <em>P</em><em>B</em> = <em>P</em><em>C</em> ⋅ <em>P</em><em>D</em></span>
but neglect to mention that <span
class="math inline"><em>P</em><em>A</em> ⋅ <em>P</em><em>B</em></span>
really represents <span
class="math inline"><em>O</em><em>P</em><sup>2</sup> − <em>r</em><sup>2</sup></span>.
If you're going to include the Law of Sines or <span
class="math inline">$\frac{1}{2}ab \sin \theta$</span>, which follow the
common theme of "manipulations of lengths and areas in triangles", maybe
you shouldn't wait five chapters before mentioning <span
class="math inline">$\frac{abc}{4R}$</span>.</p>
<p>This general principle helps you "lock the pieces in place", so to
speak.<a href="#fn5" class="footnote-ref" id="fnref5"
role="doc-noteref"><sup>5</sup></a> Since <span
class="math inline">$\frac{abc}{4R}$</span> should follow soon after the
Law of Sines and <span
class="math inline">$\frac{1}{2}ab\sin\theta$</span>, that also means
that the Law of Sines and <span
class="math inline">$\frac{1}{2}ab\sin\theta$</span> should be in
close-ish proximity to each other --- like in the same chapter.</p></li>
</ul>
<h2 id="polish">Polish</h2>
<p>Yours notes should be polished. The really obvious reason is it makes
it easier for you to go over them. But that goal shouldn't be to make it
easy for yourself, it should be to make your notes presentable to other
people.</p>
<p>If your notes are good and make sense for you, they will also make
sense for people who think like you. If they can learn the material from
your notes for the first time, chances are <a href="write-smart">it'll
be much easier for you to rederive the facts it covers yourself</a>. The
whole point of taking notes is that you'll forget the specifics, so
write them in a way that makes it as easy as possible to get up to
speed. Once you've done that, it just happens that you haven't just made
your notes useful for yourself --- you've made them useful for other
people as well.</p>
<p>The reason you want to make other people your target audience rather
than yourself is so you avoid making assumptions about what the audience
knows. Right now you know a lot about yourself and how much you know,
but over time much of that will change. If you want your notes to not
implicitly rely on these things, the first step is to have them not
explicitly rely on them.</p>
<p>In the end <a href="https://mast.mathadvance.org">my notes become my
teaching materials</a>. Because if you don't use your notes to teach
other people, how are you going to check that they make sense for other
people?</p>
<section id="footnotes" class="footnotes footnotes-end-of-document"
role="doc-endnotes">
<hr />
<ol>
<li id="fn1"><p>Extra credit if they make you take Cornell notes.<a
href="#fnref1" class="footnote-back" role="doc-backlink">↩︎</a></p></li>
<li id="fn2"><p>I don't even think it works well enough to justify
taking "summary" notes anyway.<a href="#fnref2" class="footnote-back"
role="doc-backlink">↩︎</a></p></li>
<li id="fn3"><p>However, this class of textbooks is so small I couldn't
think of any examples to name here.<a href="#fnref3"
class="footnote-back" role="doc-backlink">↩︎</a></p></li>
<li id="fn4"><p>This happens mostly in larger projects like textbooks.
This also might be an explanation for content gaps: a certain subject
might not fit in linearly, so it gets cut off.</p>
<p>I personally think it's okay to assume students have some outside
knowledge. They should be learning multiple things at the same time
because <em>learning isn't linear</em>. (Which is why you can't always
arrange <em>information</em> linearly!)<a href="#fnref4"
class="footnote-back" role="doc-backlink">↩︎</a></p></li>
<li id="fn5"><p>Side note: I don't think you're really
<em>inventing</em> a new framework when you structure your notes well,
you're just <em>discovering</em> one of the few that make sense.<a
href="#fnref5" class="footnote-back" role="doc-backlink">↩︎</a></p></li>
</ol>
</section>]]></description>
	<pubDate>25 Aug 2022</pubDate>
</item>
<item>
	<title>Competence</title>
	<link>https://dennisc.net/writing/essays/competence.md</link>
	<description><![CDATA[<p>The median score for the math section of the
SAT is 550.</p>
<p>You and I, as people who are good at math, both know the SAT is
incredibly easy. All you have to do is not suck at middle school math.
Given that, it's kind of impressive that the average person fails a
quarter of this test.</p>
<hr />
<p>By the way, the median mile time for a high school guy is around
9:00.<a href="#fn1" class="footnote-ref" id="fnref1"
role="doc-noteref"><sup>1</sup></a> Which is kind of impressive,
considering that you just have to not go super slow on lap 1 and survive
for the next 3 to get under 6:00.<a href="#fn2" class="footnote-ref"
id="fnref2" role="doc-noteref"><sup>2</sup></a></p>
<h2 id="both-statements-were-correct">Both statements were correct</h2>
<p>If you don't run, you might be thinking, "well most people can't run
under 6:00 so clearly it must be hard." You might even take it one step
further and conclude, "hey, getting an 800 on SAT math should be hard
too, since most people can't get it." <strong>But look at the damn
test.</strong></p>
<p>The alternative explanation for these scores is that people
<em>really</em> suck at math. And since the SAT just is not hard, I'm
inclined to believe it.</p>
<p>But there's nothing special about math that makes people suck at it.
I've already given another example of something most people suck at:
running. And if you can do math and running, can you</p>
<ul>
<li>cook?</li>
<li>use Linux? (For extra credit, any non-Ubuntu/Manjaro/etc
distro.)</li>
<li>program in a language that isn't Javascript?</li>
<li>write a crossword?</li>
<li>do a handstand?</li>
</ul>
<p>If you talk to someone who can do any of these things, they will tell
you that they started out believing it was hard, but once they committed
to actually doing it well, they realized it was easy. But you, who
cannot do it, will believe it's hard.</p>
<hr />
<p>When I was in elementary school, I would loudly complain that math
class was really boring and too easy. Meanwhile, half of the kids would
be in class going "Huh? What is a fraction?"</p>
<p>Then some angry adult would tell me, "no, the math we're doing here
is <em>hard</em>, can't you see that half the class doesn't get this?"
And I was really tempted to say, "well, maybe they all just suck at
math", but by then I'd learned better than to say these things.</p>
<p>But it turns out 10-year old me was right. Nobody was ever willing to
consider that most people just sucked at math --- everyone just had to
be at least competent at everything.<a href="#fn3" class="footnote-ref"
id="fnref3" role="doc-noteref"><sup>3</sup></a> And so their measure of
hard was based on failure rates, because if a bunch of competent people
do something and most of them fail, then it <em>is</em> hard.</p>
<p>It's true that difficulty is a factor in failure rates. But so is
competence. And if people are incompetent, then something doesn't need
to be so hard for it to have a high failure rate.</p>
<h2 id="doing-just-fine">Doing just fine</h2>
<p>Yeah, everyone sucks at almost everything. But the people who can't
do algebra or run a mile under 5:00 or shoot 3-pointers consistently are
doing just fine too. There are a lot of things that we can't do that
would make us better people. So many, in fact, that it's hopeless to be
competent at <em>everything</em>. And you know what? There's nothing
wrong with that.</p>
<p>But it's important to be consciously aware, "hey, in the grand scheme
of things, I basically don't know anything and can't do much," so you
don't keel over and give up after realizing you suck at most things. Not
being able to learn everything is no excuse to learn nothing. That's why
people work on self-improvement their whole lives: it's because there's
just that much to improve.</p>
<p>Putting in an effort to get genuinely good at a few of the thousands
of things you currently suck at might only decrease the percent of
things you suck at by 0.1%. But I think it makes sense to look at skills
from a <a href="mediocrity">success-oriented framework</a>. Because
going from being good at 4 things to 5 things is a genuine
accomplishment, and these days, anyone looking for talented people look
at what you can do and not what you can't.</p>
<p>So even if you failed every academic subject in school as well as
phys ed, that's still okay. You should expect to be a failure at most
things. But when you find the few things you have an aptitude and
inclination towards, treasure it. Get good at it rather than just aiming
to suck less than everyone else. It might be hard, but it probably isn't
<em>impossible</em> --- it's just that most people haven't tried hard
enough, given how many other things there are to try. So be ambitious.
Be one of the first to do whatever it is you want to do, and <strong>do
it really well</strong>.</p>
<section id="footnotes" class="footnotes footnotes-end-of-document"
role="doc-endnotes">
<hr />
<ol>
<li id="fn1"><p>I made this number up, I can't find what it actually is.
But from anecdotal experience, this time is about right, and all that
really matters is that this time is really slow.<a href="#fnref1"
class="footnote-back" role="doc-backlink">↩︎</a></p></li>
<li id="fn2"><p>6:00 is an arbitrary time, people who are better than me
could easily claim the same for a 5:30 mile, and so on.<a href="#fnref2"
class="footnote-back" role="doc-backlink">↩︎</a></p></li>
<li id="fn3"><p>I'm sure that elementary school would tell people that
everyone was <em>good</em> at everything if they could, but not even
10-year olds are that gullible. So they settle for the next best thing:
no one's allowed to point out that most people suck at some given
subject.<a href="#fnref3" class="footnote-back"
role="doc-backlink">↩︎</a></p></li>
</ol>
</section>]]></description>
	<pubDate>11 Apr 2023</pubDate>
</item>
<item>
	<title>Math Club</title>
	<link>https://dennisc.net/writing/essays/math-club.md</link>
	<description><![CDATA[<p><em>This is a republishing of an essay on my
old website. First published April 25th, 2020.</em></p>
<p>Ever since the fall of my freshman year, our high school math club
was declining. Even before the coronavirus, the math team didn't do
much: there was no one writing the highly anticipated geometry bee and
the officers I've spoken to didn't seem to know what the club was
planning. Despite the number of strong math students in our school, few
people seemed to be interested in the club.</p>
<p>The fate of our math club after the pandemic was predictable. The
officers failed to submit the club application on time, marking the end
of a club with decades of history.</p>
<p>This hasn't just been happening in my school. A number of non-elite
high schools have seen their math clubs getting worse. What's happening
here?</p>
<h2 id="interests">Interests</h2>
<p>I'll be the first to admit that I don't really care what happens in
my math club. I have the resources, connections, and experience to study
on my own.</p>
<p>I think the same holds for most students in the math contest
community. A large part of this is because almost all of them are
working on their own projects within their own organizations. There's a
lot of advantages that working outside your school brings, and they are
too good to pass up.<a href="#fn1" class="footnote-ref" id="fnref1"
role="doc-noteref"><sup>1</sup></a></p>
<p>Most smart people will not choose to host a math club at lunch for
outreach. <a href="https://mathadvance.org">I know I chose
differently.</a> But there is still a place for math clubs and those who
care enough to improve them.</p>
<h2 id="a-sense-of-urgency">A Sense of Urgency</h2>
<p>Clubs don't die because people are lazy. They die because people are
complacent. They might seem similar on the outside, but their root
causes are polar opposites.</p>
<p>Laziness happens when people don't care about bad results.
Complacency happens when people care too much about bad results. These
sorts of endeavor often end in failure, and it's very hard to stomach
the idea of something you put your heart in turning out worthless. But
that's why it's so important to entertain the idea. The only way to
prevent it is to prepare, and you can't prepare without knowing what
sorts of danger your club is in.</p>
<p>It's no coincidence that organizations see the most activity the
weeks before an event. It's not just because there's excitement. It's
because there's anxiety. Whatever the reason, people start getting
worried about the event and checking things. This is why so many changes
are made last minute.</p>
<p>Relyin on this is a very risky strategy, if it can even be called
that. Near the date of the event things happen faster, but mistakes are
often made because it's so rushed. Even worse, these mistakes aren't the
type you can prevent or catch with diligence. They only become apparent
after time.</p>
<p>So how can you emulate this sense of urgency without waiting until
the last minute? The secret is manipulating your sense of time.</p>
<p>People naturally get antsy two weeks before the event and start
making small changes rapidly. This is how people get caught up in the
atmosphere and start contributing. But the atmosphere isn't caused
directly by the impending event. That's what forces your sense of time
to shorten. But it's the feeling of things changing that gets other
people to adjust their sense of time.</p>
<p>Make small changes fast. As far as I know, this is the most reliable
way to bring significant positive changes.</p>
<p>None of this is specific to math clubs.<a href="#fn2"
class="footnote-ref" id="fnref2" role="doc-noteref"><sup>2</sup></a>
I've seen other clubs barely scrape together enough candidates for
officer positions. I've seen math contests get so caught up with
themselves that they forget to check their problems for correctness, let
alone quality. These are both caused by an excitement for your product
and an anxiety surrounding failure.</p>
<p>The important thing is not to let one overshadow the other. If you're
too excited you won't be diligent. If you're too anxious you won't get
anything done. The best balance is maintained by frequent and granular
changes.</p>
<p>I've been talking about complacency, but it turns out small changes
are also the antidote to antipathy. At the very least, if you find
yourself struggling to get small changes made, you know that the club is
going to fail and don't need to waste more energy on it.</p>
<h2 id="mass-appeal">Mass Appeal</h2>
<p>It's very noble to believe that "math club welcomes everyone." But
this sort of idealism might end up doing more harm than good.</p>
<p>It's correct to say that math club is a gateway to bigger things. You
can't do a lot with a lunch break every week or two.<a href="#fn3"
class="footnote-ref" id="fnref3" role="doc-noteref"><sup>3</sup></a> But
that doesn't mean you should make it do nothing or turn it into a social
club.</p>
<p>Surprisingly, the best way to encourage long-term growth is to care
less about it.</p>
<p>If your club is just a social club, you might attract more people
initially. But people want to do meaningful things, and the people who
might've been interested at first will leave for another club or stop
caring entirely.</p>
<p>Not everyone is interested in math the same way not everyone is
interested in psychological thrillers. If someone's asking you for
recommendations, you'd give them the best movies you've watched rather
than the most popular ones. Math club is the same way. You should teach
what appealed to you when you learned it, rather than what you think
will appeal to most people, because you will be right about the former
and wrong on the latter.</p>
<p>Going for mass appeal will lose the interest of casual members and
the respect of enthusiasts. The people who showed up are largely there
because they want to get serious about math, and they can tell if you're
not giving them that.</p>
<h2 id="specific-suggestions">Specific Suggestions</h2>
<p>The goal of math club is different than more intensive math classes,
whether contest-based or higher math. You should be aiming to have
everyone walk away with a good understanding of everything you've
presented. This means you should be conservative with the problems you
present, and you should usually be conservative with the complexity of a
lecture.<a href="#fn4" class="footnote-ref" id="fnref4"
role="doc-noteref"><sup>4</sup></a> I believe most good lecture topics
will be combinatorial because it's the most accessible topic for those
without prior knowledge.</p>
<p>Some math classes adopt the mentality of "throw stuff at the wall and
hope some of it will stick." I have mixed opinions of its effectiveness
in general, and I know math club is not the place for it. You do not
want to actively scare people away. While you do want to challenge
people, you don't want to frustrate them. <a
href="https://blog.evanchen.cc/2018/02/02/an-apology-for-hmmt-2016/">ARML's
philosophy of gimmes versus gettables also is very helpful.</a> To be
explicit, I believe the vast majority of math club lectures should only
consist of gettables.</p>
<p>What constitutes a good topic depends on how long your meetings are.
Unfortunately, you can't do much if your meetings are less than an hour.
That being said, here are a couple of topics that should be new to most
people, which will level the playing field a bit.</p>
<ul>
<li><p>Group theory. Although it's not an easy subject for
high-schoolers by any means, it's useful and surprisingly
intuitive.</p></li>
<li><p>Infinity. Like Hilbert's Hotel, countable infinity vs.
uncountable infinity, bijections, ordinals, cardinals... there's a lot
to go over.</p></li>
<li><p>USAMTS puzzles. I would not rely on this too much, but it's good
for filling in some meetings after intense events. (Think
AMCs.)</p></li>
<li><p>Mock contests and discussion. You can either mock old tests or
AoPS contests --- <a href="/math/mocks">here are a few mock contests I
like</a>, which is only a subset of the abundance of treasure in the
AoPS Mock Contests subforum.</p></li>
<li><p>Transformations in geometry. Did you know that the area of the
triangle with the lengths of the medians of <span
class="math inline">△<em>A</em><em>B</em><em>C</em></span> has <span
class="math inline">$\frac{3}{4}$</span> the area of <span
class="math inline">△<em>A</em><em>B</em><em>C</em></span>? Unless
you're already very experienced in math competitions, this obscure topic
is probably not one you're very familiar with, but it is still
approachable for those with less experience.[^transformations]
[^transformations]: When I say transformations, I am referring to a
particular class of problems that appears in math contests. If you're
interested in further details or obtaining the Transformations MAST
Handout --- a student favorite --- email me.</p></li>
<li><p>Freedom. Sometimes, whether in Perspectives or States style
counting questions, you will be given a framework with a fairly complex
set of possibilities that you can simplify by disregarding what you
don't care about. Examples include gems like MAST Diagnostic 2021/8, a
problem from my MATHCOUNTS tryouts, HMMT 2003/C10, and NARML 8.</p>
<p>You could explain this idea to a sixth grader and have them
understand it, but problems like Andy the Unicorn (the colloquial name
for MAST 2021/8) have a low enough solve-rate to indicate these problems
are genuinely difficult. I think this is one of the best things you
could do near the start of the year. It really showcases the magic of
mathematics: it's not just about formulas, grinding, and manipulation.
Incredible shifts in perspective can be made too. It is no exaggeration
to say this could change people's views of math entirely.<a href="#fn5"
class="footnote-ref" id="fnref5"
role="doc-noteref"><sup>5</sup></a></p></li>
<li><p>Remainder Theorem. This is something I think the underclassmen in
Algebra 2 will appreciate knowing, and besides is a very cool topic with
plenty of applications. Best of all, it builds on something that nearly
everyone knows how to do: polynomial division.</p></li>
<li><p>Factoring. The basics matter, and it's also quite satisfying to
do.</p></li>
<li><p>Telescoping. This is relevant to the upperclassmen in Calculus
(think partial fraction decomposition), and is also just cool and
satisfying.</p></li>
<li><p>USA TST Cars. (Sorry not sorry.) I know that nobody will solve
this, but when you take the last 5 minutes of the meeting to explain it,
everyone will be simultaneously amazed and annoyed by the
solution.</p></li>
</ul>
<p>You will notice that there is no geometry or number theory in this
list. I think that Geometry is too detail oriented for math club, while
Number Theory requires a significant amount of time to set up. In
general, lectures should be as discrete as possible for the purposes of
flexibility.</p>
<p>I think that assigning reading and homework should be done, but you
should also stress that it's optional and there's no shame in not being
able to find the time to brush up on the prerequisites. The main reason
math clubs exist is because it's difficult for people to start learning
on their own. That's why giving them something to take home and finish
on their own time is so important.</p>
<section id="footnotes" class="footnotes footnotes-end-of-document"
role="doc-endnotes">
<hr />
<ol>
<li id="fn1"><p>The two main factors I have in mind are school politics
and geographic constraints. School politics are annoying because you
have to apply to leadership each year to get approval and there are
school policies you have to follow. Perhaps the worst is that officers
are decided through election, which is just a popularity contest.</p>
<p>Geography is the more impactful factor. Just by random chance, the
best and most motivated problem writers or handout writers are going to
be scattered across the country. Only being able to work with people in
your school is very restrictive. The coronavirus sort of forced the
nation's most motivated students together. They won't want to return to
"normal" after this.<a href="#fnref1" class="footnote-back"
role="doc-backlink">↩︎</a></p></li>
<li id="fn2"><p>I actually developed this philosophy by creating math
contests. Math contests are something that requires a lot of granular
adjustments, which is why this sense of urgency is so important.<a
href="#fnref2" class="footnote-back" role="doc-backlink">↩︎</a></p></li>
<li id="fn3"><p>If you can get away with it, try to avoid telling people
that math club doesn't really mean much. You shouldn't pretend math club
is sufficient. But that doesn't mean you have to make a point of saying
the opposite.</p>
<p>People will get interested in math at their own pace. You probably
don't need to tell them "if you want to get better at math, do more of
it" --- that's obvious.<a href="#fnref3" class="footnote-back"
role="doc-backlink">↩︎</a></p></li>
<li id="fn4"><p>I say "usually" because there are times you should
present difficult lectures. Especially if you're introducing a subject
that most people have never heard of, such as real analysis or group
theory, some people will be interested and fill the gaps in on their
own. This experience, more than the contents of any particular lecture,
is the most valuable takeaway that you can get from math club.<a
href="#fnref4" class="footnote-back" role="doc-backlink">↩︎</a></p></li>
<li id="fn5"><p>I really like this topic in particular since the Andy
problem was inspired by my experience with the MS MATHCOUNTS Tryouts
problem and a penchant for misreading (I misread CMIMC Team 2019/7 and
found an idea I deemed interesting), and NARML #8 was a problem
originally too similar to Andy the Unicorn that got saved by a random
suggestion (among a list of terrible suggestions) that I make the
scientist loop through the number line, which somehow was enough to make
something interesting and novel.<a href="#fnref5" class="footnote-back"
role="doc-backlink">↩︎</a></p></li>
</ol>
</section>]]></description>
	<pubDate>4 Oct 2022</pubDate>
</item>
<item>
	<title>Learning is About Conviction</title>
	<link>https://dennisc.net/writing/essays/conviction.md</link>
	<description><![CDATA[<p>For a good bit of time, I'd never been able to
sing in the G4-A4 range consistently and effortlessly. Part of the
reason was that I really didn't try. Recently the choir has been working
on a few pieces that require me to go up in that range in chest
voice.</p>
<p>I finally figured it out when I decided to "go low to go high" (more
technically, relax the jaw and drop the larynx to get a more relaxed
sound). To put it into simpler terms: I convinced myself, fully
<strong>believed</strong> that G4 was not actually that high.</p>
<p>And then I got it.</p>
<h2 id="beyond-mantras">Beyond mantras</h2>
<p>None of the things I said like "drop the larynx" were new to me. But
to me they were just words. It wasn't until I started at a note that
actually was easy for me (a C4) and slid up to around a G4. The whole
time I convinced myself "this note isn't very high." Only once I
actually, fully believed it did I hit the G4.</p>
<p>I think math is much the same. You can repeat mantras like "category
theory is about universal properties", or "Yoneda's says an object is
determined by the morphisms into/out of it" --- and you <em>should</em>
know them --- but it is not enough. You really have to <em>believe</em>
them, and when you do, they almost become second nature.</p>
<p>How do you get this conviction?</p>
<p>For singing, it took a willingness to believe and a couple of
successful attempts before I got G4. A4b came in a couple more days. And
I swear I'll have A4 by the end of this week.</p>
<p>If you've done a physical activity like rock climbing, you know this
all too well. You can be shown the "beta" (the intended route), but it
takes truly <em>believing</em> that you can and ought to do a certain
move in a certain way to actually execute. Sure, if it is a sufficiently
easy route, having this conviction is almost trivial. You and I both
believe we can climb a ladder, whatever you consider a "ladder" to be.
But often the last barrier to climb a route is the barrier of belief,
when our physical strength is enough and we know (but don't quite
believe in) the important moves.</p>
<p>But maybe this can all be chalked up to muscle memory. Your body can
learn quickly and deeply, but math doesn't really exercise your muscles.
How can you build this conviction then?</p>
<p>I think the answer is through pain. We all despise pain, even mental.
Consider that certain constructions would be agonizing if we did not
have the right abstractions in order to perform them.</p>
<p>I will present a few examples, and for each of them, I want you to
think about how annoying it would be to prove these statements without
the correct abstractions. Sorry, they are all going to be algebraic
geometry: I think it is the best example of a field which seems to have
a lot of nonsense abstractions, only for the abstractions to prove
obviously useful when hit with a certain pain point.</p>
<h2 id="example-1-sheaf-on-a-base">Example 1: Sheaf on a Base</h2>
<p>For example, I can tell you that a sheaf can be defined on just a
base. You can repeat the mantra after me: "it's because you can describe
regular functions locally via stalks at every point". But you'll believe
this is just some abstraction I made up until I tell you what an affine
scheme is.</p>
<p>At that point you will hopefully understand how horrible the
definition would be if we <em>couldn't</em> define a sheaf on a base.
Then you see: oh, the expected behavior of the sheaf <span
class="math inline">𝒪<sub>Spec<em>R</em></sub></span> is horrible to
explicitly describe on arbitrary opens, but if we just restrict to
distinguished affine opens, our lives are good again.</p>
<h2 id="example-2-kernels-are-arrows">Example 2: Kernels are Arrows</h2>
<p>Another great example is the idea that a kernel is not actually an
object. For example, you may think of the kernel of an <span
class="math inline"><em>R</em></span>-module map <span
class="math inline"><em>p</em><em>h</em><em>i</em> : <em>M</em> → <em>N</em></span>
as <span
class="math inline"><em>k</em><em>e</em><em>r</em><em>ϕ</em></span>, the
submodule of <span class="math inline"><em>M</em></span> consisting of
the elements mapped to <span class="math inline">0</span>. But I think
of it as the inclusion <em>arrow</em> <span
class="math inline"><em>k</em><em>e</em><em>r</em><em>ϕ</em> ↪ <em>M</em></span>
satisfying some universal property.</p>
<p>You may even choose to take it at face value when I tell you this.
But if you are to actually believe me, I think it is best to convince
you that <strong>right adjoints are left-exact</strong>. Let me actually
define these terms for you (besides an adjunction). A sequence <span
class="math inline"><em>A</em>→<sup><em>f</em></sup><em>B</em>→<sup><em>g</em></sup><em>C</em></span>
in, say, the category of <span
class="math inline"><em>R</em></span>-modules (but abelian groups,
rings, etc work; anything with "an abelian group structure", more
formally an <em>abelian category</em>, will suffice) is
<strong>exact</strong> if <span
class="math inline"><em>k</em><em>e</em><em>r</em><em>f</em> = <em>i</em><em>m</em><em>g</em></span>.
A longer sequence such as <span
class="math inline">0 → <em>A</em> → <em>B</em> → <em>C</em></span> is
<strong>exact</strong> if every kernel is equal to the image of its
successor.</p>
<p>A functor <span class="math inline"><em>F</em></span> is left-exact
if it preserves exact sequences <span
class="math inline">0 → <em>A</em> → <em>B</em> → <em>C</em></span>,
i.e. applying <span class="math inline"><em>F</em></span> yields an
exact sequence <span
class="math inline">0 → <em>F</em>(<em>A</em>) → <em>F</em>(<em>B</em>) → <em>F</em>(<em>C</em>)</span>.
I will now tell you</p>
<ol type="1">
<li>right adjoints preserve limits,</li>
<li>kernels are limits,</li>
<li>and crucially, <span
class="math inline">0 → <em>A</em> → <em>B</em> → <em>C</em></span> is
exact if and only if <span
class="math inline"><em>A</em> → <em>B</em></span> is a kernel of <span
class="math inline"><em>B</em> → <em>C</em></span>.</li>
</ol>
<h2
id="example-3-why-do-we-care-about-exact-sequences-and-functors">Example
3: Why do we care about exact sequences and functors?</h2>
<p>It is the combination of these three facts that immediately implies
right adjoints are left-exact. In particular, step 3 is the important
one which is less commonly stated in the luxury. (I told you considering
kernels as arrows would be useful!)</p>
<p>In particular, it is very useful to know localization is an exact
functor in algebraic geometry. It is used to prove the "qcqs" lemma,
which asserts that given a "nice" (i.e. quasicompact and quasiseparated)
scheme <span class="math inline"><em>X</em></span>, a global function
<span class="math inline"><em>f</em></span> on <span
class="math inline"><em>X</em></span>, and a "nice" (i.e. quasicoherent)
<span class="math inline">𝒪<sub><em>X</em></sub></span> module, the
rings <span
class="math inline"><em>F</em>(<em>X</em>)<sub><em>f</em></sub></span>
and <span
class="math inline"><em>F</em>(<em>X</em><sub><em>f</em></sub>)</span>
are isomorphic.</p>
<p>The idea is that on affine opens <span
class="math inline">Spec<em>R</em><em>s</em><em>u</em><em>b</em><em>s</em><em>e</em><em>t</em>.<em>e</em><em>q</em><em>X</em></span>,
we have that <span
class="math inline"><em>F</em>(Spec<em>R</em><sub><em>f</em></sub>)</span>
is isomorphic to <span class="math inline"><em>F</em>(Spec
R)<sub><em>f</em></sub></span> for any <span
class="math inline"><em>f</em> ∈ <em>R</em></span>. Somehow we take the
exact sequence characterizing a sheaf and then localize at <span
class="math inline"><em>f</em></span>. And we know this localization
preserves the exact sequence precisely because of the discussion
before.</p>
<p>This theorem's proof is another reason we care about exact sequences
and expressing the sheaf condition as an exact sequence: the usual way
we build an isomorphism among schemes is by taking an affine open
covering of each and building isomorphisms between each affine open
patch. But here <span
class="math inline"><em>F</em>(<em>X</em>)<sub><em>f</em></sub></span>
does not quite come from any sheaf. But if we just want an isomorphism
along global sections, an isomorphism of exact sequences is enough to
induce that.</p>
<p>With all of that said, how do we prove localization is exact, i.e.
preserves exact sequences <span
class="math inline">0 → <em>A</em> → <em>B</em> → <em>C</em> → 0</span>?
Actually, we already know through the localization-forgetful functor
that localization is right-exact as it is a left adjoint. So we only
need to check exactness of <span
class="math inline">0 → <em>S</em><sup>−1</sup><em>A</em> → <em>S</em><sup>−1</sup><em>B</em></span>,
i.e. injectivity of <span
class="math inline"><em>S</em><sup>1</sup><em>A</em> → <em>S</em><sup>−1</sup><em>B</em></span>,
which is immediately obvious either through the explicit construction of
localization or by applying the universal property.</p>
<h2 id="example-4-yonedas-lemma-and-the-functor-of-points">Example 4:
Yoneda's Lemma and the Functor of Points</h2>
<p>The whole idea of category theory is to consider objects through the
vantage point of some universal property so we don't have to make
arbitrary choices and suffer from their consequences.</p>
<p>But the same problem can come into play when <em>constructing</em>
these categorical objects. As an example, what is the fibered product of
schemes? Constructing it explicitly is kind of a pain. The whole point
of category theory is to construct as many objects in a
universal/choice-free manner, and only then check the desired properties
arise out of the universal description.</p>
<p>So here is what we do. Given scheme morphisms <span
class="math inline"><em>X</em> → <em>Z</em></span> and <span
class="math inline"><em>Y</em> → <em>Z</em></span>, we take the fibered
product of <span class="math inline">Hom(−, <em>X</em>)</span> and <span
class="math inline">Hom(−, <em>Y</em>)</span>. (We know the fibered
product <em>always</em> exists in the category of functors from Scheme
to Set; this is part of the work we do with representables and the
functor category.) Now we just need to check the fibered product, a
universally constructed object that we can actually work with, is
representable.</p>
<p>Yes, the ideas are largely the same as in the direct construction.
But crucially, you do not have to perform a somewhat cumbersome check
that your object does not implode on itself as you define it.</p>
<h2 id="metaexample-category-theory-is-useful">Metaexample: Category
theory is useful</h2>
<p>All of this put together should convince you that category theory is
useful. I wouldn't have even been able to formulate what a tensor
product is without category theory. Sure, understanding a tensor product
as some quotient space might require less intellectual work in the short
term. (Heck, the even lazier option is to understand tensors as an array
of numbers. But you already know this doesn't end well for matrices; why
should the higher-dimensional analogue be any different?) But could you
imagine trying to prove the tensor product commutes with the direct sum
with these definitions? And how would we ever be able to see these kinds
of facts or frameworks are useful if we can't even talk about them
properly?</p>]]></description>
	<pubDate>9 Mar 2026</pubDate>
</item>
<item>
	<title>Solidifying Glee's design</title>
	<link>https://dennisc.net/writing/tech/glee-solidify.md</link>
	<description><![CDATA[<blockquote>
<p>Glee is a Git service meant solely to be self-hosted. It stores
repositories in a hierarchical manner, much like GitLab or a UNIX
filesystem. The web frontend will be simple and contain no
Javascript.</p>
<p>Glee is not meant to serve as an ecosystem, and as such is inherently
difficult to monetize or offer as a SaaS. Rather, it is meant to act as
one part of a software forge, with issue tracking, wikis, mailing lists,
etc being pulled in from elsewhere.</p>
<p>In terms of complexity and functionality, Glee is around the midpoint
of cgit and sourcehut.</p>
</blockquote>
<p>The above is my current draft for the official marketing slogan on
the Glee homepage, which will probably be hosted on
glee.dennisc.net.</p>
<p>I've begun work on the design for my Git service: Glee. The
repository is currently being hosted on <a
href="https://git.sr.ht/~dennisc/glee">SourceHut</a>, though the project
is unlisted. It is likely to remain that way forever, since by the time
it's ready to make public it will also be ready to self-host. I will
have to learn plenty, including diving deep into the internals of Git,
HTTP, and SSH in order to pull a project of such scope off.</p>
<h2 id="progress">Progress</h2>
<p>I've already made some progress implementing the registration
page!</p>
<div aria-hidden="true"
style="border-style: solid; border-width: 1px; padding: 0 1rem 1rem 1rem;">
<style>
a.glee {
    color: #2563eb;
}

a.glee:hover {
    text-decoration: none;
}

a.glee:visited {
    color: MediumBlue;
}

@media (prefers-color-scheme: dark) {
    a.glee {
        color: DodgerBlue;
    }
    a.glee:visited {
        color: #2563eb;
    }
}

form {
    max-width: 400px;
    display: flex;
    flex-direction: column;
}

form > label {
    margin-bottom: 0.25rem;
}

form > input {
    margin-bottom: 0.5rem;
    line-height: 1.5;
    padding: 0.25rem 0.5rem;
    font-size: 1rem;
    font-family: sans-serif;
    border-style: solid;
    border-width: 1px;
    border-color: DarkGray;
}

form > input:read-only {
    background-color: Gainsboro;
}

@media (prefers-color-scheme: dark) {
    form > input {
        color: #f0f0f0;
        background-color: #404040;
        border-style: none;
    }
    form > input:read-only {
        color: #a0a0a0;
        background-color: #282828;
    }
}

form > button {
    margin-top: 1rem;
    color: #f0f0f0;
    background-color: #2563eb;
    border-style: none;
    line-height: 1.5;
    padding: 0.25rem 0.5rem;
    font-size: 1rem;
    font-family: sans-serif;
}
</style>
<h1>
Register
</h1>
<p>
You are registering for an administrator account. If you think this is
incorrect, contact an administrator for another invite link with the
correct permissions.
</p>
<p>
All passwords must have a rating of 4 when measured against
<a class="glee" href="https://lowe.github.io/tryzxcvbn/">zxcvbn</a>. To
make a strong password, either
<a class="glee" href="https://xkcd.com/936/?correct=horse&battery=staple">use
a string of unrelated words</a> or better yet, use a
<a class="glee" href="https://www.passwordstore.org/">password
manager</a>.
</p>
<form>
<label for="email">Email address (you can't edit this)</label>
<input name="email" readonly type="text" value="dchen@dennisc.net">
<label for="password">Password</label>
<input name="password" required type="password">
<button type="submit">Register</button>
</form>
</div>
<p>As a reminder for how registration will work on Glee, an admin will
send an invite link to your email through the admin page and you will
use it to register for that specific instance of Glee. This takes
advantage of Glee's self-hosting design: since one instance should
correspond to exactly one organization, having a user account should
automatically confer you with some permissions.</p>
<p>In Glee, invite codes are sent directly to the email address, which
means that if a user registers an account with that invite code, they
obviously have access to the email. Thus we skip the email verification
step that so many other sites have. Where on other sites you have</p>
<ul>
<li>user registers for SaaS (say, GitHub)</li>
<li>has to manually verify their own email</li>
<li>sysadmin has to invite them</li>
</ul>
<p>in a Glee instance, the sysadmin just invites the user and all is
taken care of.</p>
<p>Obviously, the only way to register for a Glee instance is with an
admin's invite code. Otherwise, there would be no point having invite
codes in the first place.</p>
<h2 id="self-hosting">Self-Hosting</h2>
<p>Some issues I want to take care of before self-hosting though,
because once I self-host I do not want to wipe the OS of my server with
the source of truth for my Git repos:</p>
<ul>
<li>Switch to a sane operating system. Ubuntu is utterly unusable as a
server OS, and I'm currently still stuck with it. This means either some
BSD, Alpine Linux, or Adelie Linux. I recognize that BSD has some
technical advantages, but Alpine has the technical advantage of being
able to run <code>apk add sourcehut</code>.<a href="#fn1"
class="footnote-ref" id="fnref1"
role="doc-noteref"><sup>1</sup></a></li>
<li>Get rid of everything consuming a stupid amount of memory, and
downgrade from 2GB mem to 1GB<a href="#fn2" class="footnote-ref"
id="fnref2" role="doc-noteref"><sup>2</sup></a>:
<ul>
<li>Mailcow: I don't really want the UI anyway, and this is the biggest
memory hog of them all. I can just use Postfix, though migrating the
data out of Mailcow and into Postfix will require careful
consideration.</li>
<li>MAT-web: It's taking 200 fucking megabytes of memory. What the
absolute fuck?</li>
<li>MAST-web: I am an anti-Javascript crusader anyway, so even if it
uses much less memory than MAT-web it has to go too.</li>
</ul></li>
</ul>
<p>I also have to time it properly: I can't be nuking Mailcow when we're
hosting a contest or contacting sponsors, so this will likely require
active coordination with the rest of Math Advance. As of now, my
sysadmin plans just remain idle speculation.</p>
<p>Before I get Math Advance's server on a 1GB memory Alpine OS, I might
mirror Glee on an instance of Glee as a proof of concept, but it will
not be the single source of truth.</p>
<h2 id="frontend">Frontend</h2>
<p>I've already been letting out hints of "No JS", and though on my <a
href="/writing/tech/glee-addendums">last post</a> I made some idle
speculation about using Svelte(Kit). Fortunately, I realized the errors
of my way and promptly discarded that idea.</p>
<p>Basically, the way I'm generating HTML is just some glorified string
insertion. For maximum interoperability with the backend, I'm serving
HTML files with Rust and directly using the backend libraries. My web
framework of choice is Axum<a href="#fn3" class="footnote-ref"
id="fnref3" role="doc-noteref"><sup>3</sup></a>, but I literally do not
think it matters which you use for your project. I just get Axum the
best out of all the options I've looked at (which isn't a lot!) and you
might prefer something different.</p>
<p>A JS framework is just way too much to do what <code>format!</code>
does for you. If you want abstractions, define constants or functions.
My experiences have further solidified my belief that JS frameworks
solve a problem that no one has.</p>
<p>You might notice that the CSS is pretty much copy-pasted from
dennisc.net and mathadvance.org. This is intentional and will remain
that way, though I may offer the ability to customize CSS and
favicon.svg. Speaking of the CSS style, we've been joking in Math
Advance about "dennis.css". I may make it a real thing: a style file
with a lot of sensible defaults, meant to be used for inspiration and as
a fill-in for other websites until their frontend developers create
their own styles.</p>
<p>Also, I'm dropping Redis and just using Postgres, even for state
management. I can just run a cronjob to remove any outdated entries,
which I will probably put in a <code>contrib/</code> directory
somewhere. (This doesn't relate to frontend whatsoever, but I had
nowhere else to put this.)</p>
<h2 id="groups">Groups</h2>
<p>Here is a very tentative design for groups, which I am actually
leaning on <em>not</em> implementing:</p>
<p>Group permissions work the same way as user/admin permissions (you
set the highest permission on a repo/directory, or just
<code>inherit</code> it).</p>
<p>You can be in any number of groups, and your permission for some repo
is the highest permission of any user group you are in, including the
admin group (which makes being in a custom group kind of pointless).
It's simple and flat, groups themselves are not stored in a hierarchical
manner because that is really difficult to design well and even harder
for users to wrap their heads around. (Just look at how GitLab does it
--- it's a total disaster!)</p>
<h2 id="mailing-lists">Mailing lists</h2>
<p>You may recall that I said the following about programming Glee
proper:</p>
<blockquote>
<p>The thing about this sort of design is that it has so few details,
someone must have done it before me. Maybe I am wrong and everyone else
decided to use 7 levels of access control but only 1 level of nesting
(username/repo or org/repo). I hope I am not, though, so if you know a
self-hosted Git service that sounds something like this, please let me
know so I don’t have to build it myself. Because I would really rather
not.</p>
</blockquote>
<p>I feel the same way for the hypothetical mailing list I am about to
describe, and this time, I can probably approximate what I want without
writing a single line of code.</p>
<p>What I want from a mailing list is <a
href="https://lists.sr.ht/">lists.sr.ht</a> plus support for private
lists. SourceHut literally already has private lists, so the only reason
why I'd want to write my own mailing list is to share the same user
database and access control rules as Glee. That is really not a
convincing reason to write a whole separate mailing list when SourceHut
Lists is really good and the de-facto standard anyway. Thus, I will
likely be running a Math Advance instance of SourceHut Lists.</p>
<p>The intended way to use Glee is to combine it with the best mailing
list software or issue tracker for your purposes, rather than using an
"integrated" suite with a memory requirement that blows past the roof
and doesn't exactly do what you want. As such, writing a mailing list
and baking it into the Glee package may actually be a net negative.<a
href="#fn4" class="footnote-ref" id="fnref4"
role="doc-noteref"><sup>4</sup></a></p>
<h2 id="who-wont-glee-be-for">Who won't Glee be for?</h2>
<p>Individuals may see compelling reason to use Glee --- I am
considering creating a separate instance of Glee for my personal
projects --- but they are not the group being optimized for. For
individuals who are self-hosting and don't plan on accepting outside
contributions, CGit may be the better option. You will have to set up
git-http-backend yourself, so convenience may be a compelling reason to
use Glee.</p>
<p>The point of Glee is to provide a seamless experience for small
organizations with a semi-experienced development team (so no newbies).
You can see this in the registration design, the lack of a web IDE<a
href="#fn5" class="footnote-ref" id="fnref5"
role="doc-noteref"><sup>5</sup></a>, and the commitment to low RAM and a
lightweight web UI.<a href="#fn6" class="footnote-ref" id="fnref6"
role="doc-noteref"><sup>6</sup></a></p>
<h2 id="whats-next">What's next?</h2>
<p>As of the time of writing I will be going to Europe for just under 3
weeks. This means I will make no progress on Glee. After that, I expect
authentication to take around two weeks, and it may take several months
of research to properly handle Git repos, including HTTP operations
(read, so clone/pull) and SSH operations (read/write). Since I've
already covered account creation and authentication, my next post will
likely be on handling HTTPS/SSH Git requests and access control
(resolving permissions recursively).</p>
<p>By the way, I don't plan on setting branch access control policies.
This will make Glee unsuitable for large groups with inexperienced (or
just lazy/inept) developers, because there is no guarantee some dumbass
doesn't (force) push to master. It reduces the complexity of the
software (said complexity is a big reason I don't like GitLab as much as
I used to, and part of what spurred me to write Glee).</p>
<section id="footnotes" class="footnotes footnotes-end-of-document"
role="doc-endnotes">
<hr />
<ol>
<li id="fn1"><p>Although my mailing lists might not use SourceHut
whatsoever, see the final section.<a href="#fnref1"
class="footnote-back" role="doc-backlink">↩︎</a></p></li>
<li id="fn2"><p>The reason I want to downgrade my RAM is because if I
halve my memory cap, I also halve my server costs. This, in effect,
extends how long Math Advance can run for by a factor of 2.<a
href="#fnref2" class="footnote-back" role="doc-backlink">↩︎</a></p></li>
<li id="fn3"><p>I know I said Tide in my last post but I like axum
better now. Its ergonomics just make more sense to me, I never really
got why we had to have <code>tide::Result</code> when you can just have
an HTTP Response returned. I'm sure there's a reason, but Axum doesn't
behave like that, and a small number of pet peeves like this just added
up to my Axum switch for this project.<a href="#fnref3"
class="footnote-back" role="doc-backlink">↩︎</a></p></li>
<li id="fn4"><p>Although I can just gate it behind a feature flag.<a
href="#fnref4" class="footnote-back" role="doc-backlink">↩︎</a></p></li>
<li id="fn5"><p>Web IDEs enable and perpetuate shitty committing
practices, which is why I consider them an anti-feature. However,
objectively speaking, it does lower the bar of contribution --- if only
temporarily.<a href="#fnref5" class="footnote-back"
role="doc-backlink">↩︎</a></p></li>
<li id="fn6"><p>The size of the registration page is just over <strong>1
KB</strong>. SourceHut's is just under 4 KB, which is a perfectly
reasonable size (the difference is just pocket change and probably can
be accounted for by the extra text on sr.ht's page), but everyone else
can basically go die in a fire. GitHub manages to send 5 MB of bullshit
(and that's not counting what UBlock Origin blocked) and none of it is
cached. GitLab does a lot better, with <em>only</em> 2.4 MB --- as if.
Half of way too much is still too much. Codeberg is a lot better and
only sends about 20KB, except when it's busy sending me megabytes worth
of styles and fonts, and Gitea, which Codeberg is based off of, has a
size around that of GitLab's.</p>
<p>All numbers are uncompressed, by the way.<a href="#fnref6"
class="footnote-back" role="doc-backlink">↩︎</a></p></li>
</ol>
</section>]]></description>
	<pubDate>7 Jul 2022</pubDate>
</item>
<item>
	<title>Sets are not the end all be all</title>
	<link>https://dennisc.net/writing/blog/sets-classes.md</link>
	<description><![CDATA[<p><em>Disclaimer: I am by no means an expert on
foundations, so I cannot guarantee that mistakes,
pedagogical/philosophical oversights, etc are not present.</em></p>
<p>Mathematicians study collections of objects. (Here when we say
"collection" we mean it in a very informal sense.) For instance, we can
make claims about every even integer, or every isosceles triangle.</p>
<p>Once upon a time, there was this naive conception of collections as
<em>sets</em>, and in order to describe as many collections as possible
using the language of naive set theory, a notion of <em>unrestricted
comprehension</em> was adopted. (We will get into what that means
shortly.)</p>
<p>However, this wasn't good enough: with unrestricted comprehension we
got Russell's Paradox. This is probably old news for most readers of
this blog, but we will quickly and informally cover Russell's Paradox
again.</p>
<p><em>Unrestricted comprehension</em> says that given some predicate
<span class="math inline"><em>ϕ</em></span>, there exists a set <span
class="math inline"><em>S</em></span> whose members are precisely those
that satisfy <span class="math inline"><em>ϕ</em></span>. Because <span
class="math inline"><em>x</em> ∉ <em>x</em></span> is a valid predicate,
there exists a set <span class="math inline"><em>S</em></span>
consisting of sets that do not contain themselves. Yet the existence of
this <span class="math inline"><em>S</em></span> is
self-contradictory:</p>
<ul>
<li>If <span class="math inline"><em>S</em> ∈ <em>S</em></span>, then
<span class="math inline"><em>S</em> ∉ <em>S</em></span> is false,
meaning that <span class="math inline"><em>S</em></span> cannot be a
member of <span class="math inline"><em>S</em></span>,
contradiction.</li>
<li>If <span class="math inline"><em>S</em> ∉ <em>S</em></span>, then
<span class="math inline"><em>S</em> ∉ <em>S</em></span> is true,
meaning that <span class="math inline"><em>S</em></span> must be a
member of <span class="math inline"><em>S</em></span>,
contradiction.</li>
</ul>
<p>The axiom of unrestricted comprehension was strong. Too strong, in
fact, which is why it led to a contradiction. So rather than having a
set of implicit, "obvious" axioms with which you could construct sets,
mathematicians actually shored up the exact axioms. They comprise
<em>Zermelo–Fraenkel Set Theory with the Axiom of Choice</em>,
abbreviated to <em>ZFC</em>.</p>
<p>So how does our newly constructed set theory really work, exactly? In
other words, what is ZFC? This is where the YouTube videos all stop, and
where the meat really begins.</p>
<p>I am sure that at many points in your life, you have referred to the
set of all natural numbers. But step back for a second. How do we even
know such a set exists? In other words, what justifies us taking this
<em>collection</em> of all natural numbers (which may or may not be a
set) and decreeing it to be a set? It is ZFC that precisely allows us to
do this.</p>
<p>Our set theory is constructive in nature. Here is how ZFC works:
given some pre-existing sets, we can apply an axiom of ZFC to explicitly
construct another set.<a href="#fn1" class="footnote-ref" id="fnref1"
role="doc-noteref"><sup>1</sup></a> For example, given two sets <span
class="math inline"><em>A</em></span> and <span
class="math inline"><em>B</em></span>, we may construct the set <span
class="math inline"><em>A</em>, <em>B</em></span>. Furthermore, ZFC
gives us two sets to start with: the empty set, i.e. the set with no
elements, and an infinite set. And we may only decree a collection as a
set once we have shown it can be constructed via the axioms of ZFC.<a
href="#fn2" class="footnote-ref" id="fnref2"
role="doc-noteref"><sup>2</sup></a></p>
<p>Furthermore, in ZFC, the <em>only</em> objects of study are sets. On
the surface, this seems inadequate: how can we define the natural
numbers, let alone functions, shapes, etc? But the answer is simple: we
define the natural numbers as a sequence of sets. In particular, we
define</p>
<ul>
<li><span class="math inline">0 = {}</span>, i.e. the empty set,</li>
<li>and for each <span class="math inline"><em>n</em> ≥ 0</span>, we
define <span
class="math inline"><em>n</em> + 1 = <em>n</em> ∪ {<em>n</em>}</span>.</li>
</ul>
<p>(Note that this implies <span
class="math inline"><em>n</em> + 1 = 0, 1, …, <em>n</em></span> as
well.)</p>
<p>We also define functions as subsets of Cartesian Products. Say we
have a function <span
class="math inline"><em>f</em>: {0, 1} → {0, 1}</span> where <span
class="math inline"><em>f</em>(<em>x</em>) = <em>x</em></span>. Then we
may define <span class="math inline"><em>f</em></span> to be the set
<span class="math inline">{(0, 0), (1, 1)}</span>. Note that there is
exactly one ordered pair with <span class="math inline">0</span> as the
<span class="math inline"><em>x</em></span>-coordinate, and likewise for
<span class="math inline">1</span>. The <span
class="math inline"><em>y</em></span>-coordinate is the value associated
with the function.</p>
<p>Of course, you might ask what an ordered pair is. And the answer,
again, is a set: specifically, <span
class="math inline">(<em>x</em>, <em>y</em>) = {<em>x</em>, {<em>x</em>, <em>y</em>}}</span>.
(It is left as an exercise to show that <span
class="math inline">(<em>x</em><sub>1</sub>, <em>y</em><sub>1</sub>) = (<em>x</em><sub>2</sub>, <em>y</em><sub>2</sub>)</span>
if and only if <span
class="math inline"><em>x</em><sub>1</sub> = <em>x</em><sub>2</sub></span>
and <span
class="math inline"><em>y</em><sub>1</sub> = <em>y</em><sub>2</sub></span>,
in other words, that ordered pairs indeed uniquely identify the values
of the two coordinates.)</p>
<p>You get the idea. We now can explicitly show that certain sets exist
and study them. Furthermore, we can <em>encode</em> the rest of
mathematics within the language of set theory.</p>
<p>But there is one major catch. Let's go back to the reason
mathematicians created ZFC in the first place: because naive set theory
led to a contradiction (Russell's Paradox). And all of our work with ZFC
is largely pointless if ZFC turns out to also lead to a contradiction.
So is ZFC consistent? That is, is ZFC free of contradictions?</p>
<p>I have two pieces of bad news for you. The first is that we don't
know whether ZFC is consistent. And the second much worse piece of news
is that if ZFC is consistent, we will <em>never</em> know. This is
because of Godel's Second Incompleteness Theorem: because ZFC is
sufficiently strong,</p>
<ul>
<li>we can use ZFC to make the statement "ZFC is consistent",</li>
<li>and we cannot prove it in ZFC.</li>
</ul>
<p>Therefore, the only way we will ever know whether ZFC is consistent
is by finding an inconsistency. And this is true of any logical system
that is strong enough to perform arithmetic. So we will never truly know
whether our model of set theory is self-consistent, regardless of what
model we use.</p>
<p>But ZFC seems reasonable enough and no one has found a contradiction
yet. Having done the best we can, we move on.<a href="#fn3"
class="footnote-ref" id="fnref3" role="doc-noteref"><sup>3</sup></a></p>
<h2 id="classes">Classes</h2>
<p>I can prove to you that any singleton set <span
class="math inline"><em>S</em></span> satisfies the (trivial) statement
"<span
class="math inline"><em>x</em> ∈ <em>S</em> ∧ <em>y</em> ∈ <em>S</em> ⟹ <em>x</em> = <em>y</em></span>".
Similarly, I can make claims about every group, every homeomorphism, and
so on. So the collection of, say, singleton sets is worth making
statements about.</p>
<p>But the collection of all singleton sets is not a set! For if it was,
then we may take <span
class="math inline">⋃{{<em>a</em>}, {<em>b</em>}, …}</span> and get
<span class="math inline">{<em>a</em>, <em>b</em>, …}</span>, i.e. the
set of all sets, which leads to a contradiction (as that set would then
contain itself).</p>
<p>It is possible to just be satisfied with statements like "for every
singleton set..." and move on. But it is quite natural to ask what the
collection of singleton sets <em>really is</em>, and whether it has
anything in common with other non-set collections like the collection of
groups. To that end, we define a notion of a <em>class</em>.</p>
<p>Very briefly, a class is just a collection of sets that can be
described. To really understand what a class is, we return to
<em>unrestricted comprehension</em>.</p>
<p>We cannot define <span class="math inline">{<em>S</em> ∣ <em>S</em>
is a singleton set}</span> as a <em>set</em>. But we may define it as a
<em>class</em>. And this is how classes are defined in general: it is
just the collection of sets satisfying a certain predicate <span
class="math inline"><em>ϕ</em></span>. So saying that set <span
class="math inline"><em>S</em></span> belongs to class <span
class="math inline"><em>C</em></span> really just means that <span
class="math inline"><em>S</em></span> satisfies <span
class="math inline"><em>ϕ</em></span>.</p>
<p>A little more detail about ZFC: because unrestricted comprehension
leads to Russell's paradox, we instead have a notion of
<em>restricted</em> comprehension. That is, we may not say <span
class="math inline">{<em>x</em> ∣ <em>x</em> satisfies
<em>ϕ</em>}</span>, but given some "parent set" <span
class="math inline"><em>S</em></span>, we may say <span
class="math inline">{<em>x</em> ∈ <em>S</em> ∣ <em>x</em> satisfies
<em>ϕ</em>}</span>, which means that we can construct subsets of an
already existing set whose members satisfy some predicate. This is why
it is a big deal to talk about collections formed by unrestricted
comprehension, because they cannot be sets.</p>
<p>You might be asking why classes don't run into Russell's paradox. Why
isn't there a class of all classes that do not contain themselves?
Because by definition, classes may only contain sets as members. So it
does not make sense to talk about classes of classes, and the hope is we
sidestep such paradoxes.</p>
<p><em>Probably</em>. Recall by Godel's Second Incompleteness Theorem
that we have no way of actually knowing whether our universe of sets and
classes leads to a paradox. And again, there are multiple ways of
creating new axioms to define classes, each of which may be subtly
different. The same way set theory does not necessarily have to be
formalized via ZFC, class theory does not <em>have to</em> be formalized
via any particular set of axioms.</p>
<p>There does exist a conservative extension of ZFC with classes known
as NBG. By "conservative" I mean that any proof in NBG that solely
refers to sets is also valid in ZFC. And there is a very good <a
href="https://math.stackexchange.com/questions/136215/difference-between-zfc-nbg">StackExchange
post concerning the relative advantages of ZFC and NBG</a>.</p>
<p>Finally, I must mention that not every collection of objects may be
modeled as a class. Why? As a dumb example, the collection of all
classes is surely something worth studying. But it is not a class,
because every member of a class must be a set. The existence of proper
classes means the collection of classes cannot be a class itself.</p>
<p>More generally, classes are "describable" by a predicate, but not all
collections are describable.</p>
<h2 id="why-bother">Why bother?</h2>
<p>Quick note: when I say "proper class" I mean a class that cannot be
modeled as a set.</p>
<p>In most fields of math, <strong>as far as I am aware</strong>, there
is no reason to prefer discussing something like "the class of all
continuous functions" as opposed to just saying "if a function is
continuous..." So as one would expect, these fields implicitly use ZFC
as their set theory and make no mention of classes.</p>
<p>But there is one field that explicitly <em>does</em> mention such
collections: category theory. For example, the collection of objects in
the category of sets is "the class of all sets". And by making a
distinction between sets and classes, we may describe a category as
"small" if the collection of its objects and the collection of its
arrows are both sets, and "large" if one of these collections is a
proper class. Then we may discuss, for instance, the category of all
<em>small</em> categories, which avoids the issue of self-containment
(as this category would be <em>large</em>).</p>
<section id="footnotes" class="footnotes footnotes-end-of-document"
role="doc-endnotes">
<hr />
<ol>
<li id="fn1"><p>The biggest exception is the Axiom of Choice, which
infamously only gives the <em>existence</em> of a choice function rather
than explicitly creating one.<a href="#fnref1" class="footnote-back"
role="doc-backlink">↩︎</a></p></li>
<li id="fn2"><p>There is one important <em>descriptive</em> rather than
<em>constructive</em> constraint: the Axiom of Foundation, which states
that in every non-empty set <span class="math inline"><em>S</em></span>
there exists some element <span
class="math inline"><em>x</em> ∈ <em>S</em></span> such that <span
class="math inline"><em>x</em> ∩ <em>S</em></span> is the empty set.
From this we may conclude that no set contains itself. The rules which
we use to construct sets show that certain classes of sets exist; it can
be much harder to show that certain classes of sets do not exist. And it
can actually be shown that the Axiom of Foundation is independent of the
rest of ZFC. As many set-theoretic constructions rely on the Axiom of
Foundation, it is convenient to have it. However, <a
href="https://math.stackexchange.com/questions/4866328/do-we-really-need-the-axiom-of-regularity">it
is not really necessary</a> for some definition of "necessary".</p>
<p>There is also another <em>descriptive</em> constraint: the Axiom of
Extensionality, which states that two sets are equivalent if and only if
they have the same elements. It is much more obvious why this is an
axiom.<a href="#fnref2" class="footnote-back"
role="doc-backlink">↩︎</a></p></li>
<li id="fn3"><p>Of course, given that mathematics has such diversity of
thought, this is not the end of the story for everyone. Alternative
foundations have been proposed. Some reject the Law of Excluded Middle,
which informally states that a proposition is either true or false
(formally, <span
class="math inline"><em>x</em> ∨ ¬<em>x</em> = ⊤</span>). Others wish to
use a type-theoretic model, an idea closely tied to computer science.
Still others build their foundations from category theory, rather than
set theory.</p>
<p>Foundations are also not dogmatic. You do not need to "believe in"
ZFC and study it to the exclusion of all else. After all, when we study
ZFC set theory, we are not really proving that "no sets contain
themselves", we are proving that "under the axioms of ZFC, no sets
contain themselves". Thus it is perfectly fine to make a statement like
"in category theory, there exists a category of all categories", because
it makes no claims about ZFC. But of course, even in category theory we
must put a large asterisk next to the "category of all categories",
because depending on the foundations your category theory rests on,
self-containment is still an issue that needs to be addressed.<a
href="#fnref3" class="footnote-back" role="doc-backlink">↩︎</a></p></li>
</ol>
</section>]]></description>
	<pubDate>21 Jul 2024</pubDate>
</item>
<item>
	<title>The real numbers</title>
	<link>https://dennisc.net/writing/blog/reals.md</link>
	<description><![CDATA[<p>You probably have a good intuition about the
natural numbers (<span class="math inline">ℕ</span>). Just count: <span
class="math inline">0, 1, 2, …</span>. You also know how <span
class="math inline">+</span> and <span class="math inline">×</span> work
on <span class="math inline">ℕ</span> very well. From there defining the
integers (<span class="math inline">ℤ</span>) and then the rationals
(<span class="math inline">ℚ</span>) is quite natural: it'd be great if
we could reverse <span class="math inline">+</span> and <span
class="math inline">×</span>, and defining <span
class="math inline">ℚ</span> is how we do that.<a href="#fn1"
class="footnote-ref" id="fnref1" role="doc-noteref"><sup>1</sup></a></p>
<p>Getting from <span class="math inline">ℕ</span> to <span
class="math inline">ℚ</span> was not hard. But where on earth do the
reals (<span class="math inline">ℝ</span>) come from?</p>
<h2 id="wrong-answers-only">Wrong answers only</h2>
<p>We're going to work backwards a little. We'll touch on natural ideas
that edge closer to the real numbers, then shine a spotlight on why the
rationals are lacking (and how they naturally lead into the reals), and
then finally revisit some of these topics with our newfound
understanding of the reals.</p>
<p>At the same time I will reference the reals without explaining what
they are yet. Sorry about that, but it helps to be able to say "this
idea doesn't perfectly match the final answer" even if we don't know
what the final answer is yet.</p>
<h3 id="algebraic-numbers">Algebraic numbers</h3>
<p>You might think we'd like to invent the real numbers because we want
<span class="math inline">$\sqrt 2$</span> to exist, or more precisely,
we want <span class="math inline"><em>x</em><sup>2</sup> = 2</span> to
have a solution. Not entirely. There are two problems with <span
class="math inline">ℝ</span>: it contains too many numbers and at the
same time too few.</p>
<p>Let's take our desire of <span class="math inline">$\sqrt 2$</span>'s
existence to the extreme. We want roots for all rational polynomials:
this necessarily implies the Fundamental Theorem of Algebra holds, i.e.
that we can factor every polynomial into the form <span
class="math inline"><em>k</em>(<em>x</em> − <em>q</em><sub>1</sub>)(<em>x</em> − <em>q</em><sub>2</sub>)⋯(<em>x</em> − <em>q</em><sub><em>n</em></sub>)</span>
where all <span
class="math inline"><em>q</em><sub><em>i</em></sub></span> are
rational.</p>
<p>Actually, the set of real numbers that are solutions to a rational
polynomial are called the algebraic numbers (<span
class="math inline">$\overline{\mathbb Q}$</span>). Algebraic numbers
are countable (because polynomials are countable) yet the reals are
uncountable. By the way, the algebraic numbers are "enough" in this
setting: the Fundamental Theorem of Algebra holds for <span
class="math inline">$\overline{\mathbb Q}$</span>. There is no reason to
go "beyond" <span class="math inline">$\overline{\mathbb Q}$</span>.</p>
<p>So there are real numbers that are not algebraic. The real numbers
are, in one sense, more than the algebraic numbers. So ensuring all
polynomials have roots could not possibly be the rationale.</p>
<p>At the same time there is no solution for <span
class="math inline"><em>x</em><sup>2</sup> + 1 = 0</span> in <span
class="math inline">ℝ</span>. So the algebraic numbers contain too many
numbers, that is they contain complex numbers.</p>
<h3 id="cauchy-sequences">Cauchy sequences</h3>
<blockquote>
<p>I'd like to be able to write an infinite sequence of digits, like
<span class="math inline">3.1415…</span>, and still have that be a
number.</p>
</blockquote>
<p>Yeah, this is pretty close. One of the official reasons for defining
real numbers is so that this sequence of digits is some real number.
(It's a bit more general than that, but it is close!)</p>
<h3 id="i-want-intermediate-value-theorem-to-work">I want Intermediate
Value Theorem to work</h3>
<p>Yes! For the Intermediate Value Theorem we need continuity, which
doesn't do much for integers. A concept of continuity does exist for
rationals and works reasonably well. But actually the intermediate value
theorem fails for rationals.</p>
<p>Here is an example: consider the function <span
class="math inline"><em>f</em>(<em>x</em>) = 0</span> if <span
class="math inline"><em>x</em><sup>2</sup> &lt; 2</span> and <span
class="math inline"><em>f</em>(<em>x</em>) = 1</span> if <span
class="math inline"><em>x</em><sup>2</sup> &gt; 2</span> where <span
class="math inline"><em>f</em></span> sends rationals to rationals. This
is continuous: if you know <span
class="math inline"><em>δ</em></span>-<span
class="math inline"><em>ϵ</em></span> proofs you can check this
yourself, and if you don't you can take my word for it. (In the reals
this is discontinuous only at <span class="math inline">$\sqrt 2$</span>
and since <span class="math inline">$\sqrt 2$</span> doesn't exist it is
now continuous!) Clearly we have <span
class="math inline"><em>f</em>(0) = 0</span> and <span
class="math inline"><em>f</em>(2) = 1</span>, but we have no <span
class="math inline"><em>x</em></span> satisfying <span
class="math inline">$f(x) = \frac 12$</span>. Ouch.</p>
<p>The same goes for many other theorems like Mean Value Theorem. All
these things where we need "something in between" fail on <span
class="math inline">ℚ</span>!</p>
<h2 id="so-why-is-mathbb-q-lacking">So why is <span
class="math inline">ℚ</span> lacking?</h2>
<p>Consider the set <span
class="math inline"><em>S</em> = {<em>x</em><sup>2</sup> &lt; 2 ∣ <em>x</em> ∈ ℚ}</span>.
You can easily bound this set from above. For instance, every element in
<span class="math inline"><em>S</em></span> is less than <span
class="math inline">2</span>.</p>
<p>But is there a <em>least</em> upper bound? No. No matter what upper
bound you give me, I can always give you a smaller one. If you give me
<span class="math inline">2</span>, I will give you <span
class="math inline">1.5</span>. And then you can give me <span
class="math inline">1.45</span>. And so on and so forth: we can keep
one-upping each other.</p>
<p>Obviously if we took the reals for this set we'd have a least upper
bound: <span class="math inline">$\sqrt 2$</span>. But we want something
more general. And in fact the following is true:</p>
<blockquote>
<p>Given any non-empty set <span
class="math inline"><em>S</em> ⊆ ℝ</span> bounded from above, <span
class="math inline"><em>S</em></span> has a least upper bound <span
class="math inline">sup <em>S</em></span>.</p>
</blockquote>
<p>By "least upper bound", we mean given any upper bound <span
class="math inline"><em>b</em></span> for <span
class="math inline"><em>S</em></span>, we have <span
class="math inline"><em>b</em> ≥ sup <em>S</em></span>. Also we'd
obviously like for <span class="math inline">ℝ</span> to contain <span
class="math inline">ℚ</span>.</p>
<h2 id="constructing-the-reals">Constructing the reals</h2>
<p>But we cannot just will <span class="math inline">ℝ</span> into
existence. We actually need to prove it exists somehow. Here is the
construction:</p>
<blockquote>
<p><strong>Dedekind Cuts.</strong> A <em>Dedekind Cut</em> is a
non-empty set <span class="math inline"><em>A</em> ⊊ ℚ</span> satisfying
two properties:</p>
<ul>
<li><span class="math inline"><em>A</em></span> contains no largest
element.</li>
<li>If <span class="math inline"><em>a</em> ∈ <em>A</em></span> and
<span class="math inline"><em>b</em> ∈ ℚ \ <em>A</em></span> then <span
class="math inline"><em>a</em> &lt; <em>b</em></span>.</li>
</ul>
</blockquote>
<p>Intuitively, we cut the rational number line in half. All points to
the left are in <span class="math inline"><em>A</em></span>; all points
to the right are not in <span class="math inline"><em>A</em></span>. Of
course, this point at which we cut the rationals is not necessarily a
rational. We cannot even rigorously define such a point (if we could, no
reason to bother with Dedekind Cuts): we can only reason in terms of the
elements of <span class="math inline"><em>A</em></span>.</p>
<p>Here is the kicker. <em>These Dedekind Cuts are our real
numbers.</em> They don't merely <em>represent</em> real numbers. They
are, under the hood, what we are referring to when we say "real number".
Now it is important to note there are other ways to define the real
numbers such that they satisfy the properties we want them to. And it
turns out these notions of the real numbers are all equivalent (formally
they are isomorphic). This is well outside the scope of this post, but
for now we take this definition of the reals and run with it.</p>
<p>Recall our wishlist: we wanted a least upper bound property and we
wanted <span class="math inline">ℝ ⊃ ℚ</span>. Implicit in this wishlist
is a notion of order (i.e. <span class="math inline">≤</span>), a notion
of addition, and a notion of multiplication. Furthermore they have to be
consistent with the respective notions from <span
class="math inline">ℚ</span>. Let's get down to defining and checking
these.</p>
<h3 id="what-are-rational-numbers-in-the-reals">What are rational
numbers in the reals?</h3>
<p>A rational number <span class="math inline"><em>q</em></span>,
represented as a real, is simply <span
class="math inline">{<em>x</em> ∈ ℚ ∣ <em>x</em> &lt; <em>q</em>}</span>.
It is easy to check this is a Dedekind Cut.</p>
<h3 id="ordering">Ordering</h3>
<p>We say <span
class="math inline"><em>A</em><sub>1</sub>≤<sub>ℝ</sub><em>A</em><sub>2</sub></span>
if and only if <span
class="math inline"><em>A</em><sub>1</sub> ⊆ <em>A</em><sub>2</sub></span>.
It is easy to check that <span
class="math inline"><em>q</em><sub>1</sub>≤<sub>ℚ</sub><em>q</em><sub>2</sub> ⇔ <em>A</em><sub>1</sub>≤<sub>ℝ</sub><em>A</em><sub>2</sub></span>,
where <span class="math inline"><em>A</em><sub>1</sub></span> and <span
class="math inline"><em>A</em><sub>2</sub></span> are the reals
associated with <span class="math inline"><em>q</em><sub>1</sub></span>
and <span class="math inline"><em>q</em><sub>2</sub></span>.</p>
<p>Also we always have at least one of <span
class="math inline"><em>A</em><sub>1</sub> ≤ <em>A</em><sub>2</sub></span>
or <span
class="math inline"><em>A</em><sub>2</sub> ≤ <em>A</em><sub>1</sub></span>,
and when both are true <span
class="math inline"><em>A</em><sub>1</sub> = <em>A</em><sub>2</sub></span>.
(When people say <span class="math inline">ℝ</span> is a <em>complete
ordered</em> field, this is what they mean by "complete ordered".)</p>
<h3 id="addition">Addition</h3>
<p>We say <span
class="math inline"><em>A</em><sub>1</sub> + <em>A</em><sub>2</sub> = {<em>a</em><sub>1</sub> + <em>a</em><sub>2</sub> ∣ <em>a</em><sub>1</sub> ∈ <em>A</em><sub>1</sub>, <em>a</em><sub>2</sub> ∈ <em>A</em><sub>2</sub>}</span>.
We can check this is a Dedekind cut and it preserves ordering the same
way addition does in the rationals.</p>
<p>Also we may define the additive inverse: <span
class="math inline">−<em>A</em> = {<em>q</em> ∈ ℚ ∣ −<em>q</em> ∉ <em>A</em>}</span>
where <span class="math inline"><em>q</em></span> is not the minimal
element in <span class="math inline">ℚ \ <em>A</em></span>.</p>
<h3 id="multiplication">Multiplication</h3>
<p>This is a bit more annoying. First we have to define positive and
negative reals in the obvious way. (Remember reals are cuts and
comparison with <span class="math inline">0</span> is through subset
comparison.) For positive reals we define <span
class="math inline"><em>A</em><sub>1</sub> × <em>A</em><sub>2</sub> = {<em>a</em><sub>1</sub> × <em>a</em><sub>2</sub> ∣ <em>a</em><sub>1</sub> &gt; 0, <em>a</em><sub>1</sub> ∈ <em>A</em><sub>1</sub>, <em>a</em><sub>2</sub> &gt; 0, <em>a</em><sub>2</sub> ∈ <em>A</em><sub>2</sub>} ∪ {<em>q</em> ∣ <em>q</em> ≤ 0}</span>.
If <span class="math inline"><em>A</em><sub>1</sub></span> is negative
and <span class="math inline"><em>A</em><sub>2</sub></span> is positive
then <span
class="math inline"><em>A</em><sub>1</sub> × <em>A</em><sub>2</sub> = −((−<em>A</em><sub>1</sub>) × <em>A</em><sub>2</sub>)</span>.
There are more cases that I cannot be bothered to list here because they
provide no further instructive value.</p>
<h2 id="right-answers-only">Right answers only</h2>
<p>The details above are not particularly important. Here is what
matters: <span class="math inline">ℝ</span> is a superset of <span
class="math inline">ℚ</span> that preserves ordering, addition, and
multiplication. Furthermore, it gains the least upper bound property
("any non-empty set bounded from above has a least upper bound").
Through that it gains some other properties.</p>
<h3 id="cauchy-sequences-1">Cauchy sequences</h3>
<p>The terms in the sequence <span
class="math inline">(<em>a</em><sub><em>n</em></sub>) = 3, 3.1, 3.14, 3.141, 3.1415, …</span>
eventually get arbitrarily close to each other. Formally, for any <span
class="math inline"><em>ϵ</em> &gt; 0</span>, there is some <span
class="math inline"><em>k</em></span> such that for all <span
class="math inline"><em>n</em>, <em>m</em> &gt; <em>k</em></span>, <span
class="math inline">|<em>a</em><sub><em>n</em></sub> − <em>a</em><sub><em>m</em></sub>| &lt; <em>ϵ</em></span>.
(Any sequence satisfying this condition is called a <strong>Cauchy
sequence</strong>.) If we consider <span
class="math inline">(<em>a</em><sub><em>n</em></sub>)</span> as a
sequence of rationals, it doesn't converge to anything. We know this
because it converges to <span class="math inline"><em>π</em></span> in
the reals, which is not a rational number, and limits are unique in the
reals. (This is not obvious and requires proof, but here we take it for
granted.)</p>
<p>So there are rational Cauchy sequences that do not have a limit. This
is the other sense in which the rationals were lacking. The reals,
however, do not have this problem. Any Cauchy sequence in the reals also
converges to a real number.</p>
<h3 id="the-intermediate-value-theorem">The Intermediate Value
Theorem</h3>
<p><em>The full proof in all its detail is in Section 1.6 of Charles
Pugh's Real Mathematical Analysis.</em></p>
<p>Formally, the Intermediate Value Theorem states</p>
<blockquote>
<p>Let <span class="math inline"><em>f</em></span> be a continuous
function on <span class="math inline">[<em>a</em>, <em>b</em>]</span>
and suppose <span
class="math inline"><em>f</em>(<em>a</em>) ≤ <em>f</em>(<em>b</em>)</span>.
If <span
class="math inline"><em>f</em>(<em>a</em>) ≤ <em>k</em> ≤ <em>f</em>(<em>b</em>)</span>
then there is some <span
class="math inline"><em>a</em> ≤ <em>c</em> ≤ <em>b</em></span> such
that <span
class="math inline"><em>f</em>(<em>c</em>) = <em>k</em></span>.</p>
</blockquote>
<p>Continuity is defined with the usual <span
class="math inline"><em>δ</em></span>-<span
class="math inline"><em>ϵ</em></span> criteria: if you don't know them
and are curious you may easily Google it.</p>
<p>This is true in the reals, and the proof fully uses the least upper
bound property. The proof also relies on the facts that continuous
functions on a closed interval of <span class="math inline">ℝ</span> are
bounded: because it is longer we do not reproduce it here. We just take
it for granted. It is proven in a very similar fashion.</p>
<blockquote>
<p>Let <span class="math inline"><em>V</em>(<em>x</em>)</span> be the
set of values taken by <span
class="math inline"><em>f</em>(<em>t</em>)</span> for <span
class="math inline"><em>a</em> ≤ <em>t</em> ≤ <em>x</em></span>; in set
notation, <span
class="math inline"><em>V</em>(<em>x</em>) = {<em>f</em>(<em>t</em>) ∣ <em>a</em> ≤ <em>t</em> ≤ <em>x</em>}</span>.
Obviously each <span class="math inline"><em>V</em>(<em>x</em>)</span>
is non-empty and we took for granted that <span
class="math inline"><em>V</em>(<em>x</em>)</span> was bounded, so <span
class="math inline"><em>V</em>(<em>x</em>)</span> has a least upper
bound; let it be <span
class="math inline">sup <em>V</em>(<em>x</em>)</span>. Define <span
class="math inline"><em>X</em> = {<em>x</em> ∈ [<em>a</em>, <em>b</em>] ∣ sup <em>V</em>(<em>x</em>) ≤ <em>k</em>}</span>.
Clearly <span class="math inline"><em>X</em></span> is non-empty as
<span class="math inline"><em>a</em> ∈ <em>X</em></span> and <span
class="math inline"><em>X</em></span> is bounded from above by <span
class="math inline"><em>b</em></span>. We claim <span
class="math inline">sup <em>X</em> = <em>c</em></span>.</p>
<p>We may use the <span class="math inline"><em>δ</em></span>-<span
class="math inline"><em>ϵ</em></span> condition of continuity to show
that <span
class="math inline"><em>f</em>(<em>c</em>) &lt; <em>k</em></span> and
<span class="math inline"><em>f</em>(<em>c</em>) &gt; <em>k</em></span>
both lead to contradictions. Very informally, continuity tells us that
if <span
class="math inline"><em>f</em>(<em>c</em>) &lt; <em>k</em></span>, then
there's some <span class="math inline"><em>d</em></span> slightly larger
than <span class="math inline"><em>c</em></span> such that <span
class="math inline"><em>f</em>(<em>d</em>) &lt; <em>k</em></span> as
well (and also <span
class="math inline"><em>f</em>(<em>t</em>) &lt; <em>k</em></span> for
all <span
class="math inline"><em>c</em> ≤ <em>t</em> ≤ <em>d</em></span>).
Likewise for <span
class="math inline"><em>f</em>(<em>c</em>) &gt; <em>k</em></span>. So we
must have <span
class="math inline"><em>f</em>(<em>c</em>) = <em>k</em></span>.</p>
</blockquote>
<section id="footnotes" class="footnotes footnotes-end-of-document"
role="doc-endnotes">
<hr />
<ol>
<li id="fn1"><p>In more technical terms, <span
class="math inline">ℚ</span> is a field: we have a <span
class="math inline">+</span> and <span class="math inline">×</span>
operation, an identity with <span class="math inline">+</span> (i.e.
<span class="math inline">0</span>), an identity with <span
class="math inline">×</span> (i.e. <span class="math inline">1</span>),
and additive/multiplicative inverses. Actually, <span
class="math inline">ℚ</span> is the smallest field containing <span
class="math inline">ℕ</span>.<a href="#fnref1" class="footnote-back"
role="doc-backlink">↩︎</a></p></li>
</ol>
</section>]]></description>
	<pubDate>4 Apr 2024</pubDate>
</item>
<item>
	<title>What does the president do?</title>
	<link>https://dennisc.net/writing/essays/president.md</link>
	<description><![CDATA[<p>A non-profit has a minimum of three officers: a
president, a secretary, and a treasurer. It's clear what the secretary
and treasurer do. The secretary is in charge of rote administrative
stuff, such as emails and maintaining notes, and the treasurer is in
charge of finances. So what does the president do?</p>
<p>On the surface the president is in charge of making decisions, doing
PR, and providing a vision, among other things. But really the
president's job is to maintain standards.</p>
<p>The way <a href="https://mathadvance.org">we</a> have things set up,
I'm the president for life and I have the power to make any of my
decisions final. This means that anything we do has my approval, tacit
or explicit. But there's a lot of things that come up when you're
running a nonprofit, so ideally people will make decisions on their own
as often as possible. Plus, when it comes to the hard questions, my
perspective can be insufficient or straight up incorrect. So having
other people with the same values help make decisions is very
helpful.</p>
<p>This means that the type of person you should put in charge is the
type that thinks and cares about these things. Evidently I do: besides
this essay, I've written <a href="framework">an essay on frameworks</a>
and <a href="https://mathadvance.org/contribute">Math Advance's strict
and detailed contribution guidelines</a>. The president also has to be
willing to wrestle with the jobs no one else can or wants to do well. In
my two years as president I've already picked up programming, system
administration, legal responsibilities, public relations, writing, and
design. The upshot is that these responsibilities give you the push to
learn a lot of skills, and having high standards ensures that you learn
and do them well.<a href="#fn1" class="footnote-ref" id="fnref1"
role="doc-noteref"><sup>1</sup></a></p>
<p>A bit of history: Math Advance started forming last May<a href="#fn2"
class="footnote-ref" id="fnref2" role="doc-noteref"><sup>2</sup></a>
when Jerry asked for help on a mock AMC 10 (which would become the <a
href="https://mat.mathadvance.org/JMC10.pdf">2020 JMC 10</a>) on the
AoPS fora<a href="#fn3" class="footnote-ref" id="fnref3"
role="doc-noteref"><sup>3</sup></a> and a couple of people who would
become the initial founders agreed to help. On the surface I didn't do a
whole lot<a href="#fn4" class="footnote-ref" id="fnref4"
role="doc-noteref"><sup>4</sup></a>: I wrote two easy problems (which
pretty much anyone can do for a mock AMC 10) and two hard problems. The
vast majority of the problems were written by Jerry with problems not
written by him sprinkled in by a variety of other contributors.</p>
<p>Looking from the outside at this point in time, it would've made the
most sense to put Jerry in charge. So how did it end up being me?<a
href="#fn5" class="footnote-ref" id="fnref5"
role="doc-noteref"><sup>5</sup></a> It was because I was willing to call
the shots no one else did<a href="#fn6" class="footnote-ref" id="fnref6"
role="doc-noteref"><sup>6</sup></a>, I had relatively<a href="#fn7"
class="footnote-ref" id="fnref7" role="doc-noteref"><sup>7</sup></a>
high standards to the point where I was called "quality control", and
because I was willing to do the annoying stuff like typesetting
solutions. When we had to make a formal decision while filing our
corporate registration it ended up just being me by default. The
president doesn't have to to be the most capable or hardworking out of
everyone, though most good presidents have both these qualities. Rather,
their job is to make it as <a href="force-multipliers">easy as possible
for capable and hardworking people to contribute and create something of
value</a>.</p>
<p>Outside of setting standards I'm just another member of Math Advance.
My standards apply equally to me --- sometimes the problems I write
aren't up to par, and more often they are up to par and just can't fit
well in a certain draft --- if they didn't, no one else would take them
seriously.</p>
<p>Being the president requires a lot of restraint. Whenever I'm on the
"losing" side of a disagreement it's easy to just say "forget you, I'm
going to do things my way because I'm in charge". This behavior isn't
dangerous because I'm taking advantage of my position, which I already
am by using the company server to host my own projects, including this
website. Nor is is that I'm exerting disproportionate influence, because
I already am --- besides the JMCs, I'm one of the leading proposers in
every contest we've released so far, and I'm not even close to the most
prolific proposer in Math Advance.<a href="#fn8" class="footnote-ref"
id="fnref8" role="doc-noteref"><sup>8</sup></a> It's dangerous because
it erodes trust in standards. If it's okay for the person creating the
standards to circumvent them, why should anyone trust that they'll
continue to be enforced?</p>
<p>Sticking to your standards can lead to dissatisfaction from time to
time. Do it anyway: if the people you're working with are mature and
patient, they'll understand (and possibly even agree with or propose)
decisions that undermine their individual influence or "prestige" in
favor of group prestige. One of my colleagues and former students,
Aprameya Tripathy, is really good at writing hard olympiad-esque
geometry for computational contests, and he writes a lot of them. If you
do math contests and haven't heard of him, it's probably my fault: I
haven't counted, but I think he's released a single-digit number of
problems with us, and the number of problems he's released under every
other group combined is even less.</p>
<p>The reason we release so few of his problems is because a good MAT
only has room for one really hard geometry question. At this rate, most
of his geometry questions will never get used seeing the rate at which
he writes new ones.<a href="#fn9" class="footnote-ref" id="fnref9"
role="doc-noteref"><sup>9</sup></a> In most other organizations this
would not go over well. Most people would be tempted to take their ball
and go home if it takes a month of debate just for one of your questions
to get on the contest. Even if you're patient and willing to wait for
the payoff, in this case the wait is on the timescale of years! But it's
the standards which MAT is held to that makes it worth the wait if you
can appreciate the value of these standards. Ditto for the AMCs and
AIME, from what I hear.</p>
<p>Speaking of Aprameya, his problem statements are largely polished
from the get-go now. But this wasn't always the case. His problem
statements used to be really messy: points were defined haphazardly,
you'd see stuff like "<span
class="math inline"><em>A</em><em>B</em></span>, <span
class="math inline"><em>B</em><em>C</em></span>, and <span
class="math inline"><em>A</em><em>C</em></span>" instead of "<span
class="math inline"><em>A</em><em>B</em></span>, <span
class="math inline"><em>B</em><em>C</em></span>, and <span
class="math inline"><em>C</em><em>A</em></span>", and the answer
extractions were convoluted. The ideas were good, but none of the polish
was there.</p>
<p>The easy solution is to fix these issues in the editorial process.
But the problem is I'm pretty much the editorial process and I'm also
lazy. The root of the problem was he didn't have the right standards for
his own problems, and by working with us he absorbed our standards
through osmosis.</p>
<p>When I say "he didn't have the right standards" I don't mean that he
didn't care about writing good problems. Everyone cares about writing
good problems,<a href="#fn10" class="footnote-ref" id="fnref10"
role="doc-noteref"><sup>10</sup></a> and "standards" doesn't just mean
"a general expectation people do things well". Rather, it's a specific
set of guidelines and principles I'm talking about: for example,
problems have to be neatly presented, so any symmetry inherent to the
problem should be made apparent. This is why it's not okay to write
<span class="math inline"><em>A</em><em>C</em></span> instead of <span
class="math inline"><em>C</em><em>A</em></span> because then you lose
cyclic symmetry.</p>
<p>Fortunately it's easy to communicate your standards as long as you
are earnest about them: show yourself following them. In other words,
set a good example. Like a team captain reprimanding their teammates
during drills, you will occasionally have to hold people accountable and
remind them what you guys are all about, albeit not as directly.</p>
<p>That's all it took. His problems, along with everyone else's, got so
much better in a couple of months. Of course it's important to
acknowledge that these improvements happened with their efforts, not
mine. All I did, whether implicitly or explicitly, was provide them with
some direction.</p>
<p>Having high standards doesn't just make your product better.
Paradoxically, it makes the production process that much easier as well:
if doing things right starts coming naturally to you, then you'll do it
right the first time and won't have to fix it the second time
around.</p>
<p>You should have high standards for the people you work with. Inviting
people and giving them official responsibilities is one of the least
reversible actions you can take in a nonprofit, so be very careful who
you let in. Obviously existing members should always give input when a
new members wants to join, and I do think a final vote is a good idea.
However, most people just use a simple majority as the threshold to
confirm someone, which is a terrible idea.<a href="#fn11"
class="footnote-ref" id="fnref11" role="doc-noteref"><sup>11</sup></a>
If 5 people want a person in and 4 people don't, do you think adding
them is really a good idea? When it comes to setting policy, I always
think about how it reflects on our standards. The same way we don't want
to release shoddy work, we also shouldn't invite people unless pretty
much everyone likes them.</p>
<p>Some other math organizations I've worked with have been allowed to
grow their scope recklessly. People are allowed to do whatever they want
without considering how it will reflect back on the parent organization.
The result is that the content becomes mediocre and the organization
gets a reputation for being unreliable. They become last resorts for
whatever they're doing: they might cover more niches than everyone else,
but slowly other people will start doing what they do better and the
organization will decline.</p>
<p>Of course a good president also has to listen. Part of how I do this
is by ceding control and slowly letting other people take charge of more
projects, especially as we all get a clearer picture of the way we want
to do things. I suspect that many other presidents also do this, which
is why to the public eye they may seem like little more than
figureheads.</p>
<p>Sometimes my colleagues consider ideas that are clearly bad and
others that seem good but upon further inspection are bad.<a
href="#fn12" class="footnote-ref" id="fnref12"
role="doc-noteref"><sup>12</sup></a> My role as a final arbiter isn't
just to block them. It's to create a culture where no one decides to
implement them in the first place.</p>
<p>The secretary's job is to help with logistics. The treasurer's job is
to handle finances. My job is to put myself out of one.</p>
<section id="footnotes" class="footnotes footnotes-end-of-document"
role="doc-endnotes">
<hr />
<ol>
<li id="fn1"><p>Doing all of this while maintaining high standards is
hard, which is why I recommend limiting the scope of your organization
and cutting when you need to. (This is why we put <a
href="/writing/blog/mast-hiatus">MAST on hiatus</a>.)<a href="#fnref1"
class="footnote-back" role="doc-backlink">↩︎</a></p></li>
<li id="fn2"><p>Though we didn't know it would become what it is now
until about August.<a href="#fnref2" class="footnote-back"
role="doc-backlink">↩︎</a></p></li>
<li id="fn3"><p>In hindsight this is an incredibly bad decision. If you
need help with a creative process (which I consider math contests to
be), you should be asking people whose judgment you have reason to
trust, not just randoms. This is doubly true in math contests where most
people have bad taste and low standards.</p>
<p>For my part I ended up joining partially because I saw Jerry's posts
about anime. I'm not kidding.<a href="#fnref3" class="footnote-back"
role="doc-backlink">↩︎</a></p></li>
<li id="fn4"><p>I'm being a little unfair to myself: I was the second
most prolific author in that test and the solutions manual used my
document design (which was awful back then, by the way).<a
href="#fnref4" class="footnote-back" role="doc-backlink">↩︎</a></p></li>
<li id="fn5"><p>I was the director of MAST from day 1, although it came
after MAC (the now internal name we use for our contest team). MAST and
MAC ended up merging since the overlap between the two teams just kept
growing, so it made some sense I was in charge. But even before that I
was effectively (maybe even officially?) in charge of contest-side.<a
href="#fnref5" class="footnote-back" role="doc-backlink">↩︎</a></p></li>
<li id="fn6"><p>Which sounds really cool until you realize that no one
was willing to make these decisions because they didn't really matter.
Stuff like naming things (ironically I didn't come up with the name
"JMC", although I did for everything else) and setting dates.<a
href="#fnref6" class="footnote-back" role="doc-backlink">↩︎</a></p></li>
<li id="fn7"><p>I say "relatively" because if any of my colleagues'
standards now were as low as mine in freshman year I would have made fun
of them. Back then I said really stupid things like "I think formatting
doesn't particularly matter, anyway."<a href="#fnref7"
class="footnote-back" role="doc-backlink">↩︎</a></p></li>
<li id="fn8"><p>The primary reason for this, at least recently, is
because we build contests using <a
href="https://mapm.mathadvance.org">mapm</a>, meaning that every final
draft resides in our mapm Dropbox. If I'm pretty the only person using
mapm, obviously I'm going to be the one in charge of all the final
drafts...<a href="#fnref8" class="footnote-back"
role="doc-backlink">↩︎</a></p></li>
<li id="fn9"><p>We're trying to rectify this though! Be on the lookout
for a geometry contest from us.<a href="#fnref9" class="footnote-back"
role="doc-backlink">↩︎</a></p></li>
<li id="fn10"><p>Okay, this is far from true in general, a lot of
problem writers feel obliged to continue or are doing it for their ego
and could care less. But somehow or another, the people who've wanted to
work with us largely do not fit this description.<a href="#fnref10"
class="footnote-back" role="doc-backlink">↩︎</a></p></li>
<li id="fn11"><p>The system we use is yes, meh, and no. There's no
formal voting system (no votes, even after additional discussion, have
ever been close enough to warrant it), but it looks approximately like
this: three mehs or one no and the candidate is rejected, and we wait
for all the people who frequently give input on recruiting before
deciding (which means in practice we need at least 70% yeses).<a
href="#fnref11" class="footnote-back" role="doc-backlink">↩︎</a></p></li>
<li id="fn12"><p>In all fairness everyone comes up with stupid ideas,
and they come up with them less often than I do. Coming up with stupid
ideas is a sign that your group is willing to be innovative,
implementing them is a sign that your group has low standards.<a
href="#fnref12" class="footnote-back" role="doc-backlink">↩︎</a></p></li>
</ol>
</section>]]></description>
	<pubDate>27 Aug 2022</pubDate>
</item>
<item>
	<title>What is learning?</title>
	<link>https://dennisc.net/writing/essays/learning.md</link>
	<description><![CDATA[<p>Part of learning a subject is assimilating the
facts. For instance, if you were to take a complex analysis class, you
would learn that <span
class="math inline"><em>e</em><sup><em>i</em><em>π</em></sup> = −1</span>
(Euler's Identity). But what makes some facts more important than
others? Why is Euler's Identity any more important or interesting than
the fact that the largest mammal is a blue whale?</p>
<p>Learning is more than facts. An introductory course in complex
analysis is a story. The facts comprise the plot, each successive fact
allowing it to advance a little more. There is a climax to the story:
the Fundamental Theorem of Algebra. (Of course, we leave plenty of room
for sequels.) And though it may not be obvious, there is a moral to the
story.</p>
<p>Let me actually give you another example where the moral is clearer:
consider the basic category theory relevant to a first course in
abstract/commutative algebra. You learn that a concept such as "product"
or "free group" is not just some object; it is <em>really</em> the
object equipped with the relevant morphisms.</p>
<ol type="1">
<li>For example, the product of groups <span
class="math inline"><em>G</em></span> and <span
class="math inline"><em>H</em></span> is not just the group <span
class="math inline"><em>G</em> × <em>H</em></span>; it is also the
projections <span
class="math inline"><em>π</em><sub><em>G</em></sub> : <em>G</em> × <em>H</em>− &gt; <em>G</em></span>
and <span
class="math inline"><em>π</em><sub><em>H</em></sub> : <em>G</em> × <em>H</em>− &gt; <em>H</em></span>.</li>
<li>Likewise, the free group of <span
class="math inline"><em>S</em></span> is not just the group <span
class="math inline">Free(<em>S</em>)</span>. It is also the relevant
"inclusion map" <span
class="math inline"><em>S</em> ↪ Free(<em>S</em>)</span>.</li>
</ol>
<p>Furthermore, such objects are usually characterized by some universal
property (i.e. it is the initial or terminal object satisfying some
description). <strong>And that is the moral of category theory,</strong>
that the right way to define something in relation to other objects is
as such an arrow.</p>
<h2 id="blue-whales-are-interesting-too">Blue whales are interesting
too</h2>
<p>I doubt there are many marine biologists on this website. Odds are
most people reading this essay have gladly nodded their heads along,
agreeing that of course Euler's Identity is more important. In
mathematics? Sure.</p>
<p>But if you really start to think about blue whales, you might wonder,
"what allows it to be so large?" And you start looking at similarities
between all the largest mammals, and they turn out to <em>all</em> be
sea creatures living relatively near the surface of the ocean.
<em>Why?</em></p>
<p>Land mammals have to support their entire weight, and the square-cube
law means the pressure exerted on their feet by gravity grow as they do.
But blue whales don't have to support their entire weight; the buoyant
force of water is doing a lot of it for them! So they can grow larger.
And they live near the surface of the ocean because otherwise, water
pressure would counteract this effect --- and then some. (Deep sea
creatures are freakish!)</p>
<p>Even something mundane like a blue whale fact can be part of an
interesting story: sea creatures can grow larger because they are less
constrained by gravity. Your initial reaction to such a fact might be,
"okay, that's interesting, I guess". I know mine was. But there really
is a story behind every fact, and when you string facts together in the
right way, that's when you actually learn.</p>
<p>Little kids understand this concept. That's why they keep asking
"why?" <em>They want to know the story behind everything.</em> You and I
are older than that, but it would be unwise to forget this wisdom that
we had as children.</p>
<h2 id="why-do-we-have-stories">Why do we have stories?</h2>
<blockquote>
<p>Excessive wealth causes people to detach from others and the world,
leaving them unable to form meaningful relationships.</p>
</blockquote>
<p>I doubt you would disagree with the moral above. But do you really
<em>believe</em> these platitudes?</p>
<p>But if you have read the Great Gatsby, seen how Daisy destroys lives
with no real consequence because of her wealth, and seen how Gatsby
ultimately dies alone despite the extravagant parties he throws, you
would <em>believe</em> it. And I'm sure you can think of contemporary
examples of very wealthy people who have no real connections.</p>
<p>Yes, such a platitude rarely holds absolute. But the potential for
excessive wealth to diminish empathy is a powerful force in the world,
and the only way to further understand and internalize this idea is
through examples. These examples are <em>stories.</em></p>
<p>To put it another way, the existence of gravity is such an obvious
truth to you not because you know the formula for the gravitational
force between two objects, but because you see objects fall to the
ground on the daily. And not only that, you see them fall at the same
rate (air resistance notwithstanding).</p>
<p>Going back to math: I could tell you that universal properties are
the right way to define certain constructions like the product. But you
must work through quite a few facts before you see how this definition
can save you a lot of trouble and unlock useful new perspectives. I can
tell you the moral of the story, but for you to actually apply it
effectively, you must truly believe it. That is why every textbook works
through examples of any definition or theorem.</p>
<p>But it is important to always keep in mind that there is some moral
to be learned. And it helps even more to be aware of it on some level as
you learn a subject. When you know such a moral exists, it is easier to
relate the facts you learn to it.</p>
<h2 id="case-study-linear-algebra">Case study: linear algebra</h2>
<p>My first study of linear algebra was not very enlightening. The
course I took in community college had a very matrix-first perspective.
They were just blocks of numbers, and all we learned through the
semester was how to manipulate them.</p>
<p>Of course, you and I know that linear algebra really involves the
study of linear maps. But is it <em>just</em> that?</p>
<p>No, not really. Linear algebra was essential for pure mathematics;
for starters, the derivative is really a linear approximation of a
function at a point. In single-variable calculus we just treat it as a
number, but it really is a linear map! If I perturb the input by <span
class="math inline"><em>v</em></span> in a certain direction, then the
output is perturbed by approximately <span
class="math inline"><em>D</em><em>f</em>(<em>v</em>)</span>, where the
linear map <span class="math inline"><em>D</em><em>f</em></span> is the
<strong>derivative</strong> of some function <span
class="math inline"><em>f</em></span>. And approximating functions
linearly is very nice because linear maps are easily understood. This
justifies the study of <strong>linear algebra as the study of linear
maps</strong>.</p>
<p>But linear algebra is useful for applied math as well. A long time
ago, it could be used to solve systems of equations. But I want to talk
about a more recent development: machine learning. Machine learning
fundamentally relies on gradient descent, the idea that iterating the
best local improvements (which we approximate via the derivative) will
converge to a good global solution. When computers became commonplace,
we finally had a computational way to train models via gradient
descent.</p>
<p>So the question becomes how we represent linear maps computationally,
and how we can manipulate these representations to support faster
computations. Certain matrix operations such as SVD, PCA, etc. are not
so fundamental to linear maps. They are truly important for
<em>matrices</em> in particular. And we care about these techniques
largely for computational reasons. This justifies the study of
<strong>linear algebra as the study of matrices</strong>.</p>
<p>But even in pure mathematics, matrices are a useful computational
tool. Take the proof of the <strong>structure theorem for finitely
generated modules over a PID</strong>. It appeals to the Smith Normal
Form which is constructed via a matrix <em>algorithm</em>.</p>
<blockquote>
<p>Linear algebra is not just the study of matrices.</p>
<p>Nor is it just the study of linear maps.</p>
<p>It is the study of matrices and linear maps, <em>and</em> the
correspondence between the two.</p>
</blockquote>
<p>Of course, you cannot learn all of linear algebra at once. If you are
going through a first study of linear algebra (especially if you have
had brief exposure to linear algebra as matrix manipulations), it is
better to tell you that it really is about linear maps instead. But it
is useful to keep the entire picture in mind, because you will hit a
wall when reasoning about everything as a linear map, and the only way
to surmount it will be to appeal to blocks of numbers.</p>
<p>Here is the moral: if you have been told a moral like "linear algebra
is just about linear maps", and then you encounter some truly necessary
matrix facts that do not fit this moral, then you need to consider how
your story fits into the <em>bigger</em> story.</p>
<h2 id="stories-are-distortions-of-the-truth">Stories are (distortions
of) the truth</h2>
<p>Historically, category theory was invented to discuss natural
transformations. <a href="/cat.pdf">My introduction</a> instead treats
category theory as the natural extension of "<a
href="/writing/essays/properties">mathematical objects are their
properties</a>". Historically speaking, this is a serious distortion of
the truth. Why do I do it?</p>
<p>It is because the easiest way to convince someone category theory is
useful is not necessarily the most natural way to come up with it. Yes,
if you study anything requiring category theory, natural transformations
will inevitably come to be a large part of the story. But I only am
trying to entice you to read it for now.</p>
<p>Mathematics is not really as simple as a story. While some universes
like Star Wars have sprawling, expansive lore, it does not compare to
the natural beauty of mathematics. But stories are the best way for us
to interface with mathematics. Even if a story is not the entire
picture, the morals it reveals still hold.</p>]]></description>
	<pubDate>11 Jan 2026</pubDate>
</item>
<item>
	<title>Puzzle Construction</title>
	<link>https://dennisc.net/writing/essays/puzzle-construction.md</link>
	<description><![CDATA[<p>These are my thoughts on constructing logic
puzzles. Some of this is advice tailored towards beginners, other
thoughts are personal musings.</p>
<h2 id="what-is-a-logic-puzzle">What is a logic puzzle?</h2>
<p>When I say "logic puzzle" it could mean many things to many different
people. Some people will take it to be riddles or paradoxes ("when does
a heap of sand stop heaping?") while others will think of the 100 people
with green eyes. However, what I am referring to are <strong>pencil
puzzles</strong>: things like sudoku, kakuro, etc. Basically, you have a
set of very concrete rules that are hard to misunderstand. You don't
have to rely on "vibes" or "convention" to know your answer is correct,
unlike in a crossword or puzzle hunt.</p>
<p>The appeal of logic puzzles is twofold:</p>
<ul>
<li>You have to use concrete, mechanical rules to make air-tight logical
observations. It's kind of like doing math, you are given a set of
initial rules and an initial setup and have to figure out all the
implications of the two. Figuring out the rules is not the hard part,
but you have to <em>figure out the rules</em> (as in what they're
ACTUALLY doing) :)</li>
<li>It crosses cultural and linguistic barriers. I don't know British
English so I'd be hard-pressed to solve a British cryptic crossword.
(Not that I can solve American ones, but that's besides the point.)
Logic puzzles aren't like that: if you understand the rules, you can
rederive the logical principles used to solve it. (The more
theory-intensive the puzzle/genre is though, the harder this becomes in
practice. More on theory later.)</li>
</ul>
<p>(An exception is instructionless. Those are a very fun subversion of
the whole premise of logic puzzles.)</p>
<h2 id="how-to-start">How to start</h2>
<p>Obviously you have to solve puzzles to set puzzles, just as you have
to read books to write books. But you really don't <em>know</em> how
important solving other people's puzzles is until you do it yourself. I
want to underscore just how vital it is.</p>
<p>Most people who "solve puzzles" go to sudoku.com or NYT and do the
"Hard" sudoku. These sites have low-quality, computer generated sudoku.
Normally I wouldn't pass judgment on that sort of thing: whatever floats
your boat, I guess. But setting puzzles is a form of <em>art</em>, so if
you want to set puzzles you must have demanding standards. (Most people
serious about setting know this, but I'm including this for the people
who casually think, "Oh puzzles are cool it sounds like a thing I want
to create". Disclaimer: that used to be me.)</p>
<p>So where do you find good puzzles? <em>Cracking the Cryptic</em> and
<em>Logic Masters Germany</em> are good places to start; in fact, I
nearly exclusively solve puzzles from those two sites.
<em>puzz.link</em> is also quite popular, but a lot of genres there are
more theory-based: Heyawake, Slitherlink, and even some <em>star
battles</em> are quite theory intensive.</p>
<p>Every puzzle I've set would not have been possible if I'd stopped
doing puzzles. For many of them, I can name the exact variant/genre or
even <strong>the exact puzzle</strong> that, if I didn't do, my puzzle
would definitely not exist:</p>
<ul>
<li><p>Pointer Fillomino: KNT's "Happy Birthday, Gabi!"</p>
<p>When I saw Japanese Sums being combined with pentopia and rotation,
my mind was immediately drawn to the connection between number placement
(the Japanese Sums part) and pointer-flavored geometry (how far the
nearest of some structure was, in this case, pentopia). The weird
rotation mechanic really sealed the deal: it got me thinking the number
in an arrow should mean <em>something</em>, and I naturally gravitated
towards distance.</p>
<p>Then I had a pentopia fillomino ruleset written up, and I realized,
"Hey, arrows can also form region borders if we make them self
referencing." That was the ruleset done: I just had to think of a
break-in (and settled on something of the structure, "adjacent arrows in
the same direction can't be consecutive in one direction") and it was
off to the races.</p></li>
<li><p>Alphabet Soup: rubenscube's "The Aquarium"</p>
<p>The idea here in The Aquarium is a ton of swordfishes. However, I
thought of it as "there are exactly three 1's in the top row of their
box" (you can substitute 1 for any digit and "top row" for any
row/column of a box), which was a more global perspective. With that I
thought, "what if I take this deduction to its logical extreme: you have
to use this fact to place digits in each given box, but you don't
actually know how the boxes align until later". Only later did I realize
that my setup was insane enough <em>to take 1 and 2 in consideration at
the exact same time</em>. In hindsight, I'm glad I didn't know what a
swordfish was and had the balls to set a really ambitious puzzle back
when I was starting out. (I'd definitely be too lazy to do the trial and
error until I stumbled on something that just magically <em>worked</em>
so well now.)</p></li>
</ul>
<p>This is just a small selection of my puzzles that I can definitely
say were inspired by something in particular. Some puzzles have less
specific origin stories, and others I have forgotten. If you solve more
puzzles maybe one of them, or some combination of puzzles you have
solved, will inspire something specific. Maybe solving puzzles will just
generally make you better at spotting things and help you testsolve your
own a wee bit faster. I dunno, just solve more puzzles. (But make sure
they're actually teaching you something.)</p>
<p>By solving more puzzles, you increase the range of ideas you're
floating in your head. The primary difficulty of puzzle-setting isn't
the part where you put clues to fill in the grid; that part's only hard
when you do a dumb and make major oversights that subtly (or not so
subtly) break your puzzle. Rather, the hardest part of setting a puzzle
is <em>deciding what rules to use</em>, and then <em>convincing yourself
that your ruleset is tractable</em> (by creating an interesting
breakin). The first part is less applicable for vanilla puzzles, e.g.
German Whispers, but then you have to make the interactions logically
consistent. If you solve more puzzles, you will have more ideas. If you
have more ideas, more of them will be accidentally good.</p>
<h2 id="dont-set-a-puzzle-to-set-a-puzzle">Don't set a puzzle to set a
puzzle</h2>
<p>Once upon a time, I wrote a mock USAMTs. For those who don't know,
USAMTs is a math contest that also contains puzzles. The puzzle part is
all that matters for this story.</p>
<p>I decided "OK now I need to write a puzzle for this contest." I had
no idea what I wanted the puzzle to be about. I didn't have some sort of
logical idea I wanted to share with the world, my thought process was
just "OK and now we need a puzzle because -external reasons-".
Predictably, it ended up terribly.</p>
<p><strong>Your motivation should not be setting a puzzle just because
you want a puzzle</strong>. Of course, there is an intrinsic joy to
setting puzzles for its own sake, and "I want to set a puzzle" works
well as a <em>global</em> motivation (i.e. it's what keeps you going for
the long run, not what gets you through Puzzle X). But you can't just
sit down and say "now I will magically write a puzzle" any more than you
can sit down and say "now I will magically write a book". You have to
have an idea you've been mulling over, that would be interesting if it
worked out. What should be going on in your head when setting a puzzle
is, "Gee I wonder if -this interaction- could happen in some interesting
non-broken form" <em>and then you work to make it happen</em>, not just
"Oh setting puzzles sounds cool and now I will throw shit at the wall
until I accidentally get something unique".</p>
<p>My point is, each puzzle should actually offer something unique. For
example, X-Lines Sudoku was born out of me wondering if I could combine
sets with arithmetical logic. When you set a puzzle, you should actually
be able to point out, "and these ideas are why I decided <em>this puzzle
was worth setting</em>", even if it was born out of external
motivations. (External motivations, e.g. presents, are fine! They fall
in the category of "Stupid Inspirations" that shouldn't make sense but
somehow do after some mental gymnastics.)</p>
<h2 id="where-to-set">Where to set?</h2>
<p>Some people start out by setting on pencil and paper. Of them, many
are just unaware there are online tools.</p>
<p>The major two are <a
href="https://swargoop.github.io/penpa-edit">Penpa</a> and <a
href="https://f-puzzles.com">F-Puzzles</a>. Also puzz.link exists if you
want to use that.</p>
<h3 id="penpa">Penpa</h3>
<p>Penpa is the go-to option for non-sudoku pencil puzzles, e.g.
Fillomino, Star Battle, Kakuro, etc. It doesn't actually constrain your
inputs based on your puzzle type, which can be a little daunting. It's
like the Swiss Army Knife of setting, it can do pretty much everything
2D (including non-square grids). However, it doesn't provide any
techniques for logically checking that your puzzle a) has <em>any</em>
solutions and b) has no more than one solution, which makes sense
because you're just putting <em>stuff</em> on the grid. Penpa doesn't
know what any of that stuff means.</p>
<p>You may want first class support for variant clues, like German
Whispers or XV. None of those exist. Hell, even finding how to make a
Killer Cage is pretty hard. The general idea is, if you want to put a
clue down, it's going to be some cosmetic decoration. There is no strict
1:1 mapping between decorations and clues, and you will have to find
many clever workarounds.</p>
<h3 id="f-puzzles">F-Puzzles</h3>
<p><strong>I recommend F-Puzzles for beginners who are setting
sudoku.</strong></p>
<p>F-Puzzles, by contrast, is much more limited but also much
friendlier. Though it doesn't include some variants, you can install <a
href="https://gist.githubusercontent.com/dclamage/3d76a56c9153a8546888a31d65765cb7/raw/fpuzzles-newconstraints.js">Renban
and Whispers</a> as a Tampermonkey extension. (By a few months time,
this will likely be native in F-Puzzles.)</p>
<p>The boon of F-Puzzles is that it points out logical errors. If you
accidentally put two 1's in the same row, it will highlight that for
you. Or if your thermo has no possibilities. F-Puzzles provides some
mechanical things you can do to make your setting life easier. It
doesn't require brain cells, creativity, or good taste: it just requires
a good puzzle setting setup. (On the flip side, some setters believe
using F-Puzzles' computer assistance to set makes your puzzles worse. I
don't really subscribe to this theory, provided you aren't just blindly
putting clues down and "check solution"ing your puzzles.)</p>
<p>Additionally, you can avoid wasting your time because of logical
gaffes or super-subtle interactions using Rangks's Sudoku Solver. To
simplify, it allows you to check whether your puzzle has any solutions,
and can also do scanning for you (so if you missed a naked single it
will point it out for you). Follow the instructions to install <a
href="https://github.com/dclamage/SudokuSolver/wiki/fpuzzles-integration#additional-scripts">Rangsk's
Sudoku Solver</a> and integrate it with f-puzzles.com.</p>
<h3 id="ctc-discord">CTC Discord</h3>
<p>The Cracking the Cryptic Discord is also super helpful. While it
doesn't <em>directly</em> provide any software, it can lead you to more
helpful F-Puzzles tools and teach you the ropes of Penpa/F-Puzzles. You
can also ask people to test your puzzle to ensure a) it's correct and b)
all the deductions can be reasonably carried out by a human.</p>
<h2 id="stupid-inspirations">Stupid Inspirations</h2>
<p>I've talked about how solving puzzles can provide you with ideas for
your own puzzles. However, in some sense the puzzles you solve only
provide the initial spark for your puzzles, and you have to engage in
some serious mental acrobatics to get to the end result. For example,
Pointer Fillomino and Happy Birthday, Gabi! are two completely different
puzzles. It's like I boarded a train at the HBG station and after riding
14 stations and switching lines multiple times, I finally got to Station
Pointer Fillomino.</p>
<p>The point is, it doesn't really matter what your starting point is,
all that matters is you get a tractable puzzle idea in the end. Hell,
even <a href="/writing/blog/creative-methodical">song lyrics</a> can get
you there:</p>
<blockquote>
<p>For instance, take my puzzle Monster Without A Name. Normally, you’d
think that I wrote this puzzle and found a good name for it afterwards.
And that is true for most of my puzzles. But for this one, I came up
with the title before I had any clue what the puzzle would be about,
because I really wanted to force the song lyric.</p>
<p>So I first was thinking of just making a really hard puzzle. Problem
is, you can’t just decide to make a really hard puzzle, and I did make a
couple of semi-hard puzzles but they all had obviously better titles,
e.g. X-Lines Sudoku. So I thought, “maybe the constraint should actually
have Monster in the name, at least”.</p>
<p>When I thought of Monsters, I thought of the similar word killers,
since you have Killer Cages and Little Killers. And since Killers do
stuff with sums, Monsters should do the next simplest thing:
products.</p>
<p>Then the question is, how do I do products? Just doing the product of
every cell is really boring, since it removes a lot of nuance and
degrees of freedom. So somehow, I would want to do region sums.</p>
<p>Now I had to decide how to construct my regions. First I tried using
shading pencil puzzles like Yin-Yang or Caves to create a hybrid — and I
still think that approach has a lot of viability — but after doing a few
Chaos Construction puzzles, I realized: the most natural way to do
products of region sums, which requires region construction... is to do
the variant that uses region construction. The Monster Cages constraint
had finally crystallized.</p>
</blockquote>
<p>Any sane human would react to that story with "how the heck did you
get from point A to point B. It makes zero sense." But here's the thing:
you need to be creative, so creative that it crosses the line and
actively becomes stupid, if you want to do something
<em>interesting</em>. Sure, you could do something straightforward. But
that's obvious, and obvious is boring, because it wouldn't be obvious if
it wasn't boring. If you think of weird things no one else would think
of, and your train of thought jumps in ways no one else's would, then
you will end up with puzzles no one else would set.</p>
<p>Of course, that isn't to say you should exclusively wait for a really
stupid idea to hit you in the head and magically work out. Non-stupid
inspirations exist. But stupid inspirations exist too, and they're worth
grabbing onto as well.</p>]]></description>
	<pubDate>25 Jul 2023</pubDate>
</item>
<item>
	<title>Framework</title>
	<link>https://dennisc.net/writing/essays/framework.md</link>
	<description><![CDATA[<p>There's an implicit misconception that learning
is about facts. To be sure, if you surveyed every student and teacher in
the nation, not one of them would disagree that there are things besides
the facts that matter. But mighty few apply these principles, especially
when it matters the most.</p>
<p>Educators are aware of this on some level. They ask themselves, "how
can we focus on what's important instead of the facts?" That's where all
the post-modern math curriculums come from. But none of them have
bothered to ask, "what's important?"</p>
<h2 id="value">Value</h2>
<p>For the sake of argument, let's say that classes consist primarily of
the content you are taught. If you think about this carefully, it's a
dark view of education. It implies that your value, as a teacher or a
student, is based on how much you know.</p>
<p>This is why some teachers feel threatened when they're no longer the
smartest in the room. And this happens most commonly to math teachers,
which is why some math classes are so awful. This is also why some
students feel so defeatist about their academic prospects. When
intelligence is based on something that can be reasonably quantified,
comparison is inevitable.</p>
<p>It also says that teachers have minimal value. If class is based on
being a convenient (and mandatory) repository of information, then it's
by far not the best at its job. Google has far more comprehensive
resources. Why not just use it instead? Why bother sending kids to
school for six hours when they can just search up the War of 1812,
instead of learning about it in class?</p>
<p>You might protest this evaluation of education, and rightly so.
Teachers aren't just lookup tables. Their classes are helpful because of
the teacher's expertise, because they are coherent, and because they are
complete.</p>
<p>Expertise really means correctness. Teachers are helpful because they
are a guarantee that everything we learn is correct. Books have typoes,
video lectures have mistakes, and teachers have the ability to give
context and correct any misconceptions. So let's change the nebulous
"expertise" to a more concrete "correctness," which gives us a nice
alliterative list: <em>correct, coherent, complete</em>.</p>
<p>Facts are not the main purpose of a class. In fact, I would say that
facts are wholly unimportant on their own. The only reason classes ought
to teach facts is to construct a <em>framework</em> of the subject.</p>
<p>Why is a framework so important? Because expertise is the ability to
deal with unknown situations. No matter what profession you're going in,
it's impossible to know all the facts. You'll always have to handle new
information. A framework is just a set of tools that helps you handle
it.</p>
<p>With this in mind, coherence and completeness make a lot more sense.
It just means your framework needs to be internally consistent, and it
should be flexible enough to encompass all of the facts.</p>
<h2 id="principles">Principles</h2>
<p>The framework should be the guiding principle when teaching and
learning. Good frameworks need to be correct, coherent, and complete.
But there's a fourth principle, and it's especially important when
teaching and learning: <em>conciseness</em>.</p>
<p>Much like how good writing should contain as few words as possible, a
framework should be presented with as few ideas as possible. In other
words, a framework should aim to be minimalistic.</p>
<p>It seems like this principle conflicts with completeness. But these
principles don’t have the same priority. This is not a hard rule, but I
personally think that from most to least important, it is correctness,
coherence, completeness, and conciseness. This is because I think an
incorrect framework is more harmful than an incoherent framework, and so
on.</p>
<p>Minimalism does not mean omitting useful information. It means
including only what is useful, and aggressively cutting the rest.</p>
<p>Unless you're in writing, the arts, or programming, the principle of
conciseness won't make sense at first. But the purpose of a framework is
to be flexible. Extra baggage undermines this. It distracts from the
core of the framework.</p>
<p>A concrete example can be found in Precalculus, where teachers force
students to mark the cosine and sine for each angle that is a multiple
of <span class="math inline">$\frac{\pi}{4}$</span> or <span
class="math inline">$\frac{\pi}{6}$</span>. To show why this is
unnecessary, let's go over a good framework of trigonometry.</p>
<p>First, there is the concept of polar coordinates. You can represent a
point on the plane in two ways: you can either use the <span
class="math inline"><em>x</em></span> and <span
class="math inline"><em>y</em></span> coordinates, or you can describe
the distance from the origin and the angle. The latter is polar
coordinates. <strong>All trigonometric functions represent is a way to
convert from polar coordinates to rectangular.</strong> We need a way to
arbitrarily represent the <span class="math inline"><em>x</em></span>
and <span class="math inline"><em>y</em></span> coordinates of the point
<span class="math inline">(1, <em>θ</em>)</span> (which is written in
polar coordinates). And <em>by definition</em>, this point is <span
class="math inline">(cos <em>θ</em>, sin <em>θ</em>)</span>.</p>
<p>Perhaps a teacher might also want to correct the misconception that
sine comes before cosine. Because the <span
class="math inline"><em>x</em></span> coordinate comes before the <span
class="math inline"><em>y</em></span> coordinate, so too should cosine
come "before" sine. This would create the coherence necessary for a good
framework.</p>
<p>And this framework is flexible. You can easily understand that <span
class="math inline">tan <em>θ</em></span> represents the slope of the
line joining the origin and <span
class="math inline">(1, <em>θ</em>)</span> once you've accepted the
polar definition of cosine and sine.</p>
<p>Trigonometry is not complicated. This explanation only took a couple
of paragraphs. Yet students walk away without a solid understanding of
cosine or sine because they were forced to label points on the unit
circle. A lack of conciseness actively inhibits understanding.</p>
<p>This case is a little more nuanced than I'm letting on. I think that
marking points on the unit circle is perfectly fine, as an exercise. But
care must be taken to ensure that students do not mistakenly believe
that the "unit circle" is part of the framework they are learning about.
It is just an exercise to reinforce their understanding.</p>
<p>Communicating information about a framework is hard. But I think it
helps to explicitly use this idea of a framework. When you're trying to
explain a concept, explain how it fits into the framework you're
constructing, and explain how your framework follows the four
principles.</p>
<p>As a meta-example, let's apply these principles to this framework
itself.</p>
<ul>
<li><p>It is correct. No one would contest that a framework should be
correct, coherent, complete, and concise. Nor would anyone contest that
these principles may come into conflict.</p></li>
<li><p>It is coherent. Pieces make sense with respect to each other and
the whole.</p>
<p>It makes sense that principles are prioritized differently. That's
how you resolve conflicts between them. And each individual ordering
makes sense.<a href="#fn1" class="footnote-ref" id="fnref1"
role="doc-noteref"><sup>1</sup></a> Correctness is more important than
coherence because it's harmful to ignore facts when they don't fit your
theories. Cohesion is more important than completeness because you don't
want to cover everything <em>at the cost of confusing your
students</em>.<a href="#fn2" class="footnote-ref" id="fnref2"
role="doc-noteref"><sup>2</sup></a> And completeness is more important
than minimalism because you need to deal with common situations, at the
least.</p>
<p>Everything in this framework of frameworks follows logically. The
pieces fit together like this because <em>they can't help
themselves</em>. Everything I say about frameworks is unavoidable. If
you start with the same core principles, eventually you will end up with
similar conclusions.<a href="#fn3" class="footnote-ref" id="fnref3"
role="doc-noteref"><sup>3</sup></a></p>
<p>I think that people are most in danger of breaking coherence. They
<em>know</em> that correctness is crucial, even if some of them can't
follow the principle. But few people think that coherence is
important.</p>
<p>This is especially bad in education, because we tend to blame the
teacher for correctness, and we blame the <em>student</em> for
coherence.</p></li>
<li><p>It is complete. These four principles are enough to produce a
good framework. Each subject will have its own nuances and special
considerations, but any sufficiently intelligent student or teacher
could figure the rest out on their own.</p></li>
<li><p>It is concise. Every principle is necessary. There's nothing you
can take away without the entire idea collapsing.</p></li>
</ul>
<h2 id="reconcile">Reconcile</h2>
<p>Cohesion is probably the most difficult principle to follow properly.
At least with the other three, you can either think of a specific
example of the principle being followed, or you can understand the
consequences of breaking it. But coherence is nebulous.</p>
<p>Another way you can think of coherence is reconciliation. Good
explanations reconcile two ideas that, on their faces, do not seem
related.</p>
<p>Take factoring a quadratic, for instance. There are two ways you can
express a quadratic:<a href="#fn4" class="footnote-ref" id="fnref4"
role="doc-noteref"><sup>4</sup></a></p>
<ul>
<li>in "standard" form, <span
class="math inline"><em>x</em><sup>2</sup> + <em>b</em><em>x</em> + <em>c</em></span>,</li>
<li>or in factored form, <span
class="math inline">(<em>x</em> − <em>p</em>)(<em>x</em> − <em>q</em>)</span>.</li>
</ul>
<p>These forms seem totally unrelated. But here's the key idea:
<strong>you can represent the same quadratic with each form</strong>.
Because you're representing the quadratic in the same way, the
quadratics have to be equal. Thus, you get</p>
<p><span
class="math display"><em>x</em><sup>2</sup> + <em>b</em><em>x</em> + <em>c</em> = <em>x</em><sup>2</sup> + (−<em>p</em> − <em>q</em>)<em>x</em> + <em>p</em><em>q</em>,</span></p>
<p>and by coefficient matching, <span
class="math inline"><em>b</em> = −(<em>p</em> + <em>q</em>)</span> and
<span class="math inline"><em>c</em> = <em>p</em><em>q</em></span>.</p>
<p>This framework is powerful. It will lead you to realize Vieta's
Formulas, and it might even happen by accident. Cohesive frameworks
provide more for less: there are no diamond or box methods you have to
remember, but you understand more once you realize everything's
connected.</p>
<p>There are plenty of other examples. Take Taylor Series, for instance.
You can find the <span class="math inline"><em>n</em></span>th
derivative by differentiating <span
class="math inline"><em>n</em></span> times or by looking at an <span
class="math inline"><em>n</em></span>th degree approximation of the
function at that point. These definitions have to agree, since they're
defining the same thing. With the Power Law, you see that some fudging
of constants has to happen in order to make the definitions consistent.
<strong>That's where the factorials in the denominator come from: the
Power Law.</strong></p>
<p>Cohesion is just reconciliation on a bigger scale. Where you have to
make two ideas fit together with reconciliation, you have to make
<em>all</em> the ideas fit together with coherence.</p>
<p>This is why you teach "hard" trigonometry (angle addition, et cetera)
along with complex numbers. These concepts are identical, and once you
can grasp that, both of them will be much easier to remember and
use.</p>
<p>The most famous <a href="mast.mathadvance.org">MAST</a> unit, at
least internally, is <a
href="https://gitlab.com/mathadvance/mast/units/CQV-Perspectives">Perspectives</a>.
It's no coincidence the unit follows this idea of coherence so well. It
takes a class of seemingly unrelated combinatorial identities, like
Hockeystick and Vandermonde's, and connects them together. Even better,
it connects these identities to problems like <a
href="https://artofproblemsolving.com/wiki/index.php/2020_AMC_10B_Problems/Problem_23">AMC
10B 2020/23</a>. No longer do students need to commit a dozen theorems
to memory. Instead, they have a framework to attack these sorts of
combinatorial problems with.</p>
<p>Perspectives is not the only example of a handout about a framework.
Evan Chen's Local and Global units from OTIS also are. Frameworks aren't
a new or theoretical idea. People are actively applying them. In a
sense, this essay is just a framework itself: a framework about
frameworks.</p>
<section id="footnotes" class="footnotes footnotes-end-of-document"
role="doc-endnotes">
<hr />
<ol>
<li id="fn1"><p>The approach I take to explain these orderings is proof
by contradiction. It's hard to say exactly why one principle is more
beneficial than another. But it is very easy to give examples when
breaking one principle is more harmful than breaking another.<a
href="#fnref1" class="footnote-back" role="doc-backlink">↩︎</a></p></li>
<li id="fn2"><p>Failing to prioritize coherence over completeness leads
to <em>checkbox learning</em>, when the main goal is to get through a
series of topics, rather than learning.<a href="#fnref2"
class="footnote-back" role="doc-backlink">↩︎</a></p></li>
<li id="fn3"><p>This is how so many people can independently discover
the same idea at the same time in math. Everyone's working with the same
principles, and the principles are very intuitive.<a href="#fnref3"
class="footnote-back" role="doc-backlink">↩︎</a></p></li>
<li id="fn4"><p>I don't consider the leading coefficient because that
violates the principle of minimalism. Once you know how to factor a
monic quadratic, non-monic quadratics become easy to handle. Including
the leading coefficient in the framework of factoring is just
distracting.<a href="#fnref4" class="footnote-back"
role="doc-backlink">↩︎</a></p></li>
</ol>
</section>]]></description>
	<pubDate>16 Sep 2021</pubDate>
</item>
<item>
	<title>Why I study math</title>
	<link>https://dennisc.net/writing/essays/why-i-study-math.md</link>
	<description><![CDATA[<p>Before we get into this let me justify myself.
Why am I writing this?</p>
<p>It turns out this question is really hiding two questions. Why am
<em>I</em> writing this? And why am I writing <em>this</em>? Let me
answer these two hand-in-hand.</p>
<p>I'm an undergraduate studying mathematics (attach a few asterisks
here if you like). As such, I cannot give you a particularly
sophisticated answer of what mathematics is, or why it is worth
studying. This has a few obvious demerits, but it has a few merits as
well. The answer I give will be simple. It will be understandable to a
reasonably well-educated layperson. And a high school student, who may
have only studied up to calculus and watched a few mathematical videos,
can perhaps get a friendlier picture of what they will be studying in
college, incomplete as it may be.</p>
<p>Of course, it is no use discussing mathematics without referencing
mathematics. So forgive me if I get a little technical. The broad
strokes, I hope, will make sense regardless of whether you are familiar
with every example I mention.</p>
<p>Now, why am I discussing my philosophy of mathematics? I think it is
an appropriate juncture in my life and mathematics career to do so.
There are two questions a college student should be able to answer. What
am I studying? And why am I studying it? And the latter, again, hides
two questions. Why am <em>I</em> studying it, and why am I studying
<em>it</em>? These are especially hard questions for mathematics majors,
because there is not much you can tangibly do with mathematics. Sure,
there is applied mathematics, but that is not what I am studying and
does not have what I think makes "mathematics" so charming.</p>
<p>And these are important questions. If you are going to dedicate four
years (and potentially more) of your life to studying something, it is
quite profitable to know why you are doing it. One, because finding
satisfactory answers to these questions genuinely makes you better at
math. (At least it has for me.) And two, it is good to confirm that
mathematics is the right thing to personally study, and for reasons
besides just "I vaguely like mathematics".</p>
<p>Here is my thesis. <strong>In mathematics, everything happens for a
principled reason.</strong> Let me give you a few examples of the
opposite. High school physics and chemistry labs always annoyed me
because there would always be inexplicable "errors" in your
measurements. And in fact, half the work in making a state of the art
lab is putting in herculean amounts of effort to make sure things happen
for principled reasons. As another example, take machine learning.
Machine learning algorithms succeed and fail for no good reason
whatsoever. Certain learning schedules work better than others, and
nobody <em>really</em> knows why. And this is to say nothing of
economics or political science: stocks can rise or fall, and politicians
can get elected, and we pretty much have no idea why. Sure, if you
consider the universe to be deterministic (an assumption that is already
questionable), there is a reason for all of these things. But these are
likely not reasons we can understand, let alone good,
<em>principled</em> reasons.</p>
<p>Mathematics is a fresh of breath air. For instance, if we have a
continuous function on a closed interval <span
class="math inline">[<em>a</em>, <em>b</em>]</span>, then for every
<span class="math inline"><em>y</em></span> between <span
class="math inline"><em>f</em>(<em>a</em>)</span> and <span
class="math inline"><em>f</em>(<em>b</em>)</span>, there is some <span
class="math inline"><em>c</em> ∈ [<em>a</em>, <em>b</em>]</span> such
that <span
class="math inline"><em>f</em>(<em>c</em>) = <em>y</em></span>. This is
the Intermediate Value Theorem, and it is always <em>exactly</em>
correct. It is not like physics, where you can drop an object from <span
class="math inline"><em>m</em></span> meters and it takes more than
<span class="math inline">$\sqrt{\frac{2m}{g}}$</span> seconds to fall
to the ground because of a motley variety of reasons. The Intermediate
Value Theorem always holds, and if you understand the real numbers, the
reason can be explained in less than half a page.</p>
<p>In the physical world, we can calculate the trajectory of an object
and be wrong because air resistance suddenly pops up. And even when we
account for all these things and things go right, the final explanation
can still be a little unsatisfying. "Why do we have to account for air
resistance? And friction?" Air resistance and friction are just part of
the way this world works, sorry.</p>
<p>Whereas in mathematics, when you are wrong, you are wrong for a
principled reason. Perhaps the best example is Russel's Paradox: there
cannot be a set <span class="math inline"><em>S</em></span> of all sets
that do not contain themselves. Regardless of whether <span
class="math inline"><em>S</em> ∈ <em>S</em></span> or <span
class="math inline"><em>S</em> ∉ <em>S</em></span>, we run into a
contradiction. And if we dig a little deeper and ask why we really run
into a contradiction and how we can fix it, it turns out that our old
notion of a set was too broad. More precisely, we permitted ourselves to
create "the set <span class="math inline"><em>S</em></span> of all
objects satisfying a property <span
class="math inline"><em>P</em></span>". But if we restrict ourselves to
"the <em>sub</em>set <span class="math inline"><em>S</em></span> of all
objects satisfying a property <span
class="math inline"><em>P</em></span> that are in set <span
class="math inline"><em>A</em></span>" (which we call <strong>restricted
comprehension</strong>), we avoid this issue entirely.</p>
<p>Why the difference? It is because physics, chemistry, and biology,
are constrained by reality. The real world does not care if you would
like bowling balls and feathers to fall at the same rate. But for
mathematics, you get to decide the rules of the game. If you want
bowling balls and feathers to fall at the same rate, you may decree it
to be so.</p>
<p>Now the joy in math is that the rules interact in interesting and
unexpected (but still principled!) ways. This means, however, that we
have to be careful that our rules do not break the game. To vastly
oversimplify, suppose I declare that the sky is red and the grass is
green. This is fine, because even though they don't respect reality, our
rules respect each other. But now suppose I declare the sky is red, the
sky is blue, and the grass is green. Now the rules do not respect each
other and our entire game of mathematics is kaput. So you have to be
careful to try and avoid that.</p>
<p>Now, these contradictions can happen in more subtle ways. Maybe you
have seen this before:</p>
<ul>
<li>The sentence below is true.</li>
<li>The sentence above is false.</li>
</ul>
<p>So a priori, you should believe that it is hard to tell whether a set
of mathematical rules (which we call a <strong>theory</strong>) is
consistent. That is, it is hard to check whether a theory has no
contradictions.</p>
<p>How hard? I have bad news for you: it is impossible. This is
<strong>Godel's Second Incompleteness Theorem</strong>: very informally,
for <em>any</em> sufficiently strong theory of mathematics, we cannot
use said theory to show that it is self-consistent. What do we mean by
sufficiently strong? It turns out that if you can use the theory to
perform arithmetic, it is already too strong.</p>
<p>So mathematics is a little nuanced. We cannot truly have everything
happen for fully principled reasons, because we don't even know if our
theory of mathematics is consistent. So the best we can do is believe
and hope that our theories are reasonable and our logic is
principled.</p>
<p>Now, there are good reasons to believe that mathematics behaves in a
principled manner in the end. So if you wish, you may close the book
here and never think about it again. But we will explore the rabbithole.
Why ought we believe that mathematical reasoning is principled? Put
another way, do we have a principled reason to believe that mathematical
reasoning is principled?</p>
<p>We should first define what "mathematical reasoning" is. This is done
formally in a subfield of mathematics known as <strong>mathematical
logic</strong>. Here is an informal picture of a part of it known as
<strong>model theory</strong>. You may picture that mathematics is a
game specified by a series of rules. For example, if the game is
Euclidean geometry, the rules are Euclid's axioms. And the rules of the
game may change. For instance, we may modify the parallel postulate to
get elliptical geometry. And if our game is mathematics, we usually use
a formal set theory known as <strong>ZFC set theory</strong> for our
rules. But this picture is still incomplete.</p>
<p>Let me tell you something a little surprising. Under our standard
model of mathematics, i.e. ZFC, we do not know whether there is a set
<span class="math inline"><em>S</em></span> such that <span
class="math inline">|ℕ| &lt; |<em>S</em>| &lt; |ℝ|</span>. In other
words, we do not know if there is a set whose size is strictly between
that of the naturals and the reals. Moreover, we know that we do not
know. More accurately, it could go either way: we could have such an
<span class="math inline"><em>S</em></span> exist, and we could also
have no such <span class="math inline"><em>S</em></span> exist. The
question whether such an <span class="math inline"><em>S</em></span>
exists is known as the <strong>continuum hypothesis</strong>.</p>
<p>Now what do I mean "it could go either way"? Yes, we may change the
rules of mathematics. But once we've laid them down, assuming they are
consistent, surely every statement is either true or false? But this is
not the case. There are <strong>models</strong> of ZFC where the
continuum hypothesis is true and models where it is false.</p>
<p>As an analogy, suppose I defined a dog for you. It has four legs, it
walks, it wags its tail. You may derive that a dog also barks. But if
you asked me, "must a dog be brown?" the answer would be no. There are
dogs that are not brown. Now suppose you asked me, "must a dog be not
brown?" and my answer would still be no. There are brown dogs too.</p>
<p>The fact of the matter is, a <strong>theory</strong> (i.e. a set of
rules) is not associated with just <em>one</em> <strong>model</strong>
(a "game"). Rather, a theory is associated with many models. Given a set
of rules, there are many games that follow these rules. And when we are
studying "normal" mathematics under ZFC, we are studying a bunch of
games at the same time and figuring out, "what must be true of
<em>all</em> these games?" After all, <a
href="/writing/essays/properties">mathematical objects are their
properties</a>. And if we rightfully consider "mathematics" itself as a
mathematical object, mathematics is just its properties: the rules of
ZFC. Just as it would be silly to consider linear algebra the study of a
particular vector space, it would be silly to consider mathematics the
study of a particular model of ZFC.</p>
<p>So why do we take ZFC as our foundation? Because even if there is
"undefined behavior" (as there must be, by Godel's First Incompleteness
Theorem), we can make enough deductions in ZFC to carry out standard
mathematics. And on the flipside, there is not "too much". The axioms of
ZFC have been proven to be independent, and if we were to remove any of
them, we would lose the ability to do a lot of useful mathematics. So to
answer the original question, we are reasonably sure that ZFC is a
principled enough foundation.</p>
<p>Mathematics is not absolute. It is as relative as can be. And this
makes it tempting to despair that all this foundational stuff is
pointless. Why bother studying ZFC if, in the best case, it is
consistent and we never know? Why study a particular set of logical
rules? In other words, is there a principled reason to study any
particular theory of mathematics over another? If we answer this
question, we also figure out why we should care about mathematics as a
whole, which is totally divorced from our conversation on foundations.
Two birds with one stone.</p>
<p>There are a few mathematical ideas that we can take for granted are
worth studying. For one, the natural numbers along with the operations
<span class="math inline">(+, ×)</span> are self-evidently important.
And it is not hard to see how we get <span class="math inline">ℚ</span>
from it. The general idea of sets (collections of objects) and functions
(machines that take in objects and spit out objects) naturally lead to
set theory, and so on. The areas of math we study are those that
naturally build up from these "fundamental" mathematical objects.</p>
<p>But what makes a fundamental mathematical object fundamental? In my
eyes, there are two criteria: it has to be an abstraction of something
humanity naturally uses, and it has to lead to interesting consequences
in mathematics for principled reasons.</p>
<p>The natural numbers are a perfect example. Counting is something
people have been doing since the dawn of humanity, and the theory of
natural numbers (aptly called "number theory") is very rich. Now, both
of these criteria have to be present. Differential equations very neatly
describe time-dependent processes, but the little of it I have seen
feels quite ad hoc. So despite its usefulness, it is not the kind of
mathematics I am interested in. And logic puzzles are enjoyable
precisely because every implication happens for a principled reason. Yet
they could hardly be described as "an abstraction of something humanity
naturally uses", so they are not the kind of mathematics I am thinking
about here.</p>
<p>Now I want to unpack the phrase "interesting consequences in
mathematics". If we restrict the word <em>mathematics</em> to mean "the
mathematics I personally find worth studying", then this is completely
self-referential. But this is no problem. Just as Google PageRank
figures out which webpages are important by looking at their relative
importance to each other, we can figure out which objects of mathematics
are fundamental the same way. So long as we believe that "a field of
natural abstractions with interesting, principled connections to each
other" is a field worth studying, then it does not matter that our
justification for studying each individual abstraction is only that
"they connect to the other abstractions". It is not that any particular
object makes mathematics worth studying; it is the <em>connections</em>,
the <em>principled structure</em> that makes it worthwhile.</p>
<p>So why is mathematics so charming, and what is it really? I'm afraid
I can only give you my personal answer. For me, the charm of mathematics
is that everything happens for a principled reason. But you don't get
the nice things in life for free. So, just as much as mathematics is
about discovering these principled lines of reasoning, it is also about
finding which rules make our reasoning principled. And about
constructing objects that give us more sophisticated and useful lines of
reasoning.</p>
<p>When you are studying mathematics, you are not just playing a game.
You are asking, "What makes this game tick? And how can I make it
better?"</p>]]></description>
	<pubDate>17 Aug 2024</pubDate>
</item>
<item>
	<title>Settling for Mediocrity</title>
	<link>https://dennisc.net/writing/essays/mediocrity.md</link>
	<description><![CDATA[<p>The other day I read something from GitLab that
shocked me.</p>
<blockquote>
<p><strong>We care about what you achieve</strong>: the code you
shipped, the user you made happy, and the team member you helped.</p>
</blockquote>
<p>On the surface this seems self-evident. The reason you have a job is
to get something done. And yet this quote is surprising all the
same.</p>
<p>Our culture currently places a disproportionate emphasis on effort
rather than results. Rather than being a means to an end, effort is seen
as the end itself: if you're doing your best, you ought to be taken care
of. It is this reasoning that dooms people to fail their classes. If
you're putting in effort for effort's sake, you're going to miss all the
ways you could've gotten better results.</p>
<p>This reasoning is backwards. We should not expect people to push
themselves to the very limit to be rewarded. Taking breaks and even
slacking off is perfectly fine if you can still achieve the same
results. Here's the rest of the quote:</p>
<blockquote>
<p>You don't have to defend how you spend your day. We trust team
members to do the right thing instead of having rigid rules. Do not
incite competition by proclaiming how many hours you worked yesterday.
If you are working too many hours, talk to your manager to discuss
solutions.</p>
</blockquote>
<p>We shouldn't expect people to roll boulders up a hill just so they'll
be taken care of. We should take care of people so they'll actually
<em>get things done</em>. But by design we reward effort and not
results, because in the past two things were true: results were
proportional to effort, and it was easier to measure effort. Thus it
became and remains the substitute for results.</p>
<h2 id="roots">Roots</h2>
<p>Up until the industrial revolution, the vast majority of people
worked in agriculture, only producing enough food to live on --- and
that's only if they were lucky. So when the agricultural revolution
(which coincided with the industrial revolution) began and more food
could be produced, large portions of the population were free to
specialize for the first time.</p>
<p>It is no coincidence that public education expanded and later became
mandated as the industrial revolution reached its climax. Yields in
agricultural productivity allowed for public education to take root in
our society. But these same forces with allowed for specialization also
demanded it.</p>
<p>Education has always existed in some form, but it was only after the
industrial revolution that it became systematic. But public education
was not created to serve the interests of the students, their parents,
or their community. It was meant to serve <a
href="https://qz.com/1314814/universal-education-was-first-promoted-by-industrialists-who-wanted-docile-factory-workers/">factory
owners</a>, and more recently in the United States, <a
href="https://www.rollingstone.com/politics/politics-news/how-wall-street-profits-from-student-debt-225700/">governments,
Wall Street</a>, and <a
href="https://www.businessinsider.com/google-apple-microsoft-competing-dominate-education-technology-market-2018-11">big
tech</a>.</p>
<p>It might be worth looking at some aspects of the school system
through these lenses to get some historical context. Why do you get
<em>suspended</em> for being tardy?<a href="#fn1" class="footnote-ref"
id="fnref1" role="doc-noteref"><sup>1</sup></a> Because factories had
absolutely no tolerance for workers that showed up late. Why is the
school day so regimented? Because workers are on the clock. Is general
horseplay in elementary school really so dangerous? Of course not. But
there is a place where you absolutely cannot be running around
carelessly: the factory. To be sure, the higher up you go in the
education ladder, the less true this is. But this is because higher
education came later, and its main functions did not include training
industrial workers.<a href="#fn2" class="footnote-ref" id="fnref2"
role="doc-noteref"><sup>2</sup></a></p>
<p>In the early industrial revolution, excellent workers were not much
more efficient than merely competent ones. And even if a worker is more
efficient than another, they'd get worn down soon owing to the horrible
labor conditions of the time. There was no reason to promote excellence;
it took time, wasn't necessary, and didn't last. It was more prudent to
spend money and influence to increase the number of competent
workers.</p>
<p>In the factories, effort was pretty much the only easily mutable
trait that affected productivity. Physical condition? Seeing how
underfed the workers were and how frequent workplace accidents were,
that's off the table. And besides, you can't force them to become fit.
But you can get them to go just a little faster, and to do it right
away. Why else would school push people to the ends of exhaustion?
Surely no one believes that anyone can consistently study for seven good
hours every day: six hours of school and one hour of homework, if we're
being generous. But that's only for higher-level learning; these long,
monotonous hours are perfect if you're preparing kids for the assembly
line.</p>
<p>We're seeing a shift from physical labor into intellectual labor. And
I really mean labor. It is menial, it is uninteresting, and perhaps most
importantly, it is replaceable. The training process is longer, and it
is less likely that any particular person can do a particular job, but
it is fundamentally the same.</p>
<p>If we look at standardized testing, it's obvious that schools are
meant to ensure a baseline of competence rather than promoting talent.
You can't be telling me anyone actually believes <a
href="https://satsuite.collegeboard.org/media/pdf/sat-practice-test-1.pdf">this</a>
is a good way to figure out who's good at math.<a href="#fn3"
class="footnote-ref" id="fnref3" role="doc-noteref"><sup>3</sup></a><a
href="#fn4" class="footnote-ref" id="fnref4"
role="doc-noteref"><sup>4</sup></a> It's not even enough to evaluate
basic competence. But keep in mind that these math standards are too low
for the present.<a href="#fn5" class="footnote-ref" id="fnref5"
role="doc-noteref"><sup>5</sup></a> They were perfectly fine during the
beginning and middle of the industrial revolution, which is exactly when
the public education system was constructed. College Board is still
stuck in the nineteenth century, right where the rest of the education
system is.<a href="#fn6" class="footnote-ref" id="fnref6"
role="doc-noteref"><sup>6</sup></a></p>
<p>Think back to elementary school: no running on the blacktops, no
doing anything but what the teacher tells you and when, and no going out
to play until you're dismissed from your lunch table by the yard duty.
Are these descriptors not out of place for a factory? In a factory,
there's no such thing as "inspiring creativity": you're doing the same
thing over and over. School is the same way: do it according to
standard.<a href="#fn7" class="footnote-ref" id="fnref7"
role="doc-noteref"><sup>7</sup></a></p>
<p>Report cards and grades have been characterized as obedience letters
so often that we've forgotten <a
href="https://core-docs.s3.amazonaws.com/documents/asset/uploaded_file/1384112/Citizenship_Grades.pdf">citizenship
grades are real</a>.<a href="#fn8" class="footnote-ref" id="fnref8"
role="doc-noteref"><sup>8</sup></a> This is very scary: trying to
quantify the "social ability" of a child is already silly, but what's
worse is these evaluations are taken at face value. We're enforcing
discipline into our children at a young age: <em>but whose idea of
discipline?</em></p>
<p>It's easy to say that these "citizenship grades" are not a big deal
because pretty much everyone gets a good score here. It's like
participation points. This is less of a problem in high school, where
everyone and everything is chill most of the time, but take this from
someone who's been hosed by these "behavior grades" before: it
ultimately ends up targeting people who have ADHD, autism, etc --- in
other words, people who aren't "normal". I don't think it's on purpose,
at least most of the time, but it's what happens.</p>
<p>But I don't think these standards are targeting anyone in particular.
They just promote effort. Effort, according to the rules: the teacher's
rules, the school's rules, and society's rules. You have to put effort
in the right place and the right time exactly when you are told, because
products have to be made and the assembly line isn't waiting for you,
whether you like it or not.</p>
<h2 id="paradigms">Paradigms</h2>
<p>So industry is the origin of settling for mediocrity. But why does it
persist? Inertia alone isn't enough to account for the wide effect it's
had. It's the result of two separate paradigms: one defined by
successes, and one by failures.</p>
<p>Inventors, innovators, and writers operate under a success-based
paradigm. Take Thomas Edison as an example: the fact that he failed a
thousand times doesn't take away from the fact that he eventually
succeeded. But if a doctor or a pilot screws up once, no amount of
successful operations or flights will save them. So they operate under a
failure-based paradigm.</p>
<p>It is the latter of which causes people to turn towards mediocrity.
And rightfully so. The world may be a better place because of the
amazingly talented pilots in flight shows. But to me it is far more
important that the pilot flying my plane has basic competence.</p>
<p>A potential point of confusion: in a success-based paradigm failure
is the default and vice versa. Under a success-based paradigm, a success
is <em>notable</em>; so it follows that success is not the expected
result.</p>
<p>Up until very recently it made sense to look at the world through a
failure-based paradigm by default. Now society has tried to move in the
other direction. But the switch to a success-based paradigm might be
just as harmful. At the least, it is certainly dishonest.</p>
<p>You know how teachers and counselors say a B isn't a big deal in high
school? Sure, one bad grade might not be the end of the world. But they
are insinuating that you can experiment and fail and adapt, and in
reality, you don't have that sort of leeway with your grades.</p>
<p>And this isn't just for the students that get straight As. It's
possible that people who usually get Bs and Cs view the few As they get
as successes. But even the C students have to worry about passing all of
their classes. In this sense, only the worst students have a standard of
failure, and by then paradigms are the least of their concerns.</p>
<p>School follows a failure-based paradigm. But why is that so
dangerous? Because to learn you have to break past your limits. If you
only take classes you'll succeed in, what are you getting? Validation?
Because those classes won't force you to think in a new way. And it is
<a href="/writing/essays/framework">frameworks</a>, rather than facts,
which really matter.</p>
<p>In math olympiads<a href="#fn9" class="footnote-ref" id="fnref9"
role="doc-noteref"><sup>9</sup></a> the third problem is usually the
hardest. Yet it is approachable and even solvable surprisingly often.
The important thing is that you pretty much have to look at the third
problem, try it, and potentially make some progress. Surprisingly often
you can learn from the third problem even when you don't come close to
solving it, and the only reason your brain is receptive to learning
after the contest ends and solutions are posted is because you tried the
problem for so long. Otherwise the context of the problem, why someone
might try a certain approach, and so on would make no sense.</p>
<p>School is obscuring the existence of this third problem and giving
people the choice not to look at it, which is a shame. It's accepted in
math contests that you don't learn anything by doing problems well below
your capacity. But the only classes you should take are the ones well
below your capacity. That's why school is so boring: if it weren't,
you'd be shooting yourself in the foot.</p>
<h2 id="spontaneous-generation">Spontaneous Generation</h2>
<p>Up until now I've never explained why settling for mediocrity is bad.
And the truth is that it isn't, at least not intrinsically. There are
times where half-assing something is not only a good option, but the
best. Think about diminishing returns --- is it really worth it to put
in your very best into school and get 98s, as opposed to breezing by
with 96s?<a href="#fn10" class="footnote-ref" id="fnref10"
role="doc-noteref"><sup>10</sup></a></p>
<p>In fact, this is a good heuristic for when to settle for mediocrity.
Do you get something substantial out of the extra effort? If not, why
bother putting it in?</p>
<p>I am not arguing that everyone should give everything their all. But
there are benefits to working your hardest towards
<em>something</em>.</p>
<p>Consider the smartest person you know. Chances are, they probably are
knowledgeable in a variety of topics. In fact, anyone sufficiently good
at anything ends up being a polymath. There are very few people who are
only knowledgeable in one field. These people, by and large, are
<em>polymaths</em>.</p>
<p>Where do they come from? Spontaneous generation is the idea that
living organisms can be produced from non-living matter; that is, they
appear with seemingly no cause. Scientists of the time did have some
idea of when organisms would appear: around meat, cheese, and filth, for
instance, but they didn't know <em>why</em>. Our ideas about smart
people are much the same.</p>
<p>Just like with small organisms, smart people don't appear out of thin
air. There is a force driving them to learn so much, and to learn it
well. I don't think it's quite curiosity; curiosity only implies desire,
not action, and it implies that there is some stimulus causing said
curiosity. A more accurate descriptor for this force would be
<em>whims</em>.</p>
<p>Traditionally we view people who succumb to their whims with disdain,
and for good reason. Someone who neglects to do their homework because
they feel like partying won't get far. But wait a minute. What about the
people who neglect their homework because they're working on their
research, or the people who drop out of school to build a company? These
are two sides of the same coin.</p>
<p>The common model of studying is that you consciously decide to sit
down and pull out your calculus textbook, setting aside time and energy
every day to work on your differentiation skills. This model implies
that Barry is better at calculus because he has more discipline and
spends more time studying. When you realize that Barry <em>isn't</em> so
diligent (and in some cases, the last time Barry opened the textbook was
in August!), you come to an even worse conclusion: Barry is just
naturally smarter.</p>
<p>It doesn't help one bit that Barry probably <em>is</em> smarter,
because it obfuscates the important thing: intelligence isn't what lets
people cruise through. And nor is it diligence.</p>
<p>Let me tell you a secret. None of the smart people you know are all
that disciplined. In fact, they tend to have a very casual attitude with
regards to their studying.<a href="#fn11" class="footnote-ref"
id="fnref11" role="doc-noteref"><sup>11</sup></a> Sure, self-control has
some role in success. But it isn't enough to account for everything. And
above all, self-control is a conscious choice you have to make. And
smart people don't have enough mental energy to constantly exercise
self-control: they're too busy getting things done.</p>
<p>So how do people really get good at something? It's because they're
drawn to it. More specifically, they can't go a day without doing it. As
an anecdote, the night I finished the first draft of this essay, there
were two things I wanted to get done: my English homework and this
essay. I had maybe an hour left to do the homework<a href="#fn12"
class="footnote-ref" id="fnref12" role="doc-noteref"><sup>12</sup></a>
so it was only logical to do it first. But I didn't do that. I ended up
opening both Google Docs and Vim<a href="#fn13" class="footnote-ref"
id="fnref13" role="doc-noteref"><sup>13</sup></a> and I ended up writing
this essay first. That's how strong your whims have to be.</p>
<p>All the literary greats have written dozens of novels. Anyone who
knows at least three languages knows three more. To an outside observer
talent is the explanation. But when all is said and done, ask yourself
this: where are the people who've only gone halfway? You might know
someone who's only done a couple of things. But chances are they're hard
at work on the next.</p>
<p>Whims are sufficient for getting work done. But are they necessary?
Because you have a limited amount of attention resources, yes.</p>
<p>Attention resources is a theory that states the energy used on fairly
independent activities and decisions is finite. This intuitively makes
sense. The internet isn't distracting because it makes an assignment
take longer per se. It's because it takes effort to switch away from
something like Reddit or Twitter.</p>
<p>Importantly, it is usually harder to start something than it is to
continue something. You actually have to make a decision when you're
starting something, whereas you only need to <em>not</em> make the
decision to give up to continue. Think of running: it's much easier to
finish a workout if you're running the entire time versus if you start
walking in the middle of it. In the second scenario, you have to summon
up the motivation to start running again.</p>
<p>When you're doing SAT practice or writing an essay for English, you
will constantly have to stop to "walk." You have to think of totally new
and often disparate ideas for each new question and each new paragraph,
and each time you are mentally switching contexts. The reason writing an
English essay takes hours isn't because five hundred words take so long
to write. Anyone could write that many words in solutions to the AMC 8
in fifteen minutes if they focus. It's because by the time you're done,
you've almost depleted your store of attention resources.<a href="#fn14"
class="footnote-ref" id="fnref14"
role="doc-noteref"><sup>14</sup></a></p>
<p>Following your whims, by definition, takes the minimum amount of
attention resources. There is very little you can do to change the
amount of attention resources you have; the only substantial changes I
can think of are getting good sleep and exercise. So you have to try and
skimp on how many attention resources you are spending. That's why you
want to manipulate your whims: to reduce the activation energy required
to do what you want.</p>
<p>Just like polymaths, whims don't come out of nowhere. The first and
most obvious ingredient is exposure. You don't need a lot of it, and it
doesn't even need to be good. Even though AP Computer Science is the
worst designed class I have ever seen<a href="#fn15"
class="footnote-ref" id="fnref15" role="doc-noteref"><sup>15</sup></a>,
it was enough to get me seriously thinking about programming again ---
first through USACO and then through creating applications --- and
ultimately to follow through. I begrudgingly give it a little bit of
credit for where I am now.</p>
<p>The second ingredient is the hardest one to reproduce. It is a
personality type that naturally gets led around the world. Maybe for a
year they will be interested in Italian. And for the next three they'll
be interested in writing books. Occasionally, they might even get led
around on a wild goose chase that leads to a vast and sinister
conspiracy --- with the subtle qualifier, of course, that it is
completely fictitious.</p>
<p>The world is not kind to these people. It is filled with traps
designed to ensnare them and exploit them for profit. I have no doubt
that some of the smartest people in the world are currently wasting away
in the bubble of social media. And so there's a third ingredient that's
necessary: discernment.</p>
<p>For these sort of people, it's very easy to get invested into
something, and very hard to get out. So you have to be able to tell what
sort of work is meaningful, and what sort is nonsense.</p>
<p>There are no absolutes. But one of the heuristics I use is this:
would it make a difference if I didn't do it? To be sure, even the word
"difference" is a little vague. Would it make a difference if you didn't
write your English essay? In the sense that your grade would tank,
absolutely. Yet no one is under the delusion that English essays aren't
nonsense.</p>
<p>For something to be meaningful, its purpose should be rooted in
something external; it should not be self-referencing. Take the <a
href="https://mapm.mathadvance.org">Math Advance Problem Manager</a>,
for instance: it makes compiling contest drafts much easier for the <a
href="mat.mathadvance.org">MAT</a> team.<a href="#fn16"
class="footnote-ref" id="fnref16" role="doc-noteref"><sup>16</sup></a>
But the reason you write an English essay is to get a good grade in the
class. Yet the grade you get in the class is supposed to reflect how
good your English essays are. It's cyclical.</p>
<p>But wait a minute. Grades get you into college, which determines your
peer group. Surely that has to count for something.</p>
<p>Doing your English essay is certainly important because it indirectly
determines your future. But does your English essay actually mean
anything to you? How much do you care about the grade as opposed to what
you've actually written? That to me is the difference between
<em>meaningful</em> and <em>important</em>: do you care about the thing
itself, or do you just care about the outcome?</p>
<p>None of this discernment will do you any good if you don't act on it.
And acting on your tastes, I think, is really what it means to be
picky.</p>
<p>Picky is a word with negative connotations. You don't want to be a
picky eater or be picky about the color of your clothes. But that's
being picky without discernment. You have to be picky and be
discerning.</p>
<p>Whatever you're doing by default will most likely not be a good fit
for you. Everyone else just makes too many assumptions about what you
may or may not want to do. If you are picky but not discerning, you'll
pick the wrong fights. If you are discerning but not picky, you'll be
left feeling powerless. And if you are neither picky nor discerning,
you'll get taken advantage of. Know what's worth fighting for, and be
willing to fight for it.</p>
<p>It seems that you can't completely separate being picky about what's
important and being picky about random things. Successful people tend to
be eccentric, and they are quite picky about it. Otherwise they'd stop
as soon as they got some pushback.</p>
<p>But to play devil's advocate, eccentric by whose standards? In the
twentieth century there was a small group of people who fought against
public smoking. They were certainly seen as weird during their time.
Everyone else was smoking, so they ought to stop being a pain in the
behind and just let people have their fun. But now we see that they were
right.</p>
<p>Picky people aren't right all the time. The people who got
Prohibition passed were very picky about the "morals" of the nation, and
they ended up giving organized crime the greatest gift of their lives.
Perhaps their mistake was being picky about other people whose actions
did not concern them. Maybe that's the answer: be scrupulous when it
concerns you or your work, and otherwise, live and let live.</p>
<p>So, to summarize: expose yourself to interesting things, see where it
leads you, but know what matters and act on it. There's no guarantee
that you'll become a lot smarter after doing this, but it might at least
make it easier.</p>
<section id="footnotes" class="footnotes footnotes-end-of-document"
role="doc-endnotes">
<hr />
<ol>
<li id="fn1"><p>In all fairness, these draconian tardy policies rarely
get enforced. But the fact they exist is a sign that schools do not
trust their students, and the fact they even <em>threaten</em> such
action is a vestige of the industrial era.<a href="#fnref1"
class="footnote-back" role="doc-backlink">↩︎</a></p></li>
<li id="fn2"><p>This seems to be less true now, since more and more jobs
have been requiring a degree of some sort.<a href="#fnref2"
class="footnote-back" role="doc-backlink">↩︎</a></p></li>
<li id="fn3"><p>The relevant section begins at page 36 of the PDF.<a
href="#fnref3" class="footnote-back" role="doc-backlink">↩︎</a></p></li>
<li id="fn4"><p>There will certainly be people who will chide me for
calling the math section of the SAT easy. I am aware that many people
struggle with this test. To those people I have two responses.</p>
<ol type="1">
<li><p>The SAT section of math is objectively easy. Any other country's
high school math exam is orders of magnitude more difficult. Many
Americans are hopelessly bad at math, and that does not make the test
any harder.</p></li>
<li><p>There is no reason to assess those who do are bad at math and/or
do not intend to pursue math. It does not make sense, even from an
economic standpoint.</p></li>
</ol>
<p>In short, the SAT does not differentiate between people who will be
working with math, while brutally punishing those who will not. That,
not its difficulty, is the real problem with the SAT.<a href="#fnref4"
class="footnote-back" role="doc-backlink">↩︎</a></p></li>
<li id="fn5"><p>The math section of the SAT is a little harder than it
was <a href="https://www.erikthered.com/tutor/SAT-1926-Subtest-2.pdf">a
hundred years ago</a>, as some topics have been added, such as slopes,
means, and standard deviations. But the test is still heavily influenced
by its history, much of which is <a
href="https://www.nea.org/advocating-for-change/new-from-nea/racist-beginnings-standardized-testing">far
more significant</a> than being historically easy.<a href="#fnref5"
class="footnote-back" role="doc-backlink">↩︎</a></p></li>
<li id="fn6"><p>College Board administered its first exam in the
twentieth century, but the <a
href="https://en.wikipedia.org/wiki/Eugenics">noxious philosophy</a>
that drove it originated in the late nineteenth century.<a
href="#fnref6" class="footnote-back" role="doc-backlink">↩︎</a></p></li>
<li id="fn7"><p>The primary difference is now we get some degree of
choice. You are occasionally given time to work on whatever you please.
But it really speaks to how awful school is that you're not supposed to
have agency by default.<a href="#fnref7" class="footnote-back"
role="doc-backlink">↩︎</a></p></li>
<li id="fn8"><p>Yes, this is a <em>high school</em>. Ugh.<a
href="#fnref8" class="footnote-back" role="doc-backlink">↩︎</a></p></li>
<li id="fn9"><p>A math olympiad has two days with three problems in each
day. What I really mean is the third problem of each day, but for
simplicity's sake I treat each day as a totally separate contest here.<a
href="#fnref9" class="footnote-back" role="doc-backlink">↩︎</a></p></li>
<li id="fn10"><p>If your class rank is computed through a numerical
average rather than a letter average, this does not apply (and you have
my condolences).<a href="#fnref10" class="footnote-back"
role="doc-backlink">↩︎</a></p></li>
<li id="fn11"><p>To all parents of smart children: leave them alone
(unless they ask you to be involved). The abilities they exhibit have
nothing to do with the math and everything to do with the cognitive
independence they are exercising.<a href="#fnref11"
class="footnote-back" role="doc-backlink">↩︎</a></p></li>
<li id="fn12"><p>At least I thought it was due the next day. Turns out
it was due the day after.<a href="#fnref12" class="footnote-back"
role="doc-backlink">↩︎</a></p></li>
<li id="fn13"><p>It's no coincidence that I used Google Docs for the
thing I half-assed, i.e. my English homework, while using Vim to write
this essay. In my sophomore year when I started programming, I did my
homework using Replit (since we had to submit with it anyway) and used
Git + various IDEs for my pet projects.<a href="#fnref13"
class="footnote-back" role="doc-backlink">↩︎</a></p></li>
<li id="fn14"><p>The difference between an English essay and this essay
is largely in the structure. The ideas in an English essay are often
disjoint, only depending on the thesis. To see this, imagine removing
one of the body paragraphs and adjusting the signposting in the
introduction and conclusion accordingly. (Typically these essays have a
thesis of the form "claim + summary of each body paragraph" and you
would have to remove the summary of the body paragraph, and similarly
for the conclusion.)</p>
<p>An English essay is like a tree with depth 1; the thesis is the root
node and everything else is directly connected to the thesis. This essay
is like a line; it goes from point A to point B and so on. So in effect,
you have to transition twice as often: instead of going directly between
your points, you have to make a pitstop at the thesis every time.</p>
<p>I'm not claiming that either model is better or worse. In fact, if
you are a lawyer trying to argue that your client is innocent, you
better make sure everything ties back to that thesis. But writing
tree-style takes more energy than writing line-style.</p>
<p>(If you want to be pedantic, a "line" of connected vertices is
technically a tree. But you know what I mean.)<a href="#fnref14"
class="footnote-back" role="doc-backlink">↩︎</a></p></li>
<li id="fn15"><p>It's somehow even worse than AP Calculus.<a
href="#fnref15" class="footnote-back" role="doc-backlink">↩︎</a></p></li>
<li id="fn16"><p>More careful readers might notice that I haven't
explained why writing math contests is meaningful. It's because the MAT
provides value to other people; through the contest, participants will
actually learn something.</p>
<p>Providing value to other people isn't the only way for work to be
meaningful; the "meaning" an activity provides can just be the fun and
frustration you have struggling through it (like in math contests), or
the time you spend bonding with your friends over it (fishing, card
games, Minecraft). But it is one of them.<a href="#fnref16"
class="footnote-back" role="doc-backlink">↩︎</a></p></li>
</ol>
</section>]]></description>
	<pubDate>29 Jan 2022</pubDate>
</item>
<item>
	<title>Why mapm?</title>
	<link>https://dennisc.net/writing/tech/why-mapm.md</link>
	<description><![CDATA[<p>In the vein of <a href="latexmk">why
latexmk</a> I will explain why I wrote mapm in the first place. That
way, when you know what annoyed me enough to finally write this
software, you will have a good idea as to what it does.</p>
<p>When you are writing a math contest, you typically have
<code>problems.tex</code>:</p>
<div class="sourceCode" id="cb1"><pre
class="sourceCode tex"><code class="sourceCode latex"><span id="cb1-1"><a href="#cb1-1" aria-hidden="true" tabindex="-1"></a><span class="bu">\documentclass</span>{<span class="ex">article</span>}</span>
<span id="cb1-2"><a href="#cb1-2" aria-hidden="true" tabindex="-1"></a><span class="kw">\begin</span>{<span class="ex">document</span>}</span>
<span id="cb1-3"><a href="#cb1-3" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb1-4"><a href="#cb1-4" aria-hidden="true" tabindex="-1"></a><span class="kw">\section</span>{Problem 1}</span>
<span id="cb1-5"><a href="#cb1-5" aria-hidden="true" tabindex="-1"></a>What is <span class="ss">$1+1$</span>?</span>
<span id="cb1-6"><a href="#cb1-6" aria-hidden="true" tabindex="-1"></a><span class="kw">\end</span>{<span class="ex">document</span>}</span></code></pre></div>
<p>and <code>solutions.tex</code>, which typically contains an answer
key as well:</p>
<div class="sourceCode" id="cb2"><pre
class="sourceCode tex"><code class="sourceCode latex"><span id="cb2-1"><a href="#cb2-1" aria-hidden="true" tabindex="-1"></a><span class="bu">\documentclass</span>{<span class="ex">article</span>}</span>
<span id="cb2-2"><a href="#cb2-2" aria-hidden="true" tabindex="-1"></a><span class="kw">\begin</span>{<span class="ex">document</span>}</span>
<span id="cb2-3"><a href="#cb2-3" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb2-4"><a href="#cb2-4" aria-hidden="true" tabindex="-1"></a><span class="kw">\section</span>{Answers}</span>
<span id="cb2-5"><a href="#cb2-5" aria-hidden="true" tabindex="-1"></a><span class="kw">\begin</span>{<span class="ex">enumerate</span>}</span>
<span id="cb2-6"><a href="#cb2-6" aria-hidden="true" tabindex="-1"></a>    <span class="fu">\item</span> <span class="ss">$2$</span></span>
<span id="cb2-7"><a href="#cb2-7" aria-hidden="true" tabindex="-1"></a><span class="kw">\end</span>{<span class="ex">enumerate</span>}</span>
<span id="cb2-8"><a href="#cb2-8" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb2-9"><a href="#cb2-9" aria-hidden="true" tabindex="-1"></a><span class="kw">\section</span>{Problem 1}</span>
<span id="cb2-10"><a href="#cb2-10" aria-hidden="true" tabindex="-1"></a>What is <span class="ss">$1+1$</span>?</span>
<span id="cb2-11"><a href="#cb2-11" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb2-12"><a href="#cb2-12" aria-hidden="true" tabindex="-1"></a><span class="kw">\subsection</span>{Solution}</span>
<span id="cb2-13"><a href="#cb2-13" aria-hidden="true" tabindex="-1"></a>It is <span class="ss">$2$</span>.</span>
<span id="cb2-14"><a href="#cb2-14" aria-hidden="true" tabindex="-1"></a><span class="kw">\end</span>{<span class="ex">document</span>}</span></code></pre></div>
<p>Let's say you want to change problem 1. Then you have to edit the
problem in <code>problems.tex</code> and <code>solutions.tex</code>, as
well as the answer and solution in <code>solutions.tex</code>. That is
four places you have to update. And it gets even worse if you want to
switch two problems: that's 8 updates. And what if you want to move
everything down one slot, because your current contest is too hard? So
on and so forth.</p>
<p>So you either have two choices: get lazy and do a sloppy job because
editing a draft takes forever, even though you know <em>exactly</em>
what you want to put in, or use software that handles compilation for
you given a set of problems. I really care about the quality of my
contests, so I choose the latter.</p>
<p>With mapm, all you have to do is the following: change</p>
<div class="sourceCode" id="cb3"><pre
class="sourceCode yaml"><code class="sourceCode yaml"><span id="cb3-1"><a href="#cb3-1" aria-hidden="true" tabindex="-1"></a><span class="fu">problems</span><span class="kw">:</span></span>
<span id="cb3-2"><a href="#cb3-2" aria-hidden="true" tabindex="-1"></a><span class="at">  --- one-plus-one</span></span></code></pre></div>
<p>to</p>
<div class="sourceCode" id="cb4"><pre
class="sourceCode yaml"><code class="sourceCode yaml"><span id="cb4-1"><a href="#cb4-1" aria-hidden="true" tabindex="-1"></a><span class="fu">problems</span><span class="kw">:</span></span>
<span id="cb4-2"><a href="#cb4-2" aria-hidden="true" tabindex="-1"></a><span class="at">  --- two-plus-two</span></span></code></pre></div>
<p>One change is one change. That's how it ought to be. The rest of the
spec involves telling mapm how to determine what problem
<code>one-plus-one</code> refers to, and how to properly build a
contest. Once you think about it that way, it is very obvious what mapm
does.</p>]]></description>
	<pubDate>20 Mar 2022</pubDate>
</item>
<item>
	<title>LaTeX for Beginners</title>
	<link>https://dennisc.net/writing/tech/latex.md</link>
	<description><![CDATA[<p>People who want a high-level overview of how
TeX works may want to read <a href="/writing/tech/tex-overview">A
High-Level Overview of TeX</a> instead, or in addition to, this post.
This guide prioritizes people who bother to locally install LaTeX <a
href="https://web.evanchen.cc/faq-latex.html#L-2b">(do your homework,
people)</a>. All the information for Overleaf users is still there, but
it's included as an afterthought.</p>
<h2 id="equations">Equations</h2>
<p>Writing equations in TeX is quite simple. All you have to do is
surround whatever math you want to write with the <code>$</code> symbol.
For example, <code>$1+1=2$</code> will return <span
class="math inline">1 + 1 = 2</span>.</p>
<p>The main draw of TeX for math, though, is the ability to render
complex equations with precise (even if not always so simple) syntax.
For instance, instead of writing <code>(1+1/sqrt(x))/(2+1/(2x))</code>
and expecting your reader to parse it, you write
<code>\frac{1+\frac{1}{\sqrt{x}}}{2+\frac{1}{2x}}</code> and get <span
class="math inline">$\frac{1+\frac{1}{\sqrt{x}}}{2+\frac{1}{2x}}$</span>.
The tradeoff, though, is that when you're <em>writing</em> is much
harder for you to parse. (Although over time you get used to it.)</p>
<p>When you're new to writing equations, expect to Google aggressively.
The <a
href="https://artofproblemsolving.com/wiki/index.php/LaTeX:Symbols">AoPS
LaTeX Symbols Page</a> provides a decent selection of some common
symbols (as well as some symbols frankly no one cares about). Sometimes
there's a symbol whose name you don't know, making it hard to Google ---
in that case, use <a
href="https://detexify.kirelabs.org/classify.html">Detexify</a>. There's
also <a
href="http://tug.ctan.org/info/symbols/comprehensive/symbols-a4.pdf">the
Comprehensive LaTeX Symbol List</a>, which is exactly what it sounds
like.</p>
<p>I suspect that most people reading this already know how to write
equations in LaTeX though. (And if you don't, it's pretty easy to learn,
it takes a week to master tops.) Generating a document, though, is a
little harder...</p>
<h2 id="document-structure">Document Structure</h2>
<p>A LaTeX document is contained in a single <code>.tex</code> file,
which has exactly one documentclass and any number of packages.<a
href="#fn1" class="footnote-ref" id="fnref1"
role="doc-noteref"><sup>1</sup></a></p>
<p>Here is a simple example of a LaTeX document.</p>
<div class="sourceCode" id="cb1"><pre
class="sourceCode tex"><code class="sourceCode latex"><span id="cb1-1"><a href="#cb1-1" aria-hidden="true" tabindex="-1"></a><span class="bu">\documentclass</span>{<span class="ex">article</span>}</span>
<span id="cb1-2"><a href="#cb1-2" aria-hidden="true" tabindex="-1"></a><span class="kw">\begin</span>{<span class="ex">document</span>}</span>
<span id="cb1-3"><a href="#cb1-3" aria-hidden="true" tabindex="-1"></a>    Did you know that <span class="ss">$1+1=2$</span>?</span>
<span id="cb1-4"><a href="#cb1-4" aria-hidden="true" tabindex="-1"></a><span class="kw">\end</span>{<span class="ex">document</span>}</span></code></pre></div>
<p>Notice that we have a documentclass --- we must have one, though it
does not need to be <code>article</code> --- and we surround the
contents of the document with <code>\begin{document}</code> and
<code>\end{document}</code>. All of this is mandatory.</p>
<p>Anything that comes before <code>\begin{document}</code> is part of
the <strong>preamble</strong>. You should import packages in the
preamble, after <code>\documentclass</code> but before
<code>\begin{document}</code> What you do after
<code>\end{document}</code> almost never affects the compilation
process, but don't put anything there anyway.</p>
<p>This document is a bit boring. You can include a title, author, and
date like such:</p>
<div class="sourceCode" id="cb2"><pre
class="sourceCode tex"><code class="sourceCode latex"><span id="cb2-1"><a href="#cb2-1" aria-hidden="true" tabindex="-1"></a><span class="bu">\documentclass</span>{<span class="ex">article</span>}</span>
<span id="cb2-2"><a href="#cb2-2" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb2-3"><a href="#cb2-3" aria-hidden="true" tabindex="-1"></a><span class="fu">\title</span>{Title}</span>
<span id="cb2-4"><a href="#cb2-4" aria-hidden="true" tabindex="-1"></a><span class="fu">\author</span>{Author}</span>
<span id="cb2-5"><a href="#cb2-5" aria-hidden="true" tabindex="-1"></a><span class="fu">\date</span>{Date}</span>
<span id="cb2-6"><a href="#cb2-6" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb2-7"><a href="#cb2-7" aria-hidden="true" tabindex="-1"></a><span class="kw">\begin</span>{<span class="ex">document</span>}</span>
<span id="cb2-8"><a href="#cb2-8" aria-hidden="true" tabindex="-1"></a>    <span class="fu">\maketitle</span></span>
<span id="cb2-9"><a href="#cb2-9" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb2-10"><a href="#cb2-10" aria-hidden="true" tabindex="-1"></a>    Did you know that <span class="ss">$1+1=2$</span>?</span>
<span id="cb2-11"><a href="#cb2-11" aria-hidden="true" tabindex="-1"></a><span class="kw">\end</span>{<span class="ex">document</span>}</span></code></pre></div>
<h3 id="sections">Sections</h3>
<p>You can split your article into sections with the
<code>\section</code> command like thus:</p>
<div class="sourceCode" id="cb3"><pre
class="sourceCode tex"><code class="sourceCode latex"><span id="cb3-1"><a href="#cb3-1" aria-hidden="true" tabindex="-1"></a><span class="kw">\begin</span>{<span class="ex">document</span>}</span>
<span id="cb3-2"><a href="#cb3-2" aria-hidden="true" tabindex="-1"></a><span class="kw">\section</span>{Did you know...}</span>
<span id="cb3-3"><a href="#cb3-3" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb3-4"><a href="#cb3-4" aria-hidden="true" tabindex="-1"></a>Did you know that elephants are pink? That <span class="ss">$1+1=2$</span>?</span>
<span id="cb3-5"><a href="#cb3-5" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb3-6"><a href="#cb3-6" aria-hidden="true" tabindex="-1"></a><span class="kw">\end</span>{<span class="ex">document</span>}</span></code></pre></div>
<h2 id="compiling">Compiling</h2>
<p>Compiling is the process of turning your TeX document (the
<code>.tex</code> file) into a PDF. The compiler has nothing to do with
the text editor. Personally, I think you do yourself a disservice if you
are invoking the compiler through a graphical interface; just type
<code>pdflatex path/to/tex</code> in the terminal instead.</p>
<p>(I will not explain how to compile Overleaf documents since it is
self-explanatory.)</p>
<p>To get the compiler, <a
href="https://www.tug.org/texlive/acquire-netinstall.html">install TeX
Live</a>. It really isn't that hard. If you're using Windows, it will
take around 4 hours for a full install.<a href="#fn2"
class="footnote-ref" id="fnref2" role="doc-noteref"><sup>2</sup></a></p>
<p>If you are using Linux, you have the choice of installing TeX Live
with your package manager. I don't think it really matters if you use
the "vanilla" installer or use your package manager, but if you want
things to "just work" I recommend using the official installer.<a
href="#fn3" class="footnote-ref" id="fnref3"
role="doc-noteref"><sup>3</sup></a></p>
<p>Then, with your terminal in the <strong>same directory</strong> as
your tex file, run <code>pdflatex file.tex</code> (where
<code>file.tex</code> is replaced by the name of the actual file). You
<em>can</em> in theory run it in another directory but that's also where
all the compiled files will go, and that's not great.</p>
<p>If you want to compile asymptote, make the <code>~/.latexmkrc</code>
file and copy the following text into it:</p>
<div class="sourceCode" id="cb4"><pre
class="sourceCode bash"><code class="sourceCode bash"><span id="cb4-1"><a href="#cb4-1" aria-hidden="true" tabindex="-1"></a><span class="ex">sub</span> asy {return system<span class="er">(</span><span class="st">&quot;asy </span><span class="dt">\&quot;</span><span class="va">$_</span><span class="st">[0]</span><span class="dt">\&quot;</span><span class="st">&quot;</span><span class="kw">);</span><span class="er">}</span></span>
<span id="cb4-2"><a href="#cb4-2" aria-hidden="true" tabindex="-1"></a><span class="ex">add_cus_dep</span><span class="er">(</span><span class="st">&quot;asy&quot;</span><span class="ex">,</span><span class="st">&quot;eps&quot;</span><span class="ex">,0,</span><span class="st">&quot;asy&quot;</span><span class="kw">);</span></span>
<span id="cb4-3"><a href="#cb4-3" aria-hidden="true" tabindex="-1"></a><span class="ex">add_cus_dep</span><span class="er">(</span><span class="st">&quot;asy&quot;</span><span class="ex">,</span><span class="st">&quot;pdf&quot;</span><span class="ex">,0,</span><span class="st">&quot;asy&quot;</span><span class="kw">);</span></span>
<span id="cb4-4"><a href="#cb4-4" aria-hidden="true" tabindex="-1"></a><span class="ex">add_cus_dep</span><span class="er">(</span><span class="st">&quot;asy&quot;</span><span class="ex">,</span><span class="st">&quot;tex&quot;</span><span class="ex">,0,</span><span class="st">&quot;asy&quot;</span><span class="kw">);</span></span></code></pre></div>
<p>Then, instead of running <code>pdflatex file.tex</code>, run
<code>latexmk file.tex</code>.</p>
<h3 id="where-is-latexmkrc-on-paths-and-the-home-directory">Where is
latexmkrc? (On paths and the home directory)</h3>
<p>When I write <code>~</code> in <code>~/.latexmkrc</code>, it means
the home directory.<a href="#fn4" class="footnote-ref" id="fnref4"
role="doc-noteref"><sup>4</sup></a> This is a Unix convention and will
not work for Windows! However, it is convenient as a shorthand so I use
it anyway.</p>
<p>If you open up a new shell, it will start in the home directory, you
can just run <code>notepad .latexmkrc</code> (Windows) or
<code>nano .latexmkrc</code> (Mac/Linux) from there and copy in the
contents.</p>
<h2 id="pretty-documents">Pretty Documents</h2>
<p>If you want your documents to be pretty, typically you will want to
import custom <code>.cls</code> or <code>.sty</code> files. The
<code>scrartcl</code> class also has good defaults.</p>
<p>To import a custom <code>.cls</code> or <code>.sty</code> file, you
have two choices:</p>
<ol type="1">
<li><p>Put the package in the same directory as the TeX file. (This is
one of many reasons you should run LaTeX in the same directory as your
TeX file.)</p>
<p>I only recommend this if you plan on using the <code>.cls</code> or
<code>.sty</code> file only for that project, AND that project is a
throwaway.</p></li>
<li><p>Put the package in the <code>~/texmf/tex/latex</code> directory.
(If this directory does not exist, create it.)</p>
<p>A package does not have to be a <code>.cls</code> or a
<code>.sty</code> file. It can be a <a
href="https://gitlab.com/dennistex/bounce">directory containing sty and
cls files</a>. In this case, you copy the entire directory into
<code>~/texmf/tex/latex</code>.</p></li>
</ol>
<p>I recommend using <a
href="mast.cls">https://gitlab.com/mathadvance/tex/mast</a>, which
actually has some (admittedly bad) documentation, or <a
href="bounce.cls">https://gitlab.com/dennistex/bounce</a>. Note that the
latter has no documentation, but the commands are all the same as
<code>mast.cls</code>.</p>
<p>If you are using Overleaf, <a
href="https://www.overleaf.com/learn/how-to/How_to_upload_files_to_a_new_project">upload
the files</a> to your project. You have to do this for every project,
there's no way around it.</p>
<h2 id="gotchas">Gotchas</h2>
<p>Watch out for the following potential "gotchas" that might make your
document unreadable.</p>
<ul>
<li><p>Never use double dollar signs like <code>$$1+1=2$$</code> for
display math mode, always do <code>\[1+1=2\]</code>. <a
href="https://tex.stackexchange.com/questions/503/why-is-preferable-to?noredirect=1&amp;lq=1">This
is why.</a></p>
<ul>
<li>Unlike the double dollar sign, single dollar signs are still OK. You
can write <code>\(1+1=2\)</code> instead of <code>$1+1=2$</code> if you
want, but there are advantages and disadvantages either way. (I use the
single dollar sign.)</li>
</ul></li>
<li><p>Equations are part of sentences. Do not write</p>
<div class="sourceCode" id="cb5"><pre
class="sourceCode tex"><code class="sourceCode latex"><span id="cb5-1"><a href="#cb5-1" aria-hidden="true" tabindex="-1"></a>This is an equation.</span>
<span id="cb5-2"><a href="#cb5-2" aria-hidden="true" tabindex="-1"></a><span class="ss">$$1+1=2$$</span></span>
<span id="cb5-3"><a href="#cb5-3" aria-hidden="true" tabindex="-1"></a>It implies that <span class="ss">$2+2=4$</span>.</span></code></pre></div>
<p>Instead, write</p>
<div class="sourceCode" id="cb6"><pre
class="sourceCode tex"><code class="sourceCode latex"><span id="cb6-1"><a href="#cb6-1" aria-hidden="true" tabindex="-1"></a>The equation</span>
<span id="cb6-2"><a href="#cb6-2" aria-hidden="true" tabindex="-1"></a><span class="ss">\[1+1=2\]</span></span>
<span id="cb6-3"><a href="#cb6-3" aria-hidden="true" tabindex="-1"></a>implies that <span class="ss">$2+2=4$</span>.</span></code></pre></div></li>
<li><p>Keep punctuation outside of math mode.</p>
<ul>
<li>Don't write <code>$a, b, c$</code> because 1) the spacing will be
off and 2) LaTeX might overflow that equation past the margins (when
there's no reason it has to, since you can put a linebreak between two
variables in this example). Instead, write
<code>$a$, $b$, $c$</code>.</li>
<li>You do want to enclose intermediate punctuation (e.g. commas in
between a list of variables) in math mode when it <strong>does
not</strong> make sense for a linebreak to be inserted. For instance,
<code>\{1, 2, 3\}</code> is perfectly fine because you cannot accept a
linebreak anywhere in between.</li>
</ul></li>
<li><p>Never use two <code>\[\]</code> equations in a row; use</p>
<div class="sourceCode" id="cb7"><pre
class="sourceCode tex"><code class="sourceCode latex"><span id="cb7-1"><a href="#cb7-1" aria-hidden="true" tabindex="-1"></a><span class="kw">\begin</span>{<span class="ex">align*</span>}</span>
<span id="cb7-2"><a href="#cb7-2" aria-hidden="true" tabindex="-1"></a><span class="ss">x+2&amp;=y+4 </span><span class="sc">\\</span></span>
<span id="cb7-3"><a href="#cb7-3" aria-hidden="true" tabindex="-1"></a><span class="ss">x&amp;=y+2</span></span>
<span id="cb7-4"><a href="#cb7-4" aria-hidden="true" tabindex="-1"></a><span class="kw">\end</span>{<span class="ex">align*</span>}</span></code></pre></div>
<p>instead.</p></li>
<li><p>Never use <code>sin</code> instead of <code>\sin</code>, the
difference is pronounced: <span
class="math inline"><em>s</em><em>i</em><em>n</em></span> vs <span
class="math inline">sin </span>.</p></li>
<li><p>If you want a paragraph break between text, you must include an
empty line in between:</p>
<pre><code>Paragraph 1

Paragraph 2</code></pre>
<p>The following will just insert a space in between:</p>
<pre><code>Paragraph 1
Paragraph 2</code></pre>
<p>and you will get <code>Paragraph 1 Paragraph 2</code> as your
output.</p></li>
<li><p>Never use <code>\\</code> or <code>\vspace</code> or anything
similar in the document itself. Such manual formatting should be left to
commands and environments, ideally defined in a class or
package.</p></li>
<li><p>Similarly, there are very few circumstances where you should
manually be using <code>\noindent</code> in the document.</p></li>
<li><p>Do not use <code>\textit</code> or <code>\textbf</code> for
emphasis, use <code>\emph</code> instead and redefine <code>\emph</code>
to look how you want it to.</p></li>
</ul>
<p>You will notice that the second half relates to the WYSIWYM
philosophy of LaTeX. That comprises more than half the bad TeX people
write.</p>
<section id="footnotes" class="footnotes footnotes-end-of-document"
role="doc-endnotes">
<hr />
<ol>
<li id="fn1"><p>This is a bit of a simplification. You can use
<code>\input</code> to break apart long documents into several files
(it's recommended for books, you have one file per chapter). Also, part
of the document is also contained in the classes (<code>.cls</code>) and
packages (<code>.sty</code>) you import.<a href="#fnref1"
class="footnote-back" role="doc-backlink">↩︎</a></p></li>
<li id="fn2"><p>But you can actually mitigate this. The reason the
install is slow is because the TeX Live installer struggles to find the
closest download mirror, so the mirror you get can be pretty far. This
issue does not appear on Linux.</p>
<p>A download mirror is just where you download TeX Live from.
Obviously, the closer it is to you, the quicker the download will
happen.<a href="#fnref2" class="footnote-back"
role="doc-backlink">↩︎</a></p></li>
<li id="fn3"><p>If you're using a Debian-based distro, you're going to
get the 2019 version and miss a good number of packages. If you're using
Arch, tlmgr is bugged. More importantly, however, you can customize the
installation path, which is critical because TeX Live works much better
if you install it in the <code>$HOME</code> directory rather than in
root.</p>
<p>For example, you might want <code>texliveonfly</code> to work without
asking for <code>sudo</code> on every install.<a href="#fnref3"
class="footnote-back" role="doc-backlink">↩︎</a></p></li>
<li id="fn4"><p>This is typically <code>C:\\Users\USERNAME</code> for
Windows, <code>/Users/USERNAME</code> for Mac, and
<code>/home/USERNAME</code> for Linux.<a href="#fnref4"
class="footnote-back" role="doc-backlink">↩︎</a></p></li>
</ol>
</section>]]></description>
	<pubDate>23 Nov 2021</pubDate>
</item>
<item>
	<title>A High-Level Overview of TeX</title>
	<link>https://dennisc.net/writing/tech/tex-overview.md</link>
	<description><![CDATA[<p>If you're a beginner and want to just get LaTeX
to work, read <a href="writing/tech/latex">LaTeX for Beginners</a>
instead. I assume you know the basics of LaTeX and have a working
installation.</p>
<p>This isn't mainly about how the TeX programming language itself
works. Rather, it's moreso about the environment that (La)TeX works in,
and why some of its more puzzling behaviors occur.</p>
<h2 id="history">History</h2>
<p>TeX and LaTeX are very old, so some of the decisions they make will
be quite archaic.<a href="#fn1" class="footnote-ref" id="fnref1"
role="doc-noteref"><sup>1</sup></a> I strongly recommend that if you
want to do anything nontrivial (like <a
href="https://gitlab.com/dennistex/scrambledenvs">randomizing
hints</a>), just use another language to compile into an intermediate
TeX build file before compiling it into a PDF.<a href="#fn2"
class="footnote-ref" id="fnref2" role="doc-noteref"><sup>2</sup></a></p>
<p>Just keep this in mind as I go through some of these concepts. A lot
of these design choices may not make sense at first, but they will
become more clear through the context of "computers used to be really
weak."</p>
<h2 id="compiler">Compiler</h2>
<ul>
<li><p>You write <strong>plain text</strong> in a file that follows the
LaTeX specifications. Specifications are basically rules you have to
follow in order for your code (yes, LaTeX <em>is</em> code) to be
considered "correct."</p></li>
<li><p>The <strong>compiler</strong> is a tool that interprets your
plain text according to the rules of LaTeX and generates a PDF for you.
The thing about using a tool is <em>you have to have it in the first
place</em>. There's no point following the instructions for, say, how to
use a screwdriver if you don't have one, so get a goddamn
screwdriver!!</p></li>
</ul>
<p>The compiler does not care what you used to edit the plain text. It
just cares what's <em>in</em> the text file.</p>
<p>By the way, the LaTeX language is not unique to online editors like
Overleaf.<a href="#fn3" class="footnote-ref" id="fnref3"
role="doc-noteref"><sup>3</sup></a> That would be like thinking that
just because you bought an all-in-one desktop where the monitor is tied
with the desktop, the monitor and the desktop are the same thing, or you
have to buy them together. The worst conclusion to come to would be that
all-in-ones are the only type of desktop.<a href="#fn4"
class="footnote-ref" id="fnref4" role="doc-noteref"><sup>4</sup></a></p>
<p>There are a ton of text editors, but not that many compilers. The
most popular are pdfLaTeX, XeTeX, LuaTeX, and ConTeXt. (It's mostly
pdfLaTeX.) Compilers are usually shipped with a distribution, more on
that below.</p>
<h2 id="tex-distributions">TeX Distributions</h2>
<p>A TeX distribution is a mechanism for distributing a compiler and a
set of tools to help it. Typically this "set of tools" is a standardized
set of classes, packages, as well as compilers (like pdflatex, XeTeX,
LuaTeX). If you are using TeX Live, this "standardized set" is <a
href="https://ctan.org/?lang=en">CTAN</a>.<a href="#fn5"
class="footnote-ref" id="fnref5" role="doc-noteref"><sup>5</sup></a>
MikTeX also uses CTAN, but supposedly updates are slower since there's a
single maintainer. This doesn't matter unless you want a bleeding edge
TeX install.</p>
<p>It's important to make the following observation: when you are
importing a document class or package, <strong>you're importing a .cls
or .sty file</strong>. No matter <em>what</em> you put in there. For
instance, calling <code>\documentclass{article}</code> inserts
<code>article.cls</code> into your document. It's just that you haven't
ever looked at <code>article.cls</code> before. If you want to find it,
run <code>kpsewhich article.cls</code>.<a href="#fn6"
class="footnote-ref" id="fnref6" role="doc-noteref"><sup>6</sup></a></p>
<p>Every software distribution comes with a package manager, and TeX
Live/MiKTeX are no exception. Every TeX distribution worth using has
<code>tlmgr</code> as their package manager. For those of you coming
from a Linux background, this terminology will be familiar. Otherwise,
here is a quick explanation of what a package manager is: it is a
standardized interface which helps you install a set of software from a
repository. So instead of installing software through an installer, each
of which has its own idiosyncrasies, you run
<code>tlmgr install PACKAGE</code> and the command automatically takes
care of extraction and installation for you.</p>
<h2 id="build-process">Build Process</h2>
<p>If you want to do something non-trivial with TeX, I weakly recommend
you refrain from using the <code>latexmk</code> tool until you
understand why it would be helpful.<a href="#fn7" class="footnote-ref"
id="fnref7" role="doc-noteref"><sup>7</sup></a> Otherwise this will make
no sense because "whee latexmk compiles <em>exactly</em> the number of
times I need it to."<a href="#fn8" class="footnote-ref" id="fnref8"
role="doc-noteref"><sup>8</sup></a></p>
<p>Anyone who's run <code>pdflatex</code> instead of
<code>latexmk</code> will have noticed a couple of things.</p>
<ul>
<li>If the document has any cross-references (toc, bibliography, etc) it
has to be compiled twice.</li>
<li>If the document has asymptote, you must run
<code>pdflatex; asy *.asy; pdflatex</code>. (Well, okay, this is a bit
simplified since it's <code>asy -f pdf *.asy</code> on any Unix-based
operating system, but <code>asy *.asy</code> should work on
Windows.)</li>
</ul>
<p>This is because LaTeX code executes sequentially, period. You can't
just go back and scan every line whenever you have a reference in the
code. This isn't a batch script, people! (And what happens when the user
makes an error and the reference is undefined?)</p>
<p>Why is this an issue? Well, let's consider the following example
(fill in the rest of the document in your head):</p>
<div class="sourceCode" id="cb1"><pre
class="sourceCode tex"><code class="sourceCode latex"><span id="cb1-1"><a href="#cb1-1" aria-hidden="true" tabindex="-1"></a><span class="fu">\tableofcontents</span></span>
<span id="cb1-2"><a href="#cb1-2" aria-hidden="true" tabindex="-1"></a><span class="kw">\section</span>{Insert Title Here}</span></code></pre></div>
<p>Clearly <code>\tableofcontents</code> must run before
<code>\section</code>. But we have a problem: How is
<code>\tableofcontents</code> supposed to know what comes after it? It's
not like it can look ahead. Well, you could make it, but it would end up
being slow, annoying, and buggy.</p>
<p>So to work around this, whenever <code>pdflatex</code> is run, it
creates some auxiliary files like <code>.aux</code> and
<code>.toc</code> files. Inside these auxiliary files is information
about the last run of <code>pdflatex</code>, so when you run it next
time, it reads the auxiliary files and can generate references
correctly.</p>
<p>Keep in mind that <code>synctex</code> files are <em>not</em> part of
this, they just exist so you can navigate between PDF and code.</p>
<h2 id="tex-paths">TeX Paths</h2>
<p>There are seven directories which a TeX install writes to, we'll only
explain three of them:</p>
<ul>
<li>TEXDIR: Where the install is located</li>
<li>TEXMFLOCAL: Local files (packages, fonts, etc) that are available to
all users.</li>
<li>TEXMFSYSVAR</li>
<li>TEXMFSYSCONFIG</li>
<li>TEXMFVAR</li>
<li>TEXMFCONFIG</li>
<li>TEXMFHOME: Local files available only to the current user.</li>
</ul>
<p>Typically a TeX installation writes to your root directory, I think
this is kind of stupid if you're the only user running TeX on your
machine (or the only user on your machine, actually). If you put the TeX
tree inside your root directory, then you'll need root permissions to
run <code>tlmgr</code>. But the root user doesn't know what
<code>tlmgr</code> is because it's in your user PATH variable, and so
you then need to point it in the right place --- bah! Fortunately, it's
very easy to move a TeX install from root to HOME, you just need to
change your PATH variable after.</p>
<p>No matter where you install TeX Live, any personal packages or
classes you use should go into TEXMFHOME, period. A quick refresher:
TEXMFHOME is ~/texmf by default, you can change this in
<code>texmf.cnf</code> (run <code>kpsewhich texmf.cnf</code> to find it)
or you can run <code>export TEXMFHOME=</code> in your bashrc or whatever
shell you use.</p>
<h2 id="concluding-thoughts">Concluding Thoughts</h2>
<p>Hopefully this explains why TeX behaves on your system the way it
does. If you want to learn how TeX runs under the hood, <a
href="https://www.overleaf.com/learn/latex/How_TeX_macros_actually_work%3A_Part_1">Overleaf's
"How TeX macros actually work"</a> is really good. A lot of LaTeX's
implementation details depend on this, because TeX really does two
things uniquely:</p>
<ol type="1">
<li>It can typeset stuff nicely. (You probably already knew this.)</li>
<li>It uses category codes ("catcodes") to interpret TeX documents.</li>
</ol>
<p>Said article goes in depth about the second part. So far, I have yet
to find an accessible explanation on how TeX actually decides how to
typeset stuff, but I also haven't looked very hard.</p>
<section id="footnotes" class="footnotes footnotes-end-of-document"
role="doc-endnotes">
<hr />
<ol>
<li id="fn1"><p>On the bright side, the PDF size of a compiled document
is super small. Pretty much every PDF is reasonably under 512KB.<a
href="#fnref1" class="footnote-back" role="doc-backlink">↩︎</a></p></li>
<li id="fn2"><p>On second thought, <code>scrambledenvs</code> might have
been a smart thing to write in LaTeX. One, more people can use it ---
it's included in default in TeX Live 2021 (which is why you should
install vanilla ;) and two, you could either choose to write the
environment's contents to a file anyway and them randomise them outside
of LaTeX and make sure that refs are generated correctly or just do
everything in LaTeX. Using some other language in tandem might actually
be harder, I don't know for sure though since I never tried.<a
href="#fnref2" class="footnote-back" role="doc-backlink">↩︎</a></p></li>
<li id="fn3"><p>I say this because my school math team wanted to
continue using Overleaf because "the syntax is easy to understand." When
you don't understand what pieces are independent from each other, you
don't just make bad choices, you straight up don't understand what the
choices <em>are</em>.<a href="#fnref3" class="footnote-back"
role="doc-backlink">↩︎</a></p></li>
<li id="fn4"><p>Yes, all-in-one desktops might be more convenient in
that they take up less room. But they are less convenient because in
exchange for an upfront investment of time/money, you suffer from having
a computer with shitty specs. The same goes for using Overleaf instead
of installing a TeX distribution (more on what a TeX distribution is
later).<a href="#fnref4" class="footnote-back"
role="doc-backlink">↩︎</a></p></li>
<li id="fn5"><p>Fun fact: I actually have <a
href="https://ctan.org/author/chen-d">packages on CTAN</a>.<a
href="#fnref5" class="footnote-back" role="doc-backlink">↩︎</a></p></li>
<li id="fn6"><p>You'll notice the source code for
<code>article.cls</code> isn't very readable. That's because
<code>article.cls</code> is a compiled file, and the source is a
<code>.dtx</code> file. Typically maintainers use <code>.dtx</code>
files because they can generate multiple files from the same source and
the documentation is coupled with the source code. This is called <a
href="https://en.wikipedia.org/wiki/Literate_programming">literate
programming</a>. It is CTAN standard to use dtx files, but you do not
have to.<a href="#fnref6" class="footnote-back"
role="doc-backlink">↩︎</a></p></li>
<li id="fn7"><p>If you are using Windows this will sort of happen by
force. The OS is so shitty that you have no clue what is happening half
the time and using the terminal to compile TeX is too scary. You'll
probably be doing one of two things:</p>
<p>--- Using the TeXWorks editor and pressing green buttons to run
<code>pdflatex, asy *.asy, pdflatex</code> every time. --- Using VSCode
and pressing a green button.</p>
<p>You will end up running <code>pdflatex</code> twice enough times to
pick up on what LaTeX is really doing.<a href="#fnref7"
class="footnote-back" role="doc-backlink">↩︎</a></p></li>
<li id="fn8"><p>You might reasonably ask, "Well shouldn't running the
compile command <em>once</em> always be enough to compile it?" This is
one of the situations where you have to consider the context in which
TeX was made. However, some recent TeX-based macro packages like ConTeXt
(I believe) have made it so that you do not need to compile multiple
times.<a href="#fnref8" class="footnote-back"
role="doc-backlink">↩︎</a></p></li>
</ol>
</section>]]></description>
	<pubDate>23 Nov 2021</pubDate>
</item>
<item>
	<title>puzz.dennisc.net is out</title>
	<link>https://dennisc.net/writing/tech/puzz-dennisc.md</link>
	<description><![CDATA[<p>My old puzzle page's organization didn't make
much sense. It was separated into puzzle genres, like Sudoku, Star
Battle, and Suguru. If you know anything about my puzzles, you'll know
that almost every puzzle I've published is a Sudoku in some shape or
form. So in effect, all of my non-sudoku puzzles get buried, which makes
no sense to do.</p>
<p>But at the same time, I still want to be able to filter for Sugurus.
And this idea of filters, along with the bloated size of dennisc.net and
astronomical build times, were the impetus for me creating a separate
puzzle website. I would also frequently find myself copy and pasting the
previous puzzle Markdown into the next puzzle, which seemed like a
really bad idea when I could just generate the entire puzzle page from a
series of configuration files.</p>
<p>So here's how my new puzzle page works, more or less:</p>
<ul>
<li>Statically generate index.html and copy over all
stylesheets/images.</li>
<li>When a query string is sent, server-side generate the website
instead. This is because there are so many combinations of query strings
and I update the website often enough (i.e. I publish puzzles often
enough) that pre-generating them all just doesn't make sense.</li>
</ul>
<p>What's more, anyone can use and adapt my code for their own purposes.
<a href="https://gitlab.com/chennisden/puzzlesite">The source code is
public</a> and it is MIT licensed. It's not quite the best thing for
people inexperienced with computers to host (it wasn't written to be),
but if you have a domain and want to host your own puzzle website on my
server feel free to ask.</p>
<p>This was quite the simple project. It took me just over a day's worth
of work from conceptualization to actually finishing, which is nice when
I have a billion projects that are just <em>almost</em> done. It did
take a bit of work to transfer all my puzzles over, but a couple of
quick Rust scripts saved me a lot of work. <strong>Disclaimer: all these
Rust scripts are shitty code and you should not try to emulate
it.</strong> Like, there are very obvious mistakes/bad things I'm doing
that I just never bothered to fix, since I'd only use these scripts for
one very specific migration.</p>
<h2 id="directory-creationimage-transferring-script">Directory
creation/image transferring script</h2>
<p>I ran this and then replaced <code>.png</code> with
<code>.svg</code>. Since all my images were either PNG or SVG files,
that copied all of them over.</p>
<div class="sourceCode" id="cb1"><pre class="sourceCode rs"><code class="sourceCode rust"><span id="cb1-1"><a href="#cb1-1" aria-hidden="true" tabindex="-1"></a><span class="kw">use</span> <span class="pp">std::</span>fs<span class="op">;</span></span>
<span id="cb1-2"><a href="#cb1-2" aria-hidden="true" tabindex="-1"></a><span class="kw">use</span> <span class="pp">std::path::</span><span class="dt">Path</span><span class="op">;</span></span>
<span id="cb1-3"><a href="#cb1-3" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb1-4"><a href="#cb1-4" aria-hidden="true" tabindex="-1"></a><span class="kw">fn</span> main() <span class="op">-&gt;</span> <span class="dt">Result</span><span class="op">&lt;</span>()<span class="op">,</span> <span class="dt">Box</span><span class="op">&lt;</span><span class="kw">dyn</span> <span class="pp">std::error::</span><span class="bu">Error</span><span class="op">&gt;&gt;</span> <span class="op">{</span></span>
<span id="cb1-5"><a href="#cb1-5" aria-hidden="true" tabindex="-1"></a>    <span class="cf">for</span> file <span class="kw">in</span> <span class="pp">fs::</span>read_dir(<span class="st">&quot;/home/dennisc/dennisc.net/content/puzzles&quot;</span>)<span class="op">?</span> <span class="op">{</span></span>
<span id="cb1-6"><a href="#cb1-6" aria-hidden="true" tabindex="-1"></a>        <span class="kw">let</span> path <span class="op">=</span> file<span class="op">.</span>as_ref()<span class="op">.</span>unwrap()<span class="op">.</span>path()<span class="op">;</span></span>
<span id="cb1-7"><a href="#cb1-7" aria-hidden="true" tabindex="-1"></a>        <span class="cf">if</span> path<span class="op">.</span>is_dir() <span class="op">{</span></span>
<span id="cb1-8"><a href="#cb1-8" aria-hidden="true" tabindex="-1"></a>            <span class="kw">let</span> name <span class="op">=</span> path<span class="op">.</span>file_name()<span class="op">.</span>unwrap()<span class="op">;</span></span>
<span id="cb1-9"><a href="#cb1-9" aria-hidden="true" tabindex="-1"></a>            <span class="pp">fs::</span>create_dir_all(<span class="dt">Path</span><span class="pp">::</span>new(<span class="st">&quot;/home/dennisc/puzz-dennisc/puzzles&quot;</span>)<span class="op">.</span>join(name))<span class="op">.</span>unwrap()<span class="op">;</span></span>
<span id="cb1-10"><a href="#cb1-10" aria-hidden="true" tabindex="-1"></a>            <span class="pp">fs::</span>copy(path<span class="op">.</span>join(<span class="st">&quot;puzzle.png&quot;</span>)<span class="op">,</span> <span class="pp">format!</span>(<span class="st">&quot;/home/dennisc/puzz-dennisc/puzzles/{}/puzzle.png&quot;</span><span class="op">,</span> name<span class="op">.</span>to_str()<span class="op">.</span>unwrap()))<span class="op">;</span></span>
<span id="cb1-11"><a href="#cb1-11" aria-hidden="true" tabindex="-1"></a>        <span class="op">}</span></span>
<span id="cb1-12"><a href="#cb1-12" aria-hidden="true" tabindex="-1"></a>    <span class="op">}</span></span>
<span id="cb1-13"><a href="#cb1-13" aria-hidden="true" tabindex="-1"></a>    <span class="cn">Ok</span>(())</span>
<span id="cb1-14"><a href="#cb1-14" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code></pre></div>
<h2 id="link-formatting-script">Link formatting script</h2>
<p>Previously I had <code>.url</code> files (I made up the extension, it
doesn't really mean anything) like <code>ctc.url</code>. I wanted to
collect them all and copy the TOML-formatted <code>[links]</code> item
instead of doing it by hand.</p>
<div class="sourceCode" id="cb2"><pre class="sourceCode rs"><code class="sourceCode rust"><span id="cb2-1"><a href="#cb2-1" aria-hidden="true" tabindex="-1"></a><span class="kw">use</span> <span class="pp">std::path::</span><span class="dt">Path</span><span class="op">;</span></span>
<span id="cb2-2"><a href="#cb2-2" aria-hidden="true" tabindex="-1"></a><span class="kw">use</span> <span class="pp">std::fs::</span>read_to_string<span class="op">;</span></span>
<span id="cb2-3"><a href="#cb2-3" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb2-4"><a href="#cb2-4" aria-hidden="true" tabindex="-1"></a><span class="kw">fn</span> main() <span class="op">{</span></span>
<span id="cb2-5"><a href="#cb2-5" aria-hidden="true" tabindex="-1"></a>    <span class="kw">let</span> ctc <span class="op">=</span> <span class="cf">if</span> <span class="dt">Path</span><span class="pp">::</span>new(<span class="st">&quot;ctc.url&quot;</span>)<span class="op">.</span>exists() <span class="op">{</span></span>
<span id="cb2-6"><a href="#cb2-6" aria-hidden="true" tabindex="-1"></a>        <span class="dt">Path</span><span class="pp">::</span>new(<span class="st">&quot;ctc.url&quot;</span>)</span>
<span id="cb2-7"><a href="#cb2-7" aria-hidden="true" tabindex="-1"></a>    <span class="op">}</span> <span class="cf">else</span> <span class="op">{</span></span>
<span id="cb2-8"><a href="#cb2-8" aria-hidden="true" tabindex="-1"></a>        <span class="dt">Path</span><span class="pp">::</span>new(<span class="st">&quot;sudokupad.url&quot;</span>)</span>
<span id="cb2-9"><a href="#cb2-9" aria-hidden="true" tabindex="-1"></a>    <span class="op">};</span></span>
<span id="cb2-10"><a href="#cb2-10" aria-hidden="true" tabindex="-1"></a>    <span class="kw">let</span> fp <span class="op">=</span> <span class="dt">Path</span><span class="pp">::</span>new(<span class="st">&quot;f-puzzles.url&quot;</span>)<span class="op">;</span></span>
<span id="cb2-11"><a href="#cb2-11" aria-hidden="true" tabindex="-1"></a>    <span class="kw">let</span> penpa <span class="op">=</span> <span class="dt">Path</span><span class="pp">::</span>new(<span class="st">&quot;penpa.url&quot;</span>)<span class="op">;</span></span>
<span id="cb2-12"><a href="#cb2-12" aria-hidden="true" tabindex="-1"></a>    <span class="kw">let</span> octopuzzles <span class="op">=</span> <span class="dt">Path</span><span class="pp">::</span>new(<span class="st">&quot;octopuzzles.url&quot;</span>)<span class="op">;</span></span>
<span id="cb2-13"><a href="#cb2-13" aria-hidden="true" tabindex="-1"></a>    <span class="pp">println!</span>(<span class="st">&quot;[links]&quot;</span>)<span class="op">;</span></span>
<span id="cb2-14"><a href="#cb2-14" aria-hidden="true" tabindex="-1"></a>    <span class="pp">println!</span>(<span class="st">&quot;ctc = </span><span class="sc">\&quot;</span><span class="st">{}</span><span class="sc">\&quot;</span><span class="st">&quot;</span><span class="op">,</span> read_to_string(ctc)<span class="op">.</span>unwrap()<span class="op">.</span>trim())<span class="op">;</span></span>
<span id="cb2-15"><a href="#cb2-15" aria-hidden="true" tabindex="-1"></a>    <span class="cf">if</span> <span class="kw">let</span> <span class="cn">Ok</span>(s) <span class="op">=</span> read_to_string(octopuzzles) <span class="op">{</span></span>
<span id="cb2-16"><a href="#cb2-16" aria-hidden="true" tabindex="-1"></a>        <span class="pp">println!</span>(<span class="st">&quot;octopuzzles = </span><span class="sc">\&quot;</span><span class="st">{}</span><span class="sc">\&quot;</span><span class="st">&quot;</span><span class="op">,</span> s<span class="op">.</span>trim())<span class="op">;</span></span>
<span id="cb2-17"><a href="#cb2-17" aria-hidden="true" tabindex="-1"></a>    <span class="op">}</span></span>
<span id="cb2-18"><a href="#cb2-18" aria-hidden="true" tabindex="-1"></a>    <span class="cf">if</span> <span class="kw">let</span> <span class="cn">Ok</span>(s) <span class="op">=</span> read_to_string(penpa) <span class="op">{</span></span>
<span id="cb2-19"><a href="#cb2-19" aria-hidden="true" tabindex="-1"></a>        <span class="pp">println!</span>(<span class="st">&quot;penpa = </span><span class="sc">\&quot;</span><span class="st">{}</span><span class="sc">\&quot;</span><span class="st">&quot;</span><span class="op">,</span> s<span class="op">.</span>trim())<span class="op">;</span></span>
<span id="cb2-20"><a href="#cb2-20" aria-hidden="true" tabindex="-1"></a>    <span class="op">}</span></span>
<span id="cb2-21"><a href="#cb2-21" aria-hidden="true" tabindex="-1"></a>    <span class="cf">if</span> <span class="kw">let</span> <span class="cn">Ok</span>(s) <span class="op">=</span> read_to_string(fp) <span class="op">{</span></span>
<span id="cb2-22"><a href="#cb2-22" aria-hidden="true" tabindex="-1"></a>        <span class="pp">println!</span>(<span class="st">&quot;fpuzzles = </span><span class="sc">\&quot;</span><span class="st">{}</span><span class="sc">\&quot;</span><span class="st">&quot;</span><span class="op">,</span> s<span class="op">.</span>trim())<span class="op">;</span></span>
<span id="cb2-23"><a href="#cb2-23" aria-hidden="true" tabindex="-1"></a>    <span class="op">}</span></span>
<span id="cb2-24"><a href="#cb2-24" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code></pre></div>
<p>You'll notice that this script doesn't work if I don't have a CTC url
(which I didn't sometimes), but those were few enough that I didn't feel
like going back and fixing it.</p>]]></description>
	<pubDate>24 May 2023</pubDate>
</item>
<item>
	<title>Design for a small-scale self-hosted Git service</title>
	<link>https://dennisc.net/writing/tech/glee-design.md</link>
	<description><![CDATA[<p>In many ways this is a sort of wishlist for a
self-hosting Git solution that is much more lightweight than the big
players (GitLab etc). I love GitLab and will continue to use it to host
my important repos + stuff I expect to collaborate on, but there are
many features (PRs + issues + very fancy web view) that I just don't
need for, say, private scripts.<a href="#fn1" class="footnote-ref"
id="fnref1" role="doc-noteref"><sup>1</sup></a> Even though I am
referring to this hypothetical Git service as if I <em>plan</em> to make
it, no promises that I actually do.<a href="#fn2" class="footnote-ref"
id="fnref2" role="doc-noteref"><sup>2</sup></a></p>
<p>Additionally, I don't want private scripts under a centralized
hosting service out of my control. It's not that I'm paranoid about
having my private scripts on GitLab, but it just doesn't feel right.<a
href="#fn3" class="footnote-ref" id="fnref3"
role="doc-noteref"><sup>3</sup></a></p>
<p>Also, GitLab's namespaces are quite dry (at least GitLab SAAS). One
particular point of annoyance is that every user has a namespace. I was
very bothered that <a
href="https://gitlab.com/gitlab-org/gitlab/-/issues/19944">users could
not have subgroups</a>, but that really disguised the fundamental
problem I had with GitLab users: <strong>users should not have a
namespace by default</strong>. It's so clunky that signing up users,
<em>which are used for access control</em>, also reserves a namespace!
What if I'm just using GitLab to help maintain X software, or what if I
sign up and never use the service, period? There are a lot of
group/organization names (GitHub and GitLab respectively) that I wanted
to use that are some person's username. Said person invariably has made
0 commits in the history of ever, and the namespace is so much drier for
that. Boo!</p>
<p>OK, so that calls for a private Git server. But most of the solutions
do not have "subgroups" like GitLab, which is a total deal-breaker for
me, and GitLab is way overkill for a private Git server that literally
only exists to sync files between my desktop and laptop. But at the same
time, I have no plan of SSHing into the server and pull/pushing to repo
that way. Particularly, I want to set up API routes so that other people
can see some repos I decide to make public, and so they can create/push
to new repos as well.<a href="#fn4" class="footnote-ref" id="fnref4"
role="doc-noteref"><sup>4</sup></a></p>
<p>As far as I know there is no Git hosting service that does all of
this for you. These are my plans for building one. Tentative name:
Glee.</p>
<h2 id="filesystem-and-permissions">Filesystem and permissions</h2>
<h3 id="overview">Overview</h3>
<p>Let me tell you why I like GitLab's subgroup functionality so much:
It's like a filesystem. That's it, that's all I want from a Git hosting
service. As far as I know only GitLab supplies that: nesting with a
depth of <span class="math inline"> &gt; 1</span>. And that's great, but
the number one complaint I have about GitLab (sub)groups is that
<em>permissions are inherited in an opaque manner</em>. Projects inherit
permissions from their group somehow --- is it on creation? Is it
persistent? I have no clue, even as I'm writing this, and I care so
little about finding out that <em>I'd rather write my own Git hosting
service</em>.</p>
<p>Permissions should be handled according to the following two
rules:</p>
<ol type="1">
<li>The most specific permission option should be used.</li>
<li>If no permission is set, it "looks up" for the default option.
Here's an example. Say that we have project C, and its path is A/B/C (so
A and B are directories, C is a repo). Let us say that for some
permission P, a directory/repo can either have <code>yes</code>,
<code>no</code>, or <code>inherit</code>. So if A has <code>yes</code>
and B/C are both <code>inherit</code>, then C inherits the status from
B, which inherits the status from A, which has permission P. Therefore,
C also has it. But if A has <code>yes</code> and B has <code>no</code>,
then C inherits B which explicitly does not have permission P.
Therefore, C does not have permission P.</li>
</ol>
<p>That's how permissions should work: keep going up until you reach a
directory with the permission explicitly set (i.e. not
<code>inherit</code>). Of course, if it's just <code>inherit</code> all
the way up, there should be a default value. It doesn't particularly
matter what it is, just as long as it's sensible and made clear.</p>
<h3 id="users">Users</h3>
<p>This is the design for a a <em>small-scale</em> Git server, so every
user should be trusted. Hosting services like GitHub and Gitlab have
intricate user permissions which I have used exactly zero times. What I
am about to describe <strong>does not scale</strong> for large
enterprises, because it is not supposed to.</p>
<p>There are three levels of permissions: none (i.e. you can perform
this action without being logged in --- think public repositories),
user, and admin. For any particular repository, you can set
<code>view</code> to <code>none</code>, <code>user</code>, or
<code>admin</code>, and you can set <code>push</code> to
<code>user</code> or <code>admin</code>. Obviously users inherit the
permissions of all visitors, and admins inherit the permissions of
users.</p>
<p>The reason GitHub/Lab needs access control is because anyone can sign
up for an account. Instead, I think it's better to authenticate each
user during signup. Here I think an <span
class="math inline"><em>O</em>(<em>u</em>)</span> cost (<span
class="math inline"><em>u</em></span> is number of users) is better than
an <span class="math inline"><em>O</em>(<em>p</em>)</span> cost (<span
class="math inline"><em>p</em></span> is number of projects). This is
because I think project-side operations will be far greater than the
number of users.</p>
<p>There are a number of ways you can deal with verifying user accounts.
One way is just by allowing anyone to make an account (as in GitHub,
GitLab, or indeed, any popular public-facing website), and only
verifying accounts that come from trusted maintainers. This can get kind
of annoying because you have to drudge through potential troll/spam/test
accounts<a href="#fn5" class="footnote-ref" id="fnref5"
role="doc-noteref"><sup>5</sup></a> to verify the one or two new
legitimate users.</p>
<p>The only viable solution that I see is requiring admin intervention
to create an account. On the <code>mathadvance.org</code> mail server,
because we use the Mailcow suite, the admin has to directly make a user
account. I kind of hate this line of approach, because it puts the
impetus on the user to login to their account and change their password,
and if they don't then sucks to be you. Forced password resets are sort
of a bandaid on this, but the consequences of a user not following
through and using their account should not be that a garbage account
gets created.</p>
<p>So here is my proposed solution. The signup form has these five
fields:</p>
<div class="sourceCode" id="cb1"><pre class="sourceCode md"><code class="sourceCode markdown"><span id="cb1-1"><a href="#cb1-1" aria-hidden="true" tabindex="-1"></a>Email</span>
<span id="cb1-2"><a href="#cb1-2" aria-hidden="true" tabindex="-1"></a>Real Name</span>
<span id="cb1-3"><a href="#cb1-3" aria-hidden="true" tabindex="-1"></a>Password</span>
<span id="cb1-4"><a href="#cb1-4" aria-hidden="true" tabindex="-1"></a>Confirm Password</span>
<span id="cb1-5"><a href="#cb1-5" aria-hidden="true" tabindex="-1"></a>Signup Code</span></code></pre></div>
<p>All of the fields are self-explanatory except Signup Code. The signup
code is a <strong>one-use</strong> temporary code that an admin
generates that expires in, say, 48 hours (which is perfectly reasonable
for any actual contributor to sign up in). The idea is that if you want
someone to make an account, you give them a signup code. That way, if
they don't follow through, your temporary code expires in 48 hours
anyway and there is no harm no foul.</p>
<p>I'm thinking of storing signup codes in <code>/tmp</code>, so they
get cleaned up, and put a timestamp along with the code in the file. So
something like this:</p>
<div class="sourceCode" id="cb2"><pre class="sourceCode md"><code class="sourceCode markdown"><span id="cb2-1"><a href="#cb2-1" aria-hidden="true" tabindex="-1"></a>bqIApG2okZH2NrAJVWKVQkQpvSIwV86L</span>
<span id="cb2-2"><a href="#cb2-2" aria-hidden="true" tabindex="-1"></a>1646357721036</span></code></pre></div>
<p>Where the first line is the token, and the second line is the Unix
timestamp.</p>
<h3 id="directories">Directories</h3>
<p>The project will follow XDG specifications, so there will be two
directories where stuff<a href="#fn6" class="footnote-ref" id="fnref6"
role="doc-noteref"><sup>6</sup></a> is stored. We have
<code>$XDG_DATA_HOME/glee</code> for data generated by interfacing with
Glee and <code>$XDG_CONFIG/glee</code> for manually edited config
files.</p>
<p>Here is how <code>$XDG_CONFIG/glee</code> is going to look:</p>
<div class="sourceCode" id="cb3"><pre class="sourceCode md"><code class="sourceCode markdown"><span id="cb3-1"><a href="#cb3-1" aria-hidden="true" tabindex="-1"></a>repos/</span>
<span id="cb3-2"><a href="#cb3-2" aria-hidden="true" tabindex="-1"></a>test-repo/</span>
<span id="cb3-3"><a href="#cb3-3" aria-hidden="true" tabindex="-1"></a>actual_file.txt</span>
<span id="cb3-4"><a href="#cb3-4" aria-hidden="true" tabindex="-1"></a>.git/</span>
<span id="cb3-5"><a href="#cb3-5" aria-hidden="true" tabindex="-1"></a>dir/</span>
<span id="cb3-6"><a href="#cb3-6" aria-hidden="true" tabindex="-1"></a>nested-repo/</span>
<span id="cb3-7"><a href="#cb3-7" aria-hidden="true" tabindex="-1"></a>actual_file.txt</span>
<span id="cb3-8"><a href="#cb3-8" aria-hidden="true" tabindex="-1"></a>.git/</span>
<span id="cb3-9"><a href="#cb3-9" aria-hidden="true" tabindex="-1"></a>users/</span>
<span id="cb3-10"><a href="#cb3-10" aria-hidden="true" tabindex="-1"></a>dennisc</span>
<span id="cb3-11"><a href="#cb3-11" aria-hidden="true" tabindex="-1"></a>repo-data.json</span>
<span id="cb3-12"><a href="#cb3-12" aria-hidden="true" tabindex="-1"></a>redirects.json</span></code></pre></div>
<p>Here is what <code>repo-data.json</code> contains.<a href="#fn7"
class="footnote-ref" id="fnref7" role="doc-noteref"><sup>7</sup></a></p>
<div class="sourceCode" id="cb4"><pre
class="sourceCode json"><code class="sourceCode json"><span id="cb4-1"><a href="#cb4-1" aria-hidden="true" tabindex="-1"></a><span class="fu">{</span></span>
<span id="cb4-2"><a href="#cb4-2" aria-hidden="true" tabindex="-1"></a>    <span class="dt">&quot;test-repo&quot;</span><span class="fu">:</span> <span class="fu">{</span></span>
<span id="cb4-3"><a href="#cb4-3" aria-hidden="true" tabindex="-1"></a>        <span class="dt">&quot;perms&quot;</span><span class="fu">:</span> <span class="fu">{</span></span>
<span id="cb4-4"><a href="#cb4-4" aria-hidden="true" tabindex="-1"></a>            <span class="dt">&quot;view&quot;</span><span class="fu">:</span> <span class="st">&quot;user&quot;</span><span class="fu">,</span></span>
<span id="cb4-5"><a href="#cb4-5" aria-hidden="true" tabindex="-1"></a>            <span class="dt">&quot;push&quot;</span><span class="fu">:</span> <span class="st">&quot;admin&quot;</span><span class="fu">,</span></span>
<span id="cb4-6"><a href="#cb4-6" aria-hidden="true" tabindex="-1"></a>        <span class="fu">},</span></span>
<span id="cb4-7"><a href="#cb4-7" aria-hidden="true" tabindex="-1"></a>        <span class="dt">&quot;history&quot;</span><span class="fu">:</span> <span class="ot">[</span><span class="st">&quot;dir/test-repo&quot;</span><span class="ot">]</span></span>
<span id="cb4-8"><a href="#cb4-8" aria-hidden="true" tabindex="-1"></a>    <span class="fu">},</span></span>
<span id="cb4-9"><a href="#cb4-9" aria-hidden="true" tabindex="-1"></a>    <span class="dt">&quot;dir&quot;</span><span class="fu">:</span> <span class="fu">{</span></span>
<span id="cb4-10"><a href="#cb4-10" aria-hidden="true" tabindex="-1"></a>        <span class="dt">&quot;perms&quot;</span><span class="fu">:</span> <span class="fu">{</span></span>
<span id="cb4-11"><a href="#cb4-11" aria-hidden="true" tabindex="-1"></a>            <span class="dt">&quot;view&quot;</span><span class="fu">:</span> <span class="st">&quot;any&quot;</span><span class="fu">,</span></span>
<span id="cb4-12"><a href="#cb4-12" aria-hidden="true" tabindex="-1"></a>            <span class="dt">&quot;push&quot;</span><span class="fu">:</span> <span class="st">&quot;admin&quot;</span><span class="fu">,</span></span>
<span id="cb4-13"><a href="#cb4-13" aria-hidden="true" tabindex="-1"></a>        <span class="fu">},</span></span>
<span id="cb4-14"><a href="#cb4-14" aria-hidden="true" tabindex="-1"></a>        <span class="dt">&quot;history&quot;</span><span class="fu">:</span> <span class="ot">[]</span><span class="fu">,</span></span>
<span id="cb4-15"><a href="#cb4-15" aria-hidden="true" tabindex="-1"></a>        <span class="dt">&quot;subpaths&quot;</span><span class="fu">:</span> <span class="fu">{</span></span>
<span id="cb4-16"><a href="#cb4-16" aria-hidden="true" tabindex="-1"></a>            <span class="dt">&quot;nested-repo&quot;</span><span class="fu">:</span> <span class="fu">{</span></span>
<span id="cb4-17"><a href="#cb4-17" aria-hidden="true" tabindex="-1"></a>                <span class="dt">&quot;perms&quot;</span><span class="fu">:</span> <span class="fu">{</span></span>
<span id="cb4-18"><a href="#cb4-18" aria-hidden="true" tabindex="-1"></a>                    <span class="dt">&quot;view&quot;</span><span class="fu">:</span> <span class="st">&quot;user&quot;</span></span>
<span id="cb4-19"><a href="#cb4-19" aria-hidden="true" tabindex="-1"></a>                    <span class="st">&quot;push&quot;</span><span class="er">:</span> <span class="st">&quot;default&quot;</span></span>
<span id="cb4-20"><a href="#cb4-20" aria-hidden="true" tabindex="-1"></a>                <span class="fu">}</span></span>
<span id="cb4-21"><a href="#cb4-21" aria-hidden="true" tabindex="-1"></a>            <span class="fu">}</span></span>
<span id="cb4-22"><a href="#cb4-22" aria-hidden="true" tabindex="-1"></a>        <span class="fu">}</span></span>
<span id="cb4-23"><a href="#cb4-23" aria-hidden="true" tabindex="-1"></a>    <span class="fu">}</span></span>
<span id="cb4-24"><a href="#cb4-24" aria-hidden="true" tabindex="-1"></a><span class="fu">}</span></span></code></pre></div>
<p>If an object (like the value for key <code>dir</code>) has field
<code>subpaths</code> then it is a directory, and its subpaths are
contained in the object value of key <code>subpaths</code>. Otherwise,
it is not a directory and is a repository. If you want, you can think of
the entire JSON object as listing the subpaths of
<code>$XDG_DATA_HOME/glee/repos</code>.</p>
<p>If the <code>repos</code> flag doesn't exist, then the path itself
must be a repo, and otherwise it is a directory.</p>
<p>The <code>history</code> array is the prior locations that a
particular path was in. If it proves to be too much an implementation
hassle/I decide it isn't useful (it's not how the webserver will
determine redirects), I will cut it out. In practice I think the hardest
thing to do will be to define a simple, intuitive spec around its
behavior when moving stuff. Should the history of
<code>nested-repo</code> be added to if <code>dir</code> is moved? I am
inclined to say yes.</p>
<p>The <code>redirects.json</code> file is for redirecting from old
paths to new paths, provided that the old path is not used by something
else. Here's an example that corresponds with the previous one:</p>
<div class="sourceCode" id="cb5"><pre
class="sourceCode json"><code class="sourceCode json"><span id="cb5-1"><a href="#cb5-1" aria-hidden="true" tabindex="-1"></a><span class="fu">{</span></span>
<span id="cb5-2"><a href="#cb5-2" aria-hidden="true" tabindex="-1"></a>    <span class="dt">&quot;dir/test-repo&quot;</span><span class="fu">:</span> <span class="st">&quot;test-repo&quot;</span></span>
<span id="cb5-3"><a href="#cb5-3" aria-hidden="true" tabindex="-1"></a><span class="fu">}</span></span></code></pre></div>
<p>Now if you move A to B to C, then you have two approaches: A
redirects to B which then redirects to C or just set the link from A to
go directly to C. Now, the former is more costly on all redirects, and
the latter happens only on renames. Since redirects will be far more
common than renames (we hope), then it is better to make renames more
expensive. <code>GET</code> is more common than
<code>PUT/POST</code>.</p>
<p>This is why a <code>history</code> array might be useful: look
through the history, edit anything that appears in
<code>redirects.json</code>. Then again, when moving B to C, you could
just look at all key-val pairs with value B, edit them to C. Since this
is a <em>small-scale</em> Git hosting service (why would perms be so
broad/users require admin auth otherwise?) I don't envision such a
distinction mattering at all, since moving is a fairly rare operation.
So here's where my head's at: no <code>history</code> array, when moving
A to B, scan all redirects with value A and edit the value to B.</p>
<p>Entries will be deleted if a new repo is created (here, at
<code>dir/test-repo</code>), or moved to the old location.</p>
<p>Obviously, redirects will respect view permissions (so the old URL
will just return "no repo" if it redirects to a private repo, i.e. one
you don't have permission to view).</p>
<p>The <code>users</code> directory contains user info, probably
username + hashed password + permissions. I don't think I know enough
about Git to say for sure what should be handled by Git/the OS and what
should be handled by the program.</p>
<p>As for <code>$XDG_CONFIG_HOME/glee</code>, here is what's going into
it:</p>
<div class="sourceCode" id="cb6"><pre class="sourceCode md"><code class="sourceCode markdown"><span id="cb6-1"><a href="#cb6-1" aria-hidden="true" tabindex="-1"></a>perms.toml</span></code></pre></div>
<p>(Yeah, that's it for now; I may add more conf files if the need
arises, but if we only need one conf file that's perfect.)</p>
<p>And inside perms.toml:</p>
<div class="sourceCode" id="cb7"><pre
class="sourceCode toml"><code class="sourceCode toml"><span id="cb7-1"><a href="#cb7-1" aria-hidden="true" tabindex="-1"></a><span class="co"># The list of all roles besides `any` and `admin`</span></span>
<span id="cb7-2"><a href="#cb7-2" aria-hidden="true" tabindex="-1"></a><span class="co"># The order that they are defined in is how permissions are inherited</span></span>
<span id="cb7-3"><a href="#cb7-3" aria-hidden="true" tabindex="-1"></a><span class="co"># For instance, if `roles = [&quot;user&quot;, &quot;mod&quot;]`, then `mod` inherits</span></span>
<span id="cb7-4"><a href="#cb7-4" aria-hidden="true" tabindex="-1"></a><span class="co"># the permissions of `user` since `mod` comes after `user`.</span></span>
<span id="cb7-5"><a href="#cb7-5" aria-hidden="true" tabindex="-1"></a><span class="dt">roles</span> <span class="op">=</span> <span class="op">[</span><span class="st">&quot;user&quot;</span><span class="op">]</span></span>
<span id="cb7-6"><a href="#cb7-6" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb7-7"><a href="#cb7-7" aria-hidden="true" tabindex="-1"></a><span class="co"># The default role given to a new account.</span></span>
<span id="cb7-8"><a href="#cb7-8" aria-hidden="true" tabindex="-1"></a><span class="dt">signup_role</span> <span class="op">=</span> <span class="st">&quot;user&quot;</span></span>
<span id="cb7-9"><a href="#cb7-9" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb7-10"><a href="#cb7-10" aria-hidden="true" tabindex="-1"></a><span class="co"># Permissions assigned to the &quot;default&quot; key</span></span>
<span id="cb7-11"><a href="#cb7-11" aria-hidden="true" tabindex="-1"></a><span class="kw">[defaults]</span></span>
<span id="cb7-12"><a href="#cb7-12" aria-hidden="true" tabindex="-1"></a><span class="dt">view</span> <span class="op">=</span> <span class="st">&quot;admin&quot;</span></span>
<span id="cb7-13"><a href="#cb7-13" aria-hidden="true" tabindex="-1"></a><span class="dt">push</span> <span class="op">=</span> <span class="st">&quot;admin&quot;</span></span></code></pre></div>
<p>You will notice that <code>any</code> is not in <code>roles</code>.
This is because <code>any</code> literally means anybody, signed in or
not. So it'll be a reserved keyword, something that you can't put in
<code>roles</code>. Same for <code>admin</code>, there are special
permissions only admins have (like granting signup tokens).</p>
<p>Even though I said before (and probably will say later) that having a
bajillion levels of access control is stupid, I think I'll be keeping
roles extensible. It's lightweight and totally opt-in (just don't add
more roles if you don't want more). Just because Glee isn't designed to
scale doesn't mean I won't nab an easy opportunity to make it scale
better.</p>
<p>You will notice that the default permissions are kind of
conservative. That's by design; you don't want to accidentally expose
private repos before you read up on how default permissions work.<a
href="#fn8" class="footnote-ref" id="fnref8"
role="doc-noteref"><sup>8</sup></a></p>
<p>By the way, config files are in TOML, data files in JSON.</p>
<h2 id="webview">Webview</h2>
<p>I want to make something simplistic like <a
href="https://git.kernel.org">the Linux Kernel's Git webview</a>.<a
href="#fn9" class="footnote-ref" id="fnref9"
role="doc-noteref"><sup>9</sup></a> Actually, maybe even moreso: I don't
think I need <code>about</code>, <code>diff</code>, or
<code>stats</code>, and I probably won't even implement syntax
highlighting --- this makes the link for raw content shorter, since
there only <em>is</em> raw content. Maybe I'll allow formatted view
through a URL param like</p>
<div class="sourceCode" id="cb8"><pre class="sourceCode md"><code class="sourceCode markdown"><span id="cb8-1"><a href="#cb8-1" aria-hidden="true" tabindex="-1"></a>https://glee.dennisc.net/glee.git/tree/.gitignore?fmt.</span></code></pre></div>
<p>and have links to files/directories direct to the <code>fmt</code>
version, plaintext otherwise.<a href="#fn10" class="footnote-ref"
id="fnref10" role="doc-noteref"><sup>10</sup></a></p>
<p>Oh and also, branches via</p>
<div class="sourceCode" id="cb10"><pre
class="sourceCode md"><code class="sourceCode markdown"><span id="cb10-1"><a href="#cb10-1" aria-hidden="true" tabindex="-1"></a>https://glee.dennisc.net/glee.git/tree/.gitignore?b=dev</span></code></pre></div>
<p>I have no intentions of totally eschewing JS, by the way. I am not
nearly as militant as some other people about "no JS!!" (Ad banners
annoy me as much as anyone else, but to extrapolate that with "all JS
bad" is a stretch. Though some contexts, particularly high-security
ones, are totally right about no JS.) If I can avoid JS though I will
make an effort to, particularly since I care about people using
command-line browsers. Currently I plan to have the API return a list of
directories and files inside a repo and format accordingly (this
includes links, with <code>fmt</code> if appropriate); same for non-repo
directories, and format with JS appropriately.</p>
<p>But GitWeb, CGit, etc are not really the sort of solution I want,
since as far as I know you can't login to the web interfaces. Which
sucks for collaboration, and also sucks for personal use because what's
the point of a webview if I can't even see all my projects, most of
which are supposed to be private?</p>
<h2 id="other-vcs">Other VCS</h2>
<p>I say this is a Git hosting service (and indeed that is what I will
support, first and foremost) but in principle <em>nothing</em> I have
said will not work with something like Pijul (which I have wanted to try
for quite a while!) So a Pijul integration is something I might want to
consider, depending on my experiences with it.</p>
<h2 id="the-caveat">The Caveat</h2>
<p>The thing about this sort of design is that it has so few details,
<em>someone</em> must have done it before me. Maybe I am wrong and
everyone else decided to use 7 levels of access control but only 1 level
of nesting (<code>username/repo</code> or <code>org/repo</code>). I hope
I am not, though, so if you know a self-hosted Git service that sounds
something like this, please let me know so I don't have to build it
myself. Because I would really rather not.</p>
<section id="footnotes" class="footnotes footnotes-end-of-document"
role="doc-endnotes">
<hr />
<ol>
<li id="fn1"><p>The scripts are two or three lines long. Setting
"secrets" for them would be incredibly stupid.<a href="#fnref1"
class="footnote-back" role="doc-backlink">↩︎</a></p></li>
<li id="fn2"><p>For one, I probably won't start this project until I
have finished the mapm gui, which I also want to write about.<a
href="#fnref2" class="footnote-back" role="doc-backlink">↩︎</a></p></li>
<li id="fn3"><p>It's not just that putting private scripts on GitLab
doesn't seem "private" enough, but also that it would pollute my GitLab
(which ideally should not have bad code, even on my side).<a
href="#fnref3" class="footnote-back" role="doc-backlink">↩︎</a></p></li>
<li id="fn4"><p>The drafts for MAST units, as well as MAST units I
haven't looked over yet, are also on a private GitLab group right now.
This is why I want to set up a rudimentary web view and collaboration
abilities, which would require managing users + permissions.<a
href="#fnref4" class="footnote-back" role="doc-backlink">↩︎</a></p></li>
<li id="fn5"><p>Trust me, even if you explicitly tell people
<strong>NOT</strong> to make testing accounts, they will anyway.
Goddamnit.<a href="#fnref5" class="footnote-back"
role="doc-backlink">↩︎</a></p></li>
<li id="fn6"><p>I use such a generic term because I have to.<a
href="#fnref6" class="footnote-back" role="doc-backlink">↩︎</a></p></li>
<li id="fn7"><p>My original design was putting a <code>.glee</code> file
in each repository. This does not work for the obvious reason that it
prevents you from making a file called <code>.glee</code>. The hassle to
validate this is honestly less than the hassle of just writing a parser
for <code>repo-data.json</code>.<a href="#fnref7" class="footnote-back"
role="doc-backlink">↩︎</a></p></li>
<li id="fn8"><p>Yes, all this stuff and more will go in the docs, I'm
not <em>that</em> terrible at programming. But also I totally know no
one will read the docs until they absolutely have to, and it's better if
"absolutely have to" means "no one can see my repositories by default,
how do I change this" versus "oh crap my super secret keys got
leaked".<a href="#fnref8" class="footnote-back"
role="doc-backlink">↩︎</a></p></li>
<li id="fn9"><p>It looks like this is a patched version of cgit.<a
href="#fnref9" class="footnote-back" role="doc-backlink">↩︎</a></p></li>
<li id="fn10"><p>A directory plaintext might look something like</p>
<div class="sourceCode" id="cb9"><pre class="sourceCode md"><code class="sourceCode markdown"><span id="cb9-1"><a href="#cb9-1" aria-hidden="true" tabindex="-1"></a>src/</span>
<span id="cb9-2"><a href="#cb9-2" aria-hidden="true" tabindex="-1"></a>Cargo.toml</span>
<span id="cb9-3"><a href="#cb9-3" aria-hidden="true" tabindex="-1"></a>.gitignore</span></code></pre></div>
<p>with trailing slashes to indicate directories.<a href="#fnref10"
class="footnote-back" role="doc-backlink">↩︎</a></p></li>
</ol>
</section>]]></description>
	<pubDate>4 Mar 2022</pubDate>
</item>
</channel></rss>
