diff --git a/documents/by-course/math-8/course-notes/main.typ b/documents/by-course/math-8/course-notes/main.typ
index 316c6ac..a6e2894 100644
--- a/documents/by-course/math-8/course-notes/main.typ
+++ b/documents/by-course/math-8/course-notes/main.typ
@@ -467,6 +467,135 @@ $ exists x in U, P(x) $
   rational number $z$.
 ]<rational-between>
 
+= Lecture #datetime(day: 27, month: 1, year: 2025).display()
+
+== Basic properties of sets
+
+#definition[
+  A set is a collection of elements.
+]
+
+#definition[
+  The cardinality of a set is the amount of elements in the set.
+]
+
+#example[
+  Prove $A subset.eq B$ iff. $A sect B = A$.
+
+  #proof[
+    Assume $A subset.eq B$. Let $x in A sect B$. Then $x in A$ and $x in B$. So
+    $x in A$ and $A sect B subset.eq A$. Now let $x in A$. Since $A subset.eq
+    B$, then $x in B$. Thus $x in A$ and $x in B$, so $x in A sect B$. Then $A
+    subset.eq A sect B$.
+
+    Now we show the other direction. Assume $A sect B = A$. Then $x in A sect
+    B$ implies $x in A$ and $x in B$. In particular $forall x in A, x in B$.
+    Thus $a subset.eq B$.
+  ]
+]
+
+#theorem[
+  Let $U$ be the universe, and let $A$ and $B$ be subsets of $U$. Then
+  + $(A^c)^c = A$
+  + $A union A^c = U$
+  + $A sect A^c = emptyset$
+  + $A - B = A sect B^c$
+  + $A subset.eq B <=> B^c subset.eq A^c$
+  + $A sect B = emptyset <=> A subset.eq B^c$
+  + $(A union B)^c = A^c sect B^c$
+  + $(A sect B)^c = A^c union B^c$
+]<basic-sets>
+
+#example[part of @basic-sets][
+  Show that $(A sect B)^c = A^c union B^c$.
+
+  $
+    &x in (A sect B)^c \
+    &<=> x in.not A sect B \
+    &<=> x in A^c, x in B^c \
+    &<=> x in A^c union B^c
+  $
+]
+
+#definition[
+  The Cartesian product of sets $A$ and $B$:
+
+  $ A times B = {(a,b) : a in A "and" b in B} $
+]
+
+#fact[
+  If $A$ has cardinality $m$, $B$ has cardinality $n$, then $A times B$ has
+  cardinality $n dot m$.
+]
+
+#example[
+  Prove that $A times emptyset = emptyset$.
+
+  #proof[
+    Suppose that $A times emptyset != emptyset$. Then $exists (a,b), a in A, b in
+emptyset$. But $b in emptyset$ is a contradiction by its definition.
+  ]
+]
+
+== Index families of sets
+
+#definition[A set of sets is called a family or collection of sets.]
+
+#definition[
+  Let $Delta$ be a nonempty index set such that $forall alpha in Delta, exists
+  A_alpha$. The family of sets $cal(A) = {A_alpha : alpha in Delta}$ is an
+  index family of sets.
+]
+
+#example[
+  Let $A in {1,3}$ and consider $cal(P)(A)$.
+]
+
+#example[
+  Define $A_n = (n,n+2)$, the open interval from $n$ to $n+2$, for each $n in
+  NN$.
+
+  $cal(A) = {(n, N + 2) : n in NN} = {A_n : n in NN}$
+
+  Let $Delta = NN$ and then $alpha in Delta <=> n in NN$.
+]
+
+#definition[
+  The union over $cal(A)$ is the set
+  $ union.big_(A in cal(A)) A = {x : x in A, exists A in cal(A)} $
+]
+
+#definition[
+  The intersection over $cal(A)$ is the set
+  $ sect.big_(A in cal(A)) A = {x : x in A, forall A in cal(A)} $
+]
+
+#example[
+  Let $cal(A) = {{1}, {1,2},{2,3}}$. Then
+  $
+    &union.big_(A in cal(A)) A = {1,2,3} \
+    &sect.big_(A in cal(A)) A = emptyset
+  $
+]
+
+#example[
+  Let $A_n = [-1/n,1/n]$, the closed interval from $-1/n$ to $1/n$ for each $N in NN$. Consider the family of sets $cal(A) = {A_n : n in NN}$. Then
+
+  $
+    &union.big_(A in cal(A)) A = union.big_(n=1)^infinity A_n = A_1 union A_2 union A_3 union dots.c = {x : x in [-1,1]} \
+    &sect.big_(A in cal(A)) A = sect.big_(n=1)^infinity A_n = 0
+  $
+]
+
+#example[
+  Let $A_n = [0,n)$ for each $n in NN$ and let $cal(A) = {A_n : n in NN}$. Then
+
+  $
+    &union.big_(A in cal(A)) A = [0, infinity] \
+    &sect.big_(A in cal(A)) = [0,1)
+  $
+]
+
 = Solutions to selected exercises and problems
 
 Solutions to selected problems and exercises.
diff --git a/documents/by-course/pstat-120a/hw1/main.typ b/documents/by-course/pstat-120a/hw1/main.typ
index d19eb44..12dab87 100644
--- a/documents/by-course/pstat-120a/hw1/main.typ
+++ b/documents/by-course/pstat-120a/hw1/main.typ
@@ -9,6 +9,19 @@
 
 #set enum(spacing: 2em)
 
+#let correction = content => {
+  set text(fill: red)
+  box(stroke: 1pt, inset: 5pt, content)
+}
+
+#correction[
+  There were 7 points off, so:
+
+  Initial score: 47/54
+
+  Corrected score: 52/52
+]
+
 + #[
     #set enum(numbering: "a)", spacing: 2em)
 
@@ -44,7 +57,7 @@
     #set enum(numbering: "a)", spacing: 2em)
 
     + ${15, 25, 35, 45, 51, 53, 55, 57, 59, 65, 75, 85, 95 }$
-    + ${50, 52, 56, 58}$
+    + ${50, 52, 54, 56, 58}$
     + $emptyset$
   ]
 
@@ -64,6 +77,10 @@
         represents balls numbered 1-6, and the value represents the square it
         was sent to. So it's
         $ {{x_1,x_2,x_3,x_4,x_5,x_6} : x_i in {1,2,3,4}}, i = 1,...6 $
+
+        #correction[
+          -1. We should probably write this more explicitly as ${1,2,3,4}^6$.
+        ]
       ]
     + #[
         When the balls are indistinguishable, we can instead represent it as
@@ -100,6 +117,11 @@
 + #[
     #set enum(numbering: "a)", spacing: 2em)
 
+    #correction[
+      -4.
+      These are all correct, but need to be divided by $vec(52,5)$ for the final probability. Oops...
+    ]
+
     + #[
         First we choose two ranks for our two pairs. Then we choose 2 suits for the
         first pair and 2 suits for the second pair. Then we choose 1 card from the
@@ -159,6 +181,12 @@
     + #[
         First we enumerate all of the ways 4 numbers can add up to 13.
         $ 2 dot 4! = 8 / 35 $
+        #correction[
+          -2. Correct way: directly find the how many outcomes sum to 13
+          $ {{1,2,3,7},{1,2,4,6},{1,3,4,5}} $
+          So the answer is simply these 3 outcomes divided by total ways to choose 4 numbers from 10:
+          $ 3 / vec(10,4) approx 0.0143 $
+        ]
       ]
   ]
 
diff --git a/documents/by-course/pstat-120a/hw2/main.typ b/documents/by-course/pstat-120a/hw2/main.typ
new file mode 100644
index 0000000..6bb1ccf
--- /dev/null
+++ b/documents/by-course/pstat-120a/hw2/main.typ
@@ -0,0 +1,109 @@
+#import "@youwen/zen:0.1.0": *
+#import "@preview/ctheorems:1.1.3": *
+#import "@preview/mitex:0.2.5": *
+
+#show: zen.with(
+  title: "Homework 2",
+  author: "Youwen Wu",
+  date: "Winter 2025",
+)
+
+#set enum(spacing: 2em)
+
+#let correction = content => {
+  set text(fill: red)
+  box(stroke: 1pt, inset: 5pt, content)
+}
+
+#mitex(`
+\textbf{Problem 1}
+
+Let $P(A)$ denote the probability that a customer watches exactly one category of programs. From the problem:
+\begin{itemize}
+    \item 70\% watch more than one category: $P(A^c) = 0.7 \Rightarrow P(A) = 0.3$.
+    \item 20\% watch sports: $P(S) = 0.2$.
+    \item Of those watching more than one category, 15\% watch sports: $P(S | A^c) = 0.15$.
+\end{itemize}
+
+We need $P(A \cap S^c)$, the probability a customer watches exactly one category and it is not sports:
+\[
+P(A \cap S^c) = P(A) - P(A \cap S).
+\]
+
+Since $P(A \cap S) = 0$ (sports watchers are counted under $P(A^c)$):
+\[
+P(A \cap S^c) = P(A) = 0.3.
+\]
+\textbf{Solution:} $P(A \cap S^c) = 0.3$.
+
+\textbf{Problem 2}
+
+We need $P(6|3,4)$, the probability the 6-sided die was chosen given rolls 3 and 4.
+
+Using Bayes' Theorem:
+\[
+P(6|3,4) = \frac{P(3,4|6) P(6)}{P(3,4)}.
+\]
+Assuming equal probabilities of choosing any die ($P(4) = P(6) = P(12) = \frac{1}{3}$), and independent rolls:
+\[
+P(3,4|6) = P(3|6) P(4|6) = \frac{1}{6} \cdot \frac{1}{6} = \frac{1}{36}.
+\]
+\[
+P(3,4) = \frac{1}{3}\left(\frac{1}{16} + \frac{1}{36} + \frac{1}{144}\right).
+\]
+Simplify and compute:
+\[
+P(6|3,4) = \frac{\frac{1}{36} \cdot \frac{1}{3}}{\frac{1}{3}\left(\frac{1}{16} + \frac{1}{36} + \frac{1}{144}\right)}.
+\]
+Numerical calculation gives $P(6|3,4) \approx 0.51$.
+
+\textbf{Problem 3}
+
+Probability a marble is blue after the second draw:
+\[
+P(\text{Blue on second draw}) = \frac{b}{n} \cdot \frac{b+k}{n+k} + \frac{g}{n} \cdot \frac{g+k}{n+k}.
+\]
+Simplify and substitute as needed.
+
+\textbf{Problem 4}
+
+(a) Probability of drawing two candies with the same flavor is:
+\[
+P(\text{same flavor}) = \sum_{pockets} P(\text{flavor from pocket})^2 \cdot P(\text{pocket})^2.
+\]
+
+(b) Bayesian calculations apply. Let heads/tails represent sequences, use Bayes' theorem.
+
+(c) Set probabilities equal:
+\[
+\frac{2+x}{2+7+x} = \frac{5}{5+2}.
+\]
+Solve for $x$.
+
+\textbf{Problem 5}
+
+For independence: check $P(A \cap B) = P(A)P(B)$.
+Repeat for other pairs.
+
+\textbf{Problem 6}
+
+Partition definition and law of total probability:
+\[
+P(A|B) = \sum P(A|B_i)P(B_i|B).
+\]
+Proof by substitution.
+
+\textbf{Problem 7}
+
+(a)-(c) Condition on defendant guilt and independence.
+Use $P(\text{Guilty}) = 0.7$ and $P(\text{Innocent}) = 0.3$.
+
+\textbf{Problem 8}
+
+(a) Use total probability:
+\[
+P(A) = \sum P(A|word_i)P(word_i).
+\]
+
+(b) Enumerate possible word lengths.
+`)
diff --git a/documents/by-course/pstat-120a/hw2/package.nix b/documents/by-course/pstat-120a/hw2/package.nix
new file mode 100644
index 0000000..7879e7e
--- /dev/null
+++ b/documents/by-course/pstat-120a/hw2/package.nix
@@ -0,0 +1,37 @@
+{
+  pkgs,
+  typstPackagesCache,
+  typixLib,
+  cleanTypstSource,
+  flakeSelf,
+  ...
+}:
+let
+  src = cleanTypstSource ./.;
+  commonArgs = {
+    typstSource = "main.typ";
+
+    fontPaths = [
+      # Add paths to fonts here
+      # "${pkgs.roboto}/share/fonts/truetype"
+    ];
+
+    virtualPaths = [
+      # Add paths that must be locally accessible to typst here
+      # {
+      #   dest = "icons";
+      #   src = "${inputs.font-awesome}/svgs/regular";
+      # }
+    ];
+
+    XDG_CACHE_HOME = typstPackagesCache;
+    SOURCE_DATE_EPOCH = builtins.toString flakeSelf.lastModified;
+  };
+
+in
+typixLib.buildTypstProject (
+  commonArgs
+  // {
+    inherit src;
+  }
+)