Skip to content

Exercise 04: add Part 2 with augmented-state cases - #160

Open
nicolejrkim wants to merge 37 commits into
PDM4AR:masterfrom
nicolejrkim:ex04b
Open

Exercise 04: add Part 2 with augmented-state cases#160
nicolejrkim wants to merge 37 commits into
PDM4AR:masterfrom
nicolejrkim:ex04b

Conversation

@nicolejrkim

Copy link
Copy Markdown

Changes

  • Part 2 added: three augmented-state cases (forecast, momentum, glitch) that break the Markov property of the grid; students choose the state augmentation and reuse their Part-1 VI/PI on (M, N, Z) arrays. Handout rewritten with per-case transition tables and worked examples.
  • WONDERLAND removed entirely; Cell.CLIFF renumbered to 4.
  • Evaluation harness extended: per-z-slice report plots, transition probes with full-coverage expectation files for both parts (students can add their own probes), and per-result case_key/value_checksum stamps so the server can screen VI/PI submissions for verbatim reuse.
  • Three optional smaller test maps (6x6, 9x9, 12x12) with published solutions via ALL_MAPS; random_map(...) also generates student practice maps with the goal guaranteed reachable.
  • Data files regenerated with portable plain-int pickles (the old transition file could not be unpickled in the student container); ground truth stores all optimal actions per state, so tie-breaking is never penalized.
  • Robustness fixes from review: shape-aware templates, any-dtype policies, missing ground truth scores 0 instead of raising, consistent value-plot color scales and black cliffs, dead code removed.

Validation

  • Ground truth cross-validated against an independent implementation, an LP solve of the same model, and a student-style sample solution (accuracy 1.0 / R2 > 0.99999 everywhere).
  • Full run (54 cases; 78 with ALL_MAPS) executed end to end in the devcontainer at accuracy 1.0; all data files load in the student container.

Jaeryeong Kim added 30 commits August 16, 2026 16:28
Three cases extending ex04, each breaking the Markov property of the
bare grid; students choose the state that restores it and reuse their
ex04 VI/PI unchanged:
  - momentum (time lag): state (i, j, heading)
  - forecast (information): state (i, j, fog)
  - glitch (correlated noise): state (i, j, gear)

Design decisions (from supervisor review): fixed augmented state so all
students share one (M, N, Z) ground truth; no signature changes (one
GridMdp subclass per case); maps are the ex04 family with the wonderland
removed (same seeds, n_wonderland=0); an automated VI/PI coincidence
check on the converged matrices emits a review label when the two
submissions agree to bit level.

Ground truth generated by a validated reference implementation
(reproduces the shipped ex04 expected results when each case's
modulation is switched off; VI==PI on every case and map; policy ground
truth stores all optimal actions per state, fair to any tie-breaking).
End-to-end smoke test: 15/15 transition probes, 18/18 algo tests at
policy_accuracy 1.0 / R2 1.0, coincidence label clean on honest pairs
and raised on duplicated solvers.
12 extra wonderland-free maps (6x6 to 12x12, sanity-filtered so the goal
is reachable and worth reaching), solved by the validated reference for
all three cases, with the maps stored inside the npz so nothing is
regenerated at load time. exercises_def/ex04b/practice.py lets students
run check_solution(MySolver) and see, per map, the exact policy-accuracy
and value-R2 formulas the graded evaluation uses. Handout gains a
Practice maps section. Also: npz meta is now literal_eval-safe.

Smoke test: reference solver scores 1.0 on all 36 (case, map) runs; a
deliberately broken solver is flagged.
Exercise 04 is now one exercise in two parts. Part 1 is the base MDP
with the WONDERLAND removed completely: maps use the same generator and
seeds with n_wonderland=0, the 5x5 example replaces its wonderland cells
with grass, and the handout loses the teleport spec, hints, rewards and
worked rows (replaced with rows recomputed on the new map). Part 2 folds
in the three augmented cases (momentum, forecast, glitch) on the same
maps: same method signatures, one GridMdp subclass per case, solvers
gain an optional max_iters parameter.

Ground truth regenerated wonderland-free by the validated reference:
expected_results.npz (base, OptimalActions policies),
expected_transition_results.npz (dense 2646-entry dict on the 5x5),
expected_results_aug.npz (the nine augmented case/map pairs), and
practice_results.npz (12 practice maps now covering base + all cases,
with the student self-check moved to exercises_def/ex04/practice.py).
The VI/PI coincidence label now covers base and augmented pairs alike.
The separate ex04b exercise is removed.

End-to-end smoke test: 54 tests assembled; 30/30 transition probes;
24/24 algo tests at policy_accuracy 1.0 / R2 1.0; coincidence check
clean on 12 honest pairs and raised on 12 duplicated ones; 48/48
practice runs perfect.
New exercises_def/ex04/selfcheck.py: random_map() generates unlimited
wonderland-free maps (BFS-checked goal reachability), and self_check()
verifies a solution with no answer key, using only the student's own
model: probability sums (full-grid scan on small maps), ABANDON mass on
START, V <= 500 with V(goal) = 500, per-cell dominance for forecast and
glitch, VI-vs-PI agreement, and a Monte-Carlo rollout reproducing
V(start) within statistical error. Deliberately contains no solver
logic; the exact certificate (the Bellman residual) is described in the
handout in math only, for students to implement themselves.

Handout gains a "Make your own maps, and verify without an answer key"
section with the checklist, the certificate, and the honest caveats
(checks are necessary not sufficient; a wrong model can self-certify,
which the worked examples and practice maps anchor against).

Smoke test: reference solutions pass all checks on a fresh random map
(base and forecast); corrupted values are caught by three independent
checks.
The transition-probability file pickled Action enums under a bare
"structures" module path, so it could not be unpickled inside the student
container (and it contained stray STAY entries for non-goal states). All
four data files are now produced by the exercises-private generator with
plain-int keys and lists, saved with savez_compressed. Values and optimal
action sets are verified equivalent to the previous files.
Drops the Cell.WONDERLAND enum member (CLIFF keeps its value 5, so all
stored maps stay valid), the unused placement machinery and n_wonderland
parameter in generate_map, the wonderland plot branches and evaluation-mask
special case, the purple color entry, and every remaining mention in the
handout and comments. The generator's RNG call sequence is unchanged: all
practice maps regenerate byte-identically and the full validation suite
passes; only expected_results_aug.npz changes (a metadata string).
…e example figure

Brings back the separate Value Iteration, Policy iteration, and Expected
outcome subsections with full class skeletons (updated to the current solve
signature with max_iters), the output-format and CLIFF-exclusion paragraph,
and Figure 1 - regenerated from the new 5x5 map with the reference solution
so it matches what students see in their reports.
… no max_iters

- Cell.CLIFF renumbered from 5 to 4, closing the gap; data files regenerated
  (verified: only the cliff byte changes in the stored maps, every value,
  policy, and transition probability is identical).
- The Part-2 model constants are no longer pre-defined in structures.py;
  students take the numbers from the handout themselves.
- solve() loses the max_iters parameter everywhere (templates and handout);
  the automated VI/PI coincidence label remains the anti-copying check.
Three practice maps (6x6, 9x9, 12x12) now run inside get_exercise4 as
ungraded maps 3-5, reported and scored exactly like the public test maps,
for Part 1 and every Part-2 case. The maps regenerate deterministically
from PRACTICE_MAP_SPECS, so only their solutions ship
(expected_results_practice.npz); the separate practice.py module, its
check_solution API, and the 12-map practice_results.npz are removed.
Verified: the three maps and their solutions are identical to entries
0, 6 and 10 of the previous practice set.
The no-answer-key consistency checks are dropped; random_map (random maps
with the goal guaranteed reachable) moves verbatim into map.py, where the
practice-map regeneration and students can keep using it. Verified: the
practice maps regenerate byte-identically through the relocated function.
get_test_grids() now returns six maps (5x5, 10x10, 40x40, 6x6, 9x9, 12x12);
the smaller three regenerate deterministically from SMALL_TEST_MAP_SPECS.
Their solutions merge into expected_results(.aug).npz (keys 3-5, loaders
size themselves from the file), the separate practice plumbing and
expected_results_practice.npz are removed, and the handout lists the six
maps in the test-cases section. Still 78 built-in test cases; the server
evaluation now covers the small maps too.
The default "--exercise 04" is back to the three public maps (5x5, 10x10,
40x40). A second exercise id "04quick" runs the identical pipeline on three
smaller maps (6x6, 9x9, 12x12, report ids 3-5) for fast iteration while
developing - a full naive-solution run finishes in a fraction of the time.
The expected-results files already carry solutions for map ids 0-5; the
loaders now take the id subset. The handout explains both run modes.
…er ones

"--exercise 04" runs the three public maps (54 test cases); "--exercise
04all" runs all six maps (78 test cases), adding the 6x6, 9x9 and 12x12
maps as ids 3-5 for broader coverage.
available_exercises is back to its original single "04" entry. Students
opt into the three extra maps (6x6, 9x9, 12x12, report ids 3-5) with
PDM4AR_EX04_ALL_MAPS=1; the handout shows the command.
The env variable is replaced by ALL_MAPS = False at the top of
exercises_def/ex04/ex04.py; students flip it to True to also run the
6x6, 9x9 and 12x12 maps (report ids 3-5). Handout updated.
The student's and ground-truth panels each auto-scale their colormap; a
student array holding 0.0 at CLIFF cells (which are not states) stretched
its scale to [0, max] while the ground truth (NaN at cliffs) spanned only
the real values, so identical values rendered in different colors. Both
the base and per-slice plots now mask cliffs to NaN before imshow.
Jaeryeong Kim added 7 commits August 31, 2026 13:53
Value slices now paint black rectangles over CLIFF cells (instead of
leaving them transparent), and the policy slices skip cliff cells so no
arrow can be drawn on top of one.
The Rectangle overlays (inherited from the original code) could leave
hairline seams at small cell sizes in the PDF panels. Cliff cells are
already masked to NaN for the color scale; cmap.set_bad("k") now paints
them black inside the image raster itself, pixel-perfect, and the patch
overlays are removed from both the base and per-slice value plots.
- ex4_evaluation_algo and ex4_transition_prob_evaluation initialize their
  scores before the ground-truth guard, so a test case without an expected
  result scores 0 instead of raising UnboundLocalError.
- get_test_grids' evaluation_tests annotation matches the actual 3-field
  tuples ((m, n), n_cliff, seed).
- Removed the dead pkl-based transition-matrix helper cluster in data.py
  (no callers, reads a file no generator produces) and the unused
  is_too_close_to_rift_or_border leftover in map.py.
- get_exercise4 reuses the already-built grids for the transition probes
  instead of regenerating all maps.
- Replace the in-module VI/PI coincidence check, which could never fire
  (each test case runs in its own run_with_timer process, so the VI
  cache was never visible to the PI case), with case_key/value_checksum
  stamps on every value-test result; the comparison itself moves to the
  evaluation side. Drop the docs sentence describing the mechanism.
- Fix the misspelled __post__init__ dataclass hooks so the performance
  sanity asserts actually run, and make the empty-aggregation path
  return zeros explicitly (np.mean([]) is NaN, not ZeroDivisionError).
- Accept any integer dtype for plotted policies (int32 previously
  crashed the whole test case) and score object-dtype student policies
  by set membership (list-in-list could never match).
- Make the solver templates shape-aware so a fresh checkout returns
  (M, N, Z) zeros for Part-2 mdps and scores 0 instead of crashing
  every augmented test with an IndexError.
expected_transition_results_aug.npz holds full (state, action, next_state)
coverage per case on the 5x5 map; AUG_PROBES is now scenario-only and
get_expected_results_transition_aug looks expectations up in the file,
mirroring the Part-1 loader. As in Part 1, students can add their own
probe triples and the file already covers them. Verified to load inside
the student container (numpy 1.26).
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant