Equivalence: are two expressions the same for every value?

LLM-authored, human-reviewed

Foundations

2(x+1)2(x + 1) and 2x+22x + 2 do not look the same, but they are. x2x^2 and 2x2x look kind of similar, but they are not. The question is equivalence - “do these two produce the same value for every input?” It anchors the substitution and function exercises. This article puts the idea in one place for the equivalence and fn_equal exercises that drill it.

The question is “every value”, not “this value”

The trap is checking one input and stopping. x2x^2 and 2x2x agree at x=0x = 0 (both are 0) and at x=2x = 2 (both are 4). A quick check makes them look identical. They are not. At x=3x = 3, the first is 9 and the second is

  1. Equivalence makes the stronger claim: the same for every value the variable can take, not the same for the values you happened to try.

That one mismatching input is a counterexample. It settles the question, because “the same for every value” dies as soon as you find one value where the expressions differ. Finding an input where they agree is not enough; almost any two expressions agree somewhere. You need to decide whether any input makes them disagree.

When they are the same: a law is hiding

Equivalent pairs have an algebraic law behind them. 2(x+1)2(x + 1) and 2x+22x + 2 follow the distributive law: multiply the 22 through the parentheses. They are the same expression written two ways. (a+b)(ab)(a + b)(a - b) and a2b2a^2 - b^2 follow the difference of squares, a product that always expands to that particular subtraction. x+xx + x and 2x2x are the same because “add a thing to itself” and “double a thing” name one operation.

When a pair is equivalent, do not say, “I checked a few inputs and they matched.” Say, “a law says they are the same, so they are the same for every input.” That is the difference between sampling and reasoning. It is also the line the functions practice draws in its infinite-domain exercises: many samples finding no counterexample is still not a proof.

When they differ: one input is enough

Non-equivalent pairs fail on a specific input. Find it. x2x^2 versus 2x2x fails at x=3x = 3. 2x+3x2x + 3x versus 5x25x^2 agrees at x=1x = 1 (both are 5) but fails at x=2x = 2 (10 versus 20). (x+1)(x+1)(x + 1)(x + 1) versus x2+1x^2 + 1 agrees at x=0x = 0 (both 1) but fails at x=1x = 1 (4 versus 2). The counterexample is usually small - 0, 1, 2, a negative, or any value where a square and a double stop coinciding. Reach for the values most likely to break the resemblance, not the ones most likely to preserve it.

This is the same recognition a programmer uses when hunting a bug: do not test the happy path; test the input that might break the assumption. The edge-case-reasoning thread through these exercises builds exactly that reflex, aimed at a mathematical claim instead of a code path.

Two framings, one question

The substitution exercises ask it of expressions: “is 2(x+1)2(x + 1) the same as 2x+22x + 2 for every xx?” The function exercises ask it of functions: “is f(x)=2(x+1)f(x) = 2(x + 1) the same function as g(x)=2x+2g(x) = 2x + 2?” These are the same question in different clothes. Two functions are the same when they are the same mapping - same output for every input - and “same output for every input” is exactly “equivalent for every value.” A function is just a mapping, so function equality and expression equivalence are one idea.

The only difference is the domain. On a small finite domain, you could check every input by hand. On an infinite domain - all the integers - you cannot, so the exercise states the limit plainly: testing many samples can refute a false claim of equality but can never prove a true one. The truth-tables article makes the same distinction for logic: an exhaustive table decides a finite question; an unbounded one needs a proof, which is what the proofs and induction exercises are for.

Why this matters here

Equivalence supports three things on this site. It is the equivalence skill in the substitution exercises, the fn_equal skill in the function exercises, and - one layer up - the seed of the laws hidden in your code: a law is just an equivalence that holds for every input. That makes it safe to rely on rather than re-check. When lambda calculus later asks whether two terms are alpha-equivalent, it asks this same question again, about expressions that happen to be functions.

Where to go next

← Back to articles