Volume 3: Discrete and Probabilistic Mathematics · Part VI: Discrete Mathematics
Chapter 21. Logic and Sets
Every if statement you have ever written is a small piece of logic, and every database query is a small piece of set theory. This chapter makes that implicit knowledge explicit: propositions and the connectives that combine them, the slippery conditional "if … then", the laws (De Morgan’s above all) that let you rewrite conditions safely, the quantifiers "for all" and "there exists", and then sets, relations and the special relations called functions. By the end you will have the vocabulary that the rest of discrete mathematics, and every proof in this book, is written in.
Why this chapter matters. Outside code, the same few ideas decide whether a contract clause has been met, whether a positive medical test means what the patient hopes it means, which blood a patient can safely receive, and how many people on a survey ticked "neither". Logic is the grammar of precise rules; sets are the bookkeeping of who or what a rule applies to.
21.1. Propositions and connectives
21.1.1. The problem
A product manager writes in a ticket: "Show the discount banner if the user is a member or has spent over $100, but not if they’re logged out." You translate that into code. A week later a bug report arrives: logged-out members are seeing the banner. Was the ticket ambiguous, or was the code wrong?
English is a wonderful language for poetry and a terrible one for specifications. "Or" sometimes means "one or the other or both" and sometimes "one or the other but not both". "But" means "and" with an attitude. "Unless" means something different to almost everyone who reads it. Logic is the discipline of removing that ambiguity: it gives each connecting word one precise meaning, and then gives rules for combining and rewriting statements without changing what they say.
21.1.2. Intuition
Think of a statement as a wire that carries either true or false. Connectives are little machines that take one or two wires in and produce one wire out. "Not" flips its wire. "And" outputs true only if both inputs are true. "Or" outputs true if at least one input is true. Because each wire has only two possible values, you can describe any machine completely by listing what it does for every combination of inputs. That list is a truth table, and it is the whole definition: no further interpretation is needed or allowed.
21.1.3. Vocabulary and notation
|
Proposition
A proposition (or statement) is a declarative sentence that is either true or false, but not both. "7 is prime" is a proposition (true). "7 is even" is a proposition (false). "Close the door" (a command) and "\(x > 3\)" (whose truth depends on an unknown \(x\)) are not propositions. We name propositions with lowercase letters \(p, q, r\). The truth value of a proposition is T (true) or F (false), sometimes written 1 and 0. |
|
Connective
A logical connective (or operator) builds a new proposition from one or more existing ones. The five standard connectives are:
A proposition built from others using connectives is compound; one that cannot be broken down further is atomic. Some books write \(\sim p\) or \(\overline{p}\) for negation, \(\Rightarrow\) for \(\to\), and \(\Leftrightarrow\) or "iff" for \(\leftrightarrow\). |
The symbols \(\wedge\) (and) and \(\vee\) (or) are easy to mix up. A mnemonic: \(\wedge\) looks like the "A" in *A*nd with the crossbar missing; \(\vee\) comes from the Latin vel, "or".
21.1.4. The truth tables
Here are the definitions, all in one table. Each row is one possible combination of truth values for \(p\) and \(q\); with two inputs there are \(2^2 = 4\) rows.
| \(p\) | \(q\) | \(\neg p\) | \(p \wedge q\) | \(p \vee q\) | \(p \to q\) | \(p \leftrightarrow q\) |
|---|---|---|---|---|---|---|
T |
T |
F |
T |
T |
T |
T |
T |
F |
F |
F |
T |
F |
F |
F |
T |
T |
F |
T |
T |
F |
F |
F |
T |
F |
F |
T |
T |
Try it: The conditional’s truth table.
Three of these columns match everyday intuition. Two need comment.
Or is inclusive. \(p \vee q\) is true when both are true. If you mean "one or the other but not both", that is a different connective, exclusive or, written \(p \oplus q\) (and p != q or p ^ q in most languages). Mathematics, logic and programming languages all default to the inclusive reading.
The conditional is the subject of the next section; its last two rows surprise almost everyone.
|
Exclusive or (XOR)
\(p \oplus q\) ("\(p\) xor \(q\)") is true when exactly one of \(p, q\) is true. It equals \((p \vee q) \wedge \neg(p \wedge q)\), and it is the negation of the biconditional: \(p \oplus q \equiv \neg(p \leftrightarrow q)\). |
21.1.5. Worked example: building a truth table
Let us settle the banner ticket. Let \(m\) = "user is a member", \(s\) = "user spent over $100", \(\ell\) = "user is logged in". The most reasonable reading is Try it: Build the banner truth table.
With three atomic propositions there are \(2^3 = 8\) rows. The systematic way to list them is to count down in binary: the first column alternates in blocks of four, the second in blocks of two, the third every row. Then compute intermediate columns left to right, exactly as you would evaluate a sub-expression before the expression that uses it.
| \(m\) | \(s\) | \(\ell\) | \(m \vee s\) | \((m \vee s) \wedge \ell\) |
|---|---|---|---|---|
T |
T |
T |
T |
T |
T |
T |
F |
T |
F |
T |
F |
T |
T |
T |
T |
F |
F |
T |
F |
F |
T |
T |
T |
T |
F |
T |
F |
T |
F |
F |
F |
T |
F |
F |
F |
F |
F |
F |
F |
Rows 2 and 4 are the bug report: a member who is logged out. The specification says F. The most likely culprit is code written as is_member or big_spender and logged_in, which Python parses as \(m \vee (s \wedge \ell)\) because and binds more tightly than or. In rows 2 and 4 that gives \(T \vee (\ldots) = T\): the banner appears. A truth table makes this kind of disagreement impossible to miss.
|
Precedence is not a matter of taste
The conventional precedence, from tightest to loosest, is \(\neg\), then \(\wedge\), then \(\vee\), then \(\to\), then \(\leftrightarrow\). So \(\neg p \vee q \wedge r\) means \((\neg p) \vee (q \wedge r)\). Programming languages agree on "not before and before or", but whenever an expression mixes |
Input: a compound proposition with \(n\) distinct atomic propositions.
Steps:
-
List the atomic propositions as the first \(n\) columns.
-
Write \(2^n\) rows. Fill column \(k\) (counting from 1) with alternating blocks of T and F of length \(2^{n-k}\). This enumerates every combination exactly once.
-
Identify the sub-expressions, innermost first, and give each its own column.
-
Fill each new column row by row, using the definitions of the connectives and the columns already computed.
-
The last column is the truth value of the whole proposition.
Output: the complete truth table; the rows marked T are exactly the situations in which the proposition holds.
Try it: Truth table, step by step.
The procedure is an algorithm, so here it is as code. itertools.product([True, False], repeat=n) generates the \(2^n\) rows in exactly the order described in step 2.
from itertools import product
def truth_table(f, names):
"""Print the truth table of f, a function of len(names) booleans."""
print(" ".join(names), "| result")
for row in product([True, False], repeat=len(names)):
cells = " ".join("T" if v else "F" for v in row)
print(cells, "|", "T" if f(*row) else "F")
def implies(p, q):
return (not p) or q
truth_table(lambda p, q: implies(p, q), ["p", "q"])
p q | result T T | T T F | F F T | T F F | T
Truth tables are exhaustive, which is both their virtue and their limit: \(n\) variables need \(2^n\) rows. Ten variables means 1,024 rows; forty means about a trillion. That exponential wall is exactly why the algebraic laws later in this chapter, and the SAT solvers mentioned at the end, matter.
|
Boole, Shannon and the most important master’s thesis
George Boole published The Laws of Thought in 1854, treating logic as algebra with values 0 and 1. For eighty years it was a philosophical curiosity. Then in 1937 a 21-year-old MIT student, Claude Shannon, noticed in his master’s thesis that relay switching circuits obey exactly Boole’s laws. Simplifying the algebra simplified the circuit. That thesis is often called the most consequential master’s thesis ever written: it is the reason the type is called |
21.1.6. Where you’d use this
Everyday: rules with several conditions. A shop offers "free delivery if you are a member, or if the order is at least $40 and not oversized". With \(m\), \(f\) (at least $40) and \(o\) (oversized), that is \(m \vee (f \wedge \neg o)\). The brackets matter: \((m \vee f) \wedge \neg o\) is a different policy that charges members for oversized parcels. Writing the formula is how you settle the argument at the checkout.
Medicine: "at least two of three". The qSOFA bedside screen for sepsis flags a patient when at least two of these hold: breathing rate at least 22 per minute (\(r\)), altered mental state (\(a\)), systolic blood pressure at most 100 mmHg (\(b\)). As a formula: \((r \wedge a) \vee (r \wedge b) \vee (a \wedge b)\), the majority function. Its truth table is T in exactly 4 of the 8 rows (TTT, TTF, TFT, FTT), and the same function is the carry-out bit of a full adder.
Engineering: interlocks. An industrial press may cycle only if the guard is closed (\(g\)) and both of the operator’s hands are on the two buttons (\(\ell\), \(r\)): \(g \wedge \ell \wedge r\). Two-hand controls exist so that no hand can be under the ram; the safety argument is literally a truth table with one T row out of eight.
Computing. Search boxes that accept jaguar AND (engine OR gearbox) NOT cat are evaluating a propositional formula per document; firewall and feature-flag rules are the same thing.
21.1.7. Exercises
-
Which of the following are propositions? (a) "17 is prime." (b) "Is 17 prime?" (c) "\(x^2 \geq 0\) for every real number \(x\)." (d) "\(x + 1 = 5\)."
-
Build the truth table for \(\neg(p \wedge q)\) and for \(\neg p \wedge \neg q\). Are they the same?
-
A login is allowed if the password is correct and either the device is trusted or a one-time code was entered. Write this as a formula using \(w\) (password correct), \(d\) (trusted device), \(c\) (code entered), and find every row of its truth table that is T.
Answers
-
(a) Yes, true. (b) No, a question. (c) Yes, true (the variable is bound by "for every", so the sentence as a whole is true or false; see Section 21.4). (d) No: its truth depends on the unknown \(x\). It is a predicate.
-
\(\neg(p \wedge q)\) has column F, T, T, T (rows TT, TF, FT, FF). \(\neg p \wedge \neg q\) has column F, F, F, T. They differ in rows TF and FT, so they are not the same. (The correct partner of \(\neg(p \wedge q)\) is \(\neg p \vee \neg q\); see De Morgan’s laws.)
-
\(w \wedge (d \vee c)\). It is T exactly when \(w\) is T and at least one of \(d, c\) is T: rows (\(w,d,c\)) = (T,T,T), (T,T,F), (T,F,T). Three of eight rows.
21.2. The conditional: "if … then"
21.2.1. The problem
A parent says: "If you finish your homework, you can play video games." The child does not finish the homework and plays anyway. Did the parent lie? Most people say: no, the parent made no promise about what happens if the homework is unfinished.
Now look at the truth table for \(p \to q\) again. When \(p\) is false, \(p \to q\) is true, whatever \(q\) is. "False implies anything." This feels like a cheat when you first meet it. Why is it the right definition?
21.2.2. Intuition: a conditional is a promise
Read \(p \to q\) as a promise or a contract: "whenever \(p\) holds, I guarantee \(q\)". The only way to break such a promise is for \(p\) to happen and \(q\) not to: row T, F. In every other row the promise has not been broken, and in two-valued logic "not false" means true.
A better test case than homework is a rule that has to hold for many cases at once. Take "for every whole number \(n\), if \(n\) is divisible by 4 then \(n\) is even". Everyone agrees this is true. Now check it at \(n = 3\): "if 3 is divisible by 4 then 3 is even" has a false hypothesis and a false conclusion. At \(n = 6\): "if 6 is divisible by 4 then 6 is even" has a false hypothesis and a true conclusion. If either of these instances counted as false, then the general rule, which is the conjunction of all its instances, would be false. So for universal rules to work the way everyone wants, the conditional with a false hypothesis must be true. Logic is designed so that general statements behave; the truth table follows.
|
Vacuous truth
A conditional whose hypothesis is false is vacuously true: true because there is no case that could break it. "Every unicorn in this room is purple" is vacuously true, since there are no unicorns to check. In code, |
|
Hypothesis, conclusion, sufficient, necessary
In \(p \to q\), \(p\) is the hypothesis (or antecedent, or premise) and \(q\) is the conclusion (or consequent). All of the following say exactly \(p \to q\):
The biconditional \(p \leftrightarrow q\) ("\(p\) if and only if \(q\)", often "iff") means \((p \to q) \wedge (q \to p)\): each is necessary and sufficient for the other. |
"Only if" deserves a second look because it trips everyone. "You can vote only if you are 18 or over" means voting \(\to\) 18-or-over: being 18 is necessary. It does not say every 18-year-old can vote (they might not be registered).
21.2.3. Why it works: the conditional as an "or"
Comparing columns shows that \(p \to q\) has exactly the same truth table as \(\neg p \vee q\):
| \(p\) | \(q\) | \(\neg p\) | \(\neg p \vee q\) | \(p \to q\) |
|---|---|---|---|---|
T |
T |
F |
T |
T |
T |
F |
F |
F |
F |
F |
T |
T |
T |
T |
F |
F |
T |
T |
T |
"If it is raining, I take an umbrella" says the same as "either it is not raining, or I take an umbrella". This is how you implement implication in a language that has no implication operator, and it is the form that algebraic simplification works with.
21.2.4. Converse, inverse, contrapositive
From one conditional \(p \to q\) you can form three relatives by swapping and/or negating the parts.
| Name | Form | Example (\(p\): "it is a square", \(q\): "it is a rectangle") |
|---|---|---|
original |
\(p \to q\) |
If it is a square, it is a rectangle. (true) |
converse |
\(q \to p\) |
If it is a rectangle, it is a square. (false) |
inverse |
\(\neg p \to \neg q\) |
If it is not a square, it is not a rectangle. (false) |
contrapositive |
\(\neg q \to \neg p\) |
If it is not a rectangle, it is not a square. (true) |
The pattern in the example is universal: a conditional is always equivalent to its contrapositive, and the converse is always equivalent to the inverse (the inverse is the contrapositive of the converse). But a conditional is not equivalent to its converse. Check the contrapositive with a truth table:
| \(p\) | \(q\) | \(p \to q\) | \(\neg q\) | \(\neg p\) | \(\neg q \to \neg p\) |
|---|---|---|---|---|---|
T |
T |
T |
F |
F |
T |
T |
F |
F |
T |
F |
F |
F |
T |
T |
F |
T |
T |
F |
F |
T |
T |
T |
T |
The third and last columns agree in every row. The contrapositive is not a curiosity: it is a whole proof technique in Chapter 22, used whenever "not \(q\)" is easier to work with than \(p\).
A picture makes the asymmetry obvious. Treat \(p\) and \(q\) as properties and draw the set of things having each. "Every square is a rectangle" means the square region sits entirely inside the rectangle region. The converse would need the reverse containment, and the non-square rectangle on the right shows it fails.
|
Affirming the consequent
Confusing a statement with its converse is the most common logical error in everyday reasoning, in debugging, and in medicine. "If the server is overloaded, requests time out. Requests are timing out. So the server is overloaded." This is invalid: it uses \(q \to p\), which was never established. Timeouts could come from a network partition. The valid inference patterns are
The invalid ones are affirming the consequent (from \(q\), conclude \(p\)) and denying the antecedent (from \(\neg p\), conclude \(\neg q\)). |
21.2.5. Worked example: the four relatives of a code comment
A comment says: "If the cache is warm, the request returns in under 10 ms." Let \(w\) = "cache is warm", \(f\) = "request is fast". Then:
If you observe a slow request, the contrapositive lets you conclude the cache was cold, assuming the comment is true. If you observe a fast request, you can conclude nothing about the cache.
|
The four-card puzzle
Psychologists have measured how bad people are at this. In the Wason selection task (1966), subjects see four cards showing E, K, 4, 7 and are told "if a card has a vowel on one side, it has an even number on the other". Which cards must you turn over to test the rule? Fewer than 10% answer correctly: E and 7. The 7 is the contrapositive check (odd, so must not be a vowel). Most people pick E and 4, and the 4 is useless: it tests the converse. |
21.2.6. Where you’d use this
Everyday: reading offers and rules. "If you spend over $50, delivery is free" is broken only by a customer who spends $60 and is charged for delivery. The shop that also gives free delivery on a $30 order has not broken it (false hypothesis). "Only if" clauses are the ones people misread: "the warranty is valid only if the device has not been opened" means valid \(\to\) not opened. Not opening it is necessary, but not sufficient: a two-year-old device may be out of warranty anyway.
Medicine: a test and its converse. "If you have the disease, the test is positive" (a test with high sensitivity) is the statement labs measure. The patient wants the converse, "if the test is positive, I have the disease", and that can be badly false when the disease is rare. Quantifying how false is a job for Bayes' theorem in Chapter 29; recognising that it is a different statement is a job for this section.
Engineering: fault-finding with the contrapositive. "If the fuse is intact and the switch is closed, the lamp lights": \((f \wedge s) \to L\). The lamp is dark, so by modus tollens \(\neg(f \wedge s)\), which by De Morgan (next section) is \(\neg f \vee \neg s\): the fuse has blown or the switch is open. Check the switch first; it is cheaper.
Computing. An assert or a function’s documented precondition is a conditional: "if the input is sorted, the result is the index of the target". Calling it on unsorted input does not make the function wrong; it makes the contract vacuous, and the result meaningless.
21.2.7. Exercises
-
Write the converse, inverse and contrapositive of "If \(n\) is divisible by 6, then \(n\) is divisible by 3." Which are true for all whole numbers \(n\)?
-
Rewrite "The build passes only if all tests pass" as an "if … then" sentence.
-
Is "if \(2 + 2 = 5\), then the moon is made of cheese" true or false? Why?
-
Express \(p \leftrightarrow q\) using only \(\neg\), \(\wedge\) and \(\vee\).
Answers
-
Converse: if \(n\) is divisible by 3, then \(n\) is divisible by 6 (false: \(n = 9\)). Inverse: if \(n\) is not divisible by 6, then \(n\) is not divisible by 3 (false: \(n = 9\) again). Contrapositive: if \(n\) is not divisible by 3, then \(n\) is not divisible by 6 (true, equivalent to the original, which is true because \(6 = 2 \cdot 3\)).
-
"If the build passes, then all tests pass." "Only if" introduces the conclusion.
-
True, vacuously: the hypothesis \(2 + 2 = 5\) is false.
-
\(p \leftrightarrow q \equiv (p \to q) \wedge (q \to p) \equiv (\neg p \vee q) \wedge (\neg q \vee p)\). An equally good answer is \((p \wedge q) \vee (\neg p \wedge \neg q)\): "both true or both false".
21.3. Logical equivalence and De Morgan’s laws
21.3.1. The problem
Here is a real-world conditional from a code review:
if not (user.is_admin or (user.is_owner and not doc.locked)):
raise PermissionDenied
What does it actually say? Under what conditions is the user allowed? And can it be written so that a tired reviewer at 6 p.m. can check it? We need a way to transform logical expressions while guaranteeing the meaning does not change.
21.3.2. Intuition
Two expressions are equivalent if no situation can tell them apart: in every row of the truth table they give the same answer. Just as algebra has laws such as \(a(b + c) = ab + ac\) that let you rewrite expressions, logic has laws that let you rewrite propositions. Each law can be verified once, by truth table, and then used forever without checking again.
|
Logical equivalence, tautology, contradiction
Two propositions \(A\) and \(B\) are logically equivalent, written \(A \equiv B\), if they have identical truth tables. Equivalently, \(A \leftrightarrow B\) is true in every row. A tautology is a proposition that is true in every row (for example \(p \vee \neg p\)). A contradiction is false in every row (for example \(p \wedge \neg p\)). A proposition that is neither is contingent. A proposition is satisfiable if at least one row makes it true. \(\equiv\) is a statement about two propositions (a "meta" claim), not a connective inside one. |
21.3.3. The laws
| Name | "And" form | "Or" form |
|---|---|---|
Identity |
\(p \wedge \mathbf{T} \equiv p\) |
\(p \vee \mathbf{F} \equiv p\) |
Domination |
\(p \wedge \mathbf{F} \equiv \mathbf{F}\) |
\(p \vee \mathbf{T} \equiv \mathbf{T}\) |
Idempotent |
\(p \wedge p \equiv p\) |
\(p \vee p \equiv p\) |
Complement |
\(p \wedge \neg p \equiv \mathbf{F}\) |
\(p \vee \neg p \equiv \mathbf{T}\) |
Double negation |
\(\neg\neg p \equiv p\) |
|
Commutative |
\(p \wedge q \equiv q \wedge p\) |
\(p \vee q \equiv q \vee p\) |
Associative |
\((p \wedge q) \wedge r \equiv p \wedge (q \wedge r)\) |
\((p \vee q) \vee r \equiv p \vee (q \vee r)\) |
Distributive |
\(p \wedge (q \vee r) \equiv (p \wedge q) \vee (p \wedge r)\) |
\(p \vee (q \wedge r) \equiv (p \vee q) \wedge (p \vee r)\) |
De Morgan |
\(\neg(p \wedge q) \equiv \neg p \vee \neg q\) |
\(\neg(p \vee q) \equiv \neg p \wedge \neg q\) |
Absorption |
\(p \wedge (p \vee q) \equiv p\) |
\(p \vee (p \wedge q) \equiv p\) |
Conditional |
\(p \to q \equiv \neg p \vee q \equiv \neg q \to \neg p\) |
|
Negated conditional |
\(\neg(p \to q) \equiv p \wedge \neg q\) |
|
Notice the pattern: every law comes in a pair, obtained by swapping \(\wedge\) with \(\vee\) and \(\mathbf{T}\) with \(\mathbf{F}\). This is the duality principle. Also notice that unlike ordinary algebra, both distributive laws hold: "and" distributes over "or" (like multiplication over addition), and "or" also distributes over "and" (which has no arithmetic counterpart: \(a + bc \neq (a + b)(a + c)\) in general).
21.3.4. De Morgan’s laws, in words
To push a "not" inside a bracket, negate each piece and flip the connective. "It is not the case that the server is both up and healthy" means "the server is down or it is unhealthy". "It is not the case that it’s raining or snowing" means "it is not raining and it is not snowing".
Why must the connective flip? "Not both" fails only when both hold, so it is true as soon as one of them fails: that is an "or" of failures. "Neither" requires every option to fail: that is an "and" of failures. You saw the truth tables in the first exercise set; the Venn diagram in Section 21.5 gives the same picture for sets.
Input: a boolean expression, typically a messy condition.
Steps:
-
Replace every \(\to\) by \(\neg p \vee q\) and every \(\leftrightarrow\) by \((\neg p \vee q) \wedge (\neg q \vee p)\), so that only \(\neg, \wedge, \vee\) remain.
-
Push every \(\neg\) inward with De Morgan’s laws, flipping \(\wedge \leftrightarrow \vee\) each time, until negations sit directly on atomic propositions.
-
Remove double negations: \(\neg\neg p \equiv p\).
-
Simplify with the complement, identity, domination, idempotent and absorption laws, using distribution or factoring where it shortens the expression.
-
Check the result: either compare truth tables (for few variables) or test it mechanically, for example with the
equivalentfunction below.
Output: an equivalent, simpler expression, usually with negations only on single variables.
21.3.5. Worked example: the permission check
Let \(a\) = user.is_admin, \(o\) = user.is_owner, \(\ell\) = doc.locked. The code raises when Try it: Push the negation inward.
Push the negation inward one step at a time:
In words: deny if the user is not an admin, and either is not the owner or the document is locked. The code can be rewritten
if not user.is_admin and (not user.is_owner or doc.locked):
raise PermissionDenied
Even better is to name the positive condition, since the original’s inner expression was the allow rule all along:
can_edit = user.is_admin or (user.is_owner and not doc.locked)
if not can_edit:
raise PermissionDenied
Which is better is a judgment call; the point is that you can now move between the forms with certainty.
21.3.6. A second worked example: absorption
Simplify \((p \wedge q) \vee (p \wedge \neg q)\). Try it: Check the absorption example.
Sanity check in words: "\(p\) and \(q\), or \(p\) and not \(q\)" is true exactly when \(p\) is true, whatever \(q\) does. The variable \(q\) was irrelevant, and the code if (p and q) or (p and not q) is a smell.
21.3.7. Alternative approaches and choosing a method
You have three ways to decide whether two expressions are equivalent.
-
Truth table. Mechanical and certain. Best for up to three or four variables. Hopeless beyond about twenty.
-
Algebraic laws. Produces a simplified form and an explanation of why, which a truth table never gives you. Requires some skill to choose which law to apply.
-
Mechanical check in code. The same as a truth table but delegated to a computer, which pushes the limit to about 20–25 variables:
from itertools import product
def equivalent(f, g, n):
"""True if f and g agree on every one of the 2**n input rows."""
return all(f(*row) == g(*row) for row in product([True, False], repeat=n))
def implies(p, q):
return (not p) or q
# De Morgan
print(equivalent(lambda p, q: not (p and q), lambda p, q: (not p) or (not q), 2))
# contrapositive vs converse
print(equivalent(lambda p, q: implies(p, q), lambda p, q: implies(not q, not p), 2))
print(equivalent(lambda p, q: implies(p, q), lambda p, q: implies(q, p), 2))
# distributive law, three variables
print(equivalent(lambda p, q, r: p and (q or r),
lambda p, q, r: (p and q) or (p and r), 3))
Try it: De Morgan, row by row; Contrapositive versus conditional; Converse is not equivalent; Distributive law, three variables.
True True False True
Rule of thumb: use the laws to find a simpler form, then use a truth table or equivalent to confirm it. When refactoring a production conditional, write the confirmation as a unit test.
|
The classic De Morgan slip
The two errors that cause real bugs:
|
|
Interactive Lab: truth-table playground
Type two boolean expressions in up to five variables. The lab draws both truth tables side by side, highlights rows where they disagree, and offers a "push negation inward" button that applies De Morgan one step at a time, showing which law fired. A challenge mode gives a messy condition from real code and asks for the shortest equivalent. Try it: Open the truth-table playground |
21.3.8. Where you’d use this
Everyday: rules phrased in the negative. A cinema says "no entry unless you are over 15 or with an adult". Entry is allowed when \(a \vee w\); by De Morgan you are refused exactly when \(\neg a \wedge \neg w\), under 15 and alone. Spreadsheets obey the same law: =NOT(OR(B2>100, C2="late")) and =AND(B2⇐100, C2<>"late") filter the same rows, and the second is easier for a colleague to read.
Engineering: fewer gates. Each gate costs chip area, power and a few picoseconds of delay. The absorption example above turned \((p \wedge q) \vee (p \wedge \neg q)\) (two ANDs, a NOT and an OR, four gates) into \(p\) (no gates: a wire). Circuit synthesis tools apply exactly these laws, millions of times, to every chip design.
Computing. Database query optimisers rewrite WHERE NOT (status = 'done' OR archived) into status <> 'done' AND NOT archived so that each part can use an index; compilers push negations inward the same way. The Watch out box above is the bug you get when a human does the rewrite by hand and forgets to flip the or.
21.3.9. Exercises
-
Use De Morgan’s laws to negate: (a) "the file exists and is readable"; (b) \(x < 0 \vee x > 10\); (c)
not (a or not b). -
Simplify \(\neg(p \to q) \vee q\) using the laws, showing each step. Try it: Step through this simplification.
-
Show that \(p \wedge (p \vee q) \equiv p\) (absorption) with a truth table.
-
Is \((p \to q) \vee (q \to p)\) a tautology, a contradiction, or contingent?
-
A colleague "simplifies"
if not (is_weekend or is_holiday):toif not is_weekend or not is_holiday:. Find inputs where the two disagree and give the correct rewrite. Try it: Find where they disagree.
Answers
-
(a) The file does not exist or it is not readable. (b) \(x \ge 0 \wedge x \le 10\), i.e. \(0 \le x \le 10\). (c) \(\neg(a \vee \neg b) \equiv \neg a \wedge \neg\neg b \equiv \neg a \wedge b\), i.e.
not a and b. -
\(\neg(p \to q) \vee q \equiv (p \wedge \neg q) \vee q\) (negated conditional) \(\equiv (p \vee q) \wedge (\neg q \vee q)\) (distribute \(\vee\) over \(\wedge\)) \(\equiv (p \vee q) \wedge \mathbf{T}\) (complement) \(\equiv p \vee q\) (identity).
-
Rows (\(p,q\)): TT gives \(p \vee q = T\), so \(p \wedge T = T\); TF: \(T \wedge T = T\); FT: \(F \wedge T = F\); FF: \(F \wedge F = F\). The column T, T, F, F equals the \(p\) column.
-
A tautology. \((\neg p \vee q) \vee (\neg q \vee p) \equiv (\neg p \vee p) \vee (q \vee \neg q) \equiv \mathbf{T} \vee \mathbf{T} \equiv \mathbf{T}\). Surprising but correct: of any two propositions, one implies the other, purely by the truth-table definition.
-
With
is_weekend = True,is_holiday = False: the original givesnot True = False; the "simplification" givesFalse or True = True. Correct rewrite:if not is_weekend and not is_holiday:("neither").
21.4. Predicates and quantifiers
21.4.1. The problem
"\(x > 3\)" is not a proposition, because its truth depends on \(x\). Yet mathematics and code are full of statements like "every element of the list is positive", "some user has no password", "for every input there is a matching output". Propositional logic, with its fixed T/F atoms, cannot express any of these. We need statements with variables in them, and a way to say "all" and "some".
21.4.2. Intuition
A predicate is a proposition with a hole in it, a function that returns a boolean: is_even(n). Fill the hole with a value and you get a proposition. A quantifier fills the hole differently: instead of naming one value, it makes a claim about all values or about at least one. In code, the universal quantifier is all(…) and the existential quantifier is any(…).
|
Predicate and domain
A predicate \(P(x)\) is a statement involving a variable \(x\) that becomes a proposition when \(x\) is given a value. The set of allowed values is the domain (or universe of discourse). With domain the integers, \(P(x)\): "\(x\) is even" gives \(P(4)\) true and \(P(7)\) false. Predicates can have several variables: \(L(x, y)\): "\(x < y\)". |
|
Quantifiers
The domain is often written into the quantifier: \(\forall x \in \mathbb{Z}\) ("for every integer \(x\)"). A variable governed by a quantifier is bound; one that is not is free. Only a statement with no free variables is a proposition. |
Over a finite domain \(\{a_1, \ldots, a_n\}\), quantifiers are just long connectives:
This view explains vacuous truth again: over an empty domain, a "for all" is an empty "and", which is true (the identity for \(\wedge\)), and a "there exists" is an empty "or", which is false (the identity for \(\vee\)). It is the same reason the empty sum is 0 and the empty product is 1.
nums = [3, 8, 12, 5]
print(all(n > 0 for n in nums)) # for all n, n > 0
print(any(n % 2 == 0 for n in nums)) # there exists an even n
print(all(n % 2 == 0 for n in nums)) # for all n, n is even
print(any(n % 2 != 0 for n in nums)) # there exists an n that is not even
print(all(n > 100 for n in [])) # vacuous truth
print(any(n > 100 for n in []))
True True False True True False
Lines three and four are negations of each other, which is the next idea.
21.4.3. Negating quantified statements
To deny "every swan is white" you do not need to show that every swan is non-white. You need one black swan. To deny "some student passed" you need to show that every student failed. That is De Morgan’s law again, applied to the long "and" and the long "or":
Input: a statement with a string of quantifiers followed by a quantifier-free part.
Steps:
-
Write \(\neg\) in front of the whole statement.
-
Move the \(\neg\) rightward past each quantifier in turn, flipping it: \(\forall\) becomes \(\exists\) and \(\exists\) becomes \(\forall\). Domains (\(x \in S\)) stay unchanged.
-
When the \(\neg\) reaches the quantifier-free part, negate it with the propositional rules: De Morgan for \(\wedge\)/\(\vee\), \(\neg(p \to q) \equiv p \wedge \neg q\) for conditionals, and flip comparisons (\(\neg(a < b)\) is \(a \ge b\)).
-
Read the result back in English as a check.
Output: an equivalent statement with the negation pushed all the way in.
21.4.4. Worked example: negating a nested statement
Take the statement "every request gets a response within 2 seconds of being sent". With \(R\) the set of requests and \(S\) the set of responses:
What does a monitoring alert need to detect, i.e. what is the negation?
In English: "there is some request such that every response either does not answer it or arrives more than 2 seconds later". Equivalently: some request was not answered in time. You can also write the final disjunction as a conditional, \(\text{answers}(s,r) \to t(s) - t(r) > 2\), "any response that answers it is late".
21.4.5. Order of quantifiers matters
Compare, over the integers, Try it: Now play ∃∀; Play the ∀∃ game.
The first says "for every number there is a bigger one": true (take \(y = x + 1\)). The second says "there is one number bigger than every number": false (it would have to be bigger than itself). The only difference is the order. In the first, \(y\) is chosen after \(x\) and may depend on it; in the second, \(y\) must be chosen first, once, and work for all \(x\).
A game helps. Read \(\forall\) as your opponent’s move and \(\exists\) as yours, in left-to-right order. The statement is true if you have a winning strategy. In \(\forall x\, \exists y\), your opponent names \(x\), then you reply: easy. In \(\exists y\, \forall x\), you must commit first, and your opponent picks \(x = y\) to beat you.
|
Swapping quantifiers silently
"Every user has a password" (\(\forall u\, \exists p\)) is not "there is a password every user has" (\(\exists p\, \forall u\)); the second would be a security disaster. Quantifiers of the same kind commute (\(\forall x\, \forall y \equiv \forall y\, \forall x\)), but \(\forall\) and \(\exists\) do not. Whenever an English sentence has two quantifiers, write it symbolically and check the order. In Chapter 16 the definition of a limit has the shape "\(\forall \varepsilon\; \exists \delta\; \ldots\)" and the order is the whole point. |
21.4.6. Where you’d use this
Everyday: one counterexample is enough. A dish is safe for a guest with coeliac disease when every ingredient is gluten-free: \(\forall i\, G(i)\). Its negation is \(\exists i\, \neg G(i)\): one ingredient with gluten (soy sauce is the classic hidden one) makes the whole dish unsafe. Allergen labels, "all passengers must have a passport" and "every room has a smoke alarm" are universal claims that a single inspection can refute.
Science and engineering: universal claims and finite tests. A specification such as "for every load up to 5 kN the beam deflects less than 2 mm" is a \(\forall\) statement over infinitely many loads. Testing at 1, 2, 3, 4 and 5 kN gives five instances, not the universal claim; the claim rests on a calculation (a proof) plus a safety factor. Scientific laws have the same shape, which is why one reproducible counterexample outweighs any number of confirmations.
Computing. A foreign-key constraint, "every order belongs to some customer", is \(\forall o\, \exists c\, \text{owns}(c, o)\). The query that finds violations is its negation, \(\exists o\, \forall c\, \neg\text{owns}(c, o)\): an orphan order, written in SQL as NOT EXISTS.
21.4.7. Exercises
-
Translate into symbols with domain the integers, and decide truth: (a) every integer has a negative; (b) some integer is its own square; (c) there is an integer that divides every integer.
-
Negate, pushing the negation all the way in: \(\forall x\, \big(x > 0 \to \exists y\, (y^2 = x)\big)\).
-
Write a Python expression for "some row in
tablehas every entry zero", and for its negation.
Answers
-
(a) \(\forall x\, \exists y\, (x + y = 0)\): true (take \(y = -x\)). (b) \(\exists x\, (x^2 = x)\): true (\(x = 0\) or \(x = 1\)). (c) \(\exists d\, \forall n\, (d \text{ divides } n)\): true (\(d = 1\), or \(d = -1\)).
-
\(\exists x\, \big(x > 0 \wedge \forall y\, (y^2 \neq x)\big)\): "some positive number is not a perfect square". Steps: flip \(\forall\) to \(\exists\); negate the conditional \(\neg(p \to q) \equiv p \wedge \neg q\); flip \(\exists y\) to \(\forall y\); negate \(=\) to \(\neq\). (Over the integers this negation is true, e.g. \(x = 2\), so the original is false; over the reals the original is true.)
-
any(all(v == 0 for v in row) for row in table). Negation:all(any(v != 0 for v in row) for row in table): every row has at least one nonzero entry.
21.5. Sets
21.5.1. The problem
A marketing team wants "customers who bought in 2025 but not in 2026, excluding anyone who unsubscribed". A security team wants "every IP address that appears in both the firewall log and the threat list". A compiler wants "the variables that are live at the end of this block". Each of these is a question about collections: combining them, intersecting them, removing one from another. The language for collections is set theory, and it turns out to be logic wearing different clothes.
21.5.2. Intuition
A set is a bag of distinct things where order does not matter and duplicates do not count. The only question you can ask of a set is "is this thing in it?" Everything else, including union, intersection and complement, is defined by how it answers that question. And the answer to "is \(x\) in \(A \cup B\)?" is "is \(x\) in \(A\) or is \(x\) in \(B\)?" So each set operation is a logical connective applied to membership.
21.5.3. Vocabulary and notation
|
Set, element, membership
A set is a well-defined collection of distinct objects, called its elements or members. We write \(x \in A\) for "\(x\) is an element of \(A\)" and \(x \notin A\) for "\(x\) is not". Sets are written with braces: \(A = \{2, 3, 5, 7\}\). Order and repetition are irrelevant: \(\{1, 2, 2, 3\} = \{3, 2, 1\}\). Two sets are equal when they have exactly the same elements. The cardinality \(|A|\) is the number of elements of a finite set: \(|\{2, 3, 5, 7\}| = 4\). |
|
Standard number sets
\(\mathbb{N}\) natural numbers \(\{0, 1, 2, \ldots\}\) (some authors start at 1; computer scientists usually start at 0); \(\mathbb{Z}\) integers (from German Zahlen, "numbers"); \(\mathbb{Q}\) rationals (quotient); \(\mathbb{R}\) reals; \(\mathbb{C}\) complex numbers. See Chapter 1. |
|
Set-builder notation
Set-builder notation describes a set by a rule rather than a list:
\[\{\, x \in \mathbb{Z} \mid x > 0 \text{ and } x \text{ is even} \,\} = \{2, 4, 6, \ldots\}\]
Read the bar \(\mid\) (sometimes a colon) as "such that". The left part says where elements come from and what shape they have; the right part is a predicate they must satisfy. You can also put an expression on the left: \(\{\, n^2 \mid n \in \mathbb{N} \,\} = \{0, 1, 4, 9, \ldots\}\). Python’s set comprehension |
|
Empty set, subset, universal set
|
Two consequences of the definition of subset surprise people. First, \(\varnothing \subseteq A\) for every set \(A\): the condition "every element of \(\varnothing\) is in \(A\)" is vacuously true. Second, \(\in\) and \(\subseteq\) are different relations: \(2 \in \{1, 2\}\) but \(2 \not\subseteq \{1, 2\}\) (2 is not a set of elements of \(\{1,2\}\)); \(\{2\} \subseteq \{1, 2\}\) but \(\{2\} \notin \{1, 2\}\).
21.5.4. Operations on sets
|
Union, intersection, difference, complement
For sets \(A, B\) inside a universal set \(U\):
Sets with no common element, \(A \cap B = \varnothing\), are disjoint. |
A Venn diagram draws the universal set as a rectangle and each set as a region inside it. Shading shows the result of an operation.
Because each operation is a connective in disguise, every law of logic gives a law of sets. Replace \(\vee\) by \(\cup\), \(\wedge\) by \(\cap\), \(\neg\) by complement, \(\mathbf{T}\) by \(U\) and \(\mathbf{F}\) by \(\varnothing\):
| Law | Logic | Sets |
|---|---|---|
Distributive |
\(p \wedge (q \vee r) \equiv (p \wedge q) \vee (p \wedge r)\) |
\(A \cap (B \cup C) = (A \cap B) \cup (A \cap C)\) |
De Morgan |
\(\neg(p \vee q) \equiv \neg p \wedge \neg q\) |
\(\overline{A \cup B} = \overline{A} \cap \overline{B}\) |
De Morgan |
\(\neg(p \wedge q) \equiv \neg p \vee \neg q\) |
\(\overline{A \cap B} = \overline{A} \cup \overline{B}\) |
Complement |
\(p \vee \neg p \equiv \mathbf{T}\) |
\(A \cup \overline{A} = U\) |
Absorption |
\(p \wedge (p \vee q) \equiv p\) |
\(A \cap (A \cup B) = A\) |
A Venn diagram is a good way to discover or check a set identity. To prove one, use the membership argument below, because diagrams with three or more sets get hard to draw correctly and easy to misread.
Input: a claimed identity \(X = Y\) between two set expressions.
Steps:
-
Take an arbitrary element \(x\) and write "\(x \in X\)".
-
Unfold the definitions of the operations in \(X\), turning membership into a logical formula in statements like \(x \in A\).
-
Transform that formula with the laws of logic until it is the unfolded form of \(x \in Y\).
-
Fold it back up: "\(x \in Y\)". Since every step was an equivalence (\(\iff\)), you have shown \(x \in X \iff x \in Y\) for all \(x\), so \(X = Y\).
-
If some step is only an implication, prove the two inclusions \(X \subseteq Y\) and \(Y \subseteq X\) separately.
Output: a proof of the identity, or a counterexample element found while trying.
21.5.5. Worked example: De Morgan for sets
Prove \(\overline{A \cup B} = \overline{A} \cap \overline{B}\). Try it: De Morgan on a Venn diagram.
The set identity is literally the logic identity, applied to membership.
21.5.6. Counting: inclusion–exclusion
How many elements are in \(A \cup B\)? Adding \(|A| + |B|\) counts the overlap twice, so subtract it once: Try it: Inclusion–exclusion with counts.
Example: 120 users enabled two-factor authentication, 85 use a passkey, and 40 do both. Then \(|A \cup B| = 120 + 85 - 40 = 165\) users have at least one of the two. This principle of inclusion–exclusion grows to three or more sets in Chapter 24, and becomes the addition rule for probabilities in Chapter 29.
21.5.7. Power set and Cartesian product
Two constructions build new, bigger sets from old ones.
|
Power set
The power set \(\mathcal{P}(A)\) is the set of all subsets of \(A\), including \(\varnothing\) and \(A\) itself. For \(A = \{a, b, c\}\):
\[\mathcal{P}(A) = \big\{\varnothing,\ \{a\},\ \{b\},\ \{c\},\ \{a,b\},\ \{a,c\},\ \{b,c\},\ \{a,b,c\}\big\}.\]
If \(|A| = n\) then \(|\mathcal{P}(A)| = 2^n\), because building a subset means making an independent in-or-out decision for each of the \(n\) elements. A subset of an \(n\)-element set is an \(n\)-bit string; that is why bitmasks represent sets. |
|
Ordered pair and Cartesian product
An ordered pair \((a, b)\) is like a two-element set except that order matters: \((1, 2) \neq (2, 1)\), and \((a, b) = (c, d)\) exactly when \(a = c\) and \(b = d\). More generally an \(n\)-tuple is \((a_1, \ldots, a_n)\). The Cartesian product of \(A\) and \(B\) is the set of all ordered pairs with first entry from \(A\) and second from \(B\):
\[A \times B = \{\, (a, b) \mid a \in A,\ b \in B \,\}, \qquad |A \times B| = |A| \cdot |B|.\]
\(\mathbb{R} \times \mathbb{R} = \mathbb{R}^2\) is the coordinate plane of Chapter 10, which is where the name (after Descartes) comes from. |
|
Russell’s paradox
Can a set contain itself? Consider \(R = \{\, S \mid S \notin S \,\}\), the set of all sets that are not members of themselves. Is \(R \in R\)? If it is, then by its own rule it is not; if it is not, then by its rule it is. Bertrand Russell found this contradiction in 1901, in the foundations Gottlob Frege had just finished building. The fix, modern axiomatic set theory (ZFC), forbids building a set from an unrestricted predicate: set-builder notation must always draw from an existing set, \(\{\, x \in A \mid P(x) \,\}\). The same self-reference drives Turing’s proof that the halting problem is undecidable. |
|
Interactive Lab: Venn region painter
A three-set Venn diagram has eight regions. Type a set expression such as \((A \setminus B) \cup \overline{C}\) and the lab shades the matching regions; click regions to paint a shape and the lab finds an expression for it. A second panel shows the same regions as rows of a three-variable truth table, making the sets-equal-logic correspondence concrete. |
21.5.8. Where you’d use this
Everyday: surveys and inclusion–exclusion. Of 30 people at a meeting, 18 drink coffee, 15 drink tea and 7 drink both. Then \(18 + 15 - 7 = 26\) drink at least one, so \(30 - 26 = 4\) want neither: order 4 bottles of water, not 0 and not 30 minus 33. Try it: Coffee, tea, or neither.
Medicine: blood types are subsets. Red cells carry some subset of three antigens, A, B and the Rhesus antigen D. The eight blood types are exactly the \(2^3 = 8\) subsets: O negative is \(\varnothing\), AB positive is \(\{A, B, D\}\). A transfusion of red cells is compatible when the donor’s set is a subset of the recipient’s, because the recipient’s immune system attacks any antigen it lacks. So O negative (\(\varnothing \subseteq\) everything) is the universal donor and AB positive the universal recipient; an A-positive patient (\(\{A, D\}\)) can receive O−, O+, A− or A+, the four subsets of \(\{A, D\}\).
Computing: search and similarity. A search engine stores, for each word, the set of documents containing it (an inverted index). The query cat dog is the intersection of two such sets. Near-duplicate detection compares documents by the Jaccard similarity \(|A \cap B| / |A \cup B|\) of their word sets: "the cat sat on the mat" and "the cat lay on the mat" share 4 of 6 distinct words, a similarity of \(4/6 \approx 0.67\).
21.5.9. Exercises
-
Let \(U = \{1, \ldots, 10\}\), \(A = \{1, 2, 3, 4, 5\}\), \(B = \{4, 5, 6, 7\}\). Find \(A \cup B\), \(A \cap B\), \(A \setminus B\), \(B \setminus A\), \(\overline{A}\), and \(\overline{A \cup B}\).
-
True or false: (a) \(\varnothing \in \{1, 2\}\); (b) \(\varnothing \subseteq \{1, 2\}\); (c) \(\{1\} \in \mathcal{P}(\{1, 2\})\); (d) \(|\mathcal{P}(\mathcal{P}(\varnothing))| = 2\).
-
Write \(\{1, 4, 9, 16, 25\}\) in set-builder notation.
-
List \(\{0, 1\} \times \{a, b, c\}\). How many elements does \(\{0,1\}^{8} = \{0,1\} \times \cdots \times \{0,1\}\) (8 factors) have, and what familiar object is each element?
-
Prove \(A \setminus B = A \cap \overline{B}\) by element-chasing.
-
In a class of 30 students, 18 take Spanish, 14 take French, and 5 take neither. How many take both?
Answers
-
\(A \cup B = \{1,2,3,4,5,6,7\}\); \(A \cap B = \{4, 5\}\); \(A \setminus B = \{1,2,3\}\); \(B \setminus A = \{6, 7\}\); \(\overline{A} = \{6,7,8,9,10\}\); \(\overline{A \cup B} = \{8, 9, 10\}\). (Check De Morgan: \(\overline{A} \cap \overline{B} = \{6,\ldots,10\} \cap \{1,2,3,8,9,10\} = \{8,9,10\}\).)
-
(a) False: the elements are 1 and 2, and \(\varnothing\) is neither. (b) True: the empty set is a subset of every set. (c) True: \(\{1\} \subseteq \{1,2\}\). (d) True: \(\mathcal{P}(\varnothing) = \{\varnothing\}\) has 1 element, so its power set has \(2^1 = 2\) elements, namely \(\varnothing\) and \(\{\varnothing\}\).
-
\(\{\, n^2 \mid n \in \mathbb{Z},\ 1 \le n \le 5 \,\}\).
-
\(\{(0,a), (0,b), (0,c), (1,a), (1,b), (1,c)\}\), six pairs. \(\{0,1\}^8\) has \(2^8 = 256\) elements, each an 8-tuple of bits: a byte.
-
\(x \in A \setminus B \iff x \in A \wedge x \notin B \iff x \in A \wedge x \in \overline{B} \iff x \in A \cap \overline{B}\).
-
\(30 - 5 = 25\) take at least one. \(25 = 18 + 14 - |S \cap F|\), so \(|S \cap F| = 7\).
21.6. Relations
21.6.1. The problem
"Is less than", "divides", "has the same remainder when divided by 3", "is a prerequisite of", "follows on social media", "is in the same connected component as". Each of these takes two things and answers yes or no. Some behave very differently from others: "same remainder" sorts things into groups, "prerequisite of" puts them in an order, "follows" does neither. To reason about these patterns, and to know which algorithms apply, we need precise names for the properties a relation can have.
21.6.2. Intuition
A relation is just a set of pairs: the pairs that are related. Draw the elements as dots, and draw an arrow from \(a\) to \(b\) whenever \(a\) is related to \(b\). The properties are then visual: a loop at every dot (reflexive), every arrow paired with a reverse arrow (symmetric), every two-step path having a shortcut (transitive). That dots-and-arrows picture is a directed graph, the subject of Chapter 25.
|
Relation
A (binary) relation \(R\) from set \(A\) to set \(B\) is a subset of the Cartesian product: \(R \subseteq A \times B\). We write \(a \mathrel{R} b\) for \((a, b) \in R\). A relation on \(A\) is a relation from \(A\) to itself. Example on \(\{1,2,3\}\): "less than" is \(\{(1,2), (1,3), (2,3)\}\). |
|
Properties of a relation on a set \(A\)
Antisymmetric is not the opposite of symmetric: a relation can be both (equality) or neither ("follows"). |
21.6.3. Equivalence relations
|
Equivalence relation and equivalence class
An equivalence relation is a relation that is reflexive, symmetric and transitive. It behaves like "is the same as, in some respect". Common notation is \(a \sim b\). The equivalence class of \(a\) is \(\lbrack a] = \{\, x \in A \mid x \sim a \,\}\), everything equivalent to \(a\). The classes form a partition of \(A\): they are nonempty, pairwise disjoint, and their union is all of \(A\). Every element lives in exactly one class. |
The canonical example: on the integers, say \(a \sim b\) when \(a\) and \(b\) leave the same remainder on division by 3. Check the three properties: Try it: Same remainder mod 3.
-
Reflexive: \(a\) has the same remainder as itself.
-
Symmetric: if \(a\) has the same remainder as \(b\), then \(b\) has the same remainder as \(a\).
-
Transitive: if \(a\) matches \(b\) and \(b\) matches \(c\), all three share one remainder.
So the integers split into exactly three classes, \(\lbrack 0] = \{\ldots, -3, 0, 3, 6, \ldots\}\), \(\lbrack 1] = \{\ldots, -2, 1, 4, 7, \ldots\}\) and \(\lbrack 2] = \{\ldots, -1, 2, 5, 8, \ldots\}\). This is the "congruence modulo 3" that Chapter 23 builds a whole arithmetic on.
Why does an equivalence relation always partition? Suppose two classes \(\lbrack a]\) and \(\lbrack b]\) share some element \(x\). Then \(x \sim a\) and \(x \sim b\); by symmetry \(a \sim x\), and by transitivity \(a \sim b\). Now any \(y \in [a]\) has \(y \sim a \sim b\), so \(y \in [b]\), and vice versa. So two classes either coincide or are disjoint. Reflexivity ensures every element is in at least one class (its own).
21.6.4. Partial orders
|
Partial order
A partial order is a relation that is reflexive, antisymmetric and transitive. It behaves like "comes before or equals". A set with a partial order is a poset. It is partial because two elements may be incomparable: neither \(a \preceq b\) nor \(b \preceq a\). If every pair is comparable it is a total (or linear) order, like \(\le\) on numbers. |
"Divides" on \(\{1, 2, 3, 4, 6, 12\}\) is a partial order: every number divides itself; if \(a \mid b\) and \(b \mid a\) for positive integers then \(a = b\); and divisibility chains. But 4 and 6 are incomparable: neither divides the other. A Hasse diagram draws a poset economically: put larger elements higher, draw a line only for "immediate" relationships, and let reflexivity and transitivity be implied (12 is above 2 via 4 or 6, so no separate 2–12 line is drawn). Try it: Divisors of 12 as a Hasse diagram.
21.6.5. Worked example: classifying relations
Classify each relation on the given set. Try it: Classify “less than”.
(a) "\(a \le b\)" on the integers. Reflexive (\(a \le a\)). Not symmetric (\(1 \le 2\) but \(2 \not\le 1\)). Antisymmetric (\(a \le b\) and \(b \le a\) force \(a = b\)). Transitive. So: a partial order, in fact a total order.
(b) "\(a < b\)" on the integers. Not reflexive (\(1 \not< 1\)). Antisymmetric (vacuously: \(a < b \wedge b < a\) never happens). Transitive. Neither an equivalence relation nor a partial order; it is a strict order.
(c) "\(x\) and \(y\) are friends" on users. Symmetric, not reflexive by convention, and not transitive (your friend’s friend may be a stranger). Not an equivalence relation, which is why "friend groups" are not well-defined but "connected components" (friends-of-friends-of-… chains) are: taking the transitive closure repairs it.
The checks are mechanical enough to code. Note how each property is a quantified statement turned into all():
from itertools import product
def properties(S, R):
"""R is a set of pairs (a, b) meaning a R b, over the finite set S."""
reflexive = all((a, a) in R for a in S)
symmetric = all((b, a) in R for (a, b) in R)
transitive = all((a, d) in R
for (a, b) in R for (c, d) in R if b == c)
antisymmetric = all(a == b for (a, b) in R if (b, a) in R)
return dict(reflexive=reflexive, symmetric=symmetric,
transitive=transitive, antisymmetric=antisymmetric)
S = range(6)
same_mod3 = {(a, b) for a, b in product(S, S) if a % 3 == b % 3}
divides = {(a, b) for a, b in product(range(1, 13), repeat=2) if b % a == 0}
less_than = {(a, b) for a, b in product(S, S) if a < b}
print(properties(S, same_mod3))
print(properties(range(1, 13), divides))
print(properties(S, less_than))
{'reflexive': True, 'symmetric': True, 'transitive': True, 'antisymmetric': False}
{'reflexive': True, 'symmetric': False, 'transitive': True, 'antisymmetric': True}
{'reflexive': False, 'symmetric': False, 'transitive': True, 'antisymmetric': True}
|
Transitivity is the one people assume
Many natural relations fail transitivity, and code that assumes it breaks. "Approximately equal", |
21.6.6. Functions as special relations
A function is a relation with one extra rule. A relation \(f \subseteq A \times B\) is a function from \(A\) to \(B\), written \(f : A \to B\), if every \(a \in A\) is related to exactly one \(b \in B\). We then write \(f(a) = b\) instead of \((a, b) \in f\). In quantifier language: \(\forall a \in A\; \exists!\, b \in B\; (a, b) \in f\).
The relation "\(x\) is a square root of \(y\)" on real numbers is not a function from \(y\) to \(x\) (4 has two square roots, \(-1\) has none); the relation \(\{(x, x^2)\}\) is a function. A Python dict is a finite function: each key maps to exactly one value. The full treatment of domain, codomain, range, injective, surjective and inverse functions is in Chapter 11.
|
Function (as a relation)
A function \(f : A \to B\) is a relation from \(A\) to \(B\) in which each element of the domain \(A\) is paired with exactly one element of the codomain \(B\). "Exactly one" has two halves: at least one (defined everywhere on \(A\)) and at most one (no input has two outputs). |
|
Interactive Lab: relation property explorer
Draw arrows between up to eight dots. The lab lights up which of reflexive, symmetric, antisymmetric and transitive hold, and for any that fail it highlights a witness (a missing loop, an unreturned arrow, a two-step path with no shortcut). Buttons add the reflexive, symmetric or transitive closure; when the result is an equivalence relation the dots recolor by class, and when it is a partial order the lab redraws it as a Hasse diagram. Try it: Open the relation explorer |
21.6.7. Where you’d use this
Everyday: getting dressed is a partial order. Underwear before trousers, trousers before shoes, socks before shoes; shirt and socks are incomparable, so either order is fine. Any morning routine that respects the order is a topological sort of it, and recipes ("make the sauce while the pasta boils") are the same structure with parallel steps.
Physics: temperature exists because of an equivalence relation. The zeroth law of thermodynamics says that if bodies \(A\) and \(B\) are each in thermal equilibrium with \(C\), they are in equilibrium with each other. Together with symmetry, that is transitivity, so "in thermal equilibrium with" is an equivalence relation. A thermometer works by naming the equivalence classes: a temperature is a label for a class.
Biology and chemistry: classification. "Is a subgroup of" in taxonomy (species, genus, family, …) is a partial order whose Hasse diagram is a tree. "Has the same molecular formula" is an equivalence relation whose classes group isomers (ethanol and dimethyl ether are both \(\mathrm{C_2H_6O}\)).
Computing. Beyond the sidebar above: version constraints in a package manager compare versions by a total order, while "this commit is an ancestor of that one" in Git is a partial order (two branches' tips are incomparable until merged).
21.6.8. Exercises
-
On the set of all people, is "has the same birthday as" an equivalence relation? How many equivalence classes are there?
-
On \(\{1, 2, 3\}\), give a relation that is symmetric and transitive but not reflexive.
-
Draw the Hasse diagram of \(\mathcal{P}(\{a, b\})\) ordered by \(\subseteq\). Which pairs are incomparable? Try it: Hasse diagram of P({a, b}).
-
Which of these relations from \(\{1,2,3\}\) to \(\{x, y\}\) are functions? (a) \(\{(1,x), (2,x), (3,y)\}\); (b) \(\{(1,x), (1,y), (2,x), (3,x)\}\); (c) \(\{(1,x), (3,y)\}\).
Answers
-
Yes: reflexive, symmetric and transitive. There are 366 classes, one per calendar day including February 29 (assuming each day has at least one person born on it, which for all humanity is certainly true).
-
\(R = \{(1,1)\}\): symmetric and transitive (trivially), not reflexive because \((2,2) \notin R\). Another: \(R = \varnothing\). (This is why the "proof" that symmetry plus transitivity implies reflexivity, "\(a R b\) and \(b R a\) give \(a R a\)", fails: it assumes some \(b\) related to \(a\) exists.)
-
\(\varnothing\) at the bottom; \(\{a\}\) and \(\{b\}\) in the middle; \(\{a, b\}\) at the top; lines from \(\varnothing\) to each singleton and from each singleton to \(\{a,b\}\). The only incomparable pair is \(\{a\}\) and \(\{b\}\). The diagram is a diamond.
-
(a) Yes: each input has exactly one output. (b) No: 1 has two outputs. (c) No: 2 has no output (it is a partial function).
21.7. Coda: satisfiability, the hardest easy question
Given a boolean formula, is there any assignment of T/F to its variables that makes it true? This is the Boolean satisfiability problem, SAT. It sounds like an exercise from earlier in the chapter, and for three variables it is: try all eight rows.
from itertools import product
# (x or y) and (not x or z) and (not y or not z) and (not z or x)
clauses = [[1, 2], [-1, 3], [-2, -3], [-3, 1]] # DIMACS-style literals
def satisfies(assign, clauses):
return all(any(assign[abs(l)] == (l > 0) for l in c) for c in clauses)
def brute_force_sat(clauses, n):
for bits in product([False, True], repeat=n):
assign = dict(zip(range(1, n + 1), bits))
if satisfies(assign, clauses):
return assign
return None
print(brute_force_sat(clauses, 3))
{1: False, 2: True, 3: False}
The formula is written in conjunctive normal form (CNF): an "and" of clauses, each an "or" of literals (a variable or its negation). Literal 3 means \(z\); -3 means \(\neg z\). Any formula can be converted to CNF with the laws from Table 2. Check the answer: \(x = F, y = T, z = F\) gives \((F \vee T) \wedge (T \vee F) \wedge (F \vee T) \wedge (T \vee F) = T\). Try it: Convert a formula to CNF.
Try it: Package dependencies as SAT.
|
A 200-terabyte proof
The Boolean Pythagorean triples problem asked: can you color every positive integer red or blue so that no Pythagorean triple \(a^2 + b^2 = c^2\) is all one color? In 2016 a SAT solver showed that you can do it up to 7,824 but not to 7,825. The proof certificate was about 200 terabytes, at the time the largest proof ever produced. Every step is a resolution of clauses of the kind in this chapter. |
21.8. Interactive tools
Browser tools on the companion website that go with this chapter. Each example link in the chapter opens one of them with that example already set up.
21.9. Mastery check
-
Build the truth table of \((p \to q) \wedge (q \to p)\) and identify the connective it equals.
-
State the contrapositive and the converse of "if a function is differentiable, it is continuous". Which one is guaranteed true, given that the original is true?
-
Simplify
if not (x >= 0 and x < len(a)) or a[x] is None:so that everynotis gone (change comparisons as needed). -
Negate \(\forall \varepsilon > 0\; \exists N\; \forall n > N\; (|a_n| < \varepsilon)\), pushing the negation all the way in.
-
Let \(A = \{1, 2, 3\}\) and \(B = \{2, 3, 4\}\). Find \(A \,\triangle\, B\), \(|A \times B|\), and \(|\mathcal{P}(A \cap B)|\).
-
Is "\(a - b\) is an even integer" an equivalence relation on \(\mathbb{Z}\)? If so, describe its classes.
-
Explain in one sentence why
all([])isTruein Python andany([])isFalse.
Decision rule: All correct without hesitation → move on to Chapter 22, which puts this logic to work. Stuck on 1–3 → reread Section 21.2 and Section 21.3. Stuck on 4 or 7 → reread Section 21.4. Stuck on 5–6 → reread Section 21.5 and Section 21.6, then do their exercises.
Mastery check answers
-
Rows TT, TF, FT, FF: \(p \to q\) is T, F, T, T; \(q \to p\) is T, T, F, T; their conjunction is T, F, F, T. That is the biconditional \(p \leftrightarrow q\).
-
Contrapositive: "if a function is not continuous, it is not differentiable" (guaranteed true, equivalent to the original). Converse: "if a function is continuous, it is differentiable" (not guaranteed, and in fact false: \(|x|\) at 0, see Chapter 17).
-
De Morgan: \(\neg(x \ge 0 \wedge x < n) \equiv x < 0 \vee x \ge n\). So:
if x < 0 or x >= len(a) or a[x] is None:. Short-circuiting meansa[x]is only evaluated once the index is known to be in range. -
\(\exists \varepsilon > 0\; \forall N\; \exists n > N\; (|a_n| \ge \varepsilon)\). Each quantifier flips, the domain conditions (\(\varepsilon > 0\), \(n > N\)) stay, and \(<\) becomes \(\ge\). In words: there is some tolerance that the sequence keeps violating, no matter how far out you go; i.e. \(a_n\) does not tend to 0 (see Chapter 16).
-
\(A \,\triangle\, B = \{1, 4\}\); \(|A \times B| = 3 \cdot 3 = 9\); \(A \cap B = \{2, 3\}\), so \(|\mathcal{P}(A \cap B)| = 2^2 = 4\).
-
Yes. Reflexive: \(a - a = 0\) is even. Symmetric: if \(a - b = 2k\) then \(b - a = 2(-k)\). Transitive: if \(a - b = 2k\) and \(b - c = 2m\) then \(a - c = 2(k + m)\). Two classes: the even integers and the odd integers.
-
allof an empty collection is an "and" of no statements, vacuously true because there is no element to violate it;anyis an "or" of no statements, false because there is no witness.