Show description
MAT 243 — Visual Study Guide
MAT 243 — Visual Study Guide
MAT 243
discrete math · visual guide
module 11 · companion
proofs, primes,& the patterns hiding in numbers
a visual reference for induction, divisibility, recursion, and linear recurrence relations. every concept shows its shape. every symbol earns its keep.
01 induction
02 IH
03 primes
04 gcd
05 lcm
06 recursion
07 rec. definitions
08 lin. recurrence
09 order
10 homogeneous
11 const. coefficients
12 lhcc
13 char. equation
01 / PROOF TECHNIQUE
mathematical induction
a two-step proof machine. prove it works for the first case. prove each case implies the next. logic does the rest. this is the domino effect written in math.
the mental model
every induction proof is a line of dominos
to prove infinitely many statements, you only need to prove two things:
base case — push the first domino (prove P(1) directly)
inductive step — show each domino knocks the next (if P(k) is true, then P(k+1) is true)
if both hold, every domino falls. that's the whole trick.
← first domino is the base case · rest fall by the inductive step →
push the first domino
reset
worked example
prove: 1 + 2 + 3 + ... + n = n(n+1)/2
click through each step of the proof. watch how the inductive hypothesis becomes the bridge from k to k+1.
claim: P(n): 1 + 2 + ... + n = n(n+1)/2 for all n ≥ 1
base case. show P(1) holds.
LHS = 1
RHS = 1(1+1)/2 = 2/2 = 1 ✓
inductive step. assume P(k) holds for some k ≥ 1.
inductive hypothesis (IH):
1 + 2 + ... + k = k(k+1)/2
show P(k+1) holds. target:
1 + 2 + ... + k + (k+1) = (k+1)(k+2)/2
start with LHS:
1 + 2 + ... + k + (k+1)
= k(k+1)/2 + (k+1) ← substitute using IH
= (k+1)[k/2 + 1] ← factor out (k+1)
= (k+1)(k + 2)/2
= (k+1)(k+2)/2 ✓ ← matches target
by induction, P(n) holds for all n ≥ 1. ∎
next step →
← back
restart
step 0 / 16
template to memorize
every induction proof has the same skeleton
claim: P(n) is true for all n ≥ n₀
proof (by induction on n).
base case. show P(n₀) is true.
[plug in n₀, verify directly]
inductive step. assume P(k) for some k ≥ n₀. ← inductive hypothesis (IH)
we want to show P(k+1) is true.
[use IH to transform P(k) into P(k+1)]
therefore, by induction, P(n) holds for all n ≥ n₀. ∎
master the skeleton. the only part that changes problem-to-problem is the algebra in the inductive step.
02 / KEY TERM
the inductive hypothesis (IH)
the load-bearing assumption.…
MAT 243 — Visual Study Guide
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>MAT 243 — Visual Study Guide</title>
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Fraunces:ital,opsz,wght,SOFT@0,9..144,300..900,0..100;1,9..144,300..900,0..100&family=Instrument+Sans:ital,wght@0,400..700;1,400..700&family=JetBrains+Mono:ital,wght@0,400..700;1,400..700&display=swap" rel="stylesheet">
<style>
:root {
--ink: #0b1020;
--ink-2: #121835;
--ink-3: #1a2348;
--paper: #f4ede4;
--paper-dim: #d8cfc2;
--paper-faint: rgba(244, 237, 228, 0.15);
--amber: #ffb454;
--amber-glow: rgba(255, 180, 84, 0.35);
--mint: #7dffb8;
--mint-glow: rgba(125, 255, 184, 0.35);
--rose: #ff7a8a;
--sky: #8bb8ff;
--grid: rgba(244, 237, 228, 0.04);
--shadow: 0 20px 60px -20px rgba(0,0,0,0.6);
}
* { box-sizing: border-box; margin: 0; padding: 0; }
html { scroll-behavior: smooth; }
body {
background: var(--ink);
color: var(--paper);
font-family: 'Instrument Sans', sans-serif;
font-size: 17px;
line-height: 1.65;
overflow-x: hidden;
background-image:
linear-gradient(var(--grid) 1px, transparent 1px),
linear-gradient(90deg, var(--grid) 1px, transparent 1px);
background-size: 32px 32px;
background-position: -1px -1px;
}
body::before {
content: '';
position: fixed;
inset: 0;
background: radial-gradient(ellipse at top left, rgba(139, 184, 255, 0.08), transparent 50%),
radial-gradient(ellipse at bottom right, rgba(255, 180, 84, 0.06), transparent 50%);
pointer-events: none;
z-index: 0;
}
main { position: relative; z-index: 1; }
.wrap { max-width: 1180px; margin: 0 auto; padding: 0 2rem; }
/* === HERO === */
.hero {
padding: 6rem 0 4rem;
position: relative;
border-bottom: 1px solid var(--paper-faint);
}
.kicker {
font-family: 'JetBrains Mono', monospace;
font-size: 0.75rem;
letter-spacing: 0.2em;
text-transform: uppercase;
color: var(--amber);
margin-bottom: 1.5rem;
display: flex;
align-items: center;
gap: 0.75rem;
}
.kicker::before {
content: '';
width: 40px;
height: 1px;
background: var(--amber);
}
.hero h1 {
font-family: 'Fraunces', serif;
font-weight: 300;
font-size: clamp(3rem, 8vw, 6.5rem);
line-height: 0.95;
letter-spacing: -0.03em;
margin-bottom: 2rem;
font-variation-settings: "SOFT" 50;
}
.hero h1 em {
font-style: italic;
font-weight: 400;
color: var(--amber);
font-variation-settings: "SOFT" 100;
}
.hero p.lead {
font-size: 1.25rem;
max-width: 720px;
color: var(--paper-dim);
margin-bottom: 3rem;
}
.toc {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(180px, 1fr));
gap: 0.5rem;
font-family: 'JetBrains Mono', monospace;
font-size: 0.8rem;
}
.toc a {
color: var(--paper-dim);
text-decoration: none;
padding: 0.5rem 0.75rem;
border: 1px solid var(--paper-faint);
border-radius: 4px;
transition: all 0.2s;
display: flex;
gap: 0.5rem;
align-items: center;
}
.toc a:hover {
color: var(--ink);
background: var(--amber);
border-color: var(--amber);
}
.toc a span { color: var(--amber); opacity: 0.6; }
.toc a:hover span { color: var(--ink); opacity: 1; }
/* === SECTIONS === */
section.topic {
padding: 5rem 0;
border-bottom: 1px solid var(--paper-faint);
}
.topic-header {
display: flex;
align-items: baseline;
gap: 2rem;
margin-bottom: 3rem;
flex-wrap: wrap;
}
.topic-num {
font-family: 'JetBrains Mono', monospace;
font-size: 0.9rem;
color: var(--amber);
letter-spacing: 0.15em;
}
.topic h2 {
font-family: 'Fraunces', serif;
font-weight: 300;
font-size: clamp(2.2rem, 5vw, 3.75rem);
letter-spacing: -0.02em;
line-height: 1;
font-variation-settings: "SOFT" 50;
}
.topic h2 em {
font-style: italic;
color: var(--mint);
font-variation-settings: "SOFT" 100;
}
.topic-intro {
font-size: 1.15rem;
color: var(--paper-dim);
max-width: 760px;
margin-bottom: 2.5rem;
}
/* === CARDS === */
.card {
background: var(--ink-2);
border: 1px solid var(--paper-faint);
border-radius: 8px;
padding: 2rem;
margin: 1.5rem 0;
position: relative;
overflow: hidden;
}
.card.highlight {
background: linear-gradient(135deg, var(--ink-2) 0%, var(--ink-3) 100%);
border-color: var(--amber);
}
.card.highlight::before {
content: '';
position: absolute;
top: 0; left: 0;
width: 3px;
height: 100%;
background: var(--amber);
}
.card-label {
font-family: 'JetBrains Mono', monospace;
font-size: 0.7rem;
letter-spacing: 0.2em;
text-transform: uppercase;
color: var(--amber);
margin-bottom: 1rem;
display: block;
}
.card h3 {
font-family: 'Fraunces', serif;
font-weight: 400;
font-size: 1.6rem;
margin-bottom: 1rem;
letter-spacing: -0.01em;
}
.card h4 {
font-family: 'Fraunces', serif;
font-weight: 500;
font-size: 1.2rem;
margin: 1.5rem 0 0.75rem;
color: var(--amber);
}
.card p { margin-bottom: 1rem; }
.card p:last-child { margin-bottom: 0; }
/* === MATH === */
.math {
font-family: 'JetBrains Mono', monospace;
background: var(--ink);
border: 1px solid var(--paper-faint);
padding: 1rem 1.25rem;
border-radius: 6px;
margin: 1rem 0;
font-size: 0.95rem;
overflow-x: auto;
white-space: pre;
color: var(--mint);
}
.math.highlight { border-left: 3px solid var(--amber); color: var(--paper); }
.inline-math {
font-family: 'JetBrains Mono', monospace;
background: var(--ink);
padding: 0.1rem 0.4rem;
border-radius: 3px;
font-size: 0.88em;
color: var(--mint);
border: 1px solid var(--paper-faint);
}
code {
font-family: 'JetBrains Mono', monospace;
background: var(--ink);
padding: 0.1rem 0.4rem;
border-radius: 3px;
font-size: 0.88em;
color: var(--amber);
}
.pill {
display: inline-block;
font-family: 'JetBrains Mono', monospace;
font-size: 0.72rem;
letter-spacing: 0.1em;
text-transform: uppercase;
padding: 0.2rem 0.6rem;
border-radius: 999px;
margin-right: 0.4rem;
}
.pill.amber { background: rgba(255, 180, 84, 0.15); color: var(--amber); }
.pill.mint { background: rgba(125, 255, 184, 0.15); color: var(--mint); }
.pill.rose { background: rgba(255, 122, 138, 0.15); color: var(--rose); }
.pill.sky { background: rgba(139, 184, 255, 0.15); color: var(--sky); }
/* === BUTTONS === */
button.run {
font-family: 'JetBrains Mono', monospace;
font-size: 0.8rem;
letter-spacing: 0.1em;
text-transform: uppercase;
background: var(--amber);
color: var(--ink);
border: none;
padding: 0.75rem 1.25rem;
border-radius: 4px;
cursor: pointer;
font-weight: 700;
transition: all 0.15s;
}
button.run:hover {
transform: translateY(-1px);
box-shadow: 0 6px 20px -8px var(--amber-glow);
}
button.run:active { transform: translateY(0); }
button.run.ghost {
background: transparent;
color: var(--paper);
border: 1px solid var(--paper-faint);
}
button.run.ghost:hover {
border-color: var(--mint);
color: var(--mint);
box-shadow: none;
}
input.num {
font-family: 'JetBrains Mono', monospace;
background: var(--ink);
border: 1px solid var(--paper-faint);
color: var(--paper);
padding: 0.5rem 0.75rem;
border-radius: 4px;
width: 90px;
font-size: 0.95rem;
}
input.num:focus { outline: none; border-color: var(--amber); }
.controls {
display: flex;
gap: 0.75rem;
align-items: center;
flex-wrap: wrap;
margin: 1.5rem 0;
}
label.ctrl {
font-family: 'JetBrains Mono', monospace;
font-size: 0.8rem;
color: var(--paper-dim);
}
/* === DOMINO ANIMATION === */
.domino-stage {
background: var(--ink);
border: 1px solid var(--paper-faint);
border-radius: 8px;
padding: 3rem 1.5rem 2rem;
margin: 1.5rem 0;
overflow-x: auto;
position: relative;
}
.domino-row {
display: flex;
align-items: flex-end;
gap: 18px;
min-height: 160px;
padding-left: 2rem;
padding-bottom: 1rem;
position: relative;
}
.domino-row::before {
content: '';
position: absolute;
left: 0; right: 0; bottom: 0;
height: 2px;
background: linear-gradient(90deg, var(--paper-faint), transparent);
}
.domino {
width: 28px;
height: 110px;
background: linear-gradient(180deg, var(--paper) 0%, var(--paper-dim) 100%);
border-radius: 3px;
transform-origin: bottom right;
transition: transform 0.4s cubic-bezier(0.5, 0, 0.3, 1);
position: relative;
flex-shrink: 0;
box-shadow: 2px 2px 0 rgba(0,0,0,0.3);
}
.domino::after {
content: attr(data-n);
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
font-family: 'JetBrains Mono', monospace;
font-size: 0.7rem;
color: var(--ink);
font-weight: 700;
}
.domino.fallen { transform: rotate(75deg); }
.domino.first { background: linear-gradient(180deg, var(--amber) 0%, #d4902d 100%); }
.domino.first::after { color: var(--ink); }
.domino-label {
font-family: 'JetBrains Mono', monospace;
font-size: 0.75rem;
color: var(--paper-dim);
margin-top: 1rem;
padding-left: 2rem;
}
/* === SIEVE GRID === */
.sieve-grid {
display: grid;
grid-template-columns: repeat(10, 1fr);
gap: 4px;
margin: 1.5rem 0;
max-width: 560px;
}
.sieve-cell {
aspect-ratio: 1;
background: var(--ink-3);
border-radius: 4px;
display: flex;
align-items: center;
justify-content: center;
font-family: 'JetBrains Mono', monospace;
font-size: 0.95rem;
color: var(--paper);
transition: all 0.3s;
font-weight: 500;
}
.sieve-cell.prime {
background: var(--mint);
color: var(--ink);
transform: scale(1.05);
box-shadow: 0 0 20px var(--mint-glow);
}
.sieve-cell.composite {
background: var(--ink);
color: var(--paper-dim);
opacity: 0.4;
text-decoration: line-through;
}
.sieve-cell.current {
background: var(--amber);
color: var(--ink);
transform: scale(1.1);
box-shadow: 0 0 30px var(--amber-glow);
}
.sieve-cell.one {
background: var(--ink-2);
color: var(--paper-dim);
opacity: 0.3;
}
/* === EUCLID VISUAL === */
.euclid-steps {
margin: 1.5rem 0;
font-family: 'JetBrains Mono', monospace;
}
.euclid-step {
padding: 0.75rem 1rem;
background: var(--ink);
border-left: 3px solid var(--ink-3);
margin: 0.5rem 0;
border-radius: 4px;
opacity: 0;
transform: translateX(-10px);
transition: all 0.4s;
font-size: 0.95rem;
}
.euclid-step.show { opacity: 1; transform: translateX(0); }
.euclid-step.final { border-left-color: var(--mint); background: rgba(125, 255, 184, 0.08); color: var(--mint); }
.euclid-step .big { color: var(--amber); font-size: 1.1em; }
/* === RECURSION TREE === */
.tree-stage {
background: var(--ink);
border: 1px solid var(--paper-faint);
border-radius: 8px;
padding: 2rem 1rem;
margin: 1.5rem 0;
overflow-x: auto;
}
.tree-stage svg { display: block; margin: 0 auto; }
/* === TABLES === */
table.nice {
width: 100%;
border-collapse: collapse;
margin: 1.5rem 0;
font-family: 'JetBrains Mono', monospace;
font-size: 0.9rem;
}
table.nice th, table.nice td {
padding: 0.75rem 1rem;
text-align: left;
border-bottom: 1px solid var(--paper-faint);
}
table.nice th {
font-family: 'Instrument Sans', sans-serif;
font-size: 0.75rem;
letter-spacing: 0.15em;
text-transform: uppercase;
color: var(--amber);
font-weight: 600;
}
table.nice td.mint { color: var(--mint); }
table.nice td.amber { color: var(--amber); }
/* === GRID LAYOUTS === */
.two-col {
display: grid;
grid-template-columns: 1fr 1fr;
gap: 1.5rem;
}
@media (max-width: 720px) {
.two-col { grid-template-columns: 1fr; }
}
/* === FOOTER === */
footer {
padding: 4rem 0;
text-align: center;
color: var(--paper-dim);
font-family: 'JetBrains Mono', monospace;
font-size: 0.85rem;
}
footer strong { color: var(--amber); }
/* === DECORATIVE === */
.glyph {
position: absolute;
font-family: 'Fraunces', serif;
font-style: italic;
color: var(--paper-faint);
pointer-events: none;
user-select: none;
}
/* === INDUCTION PROOF STEPPER === */
.proof-stepper {
background: var(--ink);
border: 1px solid var(--paper-faint);
border-radius: 8px;
padding: 1.5rem;
margin: 1.5rem 0;
font-family: 'JetBrains Mono', monospace;
font-size: 0.95rem;
line-height: 1.8;
}
.proof-line {
padding: 0.5rem 0.75rem;
border-left: 2px solid transparent;
margin: 0.25rem 0;
transition: all 0.3s;
opacity: 0.3;
}
.proof-line.active {
opacity: 1;
border-left-color: var(--amber);
background: rgba(255, 180, 84, 0.06);
}
.proof-line.done { opacity: 0.8; border-left-color: var(--mint); }
.proof-line .comment { color: var(--paper-dim); font-style: italic; }
.annotate {
color: var(--amber);
font-weight: 600;
}
.annotate-mint { color: var(--mint); font-weight: 600; }
/* === RECURRENCE PANEL === */
.recurrence-grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
gap: 1rem;
margin: 1.5rem 0;
}
.rec-card {
background: var(--ink);
border: 1px solid var(--paper-faint);
border-radius: 6px;
padding: 1.25rem;
}
.rec-card .title {
font-family: 'Fraunces', serif;
font-size: 1.15rem;
color: var(--amber);
margin-bottom: 0.5rem;
}
.rec-card .formula {
font-family: 'JetBrains Mono', monospace;
color: var(--mint);
font-size: 0.95rem;
margin: 0.75rem 0;
padding: 0.5rem 0.75rem;
background: var(--ink-2);
border-radius: 4px;
}
.rec-card .note {
color: var(--paper-dim);
font-size: 0.9rem;
}
/* === CHARACTERISTIC EQUATION WALKTHROUGH === */
.walk-step {
display: grid;
grid-template-columns: 40px 1fr;
gap: 1rem;
margin: 1rem 0;
align-items: start;
}
.walk-step .num {
background: var(--amber);
color: var(--ink);
width: 32px;
height: 32px;
border-radius: 50%;
display: flex;
align-items: center;
justify-content: center;
font-family: 'JetBrains Mono', monospace;
font-weight: 700;
font-size: 0.85rem;
flex-shrink: 0;
}
.walk-step .content strong {
font-family: 'Fraunces', serif;
font-size: 1.1rem;
font-weight: 500;
display: block;
margin-bottom: 0.35rem;
color: var(--paper);
}
/* === SCROLL REVEAL === */
.reveal {
opacity: 0;
transform: translateY(20px);
transition: all 0.7s cubic-bezier(0.2, 0.7, 0.3, 1);
}
.reveal.in {
opacity: 1;
transform: translateY(0);
}
/* === NAV === */
nav.top {
position: fixed;
top: 0;
left: 0;
right: 0;
padding: 1rem 2rem;
display: flex;
justify-content: space-between;
align-items: center;
backdrop-filter: blur(12px);
background: rgba(11, 16, 32, 0.7);
border-bottom: 1px solid var(--paper-faint);
z-index: 100;
font-family: 'JetBrains Mono', monospace;
font-size: 0.8rem;
letter-spacing: 0.1em;
}
nav.top .brand { color: var(--amber); font-weight: 700; }
nav.top .meta { color: var(--paper-dim); }
</style>
</head>
<body>
<nav class="top">
<span class="brand">MAT 243</span>
<span class="meta">discrete math · visual guide</span>
</nav>
<main>
<div class="wrap">
<!-- HERO -->
<section class="hero">
<div class="kicker">module 11 · companion</div>
<h1>proofs, primes,<br>& the patterns <em>hiding in numbers</em></h1>
<p class="lead">a visual reference for induction, divisibility, recursion, and linear recurrence relations. every concept shows its shape. every symbol earns its keep.</p>
<div class="toc">
<a href="#induction"><span>01</span> induction</a>
<a href="#ih"><span>02</span> IH</a>
<a href="#primes"><span>03</span> primes</a>
<a href="#gcd"><span>04</span> gcd</a>
<a href="#lcm"><span>05</span> lcm</a>
<a href="#recursion"><span>06</span> recursion</a>
<a href="#recdef"><span>07</span> rec. definitions</a>
<a href="#lrr"><span>08</span> lin. recurrence</a>
<a href="#order"><span>09</span> order</a>
<a href="#homog"><span>10</span> homogeneous</a>
<a href="#cc"><span>11</span> const. coefficients</a>
<a href="#lhcc"><span>12</span> lhcc</a>
<a href="#chareq"><span>13</span> char. equation</a>
</div>
</section>
<!-- ============ INDUCTION ============ -->
<section class="topic" id="induction">
<div class="topic-header">
<span class="topic-num">01 / PROOF TECHNIQUE</span>
<h2>mathematical <em>induction</em></h2>
</div>
<p class="topic-intro">a two-step proof machine. prove it works for the first case. prove each case implies the next. logic does the rest. this is the domino effect written in math.</p>
<div class="card highlight">
<span class="card-label">the mental model</span>
<h3>every induction proof is a line of dominos</h3>
<p>to prove infinitely many statements, you only need to prove two things:</p>
<ol style="margin: 1rem 0 1rem 1.5rem; color: var(--paper);">
<li><strong style="color: var(--amber);">base case</strong> — push the first domino (prove P(1) directly)</li>
<li><strong style="color: var(--mint);">inductive step</strong> — show each domino knocks the next (if P(k) is true, then P(k+1) is true)</li>
</ol>
<p>if both hold, every domino falls. that's the whole trick.</p>
</div>
<div class="domino-stage">
<div class="domino-row" id="dominoRow"></div>
<div class="domino-label">← first domino is the base case · rest fall by the inductive step →</div>
<div class="controls" style="padding-left: 2rem;">
<button class="run" onclick="runDominos()">push the first domino</button>
<button class="run ghost" onclick="resetDominos()">reset</button>
</div>
</div>
<div class="card">
<span class="card-label">worked example</span>
<h3>prove: 1 + 2 + 3 + ... + n = n(n+1)/2</h3>
<p>click through each step of the proof. watch how the inductive hypothesis becomes the bridge from k to k+1.</p>
<div class="proof-stepper" id="proofBox">
<div class="proof-line" data-step="1">claim: P(n): 1 + 2 + ... + n = n(n+1)/2 for all n ≥ 1</div>
<div class="proof-line" data-step="2"><span class="annotate">base case.</span> show P(1) holds.</div>
<div class="proof-line" data-step="3"> LHS = 1</div>
<div class="proof-line" data-step="4"> RHS = 1(1+1)/2 = 2/2 = 1 ✓</div>
<div class="proof-line" data-step="5"><span class="annotate-mint">inductive step.</span> assume P(k) holds for some k ≥ 1.</div>
<div class="proof-line" data-step="6"> <span class="comment">inductive hypothesis (IH):</span></div>
<div class="proof-line" data-step="7"> 1 + 2 + ... + k = k(k+1)/2</div>
<div class="proof-line" data-step="8">show P(k+1) holds. target:</div>
<div class="proof-line" data-step="9"> 1 + 2 + ... + k + (k+1) = (k+1)(k+2)/2</div>
<div class="proof-line" data-step="10">start with LHS:</div>
<div class="proof-line" data-step="11"> 1 + 2 + ... + k + (k+1)</div>
<div class="proof-line" data-step="12"> = <span class="annotate">k(k+1)/2</span> + (k+1) <span class="comment">← substitute using IH</span></div>
<div class="proof-line" data-step="13"> = (k+1)[k/2 + 1] <span class="comment">← factor out (k+1)</span></div>
<div class="proof-line" data-step="14"> = (k+1)(k + 2)/2</div>
<div class="proof-line" data-step="15"> = (k+1)(k+2)/2 ✓ <span class="comment">← matches target</span></div>
<div class="proof-line" data-step="16">by induction, P(n) holds for all n ≥ 1. ∎</div>
</div>
<div class="controls">
<button class="run" onclick="stepProof(1)">next step →</button>
<button class="run ghost" onclick="stepProof(-1)">← back</button>
<button class="run ghost" onclick="resetProof()">restart</button>
<span style="font-family: 'JetBrains Mono', monospace; font-size: 0.85rem; color: var(--paper-dim);">step <span id="proofStep">0</span> / 16</span>
</div>
</div>
<div class="card">
<span class="card-label">template to memorize</span>
<h3>every induction proof has the same skeleton</h3>
<div class="math highlight">claim: P(n) is true for all n ≥ n₀
proof (by induction on n).
base case. show P(n₀) is true.
[plug in n₀, verify directly]
inductive step. assume P(k) for some k ≥ n₀. ← inductive hypothesis (IH)
we want to show P(k+1) is true.
[use IH to transform P(k) into P(k+1)]
therefore, by induction, P(n) holds for all n ≥ n₀. ∎</div>
<p>master the skeleton. the only part that changes problem-to-problem is the algebra in the inductive step.</p>
</div>
</section>
<!-- ============ IH ============ -->
<section class="topic" id="ih">
<div class="topic-header">
<span class="topic-num">02 / KEY TERM</span>
<h2>the <em>inductive hypothesis</em> (IH)</h2>
</div>
<p class="topic-intro">the load-bearing assumption. when you write "assume P(k) is true," that assumption IS the inductive hypothesis. it's the tool you use to reach P(k+1).</p>
<div class="two-col">
<div class="card">
<span class="card-label pill mint">what it is</span>
<h3>a temporary assumption</h3>
<p>you assume P(k) is true for some arbitrary k. you don't prove it — you just borrow it. then you use that assumption to prove P(k+1).</p>
<p>it's NOT circular reasoning. the base case is the real starting point. the IH just says: "if the chain hasn't broken by step k, it won't break at step k+1 either."</p>
</div>
<div class="card">
<span class="card-label pill rose">common mistake</span>
<h3>forgetting to use it</h3>
<p>if your proof of P(k+1) never references P(k), you're not doing induction — you're just proving each case directly. the IH is the hinge. if you don't use it, the proof isn't valid induction.</p>
<p>every time you substitute or simplify in the inductive step, ask: <em>"did i just use the IH?"</em> if not, you probably need to.</p>
</div>
</div>
</section>
<!-- ============ PRIMES ============ -->
<section class="topic" id="primes">
<div class="topic-header">
<span class="topic-num">03 / NUMBER THEORY</span>
<h2>prime <em>numbers</em></h2>
</div>
<p class="topic-intro">a prime is a natural number greater than 1 whose only positive divisors are 1 and itself. primes are the atomic elements of the integers — every other integer is built from them.</p>
<div class="card">
<span class="card-label">sieve of eratosthenes</span>
<h3>watch primes emerge from the natural numbers</h3>
<p>start with 2. circle it (prime). cross out every multiple of 2. move to the next uncircled number (3). circle it. cross out its multiples. repeat. survivors are primes.</p>
<div class="sieve-grid" id="sieveGrid"></div>
<div class="controls">
<button class="run" onclick="runSieve()">run the sieve</button>
<button class="run ghost" onclick="resetSieve()">reset</button>
</div>
<h4>key facts</h4>
<ul style="margin-left: 1.2rem;">
<li><strong>1 is NOT prime</strong> — primes must be greater than 1</li>
<li><strong>2 is the only even prime</strong> — every other even number is divisible by 2</li>
<li><strong>fundamental theorem of arithmetic</strong> — every integer > 1 has a unique prime factorization (up to order)</li>
<li><strong>there are infinitely many primes</strong> — proved by euclid around 300 BC</li>
</ul>
</div>
</section>
<!-- ============ GCD ============ -->
<section class="topic" id="gcd">
<div class="topic-header">
<span class="topic-num">04 / DIVISIBILITY</span>
<h2>greatest common <em>divisor</em></h2>
</div>
<p class="topic-intro">the gcd of two integers is the largest number that divides both of them. written gcd(a, b). the euclidean algorithm finds it in logarithmic time using just repeated remainders.</p>
<div class="card">
<span class="card-label">euclidean algorithm</span>
<h3>gcd(a, b) = gcd(b, a mod b)</h3>
<p>keep replacing the larger number with the remainder until one side becomes 0. the other side is your gcd.</p>
<div class="controls">
<label class="ctrl">a = <input type="number" class="num" id="gcdA" value="252"></label>
<label class="ctrl">b = <input type="number" class="num" id="gcdB" value="105"></label>
<button class="run" onclick="runEuclid()">compute gcd</button>
</div>
<div class="euclid-steps" id="euclidBox"></div>
<h4>why it works (intuition)</h4>
<p>if d divides both a and b, then d also divides (a - b), and more generally (a mod b). so the set of common divisors doesn't change when we swap (a, b) for (b, a mod b). the numbers shrink, but the gcd is invariant. eventually we hit 0, and whatever's left is the answer.</p>
</div>
</section>
<!-- ============ LCM ============ -->
<section class="topic" id="lcm">
<div class="topic-header">
<span class="topic-num">05 / DIVISIBILITY</span>
<h2>least common <em>multiple</em></h2>
</div>
<p class="topic-intro">the lcm of two integers is the smallest positive number that BOTH divide into. it's the gcd's dual — and they're connected by one of the cleanest formulas in number theory.</p>
<div class="card highlight">
<span class="card-label">the identity</span>
<h3>lcm(a, b) · gcd(a, b) = a · b</h3>
<div class="math highlight">lcm(a, b) = |a · b| / gcd(a, b)</div>
<p>once you know the gcd, the lcm is free. example with a=12 and b=18:</p>
<div class="math">gcd(12, 18) = 6
lcm(12, 18) = (12 · 18) / 6 = 216 / 6 = 36</div>
<h4>prime-factorization way (visual)</h4>
<table class="nice">
<tr><th>number</th><th>factorization</th></tr>
<tr><td>12</td><td class="amber">2² · 3</td></tr>
<tr><td>18</td><td class="amber">2 · 3²</td></tr>
<tr><td class="mint">gcd</td><td class="mint">2¹ · 3¹ = 6 (take the MIN exponent for each prime)</td></tr>
<tr><td class="mint">lcm</td><td class="mint">2² · 3² = 36 (take the MAX exponent for each prime)</td></tr>
</table>
</div>
</section>
<!-- ============ RECURSION ============ -->
<section class="topic" id="recursion">
<div class="topic-header">
<span class="topic-num">06 / SELF-REFERENCE</span>
<h2><em>recursion</em></h2>
</div>
<p class="topic-intro">recursion is defining something in terms of smaller versions of itself. every recursion has two parts: base case (where it stops) and recursive case (where it calls itself).</p>
<div class="card">
<span class="card-label">the shape of a recursive call</span>
<h3>factorial: n! = n · (n-1)!</h3>
<div class="math highlight">base case: 0! = 1
recursive case: n! = n · (n-1)! for n ≥ 1</div>
<p>to compute 5!, we compute 5 · 4!, which needs 4!, which needs 3!, ... all the way down to the base case. then the answers unwind back up.</p>
<div class="tree-stage">
<svg viewBox="0 0 700 320" xmlns="http://www.w3.org/2000/svg" style="width: 100%; max-width: 700px;">
<defs>
<style>
.node-bg { fill: #1a2348; stroke: #ffb454; stroke-width: 1.5; }
.node-bg.base { fill: #7dffb8; stroke: #7dffb8; }
.node-text { font-family: 'JetBrains Mono', monospace; font-size: 13px; fill: #f4ede4; }
.node-text.base { fill: #0b1020; font-weight: 700; }
.tree-line { stroke: rgba(244,237,228,0.3); stroke-width: 1.5; fill: none; }
.val-text { font-family: 'JetBrains Mono', monospace; font-size: 11px; fill: #ffb454; }
</style>
</defs>
<!-- Level 0 -->
<line class="tree-line" x1="350" y1="45" x2="350" y2="90"/>
<rect class="node-bg" x="300" y="15" width="100" height="32" rx="4"/>
<text class="node-text" x="350" y="36" text-anchor="middle">5! = 5·4!</text>
<!-- Level 1 -->
<line class="tree-line" x1="350" y1="125" x2="350" y2="160"/>
<rect class="node-bg" x="300" y="90" width="100" height="32" rx="4"/>
<text class="node-text" x="350" y="111" text-anchor="middle">4! = 4·3!</text>
<!-- Level 2 -->
<line class="tree-line" x1="350" y1="195" x2="350" y2="230"/>
<rect class="node-bg" x="300" y="160" width="100" height="32" rx="4"/>
<text class="node-text" x="350" y="181" text-anchor="middle">3! = 3·2!</text>
<!-- Level 3 -->
<line class="tree-line" x1="350" y1="265" x2="350" y2="295"/>
<rect class="node-bg" x="300" y="230" width="100" height="32" rx="4"/>
<text class="node-text" x="350" y="251" text-anchor="middle">2! = 2·1!</text>
<!-- Level 4 (base case) -->
<rect class="node-bg base" x="300" y="295" width="100" height="22" rx="4"/>
<text class="node-text base" x="350" y="311" text-anchor="middle">1! = 1 ✓</text>
<!-- Unwinding annotations -->
<text class="val-text" x="420" y="315" text-anchor="start">← base case</text>
<text class="val-text" x="420" y="250" text-anchor="start">unwinds → 2·1 = 2</text>
<text class="val-text" x="420" y="180" text-anchor="start">unwinds → 3·2 = 6</text>
<text class="val-text" x="420" y="110" text-anchor="start">unwinds → 4·6 = 24</text>
<text class="val-text" x="420" y="35" text-anchor="start">unwinds → 5·24 = 120</text>
</svg>
</div>
<p><span class="pill amber">descend</span> first the call stack grows as we hit the recursive case over and over. <span class="pill mint">ascend</span> then the base case triggers and answers climb back up.</p>
</div>
<div class="card">
<span class="card-label">important</span>
<h3>recursion always needs a base case</h3>
<p>without a base case, recursion never stops. in code this is a stack overflow. in math it's a definition that doesn't actually define anything. <strong style="color: var(--rose);">base case = the terminator.</strong></p>
</div>
</section>
<!-- ============ RECURSIVE DEFINITIONS ============ -->
<section class="topic" id="recdef">
<div class="topic-header">
<span class="topic-num">07 / DEFINITION</span>
<h2>recursive <em>definitions</em></h2>
</div>
<p class="topic-intro">a recursive definition builds an object by saying (1) what the smallest cases look like, and (2) how to build larger cases from smaller ones. it's induction's twin — both work on the same domino logic, just pointed in different directions.</p>
<div class="two-col">
<div class="card">
<span class="card-label pill amber">sequence: powers of 2</span>
<h3>2ⁿ defined recursively</h3>
<div class="math">base: a₀ = 1
recursive: aₙ = 2 · aₙ₋₁ for n ≥ 1</div>
<p>first few terms: 1, 2, 4, 8, 16, 32, ...</p>
</div>
<div class="card">
<span class="card-label pill mint">fibonacci sequence</span>
<h3>each term is the sum of the two before it</h3>
<div class="math">base: F₀ = 0, F₁ = 1
recursive: Fₙ = Fₙ₋₁ + Fₙ₋₂ for n ≥ 2</div>
<p>first few terms: 0, 1, 1, 2, 3, 5, 8, 13, 21, 34, ...</p>
</div>
</div>
<div class="card">
<span class="card-label pill sky">recursively defined SETS</span>
<h3>definitions aren't just for sequences</h3>
<p>you can define an entire set of objects recursively. example: the set S of all even non-negative integers.</p>
<div class="math highlight">base: 0 ∈ S
recursive: if x ∈ S, then (x + 2) ∈ S
exclusion: nothing else is in S</div>
<p>the exclusion clause matters — without it, you could argue anything is in S. standard practice in formal definitions.</p>
</div>
</section>
<!-- ============ LINEAR RECURRENCE RELATIONS ============ -->
<section class="topic" id="lrr">
<div class="topic-header">
<span class="topic-num">08 / RECURRENCES</span>
<h2>linear <em>recurrence relations</em></h2>
</div>
<p class="topic-intro">a recurrence relation expresses aₙ in terms of earlier terms. LINEAR means the earlier terms appear to the first power — no squaring, no multiplying terms together, no weird functions of them.</p>
<div class="card">
<span class="card-label">the general form</span>
<h3>a linear recurrence looks like this:</h3>
<div class="math highlight">aₙ = c₁·aₙ₋₁ + c₂·aₙ₋₂ + ... + c_k·aₙ₋ₖ + f(n)</div>
<p>each aₙ₋ᵢ shows up exactly once, to the first power, multiplied by some coefficient. f(n) is an optional "forcing" term (if it's 0, the recurrence is homogeneous — see next sections).</p>
<h4>linear vs NOT linear</h4>
<div class="recurrence-grid">
<div class="rec-card">
<div class="title">linear ✓</div>
<div class="formula">aₙ = 3aₙ₋₁ + 2aₙ₋₂</div>
<div class="note">earlier terms appear to the first power with constant coefficients</div>
</div>
<div class="rec-card">
<div class="title">linear ✓ (with forcing)</div>
<div class="formula">aₙ = 2aₙ₋₁ + n</div>
<div class="note">still linear — the forcing term doesn't touch earlier aₙ values</div>
</div>
<div class="rec-card">
<div class="title" style="color: var(--rose);">not linear ✗</div>
<div class="formula">aₙ = aₙ₋₁²</div>
<div class="note">earlier term is squared — nonlinear</div>
</div>
<div class="rec-card">
<div class="title" style="color: var(--rose);">not linear ✗</div>
<div class="formula">aₙ = aₙ₋₁ · aₙ₋₂</div>
<div class="note">two earlier terms multiplied together — nonlinear</div>
</div>
</div>
</div>
</section>
<!-- ============ ORDER ============ -->
<section class="topic" id="order">
<div class="topic-header">
<span class="topic-num">09 / PROPERTY</span>
<h2>the <em>order</em> of a recurrence</h2>
</div>
<p class="topic-intro">order = how far back you need to look. if aₙ depends on aₙ₋₁, it's order 1. if it depends on aₙ₋₁ and aₙ₋₂, it's order 2. simple as that.</p>
<div class="card">
<table class="nice">
<tr><th>recurrence</th><th>depends on</th><th>order</th></tr>
<tr><td class="amber">aₙ = 3aₙ₋₁</td><td>aₙ₋₁</td><td class="mint">1</td></tr>
<tr><td class="amber">Fₙ = Fₙ₋₁ + Fₙ₋₂</td><td>previous two</td><td class="mint">2</td></tr>
<tr><td class="amber">aₙ = aₙ₋₁ + 2aₙ₋₃</td><td>aₙ₋₁ and aₙ₋₃</td><td class="mint">3</td></tr>
<tr><td class="amber">aₙ = 5aₙ₋₁ − 6aₙ₋₂ + aₙ₋₄</td><td>aₙ₋₁, aₙ₋₂, aₙ₋₄</td><td class="mint">4</td></tr>
</table>
<p style="margin-top: 1rem;"><strong>rule:</strong> order = <em>largest index gap</em> between aₙ and the earliest term on the right-hand side. an order-k recurrence needs k initial conditions (a₀ through aₖ₋₁, or similar) to be fully determined.</p>
</div>
</section>
<!-- ============ HOMOGENEOUS ============ -->
<section class="topic" id="homog">
<div class="topic-header">
<span class="topic-num">10 / PROPERTY</span>
<h2><em>homogeneous</em></h2>
</div>
<p class="topic-intro">a recurrence is homogeneous when there's no "extra" term. every piece of the equation involves aₙ or earlier aₙ values. nothing else.</p>
<div class="card">
<span class="card-label">the test</span>
<h3>if everything can be moved to one side and equals 0 — it's homogeneous</h3>
<div class="two-col">
<div class="rec-card">
<div class="title">homogeneous ✓</div>
<div class="formula">aₙ = 3aₙ₋₁ − 2aₙ₋₂</div>
<div class="note">rewrite as: aₙ − 3aₙ₋₁ + 2aₙ₋₂ = 0 — every term has an aₙ subscript</div>
</div>
<div class="rec-card">
<div class="title" style="color: var(--rose);">NOT homogeneous ✗</div>
<div class="formula">aₙ = 3aₙ₋₁ + 5</div>
<div class="note">the "+ 5" has nothing to do with aₙ values. that extra term makes it non-homogeneous (or "inhomogeneous")</div>
</div>
<div class="rec-card">
<div class="title" style="color: var(--rose);">NOT homogeneous ✗</div>
<div class="formula">aₙ = 2aₙ₋₁ + n²</div>
<div class="note">n² is a function of n, not of earlier aₙ values. non-homogeneous</div>
</div>
<div class="rec-card">
<div class="title" style="color: var(--rose);">NOT homogeneous ✗</div>
<div class="formula">aₙ = aₙ₋₁ + 3ⁿ</div>
<div class="note">same deal — 3ⁿ is a forcing term unrelated to earlier aₙ values</div>
</div>
</div>
</div>
</section>
<!-- ============ CONSTANT COEFFICIENTS ============ -->
<section class="topic" id="cc">
<div class="topic-header">
<span class="topic-num">11 / PROPERTY</span>
<h2><em>constant coefficients</em> (CC)</h2>
</div>
<p class="topic-intro">the numbers multiplying aₙ₋₁, aₙ₋₂, etc. are actual numbers — not functions of n.</p>
<div class="card">
<div class="two-col">
<div class="rec-card">
<div class="title">constant coefficients ✓</div>
<div class="formula">aₙ = <span style="color: var(--amber);">3</span>aₙ₋₁ + <span style="color: var(--amber);">5</span>aₙ₋₂</div>
<div class="note">coefficients are 3 and 5 — plain numbers, don't change with n</div>
</div>
<div class="rec-card">
<div class="title">constant coefficients ✓</div>
<div class="formula">aₙ = <span style="color: var(--amber);">−7</span>aₙ₋₁ + <span style="color: var(--amber);">12</span>aₙ₋₃</div>
<div class="note">negative and positive constants are both fine</div>
</div>
<div class="rec-card">
<div class="title" style="color: var(--rose);">NOT constant coefficients ✗</div>
<div class="formula">aₙ = <span style="color: var(--rose);">n</span>·aₙ₋₁</div>
<div class="note">the coefficient is n itself — changes with every step. variable coefficient</div>
</div>
<div class="rec-card">
<div class="title" style="color: var(--rose);">NOT constant coefficients ✗</div>
<div class="formula">aₙ = <span style="color: var(--rose);">(n+1)</span>aₙ₋₁ + <span style="color: var(--rose);">n²</span>aₙ₋₂</div>
<div class="note">both coefficients depend on n — variable coefficients</div>
</div>
</div>
</div>
</section>
<!-- ============ LHCC ============ -->
<section class="topic" id="lhcc">
<div class="topic-header">
<span class="topic-num">12 / COMPOUND</span>
<h2><em>LHCC</em> — linear, homogeneous, constant coefficients</h2>
</div>
<p class="topic-intro">combine all three properties and you get an LHCC recurrence. this is the sweet spot — LHCCs are the recurrences we know how to solve in closed form using the characteristic equation.</p>
<div class="card highlight">
<span class="card-label">the checklist</span>
<h3>a recurrence is LHCC if ALL three hold:</h3>
<ol style="margin: 1rem 0 1rem 1.5rem;">
<li><span class="pill amber">LINEAR</span> each aₙ₋ᵢ appears to the first power, not multiplied by each other</li>
<li><span class="pill mint">HOMOGENEOUS</span> no extra forcing term — only aₙ-subscripted pieces</li>
<li><span class="pill sky">CONSTANT COEFFICIENTS</span> the multipliers are numbers, not functions of n</li>
</ol>
<h4>canonical form of an order-k LHCC</h4>
<div class="math highlight">aₙ = c₁·aₙ₋₁ + c₂·aₙ₋₂ + ... + c_k·aₙ₋ₖ
where c₁, c₂, ..., c_k are constants and c_k ≠ 0</div>
<h4>examples</h4>
<table class="nice">
<tr><th>recurrence</th><th>LHCC?</th><th>why</th></tr>
<tr><td class="amber">aₙ = 3aₙ₋₁ − 2aₙ₋₂</td><td class="mint">yes</td><td>linear, homogeneous, CC — order 2</td></tr>
<tr><td class="amber">Fₙ = Fₙ₋₁ + Fₙ₋₂</td><td class="mint">yes</td><td>fibonacci is LHCC, order 2</td></tr>
<tr><td class="amber">aₙ = 5aₙ₋₁ + 2</td><td style="color: var(--rose);">no</td><td>the "+ 2" breaks homogeneity</td></tr>
<tr><td class="amber">aₙ = n·aₙ₋₁</td><td style="color: var(--rose);">no</td><td>coefficient n is not constant</td></tr>
<tr><td class="amber">aₙ = aₙ₋₁²</td><td style="color: var(--rose);">no</td><td>not linear</td></tr>
</table>
</div>
</section>
<!-- ============ CHARACTERISTIC EQUATION ============ -->
<section class="topic" id="chareq">
<div class="topic-header">
<span class="topic-num">13 / SOLUTION METHOD</span>
<h2>the <em>characteristic equation</em></h2>
</div>
<p class="topic-intro">the big payoff. for any LHCC, you can turn the recurrence into a polynomial equation, solve it, and write down an exact closed-form formula for aₙ. no more computing term-by-term.</p>
<div class="card">
<span class="card-label">the core trick</span>
<h3>guess aₙ = rⁿ. see what r has to be.</h3>
<p>start with an LHCC like <span class="inline-math">aₙ = c₁·aₙ₋₁ + c₂·aₙ₋₂</span>. substitute <span class="inline-math">aₙ = rⁿ</span>:</p>
<div class="math">rⁿ = c₁·rⁿ⁻¹ + c₂·rⁿ⁻²</div>
<p>divide both sides by rⁿ⁻²:</p>
<div class="math highlight">r² = c₁·r + c₂
→ r² − c₁·r − c₂ = 0 ← characteristic equation</div>
<p>solve this quadratic. the roots tell you the building blocks of the closed form.</p>
</div>
<div class="card highlight">
<span class="card-label">worked example</span>
<h3>solve fibonacci: Fₙ = Fₙ₋₁ + Fₙ₋₂, F₀ = 0, F₁ = 1</h3>
<div class="walk-step">
<div class="num">1</div>
<div class="content"><strong>write the characteristic equation.</strong>
substitute Fₙ = rⁿ: rⁿ = rⁿ⁻¹ + rⁿ⁻². divide by rⁿ⁻²:
<div class="math">r² = r + 1 → r² − r − 1 = 0</div>
</div>
</div>
<div class="walk-step">
<div class="num">2</div>
<div class="content"><strong>solve for r using the quadratic formula.</strong>
<div class="math">r = (1 ± √5) / 2
r₁ = (1 + √5) / 2 ≈ 1.618 ← the golden ratio φ
r₂ = (1 − √5) / 2 ≈ −0.618 ← ψ (its conjugate)</div>
</div>
</div>
<div class="walk-step">
<div class="num">3</div>
<div class="content"><strong>write the general solution.</strong>
when the roots are distinct, every solution is a linear combination of r₁ⁿ and r₂ⁿ:
<div class="math">Fₙ = A · r₁ⁿ + B · r₂ⁿ</div>
A and B are constants we'll determine from initial conditions.
</div>
</div>
<div class="walk-step">
<div class="num">4</div>
<div class="content"><strong>plug in initial conditions to find A and B.</strong>
<div class="math">F₀ = 0: A + B = 0 → B = −A
F₁ = 1: A·r₁ + B·r₂ = 1 → A(r₁ − r₂) = 1
r₁ − r₂ = √5 → A = 1/√5, B = −1/√5</div>
</div>
</div>
<div class="walk-step">
<div class="num">5</div>
<div class="content"><strong>write the closed form (Binet's formula).</strong>
<div class="math highlight">Fₙ = (1/√5) · [ ((1+√5)/2)ⁿ − ((1−√5)/2)ⁿ ]</div>
now you can compute F₁₀₀ without computing all 99 previous terms. check: F₁₀ = 55, formula gives 55 ✓.
</div>
</div>
</div>
<div class="card">
<span class="card-label">the roots ↔ solutions cheat sheet</span>
<h3>what the characteristic equation's roots mean</h3>
<table class="nice">
<tr><th>roots of char. equation</th><th>general solution</th></tr>
<tr><td class="amber">distinct real roots r₁, r₂</td><td class="mint">aₙ = A·r₁ⁿ + B·r₂ⁿ</td></tr>
<tr><td class="amber">repeated root r (mult. 2)</td><td class="mint">aₙ = (A + Bn)·rⁿ</td></tr>
<tr><td class="amber">three distinct roots r₁, r₂, r₃</td><td class="mint">aₙ = A·r₁ⁿ + B·r₂ⁿ + C·r₃ⁿ</td></tr>
<tr><td class="amber">root r repeated m times</td><td class="mint">(A + Bn + Cn² + ... + constants·n^(m-1))·rⁿ</td></tr>
</table>
<p style="margin-top: 1rem;">the constants A, B, C, ... always come from plugging in the initial conditions (you'll need as many conditions as the order of the recurrence).</p>
</div>
<div class="card">
<span class="card-label pill mint">big picture</span>
<h3>why the characteristic equation is a big deal</h3>
<p>it turns an infinite recursive process into a finite algebraic one. instead of computing aₙ by grinding through every earlier term, you solve a polynomial once and get a formula that works for all n. for LHCCs this is guaranteed to work. for non-LHCCs (inhomogeneous, nonlinear, or variable coefficients) you need other techniques — generating functions, substitution, the "method of undetermined coefficients," or just computing term-by-term.</p>
</div>
</section>
<footer>
<p>MAT 243 visual guide · built for <strong>module 11 & beyond</strong></p>
<p style="margin-top: 0.5rem; opacity: 0.6;">proofs, primes, and the patterns hiding in numbers</p>
</footer>
</div>
</main>
<script>
// ========== DOMINO ANIMATION ==========
function buildDominos() {
const row = document.getElementById('dominoRow');
row.innerHTML = '';
for (let i = 1; i <= 18; i++) {
const d = document.createElement('div');
d.className = 'domino' + (i === 1 ? ' first' : '');
d.setAttribute('data-n', i);
row.appendChild(d);
}
}
function runDominos() {
const dominos = document.querySelectorAll('.domino');
dominos.forEach((d, i) => {
setTimeout(() => d.classList.add('fallen'), i * 120);
});
}
function resetDominos() {
document.querySelectorAll('.domino').forEach(d => d.classList.remove('fallen'));
}
buildDominos();
// ========== PROOF STEPPER ==========
let proofCurrent = 0;
const proofTotal = 16;
function stepProof(dir) {
proofCurrent = Math.max(0, Math.min(proofTotal, proofCurrent + dir));
renderProof();
}
function resetProof() { proofCurrent = 0; renderProof(); }
function renderProof() {
document.getElementById('proofStep').textContent = proofCurrent;
document.querySelectorAll('.proof-line').forEach(line => {
const s = parseInt(line.dataset.step);
line.classList.remove('active', 'done');
if (s < proofCurrent) line.classList.add('done');
else if (s === proofCurrent) line.classList.add('active');
});
}
renderProof();
// ========== SIEVE OF ERATOSTHENES ==========
function buildSieveGrid() {
const grid = document.getElementById('sieveGrid');
grid.innerHTML = '';
for (let i = 1; i <= 50; i++) {
const c = document.createElement('div');
c.className = 'sieve-cell';
c.id = 'sv-' + i;
c.textContent = i;
if (i === 1) c.classList.add('one');
grid.appendChild(c);
}
}
function resetSieve() { buildSieveGrid(); }
async function runSieve() {
resetSieve();
const N = 50;
const marked = new Array(N + 1).fill(false);
marked[1] = true;
for (let p = 2; p <= N; p++) {
if (marked[p]) continue;
const cell = document.getElementById('sv-' + p);
cell.classList.add('current');
await sleep(350);
cell.classList.remove('current');
cell.classList.add('prime');
await sleep(150);
for (let m = p * 2; m <= N; m += p) {
if (!marked[m]) {
marked[m] = true;
const mc = document.getElementById('sv-' + m);
mc.classList.add('composite');
await sleep(50);
}
}
await sleep(200);
}
}
function sleep(ms) { return new Promise(r => setTimeout(r, ms)); }
buildSieveGrid();
// ========== EUCLIDEAN ALGORITHM ==========
async function runEuclid() {
const box = document.getElementById('euclidBox');
box.innerHTML = '';
let a = Math.abs(parseInt(document.getElementById('gcdA').value) || 0);
let b = Math.abs(parseInt(document.getElementById('gcdB').value) || 0);
if (!a || !b) {
const e = document.createElement('div');
e.className = 'euclid-step show';
e.textContent = 'enter two positive integers';
box.appendChild(e);
return;
}
if (a < b) [a, b] = [b, a];
let step = 1;
while (b !== 0) {
const q = Math.floor(a / b);
const r = a % b;
const line = document.createElement('div');
line.className = 'euclid-step';
line.innerHTML = `step ${step}: <span class="big">${a}</span> = <span class="big">${b}</span> · ${q} + <span class="big">${r}</span> <span style="opacity:0.6"> → gcd(${b}, ${r})</span>`;
box.appendChild(line);
await sleep(120);
line.classList.add('show');
await sleep(500);
a = b;
b = r;
step++;
}
const done = document.createElement('div');
done.className = 'euclid-step final';
done.innerHTML = `∴ gcd = <span class="big">${a}</span> (remainder hit 0)`;
box.appendChild(done);
await sleep(120);
done.classList.add('show');
}
// ========== SCROLL REVEAL ==========
const io = new IntersectionObserver((entries) => {
entries.forEach(e => { if (e.isIntersecting) e.target.classList.add('in'); });
}, { threshold: 0.08 });
document.querySelectorAll('.card, .topic-header, .topic-intro').forEach(el => {
el.classList.add('reveal');
io.observe(el);
});
</script>
</body>
</html>