File size: 3,550 Bytes
6a1771b
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
"""Check the (puzzle, instance) epoch enumeration on the real stage-1 counts.

Verifies the property the experiment rests on: after E epochs every instance of
every puzzle has been used exactly E times, and a batch holds distinct puzzles
(one instance of a given puzzle per batch).
"""
import numpy as np


def build_pairs(starts, counts, stage, n_puz):
    """Same expansion as SudokuDataset._build_instance_epoch_list."""
    c = np.asarray(counts[:n_puz, stage]).astype(np.int64)
    s = np.asarray(starts[:n_puz, stage]).astype(np.int64)
    total = int(c.sum())
    puzzle_ids = np.repeat(np.arange(n_puz, dtype=np.int64), c)
    offsets = np.arange(total, dtype=np.int64) - np.repeat(np.cumsum(c) - c, c)
    rows = np.repeat(s, c) + offsets
    return puzzle_ids, rows, c


def main():
    d = "/tmp/sudoku_superposition"
    starts = np.load(f"{d}/train_starts.npy")
    counts = np.load(f"{d}/train_counts.npy")
    stage, n_puz, epochs, bs = 0, 20000, 5, 64

    pids, rows, c = build_pairs(starts, counts, stage, n_puz)
    total = len(rows)
    print(f"stage {stage + 1}: {n_puz} puzzles -> {total} pairs, "
          f"{c.min()}-{c.max()} instances/puzzle (mean {c.mean():.2f})")

    # 1. rows are exactly each puzzle's contiguous assignment block, no repeats
    assert total == int(c.sum())
    assert len(np.unique(rows)) == total, "duplicate assignment rows"
    for p in (0, 1, 7, n_puz - 1):
        want = np.arange(starts[p, stage], starts[p, stage] + counts[p, stage])
        got = np.sort(rows[pids == p])
        assert np.array_equal(got, want), (p, got, want)
    print("rows match each puzzle's assignment block            OK")

    # 2. every instance seen exactly `epochs` times
    rng = np.random.RandomState(0)
    seen = np.zeros(total, dtype=np.int32)
    order = np.arange(total)
    batch_dup = 0
    n_batches = 0
    for _ in range(epochs):
        rng.shuffle(order)
        seen[order] += 1
        for b in range(0, total - bs, bs):
            sl = pids[order[b:b + bs]]
            batch_dup += bs - len(np.unique(sl))
            n_batches += 1
    assert seen.min() == seen.max() == epochs, (seen.min(), seen.max())
    print(f"every instance seen exactly {epochs}x                     OK")

    # 3. per-puzzle: all of its instances covered, each `epochs` times
    per_puzzle = np.bincount(pids, weights=seen, minlength=n_puz)
    assert np.array_equal(per_puzzle, epochs * c)
    print("every puzzle: all instances x epochs                 OK")

    # 4. batches hold distinct puzzles
    print(f"same-puzzle collisions in a batch: {batch_dup} over "
          f"{n_batches} batches ({batch_dup / (n_batches * bs) * 100:.3f}% "
          f"of slots)")

    # 5. averaged over the epochs, the target at a cell IS the candidate set
    A = np.load(f"{d}/train_assignments.npy", mmap_mode="r")
    p = 3
    blk = np.asarray(A[starts[p, stage]:starts[p, stage] + counts[p, stage]])
    multi = [c_ for c_ in range(81) if len(np.unique(blk[:, c_])) > 1]
    print(f"\npuzzle {p}: {counts[p, stage]} instances, "
          f"{len(multi)} cells whose digit varies across instances")
    for cell in multi[:5]:
        vals, cnt = np.unique(blk[:, cell], return_counts=True)
        emp = ", ".join(f"{v}:{n}/{len(blk)}" for v, n in zip(vals, cnt))
        print(f"  cell (r{cell // 9}, c{cell % 9}) digits {emp}")
    print("\nthis empirical spread over instances is exactly what the model "
          "must reproduce; it only sees it if all instances are visited")


if __name__ == "__main__":
    main()