File size: 3,480 Bytes
96b4304 | 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 85 86 87 88 89 90 91 92 | """How often has each candidate digit actually been shown, so far and by the
end of the epoch.
Counts are a property of the stored pool: if digit d appears in c of puzzle p's
instances at that cell, then after P passes over the pair list the model has
seen (cell -> d) exactly c*P times. So the whole exposure picture follows from
the pool's per-(cell, candidate) count histogram times the pass count.
"""
import argparse
import numpy as np
D = "/tmp/sudoku_superposition"
CAND = "/tmp/sudoku_s12/train_cand_masks.npy"
STAGE = 0
BS = 64
def digits(m):
return [d for d in range(1, 10) if int(m) & (1 << (d - 1))]
def main():
ap = argparse.ArgumentParser()
ap.add_argument("--step", type=int, required=True)
ap.add_argument("--puzzles", type=int, default=300)
args = ap.parse_args()
starts = np.load(f"{D}/train_starts.npy")
counts = np.load(f"{D}/train_counts.npy")
A = np.load(f"{D}/train_assignments.npy", mmap_mode="r")
masks = np.load(CAND, mmap_mode="r")
n_puz = counts.shape[0]
pairs = int(np.asarray(counts[:, STAGE]).astype(np.int64).sum())
per_pass = pairs / BS
P = args.step / per_pass
print(f"TRAIN {n_puz:,} puzzles stage-1 (puzzle, instance) pairs "
f"{pairs:,} {pairs / n_puz:.2f} instances/puzzle")
print(f"one pass = {per_pass:,.0f} steps at batch {BS}; "
f"one epoch = 5 passes = {5 * per_pass:,.0f} steps")
print(f"step {args.step:,} -> {P:.2f} passes done "
f"({P / 5 * 100:.1f}% of the epoch)")
print(f" each puzzle shown {P * pairs / n_puz:.1f} times so far, "
f"{5 * pairs / n_puz:.1f} by the end")
print(f" each specific instance seen {P:.2f} times so far, 5 at the end")
# per-(cell, candidate) counts inside the pool
hist = np.zeros(8, dtype=np.int64)
tot = 0
ncand_sum = 0
ncell = 0
for q in range(args.puzzles):
m = np.asarray(masks[q, STAGE])
n = int(counts[q, STAGE])
blk = np.asarray(A[starts[q, STAGE]:starts[q, STAGE] + n])
for c in range(81):
S = digits(m[c])
if len(S) < 2:
continue
ncell += 1
ncand_sum += len(S)
v, k = np.unique(blk[:, c], return_counts=True)
cnt = {int(a): int(b) for a, b in zip(v, k)}
for d in S:
hist[min(cnt.get(d, 0), 7)] += 1
tot += 1
print(f"\nover {args.puzzles} puzzles, {ncell:,} multi-candidate cells, "
f"mean |S| {ncand_sum / ncell:.2f}")
print(f"how many of the puzzle's ~6 instances carry each candidate:")
print(f" {'times in pool':>14} {'share of (cell,cand)':>21} "
f"{'seen so far':>12} {'seen by epoch end':>18}")
for c in range(8):
lab = f"{c}" if c < 7 else "7+"
print(f" {lab:>14} {hist[c] / tot * 100:>20.1f}% "
f"{c * P:>12.1f} {c * 5:>18}")
mean_c = float((np.arange(8) * hist).sum() / tot)
print(f"\n mean over candidates: {mean_c:.2f} instances carry it, so "
f"~{mean_c * P:.1f} sightings so far, ~{mean_c * 5:.1f} by epoch end")
print(f" never shown (0 in pool): {hist[0] / tot * 100:.1f}% of "
f"(cell, candidate) pairs -- stays 0 forever")
tst = np.load(f"{D}/test_counts.npy")
print(f"\nVALIDATION {tst.shape[0]:,} test puzzles available")
print(f" each eval uses eval_epochs=5 x batch {BS} = {5 * BS} puzzles")
if __name__ == "__main__":
main()
|