open atlas
↑ Back to track
Logic, from zero LOGIC · 04 · 03

Counterexamples and claims: who carries the burden of proof

Quantifier shape decides the burden of proof: a ∀-claim dies to one counterexample and is never proven by examples; an ∃-claim is proven by one witness. A failing test is a counterexample, edge values are where they hide, and a vague claim with no quantifier cannot be argued.

LOGIC Foundations ◷ 14 min
Level
FoundationsJuniorMiddleSenior

“I ran it on ten inputs — it works.” The PR was merged on that sentence. The next morning a customer hit checkout with an empty cart and the total came out NaN. One user, one input, and the claim “it works” was dead. Notice the asymmetry: ten green examples could not establish the claim, and a single red one destroyed it. That is not bad luck — it is logic. “It works” secretly means for all inputs, the code behaves correctly — a ∀-claim, and ∀-claims play on a brutal scoreboard: examples in favor count for almost nothing, while one example against ends the game. ∃-claims play on the mirror-image scoreboard, where one example wins outright.

Goal

After this lesson you can read a claim’s quantifier and assign the correct burden of proof, supply a counterexample to a false ∀-claim, supply a witness for an ∃-claim, identify where counterexamples live, and rewrite an unfalsifiable claim into a quantified form that can be argued.

1

The quantifier decides the burden of proof.

Claim shapeOne example proves it?One example kills it?
∀x P(x)never — examples only supportyes: a counterexample, an x with ¬P(x)
∃x P(x)yes: a witness, an x with P(x)never — failed searches only fail

To prove a ∀-claim: an argument covering every member of the domain, or exhaustive enumeration when the domain is genuinely small and finite. To refute one: one counterexample. The mirror is exact because ¬∀x P(x) ≡ ∃x ¬P(x) — refuting a universal is proving an existential, which is why one object can do it.

2

Counterexamples live at the edges. The standard zoo, worth memorizing: 0, 1, −1, the empty collection, the single-element collection, boundaries (first/last index, min/max values), duplicates, sorted and reverse-sorted inputs, unicode beyond ASCII, null/missing fields. Authors write ∀-claims while imagining a typical input — but the quantifier ranges over all of them, including every one nobody imagined. The zoo is the catalogue of the unimagined.

// Claim: for every array xs of numbers, average(xs) returns a finite number.
function average(xs) {
  let sum = 0;
  for (const x of xs) sum += x;
  return sum / xs.length;
}

average([2, 4, 9]);  // 5  — supporting example
average([7]);        // 7  — singleton cage: survives
average([]);         // NaN — 0/0. Counterexample. ∀-claim dead.

One red line outvotes any number of green ones.

3

Quantify a claim before arguing it. “The API is fast” — no observation can refute it. Any slow request can be waved away as “not what I meant.” A claim that no possible evidence could refute is unfalsifiable, and unfalsifiable claims cannot be argued — only believed or disbelieved, never settled. The fix is mechanical: for every GET /search request under nominal load, p95 latency over any 5-minute window stays at or below 200 ms. Now the claim has a domain, a measurable predicate, and a quantifier. A counterexample is a concrete 5-minute window with p95 above 200 ms. Same surgery for “the migration is safe”, “this never happens”, “the cache makes things faster.”

4

“I tested ten cases, so it works” — a ∀-claim is never proven by sampling. What settles it positively: a proof, an argument over all inputs; or exhaustive enumeration of a genuinely small finite domain (all 256 byte values, fine; all pairs of 64-bit floats, never). Dijkstra compressed this lesson into one sentence: testing can show the presence of bugs, never their absence — which is quantifier logic, nothing more. The practical posture: keep tests as cheap counterexample hunters and zoo-feeders; be precise about what green means: survived the hunt so far.

Worked example

A counterexample hunt on a plausible theorem.

Claim. Every function with n roots has degree at least n.

It sounds right. A line (degree 1) crosses zero at most once, a parabola (degree 2) at most twice — surely many roots demand high degree. But hunt: what is the weirdest function you can feed it? Try f(x) = 0, the zero function. Every input is a root — infinitely many. Its degree? The zero polynomial has no degree (by convention sometimes −∞) — certainly not “at least n” for any n. One degenerate object, and the ∀-claim is dead.

What the death bought: the counterexample did not destroy the idea — it located its boundary. The repaired claim, every nonzero polynomial with n distinct roots has degree at least n, is a genuine theorem. Treat every counterexample as a free consultant marking where your claim’s domain actually ends.

Why this works

Property-based testing tools — Hypothesis in Python, fast-check in JavaScript, QuickCheck in Haskell — automate the hunt. You state the property as a genuine ∀-claim, and the tool fires hundreds of zoo-biased inputs at it. On failure it shrinks the input down to a minimal one — typically the empty array, 0, or "". One honest caveat: a green run is still examples, not a proof. It raises confidence; it never proves the ∀. What it automates is the zoo, not the proof.

Practice 0 / 5

Does one passing test prove a ∀-claim? Answer yes or no.

Does one witness prove an ∃-claim? Answer yes or no.

average([]) returns NaN. Is this a counterexample to 'average always returns a finite number'? Answer yes or no.

A teammate fuzzes 100,000 random inputs and finds no crash. Does this refute 'there exists an input that crashes the parser'? Answer yes or no.

Rewrite 'the cache makes things faster' as a quantified, falsifiable claim. What key ingredient must you add?

Check yourself
Quiz

Claim: 'there exists an input that crashes this parser.' A teammate fuzzes 100,000 random inputs, sees no crash, and declares the claim refuted. What is wrong?

Recap

A claim’s quantifier assigns the burden of proof before any argument starts. ∀x P(x) is proven only by an argument covering the whole domain or exhaustive enumeration of a small finite one — and dies to one counterexample; no pile of supporting examples proves it. ∃x P(x) mirrors exactly: one witness proves it, and only an argument that every candidate fails can refute it. The mirror is the equivalence of ¬∀ with ∃¬: refuting a universal is proving an existential. Counterexamples live at the edges — 0, 1, −1, empty, singleton, boundaries, duplicates, unicode, null — because the quantifier ranges over all inputs while the author imagines a typical one. A counterexample rarely destroys the idea; it marks the boundary and the repaired claim says exactly where the truth lives. A failing test is a counterexample; a green suite is a list of survivors; property-based tools automate the zoo but a green run still proves nothing. Before arguing any claim, quantify it — “the API is fast” admits no counterexample and so cannot even be argued. A claim you cannot lose is one you also cannot win.

Practice

Start at the top. Tasks go easiest → hardest: recall a fact, apply it to a case, then a senior-level stretch. Open one, attempt it, then reveal.

recallapplystretch0 of 5 done

Something unclear?

Ask a question about this lesson. Questions are anonymous and go straight to the author to make the lesson better.

shortcuts expand
search
K
prev piece
k
next piece
j
cycle tier
t
this menu
?
sources3
expand
  1. 01
  2. 02
  3. 03

Trademarks belong to their respective owners. Editorial reference only.