<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:content="http://purl.org/rss/1.0/modules/content/"><channel><title>CS Theorems</title><link>https://cs.lozic.me/</link><description>Recent content on CS Theorems</description><generator>Hugo</generator><language>en-us</language><lastBuildDate>Fri, 06 Aug 2027 12:00:00 +0100</lastBuildDate><atom:link href="https://cs.lozic.me/index.xml" rel="self" type="application/rss+xml"/><item><title>The Myhill–Nerode Theorem</title><link>https://cs.lozic.me/posts/t040-the-myhill-nerode-theorem/</link><pubDate>Fri, 06 Aug 2027 12:00:00 +0100</pubDate><guid>https://cs.lozic.me/posts/t040-the-myhill-nerode-theorem/</guid><description>&lt;h2 id="symptom"&gt;Symptom&lt;/h2&gt;
&lt;p&gt;You need to prove a language is not regular. Everyone points you at the pumping
lemma, and you spend an afternoon losing to it.&lt;/p&gt;
&lt;p&gt;The statement is a nest of quantifiers: for every regular language there exists
a pumping length $p$ such that for every string $w$ with $|w| \ge p$ there exists
a decomposition $w = xyz$ with $|xy| \le p$ and $|y| &amp;gt; 0$ such that for all $i
\ge 0$, $xy^i z$ is in the language. To use it you negate all of that and play a
game against an adversary who picks $p$ and the decomposition while you pick $w$
and $i$.&lt;/p&gt;</description></item><item><title>Kleene's Theorem: Regexes Are Finite Automata</title><link>https://cs.lozic.me/posts/t039-kleenes-theorem-regexes-are-finite-automata/</link><pubDate>Fri, 30 Jul 2027 12:00:00 +0100</pubDate><guid>https://cs.lozic.me/posts/t039-kleenes-theorem-regexes-are-finite-automata/</guid><description>&lt;h2 id="symptom"&gt;Symptom&lt;/h2&gt;
&lt;p&gt;Your service goes down. CPU pinned at 100% on one core, no memory growth, no
error logs, requests timing out.&lt;/p&gt;
&lt;p&gt;The cause is a validation regex — something reasonable-looking like
&lt;code&gt;^(a+)+$&lt;/code&gt;, or in real life a URL or email validator with nested quantifiers —
matched against a 30-character string that happens not to match. The engine is
exploring an exponential number of ways to split the input among the nested
groups, and it will get there eventually, some time after the heat death of
everything.&lt;/p&gt;</description></item><item><title>BPP, Pseudorandomness, and Derandomization</title><link>https://cs.lozic.me/posts/t035-bpp-pseudorandomness-and-derandomization/</link><pubDate>Fri, 23 Jul 2027 12:00:00 +0100</pubDate><guid>https://cs.lozic.me/posts/t035-bpp-pseudorandomness-and-derandomization/</guid><description>&lt;h2 id="symptom"&gt;Symptom&lt;/h2&gt;
&lt;p&gt;You need to test whether two arithmetic circuits compute the same polynomial.
The deterministic approach is to expand both into normal form, and the expansion
is exponentially large.&lt;/p&gt;
&lt;p&gt;The randomized approach takes four lines. Pick a random point, evaluate both
circuits there, compare. If they differ as polynomials, the
Schwartz-Zippel lemma says a random point catches it with probability at least
$1 - d/|S|$. Repeat a few times and the error is negligible.&lt;/p&gt;</description></item><item><title>The Exponential Time Hypothesis and Fine-Grained Complexity</title><link>https://cs.lozic.me/posts/t037-the-exponential-time-hypothesis-and-fine-grained-complexity/</link><pubDate>Fri, 16 Jul 2027 12:00:00 +0100</pubDate><guid>https://cs.lozic.me/posts/t037-the-exponential-time-hypothesis-and-fine-grained-complexity/</guid><description>&lt;h2 id="symptom"&gt;Symptom&lt;/h2&gt;
&lt;p&gt;You have a string algorithm. Edit distance between two sequences, the classic
dynamic program, $O(n^2)$ time. It has been in production for years.&lt;/p&gt;
&lt;p&gt;Now the inputs are genome-scale. At $n = 10^5$ characters, $n^2 = 10^{10}$
operations, about &lt;strong&gt;10 seconds&lt;/strong&gt; at a billion ops per second. At $n = 10^6$ it is
$10^{12}$ operations, about &lt;strong&gt;1000 seconds&lt;/strong&gt; — seventeen minutes for one pair of
strings. You need to do a million pairs.&lt;/p&gt;</description></item><item><title>Parity Is Not in AC^0</title><link>https://cs.lozic.me/posts/t034-parity-is-not-in-ac0/</link><pubDate>Fri, 09 Jul 2027 12:00:00 +0100</pubDate><guid>https://cs.lozic.me/posts/t034-parity-is-not-in-ac0/</guid><description>&lt;h2 id="symptom"&gt;Symptom&lt;/h2&gt;
&lt;p&gt;You have just read T030 and you are demoralized. Relativization kills the
techniques that treat machines as black boxes. Natural proofs kill the
combinatorial ones, assuming pseudorandom functions exist. Between them they
appear to rule out everything anyone knows how to do, and the honest summary of
fifty years is that nobody can prove any interesting problem is hard.&lt;/p&gt;</description></item><item><title>The No-Cloning Theorem</title><link>https://cs.lozic.me/posts/t110-the-no-cloning-theorem/</link><pubDate>Fri, 02 Jul 2027 12:00:00 +0100</pubDate><guid>https://cs.lozic.me/posts/t110-the-no-cloning-theorem/</guid><description>&lt;h2 id="symptom"&gt;Symptom&lt;/h2&gt;
&lt;p&gt;You have spent this whole part learning that information wants to be copied.
Entropy bounds compression (T018), Huffman hits the bound (T020), redundancy
buys error correction (T021). Every result so far treats &amp;ldquo;make another copy&amp;rdquo; as
the free operation — the thing you do without thinking, the reason &lt;code&gt;cp&lt;/code&gt; has no
interesting failure modes.&lt;/p&gt;</description></item><item><title>The Nyquist–Shannon Sampling Theorem</title><link>https://cs.lozic.me/posts/t106-the-nyquist-shannon-sampling-theorem/</link><pubDate>Fri, 25 Jun 2027 12:00:00 +0100</pubDate><guid>https://cs.lozic.me/posts/t106-the-nyquist-shannon-sampling-theorem/</guid><description>&lt;h2 id="symptom"&gt;Symptom&lt;/h2&gt;
&lt;p&gt;Your dashboard shows CPU utilization averaging 40%, comfortably under budget.
Users are reporting timeouts. You add more logging and the average stays at 40%.&lt;/p&gt;
&lt;p&gt;Eventually someone captures a one-second trace and finds the truth: the service
spikes to 100% for eight seconds out of every ninety, and your monitoring
samples every sixty seconds. The spikes are real, periodic, and invisible.&lt;/p&gt;</description></item><item><title>The Byzantine Generals Problem</title><link>https://cs.lozic.me/posts/t063-the-byzantine-generals-problem/</link><pubDate>Fri, 18 Jun 2027 12:00:00 +0100</pubDate><guid>https://cs.lozic.me/posts/t063-the-byzantine-generals-problem/</guid><description>&lt;h2 id="symptom"&gt;Symptom&lt;/h2&gt;
&lt;p&gt;A node in your cluster is not down. It is worse than down.&lt;/p&gt;
&lt;p&gt;Its disk is returning corrupted blocks that pass the checksum because the
checksum is corrupted too. Or a NIC with a firmware bug is duplicating and
reordering frames. Or a bad memory module flipped a bit in a config value and
the node now believes it owns a shard it does not. Or someone has root on one
machine.&lt;/p&gt;</description></item><item><title>FLP Impossibility</title><link>https://cs.lozic.me/posts/t062-flp-impossibility/</link><pubDate>Fri, 11 Jun 2027 12:00:00 +0100</pubDate><guid>https://cs.lozic.me/posts/t062-flp-impossibility/</guid><description>&lt;h2 id="symptom"&gt;Symptom&lt;/h2&gt;
&lt;p&gt;Your cluster of five nodes elects a leader. It works. It has worked for a year.&lt;/p&gt;
&lt;p&gt;Then one afternoon a garbage collection pause on the leader runs for twelve
seconds. The followers time out, start an election, and elect a new leader. The
old leader wakes up, has no idea it was deposed, and keeps serving writes. For a
few hundred milliseconds you have two leaders, and if your fencing is not
airtight, two writes that should have been ordered land in an order nobody
chose.&lt;/p&gt;</description></item><item><title>Vector Clocks and Causal Consistency</title><link>https://cs.lozic.me/posts/t059-vector-clocks-and-causal-consistency/</link><pubDate>Fri, 04 Jun 2027 12:00:00 +0100</pubDate><guid>https://cs.lozic.me/posts/t059-vector-clocks-and-causal-consistency/</guid><description>&lt;h2 id="symptom"&gt;Symptom&lt;/h2&gt;
&lt;p&gt;You took the lesson from T058 and stopped trusting wall clocks. Every event now
carries a Lamport timestamp, and your writes are ordered by it. The vanishing
updates stopped.&lt;/p&gt;</description></item><item><title>Happens-Before and Lamport Clocks</title><link>https://cs.lozic.me/posts/t058-happens-before-and-lamport-clocks/</link><pubDate>Fri, 28 May 2027 12:00:00 +0100</pubDate><guid>https://cs.lozic.me/posts/t058-happens-before-and-lamport-clocks/</guid><description>&lt;h2 id="symptom"&gt;Symptom&lt;/h2&gt;
&lt;p&gt;Two writes to the same key. Which one wins?&lt;/p&gt;
&lt;p&gt;Your first instinct is timestamps: whichever has the later wall-clock time is
newer. This works in testing. In production you get a bug report saying an
update vanished, and when you dig in, node B&amp;rsquo;s clock was 40 ms behind node A&amp;rsquo;s,
so B&amp;rsquo;s &lt;em&gt;later&lt;/em&gt; write carried an &lt;em&gt;earlier&lt;/em&gt; timestamp and lost. NTP is running.
NTP does not make clocks identical, it makes them close, and &amp;ldquo;close&amp;rdquo; is not
&amp;ldquo;ordered.&amp;rdquo;&lt;/p&gt;</description></item><item><title>Parameterized Complexity (FPT and W[1])</title><link>https://cs.lozic.me/posts/t033-parameterized-complexity-fpt-and-w1/</link><pubDate>Fri, 21 May 2027 12:00:00 +0100</pubDate><guid>https://cs.lozic.me/posts/t033-parameterized-complexity-fpt-and-w1/</guid><description>&lt;h2 id="symptom"&gt;Symptom&lt;/h2&gt;
&lt;p&gt;Your problem is NP-hard, and yet it keeps being easy.&lt;/p&gt;
&lt;p&gt;You are computing a minimum vertex cover to select monitoring points in a
network. Twelve thousand nodes. NP-hard, per T028, so you brace for the worst —
and the answer comes back in under a second, every time. The cover is small,
around thirty nodes, because the network is sparse and the interesting nodes are
few.&lt;/p&gt;</description></item><item><title>Approximation Algorithms and Ratios</title><link>https://cs.lozic.me/posts/t032-approximation-algorithms-and-ratios/</link><pubDate>Fri, 14 May 2027 12:00:00 +0100</pubDate><guid>https://cs.lozic.me/posts/t032-approximation-algorithms-and-ratios/</guid><description>&lt;h2 id="symptom"&gt;Symptom&lt;/h2&gt;
&lt;p&gt;You have accepted that the problem is NP-hard. Now what?&lt;/p&gt;
&lt;p&gt;The literature offers a wall of results with numbers attached: 2-approximation,
$\ln n$-approximation, PTAS, FPTAS, 0.878. Nobody explains what these numbers
buy you, how they are proved, or how they connect to the heuristic you already
wrote. Meanwhile your greedy heuristic is running in production and you have no
idea whether it is within 5% or a factor of 50 of optimal, because &lt;strong&gt;you cannot
compute the optimum to compare against&lt;/strong&gt; — that was the whole problem.&lt;/p&gt;</description></item><item><title>The PCP Theorem and Inapproximability</title><link>https://cs.lozic.me/posts/t031-the-pcp-theorem-and-inapproximability/</link><pubDate>Fri, 07 May 2027 12:00:00 +0100</pubDate><guid>https://cs.lozic.me/posts/t031-the-pcp-theorem-and-inapproximability/</guid><description>&lt;h2 id="symptom"&gt;Symptom&lt;/h2&gt;
&lt;p&gt;You gave up on exact (T028) and went looking for an approximation.&lt;/p&gt;
&lt;p&gt;Vertex cover: you find a 2-approximation in four lines. Knapsack: an FPTAS, any
accuracy you want. Encouraged, you go looking for the same for max-clique, and
you find nothing. Not &amp;ldquo;nothing good&amp;rdquo; — the best known ratio is around
$n/(\log n)^2$, which on a 10,000-vertex graph means the algorithm might return
a clique nearly 60 times smaller than the true maximum. That is not an
approximation, it is a rumour.&lt;/p&gt;</description></item><item><title>Streaming Lower Bounds and Sketching</title><link>https://cs.lozic.me/posts/t105-streaming-lower-bounds-and-sketching/</link><pubDate>Fri, 30 Apr 2027 12:00:00 +0100</pubDate><guid>https://cs.lozic.me/posts/t105-streaming-lower-bounds-and-sketching/</guid><description>&lt;h2 id="symptom"&gt;Symptom&lt;/h2&gt;
&lt;p&gt;Product wants the daily unique-visitor count. You have a firehose of events.&lt;/p&gt;
&lt;p&gt;The obvious implementation is a set. Add each visitor ID, report the size. At a
billion distinct IDs, eight bytes each, that is 8 GB before any hash table
overhead, and in practice a &lt;code&gt;HashSet&lt;/code&gt; will cost you two to three times that.
Per day. Per dimension you want to slice by. Multiply by country, by platform,
by campaign, and the memory bill is absurd for a number nobody looks at past two
significant figures.&lt;/p&gt;</description></item><item><title>Universal Hashing</title><link>https://cs.lozic.me/posts/t104-universal-hashing/</link><pubDate>Fri, 23 Apr 2027 12:00:00 +0100</pubDate><guid>https://cs.lozic.me/posts/t104-universal-hashing/</guid><description>&lt;h2 id="symptom"&gt;Symptom&lt;/h2&gt;
&lt;p&gt;Your service went down under a hash collision attack.&lt;/p&gt;
&lt;p&gt;Somebody noticed your web framework put POST parameters into a hash table, found
thousands of distinct keys colliding under its hash function, and posted a form
with 20,000 of them. Every insert walked a chain. Quadratic behaviour, one CPU
pinned per request, service dead. This actually happened, across PHP, Python,
Ruby, Java and .NET in 2011, and again against Rust&amp;rsquo;s default &lt;code&gt;HashMap&lt;/code&gt; before
it switched to SipHash.&lt;/p&gt;</description></item><item><title>Minimum Description Length and Occam's Razor</title><link>https://cs.lozic.me/posts/t025-minimum-description-length-and-occams-razor/</link><pubDate>Fri, 16 Apr 2027 12:00:00 +0100</pubDate><guid>https://cs.lozic.me/posts/t025-minimum-description-length-and-occams-razor/</guid><description>&lt;h2 id="symptom"&gt;Symptom&lt;/h2&gt;
&lt;p&gt;You fit a model. It scores 94% on training data and 71% on held-out data.&lt;/p&gt;
&lt;p&gt;So you simplify: fewer parameters, more regularization. Training drops to 88%,
held-out rises to 84%. You simplify further and both drop. Somewhere in there
was an optimum, and you found it by trial and error, with a validation set and
patience.&lt;/p&gt;</description></item><item><title>Kolmogorov Complexity</title><link>https://cs.lozic.me/posts/t023-kolmogorov-complexity/</link><pubDate>Fri, 09 Apr 2027 12:00:00 +0100</pubDate><guid>https://cs.lozic.me/posts/t023-kolmogorov-complexity/</guid><description>&lt;h2 id="symptom"&gt;Symptom&lt;/h2&gt;
&lt;p&gt;You have two files, each exactly one megabyte.&lt;/p&gt;
&lt;p&gt;The first is a megabyte of the byte &lt;code&gt;0x00&lt;/code&gt;. The second is a megabyte from
&lt;code&gt;/dev/urandom&lt;/code&gt;. Gzip the first and you get a few hundred bytes. Gzip the second
and you get slightly more than a megabyte, because the header costs something and
there is nothing to exploit.&lt;/p&gt;</description></item><item><title>The Barriers: Relativization and Natural Proofs</title><link>https://cs.lozic.me/posts/t030-the-barriers-relativization-and-natural-proofs/</link><pubDate>Fri, 02 Apr 2027 12:00:00 +0100</pubDate><guid>https://cs.lozic.me/posts/t030-the-barriers-relativization-and-natural-proofs/</guid><description>&lt;h2 id="symptom"&gt;Symptom&lt;/h2&gt;
&lt;p&gt;You have read T026 and T027 and you are wondering the obvious thing.&lt;/p&gt;
&lt;p&gt;Fifty years. Thousands of researchers. A million-dollar prize. And P vs NP has
not moved. That is strange — most famous problems yield partial results, near
misses, special cases that suggest the shape of the answer. Here there is
almost nothing. We cannot even prove that NP requires more than linear-size
circuits, which is a laughably weak statement compared to what everyone
believes.&lt;/p&gt;</description></item><item><title>Karp's 21 Problems</title><link>https://cs.lozic.me/posts/t028-karps-21-problems/</link><pubDate>Fri, 26 Mar 2027 12:00:00 +0100</pubDate><guid>https://cs.lozic.me/posts/t028-karps-21-problems/</guid><description>&lt;h2 id="symptom"&gt;Symptom&lt;/h2&gt;
&lt;p&gt;Three weeks into a project, you are still trying to write an exact algorithm.&lt;/p&gt;
&lt;p&gt;The problem is yours and it looks specific: assign delivery vans to routes such
that every stop is covered, no van exceeds its capacity, and the total distance
is minimized. Nothing in the literature matches it exactly. So you keep going —
better data structures, smarter pruning, a cleverer greedy pass with a repair
step — and each version works on your test set and falls over on production
data.&lt;/p&gt;</description></item><item><title>The Cook–Levin Theorem</title><link>https://cs.lozic.me/posts/t027-the-cook-levin-theorem/</link><pubDate>Fri, 19 Mar 2027 12:00:00 +0100</pubDate><guid>https://cs.lozic.me/posts/t027-the-cook-levin-theorem/</guid><description>&lt;h2 id="symptom"&gt;Symptom&lt;/h2&gt;
&lt;p&gt;You know reductions (T017): to prove your problem hard, reduce a known-hard
problem to it. Fine. But that begs the obvious question, and it is the question
a sharp colleague asks the first time you use the technique.&lt;/p&gt;</description></item><item><title>P vs NP</title><link>https://cs.lozic.me/posts/t026-p-vs-np/</link><pubDate>Fri, 12 Mar 2027 12:00:00 +0100</pubDate><guid>https://cs.lozic.me/posts/t026-p-vs-np/</guid><description>&lt;h2 id="symptom"&gt;Symptom&lt;/h2&gt;
&lt;p&gt;You are handed a scheduling problem. Two hundred tasks, precedence constraints,
shared resources, and a deadline. Somebody wants an optimal schedule.&lt;/p&gt;
&lt;p&gt;Checking a proposed schedule takes seconds: walk the list, verify each
constraint, add up the makespan. Finding one is different. Your search runs for
a day and finds nothing. You try simulated annealing, then a genetic algorithm,
then branch and bound. Each gives good schedules and none gives the best one, and
you cannot tell whether the problem is hard or you are not clever enough.&lt;/p&gt;</description></item><item><title>The Hamming Bound and Error-Correcting Codes</title><link>https://cs.lozic.me/posts/t022-the-hamming-bound/</link><pubDate>Fri, 05 Mar 2027 12:00:00 +0100</pubDate><guid>https://cs.lozic.me/posts/t022-the-hamming-bound/</guid><description>&lt;h2 id="symptom"&gt;Symptom&lt;/h2&gt;
&lt;p&gt;You are specifying ECC memory for a fleet. The vendor quotes SECDED: single
error correct, double error detect, at 8 check bits per 64 data bits. That is
12.5% overhead, and someone in the room asks the obvious question — why not
correct two errors? Or three? What does it cost?&lt;/p&gt;</description></item><item><title>The Noisy-Channel Coding Theorem</title><link>https://cs.lozic.me/posts/t021-the-noisy-channel-coding-theorem/</link><pubDate>Fri, 26 Feb 2027 12:00:00 +0100</pubDate><guid>https://cs.lozic.me/posts/t021-the-noisy-channel-coding-theorem/</guid><description>&lt;h2 id="symptom"&gt;Symptom&lt;/h2&gt;
&lt;p&gt;Your link drops 1% of bits. You need reliable delivery, so you triple every bit
and take a majority vote. Now an error needs two of three bits to flip, which
happens with probability about $3 \times 10^{-4}$ — better, but you paid 3x in
bandwidth and the error rate is still not zero.&lt;/p&gt;</description></item><item><title>Huffman Coding Is Optimal</title><link>https://cs.lozic.me/posts/t020-huffman-coding-is-optimal/</link><pubDate>Fri, 19 Feb 2027 12:00:00 +0100</pubDate><guid>https://cs.lozic.me/posts/t020-huffman-coding-is-optimal/</guid><description>&lt;h2 id="symptom"&gt;Symptom&lt;/h2&gt;
&lt;p&gt;You are compressing a log file. The symbols are wildly skewed: &lt;code&gt;INFO&lt;/code&gt; is 90% of
the lines, &lt;code&gt;WARN&lt;/code&gt; is 9%, &lt;code&gt;ERROR&lt;/code&gt; and &lt;code&gt;FATAL&lt;/code&gt; split the rest. Fixed-width
two-bit codes give you exactly 2 bits per symbol, and entropy (T018) says the
floor is about 0.53 bits. There is a factor of four sitting there.&lt;/p&gt;</description></item><item><title>Balls Into Bins and the Power of Two Choices</title><link>https://cs.lozic.me/posts/t009-balls-into-bins/</link><pubDate>Fri, 12 Feb 2027 12:00:00 +0100</pubDate><guid>https://cs.lozic.me/posts/t009-balls-into-bins/</guid><description>&lt;h2 id="symptom"&gt;Symptom&lt;/h2&gt;
&lt;p&gt;You have 100 backends and a load balancer hashing request IDs to pick one.
Expected load per backend is exactly 1%, and you have checked the hash is good.&lt;/p&gt;</description></item><item><title>Reductions</title><link>https://cs.lozic.me/posts/t017-reductions/</link><pubDate>Fri, 05 Feb 2027 12:00:00 +0100</pubDate><guid>https://cs.lozic.me/posts/t017-reductions/</guid><description>&lt;h2 id="symptom"&gt;Symptom&lt;/h2&gt;
&lt;p&gt;You have a new problem. Your build system needs to decide whether two
configuration files can ever produce conflicting outputs. Or your linter needs to
decide whether a regex with backreferences can match a string of a given length.
Or your scheduler needs to decide whether a set of periodic tasks is feasible.&lt;/p&gt;</description></item><item><title>The Coffman Conditions</title><link>https://cs.lozic.me/posts/t051-the-coffman-conditions/</link><pubDate>Fri, 29 Jan 2027 12:00:00 +0100</pubDate><guid>https://cs.lozic.me/posts/t051-the-coffman-conditions/</guid><description>&lt;h2 id="symptom"&gt;Symptom&lt;/h2&gt;
&lt;p&gt;Production is wedged. Not slow — wedged. CPU is at zero, no errors are being
logged, and two threads are sitting in a lock wait with no timeout. The stack
traces show thread A holding the account lock and waiting for the ledger lock,
thread B holding the ledger lock and waiting for the account lock. Somebody
restarts the service and it goes away.&lt;/p&gt;</description></item><item><title>Godel's Incompleteness Theorems</title><link>https://cs.lozic.me/posts/t015-godels-incompleteness-theorems/</link><pubDate>Fri, 22 Jan 2027 12:00:00 +0100</pubDate><guid>https://cs.lozic.me/posts/t015-godels-incompleteness-theorems/</guid><description>&lt;h2 id="symptom"&gt;Symptom&lt;/h2&gt;
&lt;p&gt;The proof assistant is failing you. You are trying to verify a piece of
concurrent code in Coq or Lean, and the tool will not accept your termination
argument. A colleague says, without much conviction, &amp;ldquo;well, Gödel — you can&amp;rsquo;t
prove everything anyway.&amp;rdquo;&lt;/p&gt;</description></item><item><title>Kleene's Recursion Theorem</title><link>https://cs.lozic.me/posts/t014-kleenes-recursion-theorem/</link><pubDate>Fri, 15 Jan 2027 12:00:00 +0100</pubDate><guid>https://cs.lozic.me/posts/t014-kleenes-recursion-theorem/</guid><description>&lt;h2 id="symptom"&gt;Symptom&lt;/h2&gt;
&lt;p&gt;Write a program that prints its own source code. No file I/O, no reading
&lt;code&gt;__file__&lt;/code&gt;, no cheating.&lt;/p&gt;
&lt;p&gt;The first attempt fails instantly. To print the source you must contain the
source, and then the containing text is also part of the source, so you must
contain that too. The regress is obviously infinite, and most people conclude
after ten minutes that the task is impossible.&lt;/p&gt;</description></item><item><title>The Chomsky Hierarchy</title><link>https://cs.lozic.me/posts/t038-the-chomsky-hierarchy/</link><pubDate>Fri, 08 Jan 2027 12:00:00 +0100</pubDate><guid>https://cs.lozic.me/posts/t038-the-chomsky-hierarchy/</guid><description>&lt;h2 id="symptom"&gt;Symptom&lt;/h2&gt;
&lt;p&gt;The most upvoted answer in Stack Overflow history is a refusal to answer. Someone
asked how to match nested HTML tags with a regular expression, and the reply is
a page of escalating horror about the centre not holding. It is funny, and it is
also a theorem, which is not obvious from reading it.&lt;/p&gt;</description></item><item><title>The Universal Machine</title><link>https://cs.lozic.me/posts/t013-the-universal-machine/</link><pubDate>Fri, 01 Jan 2027 12:00:00 +0100</pubDate><guid>https://cs.lozic.me/posts/t013-the-universal-machine/</guid><description>&lt;h2 id="symptom"&gt;Symptom&lt;/h2&gt;
&lt;p&gt;You write a Python program. It runs. What ran it?&lt;/p&gt;
&lt;p&gt;CPython — itself a program, written in C, compiled to x86 instructions, executed
by a CPU whose control unit is arguably interpreting microcode, possibly inside
a virtual machine, on a kernel that scheduled it, all perhaps within a container
image. At no point in that stack does anyone find it strange that a program&amp;rsquo;s
job is running other programs. We build emulators, JITs, WebAssembly runtimes,
Docker, QEMU, and browsers that download and execute arbitrary code from
strangers, and treat every layer as ordinary engineering.&lt;/p&gt;</description></item><item><title>The Church–Turing Thesis</title><link>https://cs.lozic.me/posts/t012-the-church-turing-thesis/</link><pubDate>Fri, 25 Dec 2026 12:00:00 +0100</pubDate><guid>https://cs.lozic.me/posts/t012-the-church-turing-thesis/</guid><description>&lt;h2 id="symptom"&gt;Symptom&lt;/h2&gt;
&lt;p&gt;Somebody says &amp;ldquo;CSS is Turing-complete&amp;rdquo; and the room splits. Half the people
treat it as a joke about a styling language, the other half as a serious claim
with consequences. Both reactions are common and only one is right.&lt;/p&gt;</description></item><item><title>Concentration Bounds (Chernoff/Hoeffding)</title><link>https://cs.lozic.me/posts/t008-concentration-bounds/</link><pubDate>Fri, 18 Dec 2026 12:00:00 +0100</pubDate><guid>https://cs.lozic.me/posts/t008-concentration-bounds/</guid><description>&lt;h2 id="symptom"&gt;Symptom&lt;/h2&gt;
&lt;p&gt;Your service handles four billion requests a month and you want the error rate.
Computing it exactly means a job over four billion log lines. Someone suggests
sampling ten thousand of them.&lt;/p&gt;</description></item><item><title>Amortized Analysis and the Potential Method</title><link>https://cs.lozic.me/posts/t006-amortized-analysis-and-the-potential-method/</link><pubDate>Fri, 11 Dec 2026 12:00:00 +0100</pubDate><guid>https://cs.lozic.me/posts/t006-amortized-analysis-and-the-potential-method/</guid><description>&lt;h2 id="symptom"&gt;Symptom&lt;/h2&gt;
&lt;p&gt;You have a dynamic array. &lt;code&gt;push&lt;/code&gt; writes one element and bumps a counter, which
is clearly $O(1)$ — except when the array is full, in which case it allocates a
new buffer of twice the size, copies every element across, and frees the old
one. That is $O(n)$.&lt;/p&gt;</description></item><item><title>Adversary Arguments</title><link>https://cs.lozic.me/posts/t005-adversary-arguments/</link><pubDate>Fri, 04 Dec 2026 12:00:00 +0100</pubDate><guid>https://cs.lozic.me/posts/t005-adversary-arguments/</guid><description>&lt;h2 id="symptom"&gt;Symptom&lt;/h2&gt;
&lt;p&gt;You need the largest and second-largest element of an array. The obvious way is
two passes: $n-1$ comparisons for the max, then $n-2$ for the max of the rest.
That is $2n - 3$.&lt;/p&gt;</description></item><item><title>Linearity of Expectation</title><link>https://cs.lozic.me/posts/t007-linearity-of-expectation/</link><pubDate>Fri, 27 Nov 2026 12:00:00 +0100</pubDate><guid>https://cs.lozic.me/posts/t007-linearity-of-expectation/</guid><description>&lt;h2 id="symptom"&gt;Symptom&lt;/h2&gt;
&lt;p&gt;You are analyzing a hash table. You want the expected number of buckets that end
up empty. The bucket occupancies are all tangled together — one key landing in
bucket 3 makes every other bucket slightly less likely to be chosen — and the
dependencies look like they will make the sum intractable.&lt;/p&gt;</description></item><item><title>The Omega(n log n) Comparison-Sort Bound</title><link>https://cs.lozic.me/posts/t003-comparison-sort-lower-bound/</link><pubDate>Fri, 20 Nov 2026 12:00:00 +0100</pubDate><guid>https://cs.lozic.me/posts/t003-comparison-sort-lower-bound/</guid><description>&lt;h2 id="symptom"&gt;Symptom&lt;/h2&gt;
&lt;p&gt;Every general-purpose sort in every standard library is $O(n \log n)$.
Timsort, introsort, pdqsort, merge sort, heapsort. Decades of work by extremely
motivated people, an enormous amount of money riding on it, and they all land on
the same exponent.&lt;/p&gt;</description></item><item><title>Shannon Entropy and the Source Coding Theorem</title><link>https://cs.lozic.me/posts/t018-shannon-entropy-and-source-coding/</link><pubDate>Fri, 13 Nov 2026 12:00:00 +0100</pubDate><guid>https://cs.lozic.me/posts/t018-shannon-entropy-and-source-coding/</guid><description>&lt;h2 id="symptom"&gt;Symptom&lt;/h2&gt;
&lt;p&gt;You gzip a log file and it drops to 8% of its original size. You gzip the
already-gzipped file and it gets slightly &lt;em&gt;bigger&lt;/em&gt;. Somebody asks why, and the
honest answer you have is &amp;ldquo;because it&amp;rsquo;s already compressed,&amp;rdquo; which is a
restatement, not a reason.&lt;/p&gt;</description></item><item><title>The Birthday Bound</title><link>https://cs.lozic.me/posts/t074-the-birthday-bound/</link><pubDate>Fri, 06 Nov 2026 12:00:00 +0100</pubDate><guid>https://cs.lozic.me/posts/t074-the-birthday-bound/</guid><description>&lt;h2 id="symptom"&gt;Symptom&lt;/h2&gt;
&lt;p&gt;You need a short ID for uploads. Eight hex characters feels generous, so you
take the first 32 bits of a hash and move on.&lt;/p&gt;
&lt;p&gt;At about 80,000 uploads, two files collide, and one of them silently overwrites
the other, and the bug report says the customer&amp;rsquo;s invoice contains someone
else&amp;rsquo;s line items.&lt;/p&gt;</description></item><item><title>The Two Generals Problem</title><link>https://cs.lozic.me/posts/t061-the-two-generals-problem/</link><pubDate>Fri, 30 Oct 2026 12:00:00 +0100</pubDate><guid>https://cs.lozic.me/posts/t061-the-two-generals-problem/</guid><description>&lt;h2 id="symptom"&gt;Symptom&lt;/h2&gt;
&lt;p&gt;You call the payment API. The request goes out. Nothing comes back.&lt;/p&gt;
&lt;p&gt;Did the charge happen? You genuinely do not know. Retrying might double-charge
the customer. Not retrying might drop the payment. There is no third option
available, and no amount of care in your client library creates one.&lt;/p&gt;</description></item><item><title>Conway's Law</title><link>https://cs.lozic.me/posts/t089-conways-law/</link><pubDate>Fri, 23 Oct 2026 12:00:00 +0200</pubDate><guid>https://cs.lozic.me/posts/t089-conways-law/</guid><description>&lt;h2 id="symptom"&gt;Symptom&lt;/h2&gt;
&lt;p&gt;The service has four layers. Nobody designed four layers. There were four teams.&lt;/p&gt;
&lt;p&gt;Or the version that arrives in a postmortem: the outage happened at the boundary
between two services, in the retry logic, because each side assumed the other
owned the deduplication. Both teams were right about their own component and
neither had ever been in a room with the other.&lt;/p&gt;</description></item><item><title>Rice's Theorem</title><link>https://cs.lozic.me/posts/t011-rices-theorem/</link><pubDate>Fri, 16 Oct 2026 12:00:00 +0200</pubDate><guid>https://cs.lozic.me/posts/t011-rices-theorem/</guid><description>&lt;h2 id="symptom"&gt;Symptom&lt;/h2&gt;
&lt;p&gt;The security team asks for a scanner with no false positives and no false
negatives. Every piece of malware caught, nothing legitimate quarantined.&lt;/p&gt;
&lt;p&gt;The platform team asks whether the analyzer can flag every function that
performs I/O, so the pure ones can be cached automatically.&lt;/p&gt;</description></item><item><title>The Halting Problem</title><link>https://cs.lozic.me/posts/t010-the-halting-problem/</link><pubDate>Fri, 09 Oct 2026 12:00:00 +0200</pubDate><guid>https://cs.lozic.me/posts/t010-the-halting-problem/</guid><description>&lt;h2 id="symptom"&gt;Symptom&lt;/h2&gt;
&lt;p&gt;Your CI has a test that hangs. Not fails — hangs. Somebody suggests the obvious
fix: before running a test, check whether it terminates, and skip it if not.&lt;/p&gt;</description></item><item><title>Cantor's Diagonal Argument</title><link>https://cs.lozic.me/posts/t002-cantors-diagonal-argument/</link><pubDate>Fri, 02 Oct 2026 12:00:00 +0200</pubDate><guid>https://cs.lozic.me/posts/t002-cantors-diagonal-argument/</guid><description>&lt;h2 id="symptom"&gt;Symptom&lt;/h2&gt;
&lt;p&gt;Somebody proposes a tool that will find all the bugs. Not most bugs. All of
them. The pitch has the shape: we enumerate the failure modes, we write a
checker for each, we keep adding checkers, and the set of undetected bugs
shrinks toward zero.&lt;/p&gt;</description></item><item><title>Gustafson's Law and the Universal Scalability Law</title><link>https://cs.lozic.me/posts/t082-gustafsons-law-and-the-usl/</link><pubDate>Fri, 25 Sep 2026 12:00:00 +0200</pubDate><guid>https://cs.lozic.me/posts/t082-gustafsons-law-and-the-usl/</guid><description>&lt;h2 id="symptom"&gt;Symptom&lt;/h2&gt;
&lt;p&gt;Two measurements that both look like they break the previous post.&lt;/p&gt;
&lt;p&gt;The first: your Spark job takes four hours on ten nodes. You move it to a
hundred nodes and it still takes four hours — but it is now processing ten times
the data. &lt;a href="https://cs.lozic.me/posts/t081-amdahls-law/"&gt;T081&lt;/a&gt; said the ceiling was
20×, and nobody hit a ceiling.&lt;/p&gt;</description></item><item><title>Amdahl's Law</title><link>https://cs.lozic.me/posts/t081-amdahls-law/</link><pubDate>Fri, 18 Sep 2026 12:00:00 +0200</pubDate><guid>https://cs.lozic.me/posts/t081-amdahls-law/</guid><description>&lt;h2 id="symptom"&gt;Symptom&lt;/h2&gt;
&lt;p&gt;The profile was unambiguous: 94% of wall-clock time in one loop, and the loop&amp;rsquo;s
iterations are independent. You parallelise it across sixteen cores, the flame
graph flattens exactly as predicted, and the end-to-end time goes from 40
seconds to 17.&lt;/p&gt;</description></item><item><title>Hyrum's Law and Postel's Principle</title><link>https://cs.lozic.me/posts/t091-hyrums-law-and-postels-principle/</link><pubDate>Fri, 11 Sep 2026 12:00:00 +0200</pubDate><guid>https://cs.lozic.me/posts/t091-hyrums-law-and-postels-principle/</guid><description>&lt;h2 id="symptom"&gt;Symptom&lt;/h2&gt;
&lt;p&gt;You fix a typo in an error message. Four days later a customer escalates:
their alerting pipeline greps for the old string and has gone quiet.&lt;/p&gt;
&lt;p&gt;Or you make a function faster, and a test suite that had been green for two years
starts failing intermittently — not because the function is wrong, but because
it used to be slow enough to hide a race.&lt;/p&gt;</description></item><item><title>No Universal Lossless Compressor</title><link>https://cs.lozic.me/posts/t004-no-universal-lossless-compressor/</link><pubDate>Fri, 04 Sep 2026 12:00:00 +0200</pubDate><guid>https://cs.lozic.me/posts/t004-no-universal-lossless-compressor/</guid><description>&lt;h2 id="symptom"&gt;Symptom&lt;/h2&gt;
&lt;p&gt;Someone sends you a pitch deck. The claim is a compression algorithm that
reduces &lt;em&gt;any&lt;/em&gt; file by a guaranteed ratio, and — this is always the tell — that
it can be applied repeatedly. Four gigabytes down to one, then one down to two
fifty, and so on until the whole film is a few hundred bytes and a clever
decoder.&lt;/p&gt;</description></item><item><title>The Pigeonhole Principle</title><link>https://cs.lozic.me/posts/t001-pigeonhole-principle/</link><pubDate>Fri, 28 Aug 2026 12:00:00 +0200</pubDate><guid>https://cs.lozic.me/posts/t001-pigeonhole-principle/</guid><description>&lt;h2 id="symptom"&gt;Symptom&lt;/h2&gt;
&lt;p&gt;You are asked to build a cache key. You have a 64-bit hash, and someone on the
team says: &amp;ldquo;collisions are basically impossible, there are eighteen quintillion
values.&amp;rdquo;&lt;/p&gt;
&lt;p&gt;Or: your service assigns short IDs to uploads, six characters of base-36, and
you are wondering when you need to worry.&lt;/p&gt;</description></item><item><title>Index of results</title><link>https://cs.lozic.me/index-of-results/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://cs.lozic.me/index-of-results/</guid><description>Every result in the series, in book order.</description></item></channel></rss>