Discrete Mathematics YMT211 · Fall 2026 Assoc. Prof. Ferhat Uçar
05 Predicate Logic Monday, October 19, 2026

Nested Quantifiers and Specifications

Statements with two quantifiers, why their order changes everything, how to negate them step by step, and how engineers use them to write precise specifications.

Learning objectives

By the end of this week you can:

  • 1 Read a statement with two quantifiers aloud and explain what it claims.
  • 2 Explain why ∀x∃y and ∃y∀x mean different things, and show it with a counterexample.
  • 3 Decide the truth value of nested statements over small and familiar domains.
  • 4 Translate English and mathematical sentences with two quantifiers into logic, and back.
  • 5 Negate a nested statement one quantifier at a time, and state the result in plain English.
  • 6 Write a precise specification for a small program with quantifiers, and check it in Python.

★ the wow moment

“Everyone follows someone” is not “someone is followed by everyone”.

∀x ∃y F(x, y) and ∃y ∀x F(x, y) use the same two symbols in a different order. The first describes almost any social network; the second claims there is a celebrity whom literally everyone follows. In the grid on this page you will see the difference as rows versus columns, and in the lab you will find out which one holds in a real network.

From one quantifier to two

Last week every statement had a single quantifier: “every student has taken Java”, “some server is overloaded”. That was enough to talk about properties of individual things. But many of the most interesting statements in computing are about relationships between things, and a relationship has two sides.

Think about a social network. “Everyone follows someone” talks about two people at once: the follower and the one being followed. So does “every user has a password”, “every request is answered by some server”, and “for every number there is a bigger one”. To write any of these we need a predicate with two variables, and a quantifier for each of them. When one quantifier sits inside the scope of another, we call them nested quantifiers.

Nothing new is needed to understand them. A nested statement is simply a quantified statement whose body is itself a quantified statement. You can always read it in two steps. In ∀x ∃y  P(x,y)\forall x\, \exists y\; P(x, y), first fix one particular xx; the part ∃y  P(x,y)\exists y\; P(x, y) is then an ordinary week 4 statement about that one xx. The outer ∀x\forall x asks whether this inner statement holds for every choice of xx.

Nested quantifiers are nested loops

If you have written a loop inside a loop, you already know how to evaluate a nested statement over a finite domain. Here is “everyone follows someone”, with F(x,y)F(x, y) meaning “xx follows yy”:

def everyone_follows_someone(people, F):
    for x in people:                 # ∀x : check every person ...
        found = False
        for y in people:             #   ∃y : ... has at least one y
            if F(x, y):
                found = True
                break                #   witness found for this x, move on
        if not found:
            return False             # this x is a counterexample
    return True

The outer loop is the ∀\forall, the inner loop is the ∃\exists. In Python the same thing fits on one line, and reading the line from the outside in gives exactly the logic:

all(any(F(x, y) for y in people) for x in people)     # ∀x ∃y F(x, y)

Notice that the inner loop runs once for each xx. Over a domain of nn people, a nested statement may look at up to n×nn \times n pairs. That is why checking such statements on large data is expensive, a theme we return to when we study algorithms.

Two quantifiers of the same kind

When both quantifiers are the same, their order does not matter. “For every xx and every yy” covers every pair no matter which variable you pick first, just as a double loop visits every cell of a table whether you go row by row or column by column. The same is true for two existentials: “there is an xx and there is a yy” only asks for one suitable pair.

∀x ∀y  P(x,y)  ≡  ∀y ∀x  P(x,y)∃x ∃y  P(x,y)  ≡  ∃y ∃x  P(x,y)\forall x\, \forall y\; P(x, y) \;\equiv\; \forall y\, \forall x\; P(x, y) \qquad\qquad \exists x\, \exists y\; P(x, y) \;\equiv\; \exists y\, \exists x\; P(x, y)

For example, over the real numbers, ∀x ∀y  (x+y=y+x)\forall x\, \forall y\; (x + y = y + x) states that addition is commutative, and it is true. The statement ∃x ∃y  (x+y=10∧x−y=4)\exists x\, \exists y\; (x + y = 10 \land x - y = 4) asks whether the system of two equations has a solution, and it does: x=7x = 7, y=3y = 3.

When the order matters

The real subtlety begins when the quantifiers are mixed. Compare these two statements, where the domain is all integers:

∀x ∃y  (x+y=10)and∃y ∀x  (x+y=10)\forall x\, \exists y\; (x + y = 10) \qquad\text{and}\qquad \exists y\, \forall x\; (x + y = 10)

The first one says: whatever integer xx you give me, I can find a yy that brings the sum to 10. That is true, because I simply choose y=10−xy = 10 - x. The important detail is that my choice of yy depends on your xx: for x=3x = 3 I answer 7, for x=12x = 12 I answer −2-2.

The second one says something much stronger: there is a single integer yy that works for every xx at the same time. There is no such number. If yy makes 1+y=101 + y = 10, then y=9y = 9, and 2+9≠102 + 9 \ne 10. The second statement is false.

Seeing it in a network

The grid below shows a small network of five people. A 1 in row xx and column yy means “xx follows yy”. Choose a statement, read the explanation, and click cells to change who follows whom. The most useful exercise is to compare the first two buttons.

order matters · F(x, y): x follows y · row = x, column = y

Click a cell to switch “x follows y” on or off.

Python: a loop inside a loop

The grid turns the abstract difference into a picture. ∀x ∃y  F(x,y)\forall x\, \exists y\; F(x, y) says that every row contains at least one 1: each person follows somebody, and each row may find its 1 in a different place. ∃y ∀x  F(x,y)\exists y\, \forall x\; F(x, y) says that some column is completely filled: one person, the same for everyone, is followed by all the others. In the starting network, every row has a 1 but no column is full, so the first statement is true and the second is false. If you make everyone follow Ada, Ada’s column fills up and the second statement becomes true as well.

The checkbox matters too. With “ignore x=yx = y” turned off, the diagonal counts, and a celebrity would also have to follow themselves to fill their column. This is why careful translations often say “everyone else” and add the condition x≠yx \ne y, as you will see below.

One direction always works

The two statements are not equivalent, but they are not unrelated either. If there is a celebrity whom everyone follows, then certainly everyone follows someone, because they all follow the celebrity. In symbols:

∃y ∀x  P(x,y)  →  ∀x ∃y  P(x,y)is always true,\exists y\, \forall x\; P(x, y) \;\to\; \forall x\, \exists y\; P(x, y) \quad\text{is always true,}

while the converse fails, as the integer example and the network both show. A useful way to remember it: ∃∀\exists\forall is the strong, rare statement, and ∀∃\forall\exists is the weak, common one.

The four mixed and pure forms at a glance

For a predicate P(x,y)P(x, y) of two variables, here is when each pattern is true and when it is false. It is worth reading slowly, one line at a time.

StatementIt is true whenIt is false when
∀x ∀y  P(x,y)\forall x\, \forall y\; P(x, y)P(x,y)P(x, y) holds for every pairthere is a pair with P(x,y)P(x, y) false
∀x ∃y  P(x,y)\forall x\, \exists y\; P(x, y)for every xx there is some yy (which may depend on xx) with P(x,y)P(x, y)there is an xx for which P(x,y)P(x, y) is false for every yy
∃x ∀y  P(x,y)\exists x\, \forall y\; P(x, y)there is one xx for which P(x,y)P(x, y) holds for every yyfor every xx there is some yy with P(x,y)P(x, y) false
∃x ∃y  P(x,y)\exists x\, \exists y\; P(x, y)there is at least one pair with P(x,y)P(x, y) trueP(x,y)P(x, y) is false for every pair

Statements from mathematics

Much of mathematics is written with nested quantifiers, often hidden behind ordinary words. Uncovering them is a good exercise in careful reading.

“The sum of two positive integers is always positive.” Two arbitrary integers are involved, and “always” means for all of them. With the domain of all integers:

∀x ∀y  ((x>0∧y>0)→x+y>0)\forall x\, \forall y\; \big( (x > 0 \land y > 0) \to x + y > 0 \big)

“Every real number except zero has a multiplicative inverse.” For each nonzero xx we need some yy with xy=1xy = 1, and the yy clearly depends on xx (for 4 it is 0.25, for −2-2 it is −0.5-0.5):

∀x (x≠0→∃y  (xy=1))\forall x\, \big( x \ne 0 \to \exists y\; (xy = 1) \big)

This is true over the real numbers and false over the integers, where 2 has no integer inverse. Once again, the domain decides.

“There is no largest integer.” Saying that a largest integer exists would be ∃y ∀x  (x≤y)\exists y\, \forall x\; (x \le y). Its negation, as we will learn below, is ∀y ∃x  (x>y)\forall y\, \exists x\; (x > y): whatever integer you name, there is a bigger one.

Translating English into logic

Translation with two quantifiers follows the same recipe as last week, with one extra habit: give each “thing” in the sentence its own variable, and decide for each variable whether the sentence means every one of them or some of them. Then the golden rule from week 4 applies to each quantifier separately: ∀\forall goes with →\to, and ∃\exists goes with ∧\land.

Let us work through several examples. In the first group the domain is all users of a messaging system, and M(x,y)M(x, y) means “xx has sent a message to yy”.

“Every user has sent a message to at least one other user.” “Every user” is the outer ∀x\forall x, “at least one other user” is an inner ∃y\exists y, and “other” means yy is not xx itself:

∀x ∃y  (x≠y∧M(x,y))\forall x\, \exists y\; \big( x \ne y \land M(x, y) \big)

“There is a user who has sent messages to all other users.” Now the outer quantifier is ∃x\exists x, and “all other users” is a ∀y\forall y restricted to y≠xy \ne x, so it takes an implication:

∃x ∀y  (x≠y→M(x,y))\exists x\, \forall y\; \big( x \ne y \to M(x, y) \big)

“There are two users who have sent messages to each other.”

∃x ∃y  (x≠y∧M(x,y)∧M(y,x))\exists x\, \exists y\; \big( x \ne y \land M(x, y) \land M(y, x) \big)

“Some user has never received a message.” The user who receives is yy, and “never” means from nobody:

∃y ∀x  ¬M(x,y)\exists y\, \forall x\; \neg M(x, y)

The next examples use other domains. Read each sentence, decide on the variables, and only then look at the formula.

“Every student either has a computer or has a friend who has one.” With the domain all students in the school, C(x)C(x): xx has a computer, and F(x,y)F(x, y): xx and yy are friends:

∀x (C(x)∨∃y (C(y)∧F(x,y)))\forall x\, \Big( C(x) \lor \exists y\, \big( C(y) \land F(x, y) \big) \Big)

“There is a woman who has taken a flight on every airline in the world.” Three kinds of things appear: women, flights and airlines. Let P(w,f)P(w, f) mean that ww has taken flight ff, and Q(f,a)Q(f, a) that flight ff belongs to airline aa. The sentence names one woman, every airline, and for each airline some flight:

∃w ∀a ∃f  (P(w,f)∧Q(f,a))\exists w\, \forall a\, \exists f\; \big( P(w, f) \land Q(f, a) \big)

The flight is chosen after the airline, because it must be a flight of that airline. If you moved ∃f\exists f to the front, you would claim that a single flight belongs to every airline, which is nonsense.

From logic back to English

Reading formulas aloud is just as important as writing them, and the goal is a sentence a person would actually say. Take L(x,y)L(x, y): “xx loves yy”, with the domain all people.

∀x ∃y  L(x,y)\forall x\, \exists y\; L(x, y) says, word by word, “for every person xx there is a person yy such that xx loves yy”, which is simply “everybody loves somebody.” The somebody may be different for each person.

∃y ∀x  L(x,y)\exists y\, \forall x\; L(x, y) says “there is a person yy such that every person xx loves yy”, that is, “there is someone whom everybody loves.” This is a much bolder claim, and the earlier result tells us it implies the first one.

∀x ∀y  (L(x,y)→L(y,x))\forall x\, \forall y\; \big( L(x, y) \to L(y, x) \big) says that love is always returned: “if one person loves another, the other loves them back.” Unfortunately, a single counterexample from real life is enough to make it false.

Negating nested statements

To negate a nested statement, we use De Morgan’s laws for quantifiers from last week, one quantifier at a time, moving the negation from the outside inwards. Each time the negation passes a quantifier, that quantifier flips: ∀\forall becomes ∃\exists and ∃\exists becomes ∀\forall. When the negation finally reaches the body, we simplify it with the laws from week 3.

The same procedure handles longer statements. Here are two from the practice slides, worked one step at a time. Try each one yourself before reading the solution.

Negate ∀x ∃y  (P(x)→Q(x,y))\forall x\, \exists y\; \big( P(x) \to Q(x, y) \big)¬ ∀x ∃y  (P(x)→Q(x,y))≡∃x  ¬∃y  (P(x)→Q(x,y))≡∃x ∀y  ¬(P(x)→Q(x,y))≡∃x ∀y  (P(x)∧¬Q(x,y))\begin{aligned} \neg\, \forall x\, \exists y\; \big( P(x) \to Q(x, y) \big) &\equiv \exists x\; \neg \exists y\; \big( P(x) \to Q(x, y) \big)\\ &\equiv \exists x\, \forall y\; \neg \big( P(x) \to Q(x, y) \big)\\ &\equiv \exists x\, \forall y\; \big( P(x) \land \neg Q(x, y) \big) \end{aligned}
Negate ∃x ∀y  (R(x)∧S(y))\exists x\, \forall y\; \big( R(x) \land S(y) \big)¬ ∃x ∀y  (R(x)∧S(y))≡∀x  ¬∀y  (R(x)∧S(y))≡∀x ∃y  ¬(R(x)∧S(y))≡∀x ∃y  (¬R(x)∨¬S(y))\begin{aligned} \neg\, \exists x\, \forall y\; \big( R(x) \land S(y) \big) &\equiv \forall x\; \neg \forall y\; \big( R(x) \land S(y) \big)\\ &\equiv \forall x\, \exists y\; \neg \big( R(x) \land S(y) \big)\\ &\equiv \forall x\, \exists y\; \big( \neg R(x) \lor \neg S(y) \big) \end{aligned}

Specifications: saying exactly what a program must do

Engineers use nested quantifiers every day, usually without calling them that, whenever they write down what a program is supposed to do. Such a description is called a specification. It usually has two parts: a precondition, which says what the program may assume about its input, and a postcondition, which says what must be true about its output when it finishes.

Take a function that sorts a list aa of length nn and returns a list bb. What does “sorted correctly” actually mean? It means two things, and both need quantifiers.

The output must be in order. Every element is at most the next one:

∀i  (0≤i<n−1→b[i]≤b[i+1])\forall i\; \big( 0 \le i < n - 1 \to b[i] \le b[i+1] \big)

And the output must contain the same elements as the input, nothing lost and nothing invented. A first attempt is to say that every value of aa appears somewhere in bb:

∀i ∃j  (a[i]=b[j])\forall i\, \exists j\; \big( a[i] = b[j] \big)

This is a good start, but it is not quite enough. If a=[3,3,1]a = [3, 3, 1], the list b=[1,3,5]b = [1, 3, 5] is in order and contains every value of aa, yet it is clearly wrong: one 3 is missing and a 5 appeared from nowhere. A complete specification must also say that each value occurs the same number of times in both lists. Finding such gaps is exactly the point of writing specifications precisely: a vague “the output is the sorted input” hides the question, while the formula forces you to face it.

The same ideas translate directly into tests:

def is_sorted(b):
    return all(b[i] <= b[i + 1] for i in range(len(b) - 1))                      # ∀i

def keeps_values(a, b):
    return all(any(a[i] == b[j] for j in range(len(b))) for i in range(len(a)))  # ∀i ∃j

def keeps_counts(a, b):
    return all(a.count(v) == b.count(v) for v in set(a) | set(b))                # ∀v

Many guarantees of real systems have the same shape. Here are a few, written with the obvious predicates.

GuaranteeLogic
Every request receives a response.∀r ∃s  Responds(s,r)\forall r\, \exists s\; \mathit{Responds}(s, r)
No two users share an ID.∀x ∀y  (x≠y→id(x)≠id(y))\forall x\, \forall y\; \big( x \ne y \to \mathit{id}(x) \ne \mathit{id}(y) \big)
Some backup server can take over any request.∃s ∀r  CanServe(s,r)\exists s\, \forall r\; \mathit{CanServe}(s, r)
Every user who is an admin can read every table.∀u (A(u)→∀t  Read(u,t))\forall u\, \big( A(u) \to \forall t\; \mathit{Read}(u, t) \big)

Summary

A statement with nested quantifiers is read from the left, and each quantifier covers everything to its right. Two quantifiers of the same kind can be swapped freely, but a mixed pair cannot: ∀x ∃y\forall x\, \exists y lets the choice of yy depend on xx, while ∃y ∀x\exists y\, \forall x demands one yy that works for every xx. The second always implies the first, never the other way round. To decide which order a sentence needs, ask whether one choice depends on the other.

Over finite data, nested quantifiers are nested loops, and in Python they become nested calls to all and any. To negate a nested statement, move the negation inwards one quantifier at a time, flipping each quantifier it passes, and then simplify the body with the laws of logic. Finally, specifications are nested-quantifier statements about programs, and writing them precisely is one of the most practical skills this course offers.

Practice

Answers
  1. ∀x ∃y  (y>x)\forall x\, \exists y\; (y > x), which is true: for any xx, take y=x+1y = x + 1. Swapping gives ∃y ∀x  (y>x)\exists y\, \forall x\; (y > x), “there is an integer larger than every integer”. It is false, because no integer is larger than itself (or than itself plus one).
  2. Over the integers it is false: it claims there is a smallest integer, but for any xx the number x−1x - 1 is smaller. Over the natural numbers it is true, with the witness x=0x = 0.
  3. It is false. The negation is ∃x ∀y  (xy≠1)\exists x\, \forall y\; (xy \ne 1), and x=0x = 0 is a witness: 0⋅y=0≠10 \cdot y = 0 \ne 1 for every yy. Zero has no inverse.
  4. ¬∃x ∀y  (x≠y→M(x,y))\neg \exists x\, \forall y\; \big( x \ne y \to M(x, y) \big), which is equivalent to ∀x ∃y  (x≠y∧¬M(x,y))\forall x\, \exists y\; \big( x \ne y \land \neg M(x, y) \big): “everyone has at least one other person they have not written to.”
  5. ∀i ∃j  (a[i]=b[j])\forall i\, \exists j\; (a[i] = b[j]), and in Python all(any(a[i] == b[j] for j in range(len(b))) for i in range(len(a))), or more simply all(v in b for v in a).
  6. “Whenever two people follow each other, they are friends.”

Before the lab

In Lab 4 you will check nested-quantifier statements on a small social network: whether everyone follows someone, whether there is a celebrity, whether following is mutual. You will find witnesses and counterexamples with nested loops, and you will put the negation rule from this page into code.

In industry

  • Formal specifications

    Engineers at Amazon Web Services and Microsoft write specifications in TLA+, a language built on nested quantifiers, to find design bugs before any code exists.

  • Program correctness

    “The output is sorted” is ∀i (a[i] ≤ a[i+1]), and “nothing was lost” is ∀v ∃j (b[j] = v). Test frameworks and code reviewers check exactly these statements.

  • Calculus and numerical code

    The ε–δ definition of a limit is ∀ε ∃δ ∀x. Every convergence test in numerical software is an attempt to check a statement of this shape.

  • Distributed systems

    “For every request there is a server that answers it” and “there is a server that answers every request” are different guarantees, and only one of them survives the loss of a single machine.

Lab 4: Nested Quantifiers: Checking a Social Network

Write the four shapes of a nested statement, find witnesses and counterexamples, check a social network for celebrities and unreturned follows, negate a nested statement in code, and turn a sorting specification into a test.

due Fri, Oct 23 · 23:59 · 100 points · open now

Go deeper

Tags:nested quantifiersorder of quantifiersnegationspecificationpreconditionpostconditionε–δTLA+allany