Lab 3 · Explore: ∀ and ∃ in pandas and in a real SQL database¶
Discrete Mathematics (YMT211) · Fall 2026
The playground half of Lab 3. Nothing here is graded. You will ask the same questions as in quantifiers.py,
first with a table library (pandas), then with a real SQL database. Watch how ∀ and ∃ show up everywhere.
1 · The class as a table¶
The same ten fictional students as in data.py, written out here so the notebook also runs on its own.
import pandas as pd
STUDENTS = [
("Ada", 2, "Python,C", True, 92), ("Bora", 1, "Python", True, 67), ("Cemre", 2, "Python,Java", True, 74),
("Doruk", 3, "Java,C,SQL", False, 58), ("Ece", 1, "C", True, 81), ("Fırat", 2, "Java", True, 49),
("Gizem", 4, "Python,SQL", True, 88), ("Hakan", 1, "", False, 55), ("Irmak", 3, "Python,Java,C", True, 95),
("Kaan", 2, "Python", False, 62),
]
df = pd.DataFrame(STUDENTS, columns=["name", "year", "langs", "github", "math"])
df["python"] = df.langs.str.contains("Python")
df["java"] = df.langs.str.contains("Java")
df
| name | year | langs | github | math | python | java | |
|---|---|---|---|---|---|---|---|
| 0 | Ada | 2 | Python,C | True | 92 | True | False |
| 1 | Bora | 1 | Python | True | 67 | True | False |
| 2 | Cemre | 2 | Python,Java | True | 74 | True | True |
| 3 | Doruk | 3 | Java,C,SQL | False | 58 | False | True |
| 4 | Ece | 1 | C | True | 81 | False | False |
| 5 | Fırat | 2 | Java | True | 49 | False | True |
| 6 | Gizem | 4 | Python,SQL | True | 88 | True | False |
| 7 | Hakan | 1 | False | 55 | False | False | |
| 8 | Irmak | 3 | Python,Java,C | True | 95 | True | True |
| 9 | Kaan | 2 | Python | False | 62 | True | False |
2 · ∀ and ∃ in pandas¶
A column of True/False values has .all() (∀) and .any() (∃).
print("Q1 ∀ github :", df.github.all())
print("Q2 ∃ java :", df.java.any())
second = df[df.year == 2] # the filter A(x): restrict the domain
print("Q3 ∀ (Y2 → Python) :", second.python.all())
print(" counterexample :", list(second[~second.python].name))
first = df[df.year == 1]
print("Q4 ¬∃ (Y1 ∧ fail) :", not (first.math < 50).any())
Q1 ∀ github : False Q2 ∃ java : True Q3 ∀ (Y2 → Python) : False counterexample : ['Fırat'] Q4 ¬∃ (Y1 ∧ fail) : True
Notice:
df[df.year == 2]is the golden rule. Keeping only the second-years and then asking.all()is exactly $\forall x\,(Y_2(x) \to P(x))$: the people outside the filter can never break it.
3 · The same questions in SQL¶
Python ships with a small database engine, SQLite. We load the class into a table and ask SQL.
import sqlite3
db = sqlite3.connect(":memory:")
df.drop(columns=["langs"]).to_sql("students", db, index=False)
def ask(query):
return db.execute(query).fetchone()[0]
print("Q2 ∃ java:", ask("SELECT EXISTS (SELECT * FROM students WHERE java)"))
Q2 ∃ java: 1
SQL has no FOR ALL. To ask “does every second-year know Python?” a database uses De Morgan: $\forall x\,(Y_2 \to P) \equiv \neg\exists x\,(Y_2 \land \neg P)$, that is, there is no second-year who does not know Python.
q3 = (
"SELECT NOT EXISTS ("
" SELECT * FROM students"
" WHERE year = 2 AND NOT python"
")"
)
print("Q3 ∀ (Y2 → Python):", ask(q3))
print("who breaks it:", db.execute("SELECT name FROM students WHERE year = 2 AND NOT python").fetchall())
Q3 ∀ (Y2 → Python): 0
who breaks it: [('Fırat',)]
4 · The two classic mistakes, in data¶
The wrong translations from the week 4 notes give silly answers on real data too.
wrong_and = (df.year.eq(2) & df.python).all() # ∀x (Y2 ∧ P): "everyone is a 2nd-year who knows Python"
wrong_imp = ((~df.year.eq(2)) | df.python).any() # ∃x (Y2 → P): true thanks to anyone who is not a 2nd-year
print("∀x (Y2 ∧ P) :", wrong_and)
print("∃x (Y2 → P) :", wrong_imp)
∀x (Y2 ∧ P) : False ∃x (Y2 → P) : True
5 · Empty domains¶
What is “every student in year 5 has GitHub”? There are no year-5 students.
fifth = df[df.year == 5]
print("rows :", len(fifth))
print("∀ (.all()) :", fifth.github.all(), " ← vacuously true: no counterexample exists")
print("∃ (.any()) :", fifth.github.any(), " ← false: no witness exists")
rows : 0 ∀ (.all()) : True ← vacuously true: no counterexample exists ∃ (.any()) : False ← false: no witness exists
6 · Hunting for counterexamples¶
A claim about all integers can never be checked by a loop, but a loop can hunt for a counterexample. The polynomial $n^2 - n + 41$ looks like it always gives a prime. Does it?
def is_prime(n):
return n > 1 and all(n % d for d in range(2, int(n ** 0.5) + 1))
n = next(n for n in range(1000) if not is_prime(n * n - n + 41))
print(f"counterexample: n = {n}, n² - n + 41 = {n*n - n + 41} = 41 × {(n*n - n + 41)//41}")
counterexample: n = 41, n² - n + 41 = 1681 = 41 × 41
Every value from $n = 0$ to $n = 40$ gives a prime, then $n = 41$ breaks it. Checking examples can disprove a ∀ statement, never prove it. That is why week 7 is about proofs.
Your turn¶
- Ask in pandas and in SQL: “some first-year student knows C.”
- Ask “every student with a GitHub account knows at least one language.” (Hint:
df.langs != "".) - Change one student in
STUDENTSso that Q3 becomes true, and re-run sections 2 and 3.