Files
Rohit Ghumare dda194f840 fix(quiz): correct answer is always in the same position (slot B) (#381)
Every "Test Your Understanding" quiz placed the correct answer in option B.
Across the 2026 questions in 338 quiz files the correct answer sat at index 1
in 61.5% of cases (uniform would be ~25%), and 107 files had every answer at B,
making the quizzes guessable without reading them.

scripts/debias_quizzes.py rewrites each question's option order with a
deterministic, content-seeded permutation and updates the correct index to
follow the moved answer. It is idempotent: options are canonicalised to a sorted
base before permuting, so re-running produces byte-identical output. Questions
whose options reference each other by position ("all of the above", "both A and
B") are left untouched. The correct-answer value, the option set, and every
explanation are preserved exactly; only order and the index change.

Result: A 23.8% / B 26.3% / C 23.5% / D 26.4%.

The script doubles as a CI guard: `--check` exits non-zero if any quiz is not
de-biased, wired into the curriculum workflow so new lessons cannot regress.

Fixes #368
2026-08-01 14:24:15 +01:00

65 lines
3.2 KiB
JSON

{
"questions": [
{
"stage": "pre",
"question": "What does the adjacency matrix A[i][j] = 1 represent?",
"options": [
"Node i has degree j",
"Node i and node j have the same label",
"The shortest path from i to j has length 1",
"There is an edge from node i to node j"
],
"correct": 3,
"explanation": "The adjacency matrix is the core representation of a graph. A[i][j] = 1 means there is an edge connecting node i to node j. For undirected graphs, the matrix is symmetric (A[i][j] = A[j][i])."
},
{
"stage": "pre",
"question": "What data structure does BFS use and what does it find?",
"options": [
"Stack; finds connected components",
"Queue; finds shortest paths in unweighted graphs",
"Priority queue; finds minimum spanning tree",
"Hash map; finds duplicate nodes"
],
"correct": 1,
"explanation": "BFS uses a queue (FIFO) to explore all neighbors at distance k before moving to distance k+1. This guarantees that the first time a node is discovered, it is via a shortest path from the source."
},
{
"stage": "post",
"question": "The graph Laplacian L = D - A of a connected graph has how many zero eigenvalues?",
"options": [
"Zero",
"Equal to the number of nodes",
"Equal to the number of edges",
"Exactly one"
],
"correct": 3,
"explanation": "The number of zero eigenvalues of the Laplacian equals the number of connected components. A connected graph has exactly one connected component, so exactly one zero eigenvalue. A graph with k disconnected pieces has k zero eigenvalues."
},
{
"stage": "post",
"question": "In GNN message passing, what does h_v^(k+1) = sigma(W * mean({h_u^(k) : u in neighbors(v)})) compute?",
"options": [
"The PageRank score of node v",
"The shortest path from v to all other nodes",
"A new feature vector for node v by aggregating neighbor features, transforming with learned weights, and applying a nonlinearity",
"The degree of node v at layer k+1"
],
"correct": 2,
"explanation": "Each node collects features from its neighbors (mean aggregation), multiplies by a learned weight matrix W, and applies an activation function sigma. After k rounds, each node has information from its k-hop neighborhood."
},
{
"stage": "post",
"question": "How does spectral clustering use the Fiedler vector (eigenvector of the second-smallest eigenvalue of L)?",
"options": [
"Nodes with the largest Fiedler vector entries form one cluster",
"The Fiedler vector is used as edge weights",
"Nodes with positive Fiedler vector values go in one group, nodes with negative values go in the other",
"The Fiedler vector determines the number of clusters"
],
"correct": 2,
"explanation": "The Fiedler vector encodes the smoothest non-trivial function on the graph. Nodes in the same tightly-connected cluster get similar values, while nodes separated by a bottleneck get values with opposite signs. The sign split partitions the graph into two clusters."
}
]
}