Direct proof, proof by contradiction, contrapositive, dan mathematical induction adalah teknik penalaran formal — yang secara langsung berkaitan dengan reasoning rekursi, testing edge-case backward, dan loop invariants dalam kode kalian.

Setelah di episode 8 kita memahami relasi dan fungsi — injective, surjective, bijective — pada episode ini kita mempelajari proof techniques: teknik membuktikan pernyataan matematika secara formal. Membuktikan bukan sekadar "menunjukkan contoh" — ini adalah penalaran logis yang meyakinkan bahwa pernyataan benar untuk semua kasus, bukan hanya beberapa.
Mengapa proof techniques penting untuk programmer? Karena kalian sebenarnya sudah melakukan bukti informal setiap hari: ketika kalian menulis unit test, itu adalah verifikasi untuk beberapa kasus. Ketika kalian menulis loop invariant, itu adalah bukti informal bahwa loop menghasilkan output benar. Ketika kalian menulis property-based testing, itu adalah verifikasi untuk semua kasus dalam domain. Memahami bukti formal membuat kalian bisa menulis kode yang terbukti benar, bukan hanya "sepertinya benar".
Cara paling sederhana: asumsikan hipotesis benar, gunakan langkah logis berurutan hingga kesimpulan tercapai.
Pernyataan: Jika a dan b genap, maka a + b genap.
Bukti:
def is_even(n):
return n % 2 == 0
# Verifikasi untuk banyak pasangan
for a in range(0, 20, 2): # genap
for b in range(0, 20, 2):
assert is_even(a + b), f"Failed: {a} + {b} = {a+b}"
print("Direct proof verified: genap + genap = genap")Asumusikan pernyataan yang ingin dibuktikan salah, lalu tunjukkan ini menghasilkan kontradiksi.
Pernyataan: √2 irasional (tidak bisa a/b di mana a, b integer).
Bukti:
import math
# Tunjukkan bahwa a² tidak pernah = 2b² untuk a,b kecil
found = False
for b in range(1, 10000):
for a in range(1, 10000):
if a**2 == 2 * b**2:
found = True
break
if found:
break
print(f"a² = 2b² ditemukan? {found}") # False — tidak ada solusi integer
print(f"√2 ≈ {math.sqrt(2):.15f}") # 1.4142135623730951 — desimal tak hinggaMembuktikan P → Q dengan membuktikan ¬Q → ¬P (yang secara logika ekuivalen).
Bukti (contrapositive): Jika a ganjil, maka a² ganjil.
def bukti_contrapositive():
"""Verifikasi: jika a² genap, a pasti genap."""
for a in range(-100, 101):
if a ** 2 % 2 == 0: # a² genap
assert a % 2 == 0, f"Counterexample: a={a}, a²={a**2}"
print("Contrapositive verified: a² genap → a genap")
bukti_contrapositive()Induksi adalah teknik untuk membuktikan pernyataan untuk semua bilangan natural: buktikan base case (n=0 atau n=1), lalu buktikan jika berlaku untuk n=k, maka berlaku untuk n=k+1.
Base case (n=1): 1² = 1. Rumus: 1(2)(3)/6 = 1. ✓
Inductive step: Asumsikan berlaku untuk n=k. Tunjukkan berlaku untuk n=k+1.
def sigma_kuadrat_manual(n):
"""Penjumlahan manual."""
return sum(i**2 for i in range(1, n + 1))
def sigma_kuadrat_rumus(n):
"""Rumus tertutup."""
return n * (n + 1) * (2 * n + 1) // 6
# Verifikasi untuk banyak nilai n
for n in range(1, 101):
manual = sigma_kuadrat_manual(n)
rumus = sigma_kuadrat_rumus(n)
assert manual == rumus, f"Failed at n={n}: {manual} != {rumus}"
print(f"Σi² (n=1..10) manual: {sigma_kuadrat_manual(10)}")
print(f"Σi² (n=1..10) rumus: {sigma_kuadrat_rumus(10)}")
print(f"Induksi terverifikasi untuk n=1 sampai 100!")Dalam programming, rekursi adalah implementasi langsung dari induksi: base case = base case induksi; recursive case = inductive step:
def faktorial(n):
"""Base case: 0! = 1. Recursive: n! = n × (n-1)!"""
if n == 0: # Base case
return 1
return n * faktorial(n - 1) # Inductive step
def power(b, n):
"""Base case: b^0 = 1. Recursive: b^n = b × b^(n-1)."""
if n == 0:
return 1
return b * power(b, n - 1)
print(f"5! = {faktorial(5)}") # 120
print(f"2^10 = {power(2, 10)}") # 1024Loop invariant adalah properti yang selalu benar sebelum dan sesudah setiap iterasi loop — ini adalah bukti informal bahwa loop menghasilkan output yang benar.
Invariant: Setelah setiap iterasi outer loop, elemen terakhir yang diproses berada di posisi yang benar.
def bubble_sort(arr):
"""
Invariant: Setelah iterasi i, elemen arr[n-i:] sudah terurut.
"""
n = len(arr)
for i in range(n):
swapped = False
for j in range(0, n - i - 1):
if arr[j] > arr[j + 1]:
arr[j], arr[j + 1] = arr[j + 1], arr[j]
swapped = True
# Invariant check (untuk debugging):
# assert all(arr[j] <= arr[j+1] for j in range(n-i-1, n))
if not swapped:
break
return arr
data = [64, 34, 25, 12, 22, 11, 90]
print(f"Before: {data}")
print(f"After: {bubble_sort(data.copy())}")Note
Loop invariants bukan hanya latihan akademis — mereka adalah tool debugging yang powerful. Jika kalian bisa menyatakan invariant loop kalian secara eksplisit, kalian bisa menulis assertion yang mendeteksi bug saat runtime. Ini lebih efektif dari 100 unit test untuk kasus edge.
Inti yang harus dibawa pulang:
¬Q → ¬P sebagai ganti P → Q — kadang lebih mudah.Di episode 10 selanjutnya kita akan mempelajari counting: sum rule dan product rule — prinsip dasar menghitung kombinasi yang menjadi fondasi dari combinatorics. Bukti induction yang baru kalian pelajari akan sering menggunakan teknik counting untuk menghitung jumlah kasus!