7 routes42 sections324 units

Unit 1.3 · about 4 h

90 / 324

Loop invariants, brute-force oracles and differential tests

Stating the invariant first turns debugging into checking. A brute-force oracle plus shrinking turns a wrong program into a minimal counterexample.

  • derive
  • implement

You can now

  • State a loop invariant with initialization, maintenance and termination before coding, following the state-machine pattern.
  • Write a Hypothesis differential test that compares an optimized linear routine against a brute-force oracle with controlled seeds.
  • Read a shrunken failing input back to the violated invariant.

Covers

  • Loop invariants, initialization, maintenance and termination
  • Brute-force oracles and randomized differential tests

Study, in this order

5 steps

  1. Mathematics for Computer Science, Chapter 5, Section 5.4
    MIT 6.042J - asymptotics and invariants

    5.4.1 States and Transitions; 5.4.2 Invariant for a Diagonally-Moving Robot with Lemma 5.4.1 and Theorem 5.4.2; 5.4.3 The Invariant Principle with Definitions 5.4.4 and 5.4.5

    Depth · Skim 5.4.4 Die Hard as a second example; skip 5.4.5 Fast Exponentiation.

  2. Hypothesis Quickstart
    Hypothesis documentation - Quickstart and stateful testing

    Write your first test (@given with integers and lists strategies); Running in a test suite; Combining Hypothesis with pytest

    Depth · Skip the database and shrinking-internals pages; shrinking behavior is used here, not studied.

  3. Hypothesis: Configuring test settings
    Hypothesis documentation - Quickstart and stateful testing

    Configuring a single test (@settings with max_examples) and the commonly used settings, where derandomize makes runs deterministic

  4. Hypothesis stateful testing
    Hypothesis documentation - Quickstart and stateful testing

    Rule-based state machines: rule, precondition and invariant; run_state_machine_as_test

    Depth · Read the rules-and-invariants shape only; full stateful harnesses arrive with Design HashMap in the hash-table unit.

  5. Sliding window: fixed size (invariant-in-code example)
    DSA Handbook - Foundations and linear patterns

    The pattern (build-first-window then slide) and the four primitives table

    Depth · Read only the pattern and primitives as the invariant written in code; the full chapter belongs to the two-pointer unit.

Focus on

  • An invariant has three obligations: true at the start, preserved by each step, and strong enough to imply the answer at the end.
  • The oracle must be too simple to share the bug: brute force against optimized, with independent code paths.
  • derandomize (or a fixed seed) makes the run replayable; shrinking then minimizes the failure, which you map back to the invariant clause.
  • State the invariant in one sentence before the loop; the window primitives show the shape.

Reproduce closed-book

Write test_window.py comparing the sliding-window max-average against the \(O(nk)\) brute-force oracle with Hypothesis lists of ints in [-100, 100] of length 1 to 30 and \(k\) drawn from 1 to len(nums), max_examples=200, derandomize=True. Run under pytest in Python 3.13 with Hypothesis 6.169.0 and pytest 9.1.1: expect 1 passed. Then break the slide step once (drop the minus term) and confirm the test fails on a shrunken input.

Traps

  • Testing the optimized code against itself by reusing its helper in the oracle. The oracle shares the bug and everything passes.
  • Random tests without seed control: a failure you cannot replay is a rumor, not a regression test.
  • Showing maintenance without checking that the invariant implies the postcondition at termination.

Practice

LeetCode 643: Maximum Average Subarray I

Solve with the build-first-window slide. Commit a Hypothesis differential test against the \(O(nk)\) brute force alongside the solution; judge with the worked example nums = [2, 1, 5, 1, 3, 2, 1, 4], \(k = 3\).

After submitting, re-read the handbook sliding-window-fixed worked example and check your trace emits the same running maxima.

Self-test

  1. State the Invariant Principle in one sentence.

  2. Why does the max-average oracle use the \(O(nk)\) double loop instead of a second window implementation?

  3. Hypothesis reports a failing input of length 24. What do you do before touching the code?

  4. Write the invariant for the fixed-size window slide.

Completion criterion

Stop when

Your committed test replays deterministically, catches the seeded minus-term bug, and you can point at the invariant line the shrunken input breaks.

Mark passed, then open 1.4 Only mark this when you can do it without notes.

Leads to

Resources for this unit

  • DSA Handbook - Foundations and linear patterns
    Handbook Academyprimarycourse
    Study Part 0, Part 1, Part 3 and Part 4 in order, plus the Part 5 Linked-list fundamentals chapter. Use the routing-rule pages for arrays versus lists, map choice, stack versus queue, two pointers, sliding windows and prefix methods before seeing solved code.
  • MIT 6.042J - asymptotics and invariants
    MIT OpenCourseWaresupporttheory
    Use the asymptotics, state-machine invariants and proof-method readings when a cost or correctness argument is weak. Solve only the matching problems.
  • Hypothesis documentation - Quickstart and stateful testing
    Hypothesissupportreference
    Follow Quickstart for @given strategies and the pytest combination, Configuring test settings for max_examples and derandomize, then Rule-based state machines (rule, precondition, invariant, run_state_machine_as_test) for randomized operation histories against dict and deque oracles.

Also in this section

  • AlgoMaster DSA - linear structures slice
    AlgoMasterrequiredpractice
    Attempt Design HashMap, Longest Substring Without Repeating Characters and Sliding Window Maximum cold. Hide tags, state the invariant first, and add randomized operation histories to Design HashMap.
  • Algorithms lecture notes - amortized analysis and hashing
    Jeff Ericksonsupporttheory
    Use note 9 Amortized Analysis for the summation, taxation, charging and potential-function proofs, and note 5 Hashing for chaining, universal hashing and open-addressing analysis, when the handbook treatment is too brief for a proof.
  • Algorithmica - memory and data layout
    Sergey Slotinsupportapplication
    Read the memory hierarchy, cache and complexity-model chapters, then measure one contiguous-versus-linked and one hash-versus-ordered workload crossover.
  • NeetCode - unseen linear problems
    NeetCodeoptionalassessment
    Use only for two tag-hidden transfer problems after the AlgoMaster slice. Do not start another full roadmap or watch a solution before the attempt is complete.
  • CPython source - list and dict objects
    Python Software Foundationreferencereference
    Read list_resize in Objects/listobject.c for the growth formula and pattern comment, and the USABLE_FRACTION definition, perturbation-probing comment and dummy-entry handling in Objects/dictobject.c. Read the cited functions and comments only.

Quick find

Search Michi

Type to search every route, section, unit, topic and resource.

Enter opens the first result Esc closes

Reference

Keyboard shortcuts

n
Continue to the first unit not passed
j / k
Next / previous unit
1 2 3
Toggle learned, practised, passed
/
Open search
?
Show this help
Esc
Close open panels