// Independent verifier: reads a blocks text file and checks the covering property exhaustively. // Usage: node verify.mjs v k t blockfile import { readFileSync } from "node:fs"; const [v, k, t] = process.argv.slice(2, 5).map(Number); const file = process.argv[5]; const text = readFileSync(file, "utf8"); const lines = text.split(/\r?\n/).filter(l => l.trim().length > 0); const blocks = lines.map(l => l.split(/\s+/).map(Number)); let malformed = 0; for (const b of blocks) { if (b.length !== k || !b.every((x, i) => Number.isInteger(x) && x >= 0 && x < v && (i === 0 || x > b[i - 1]))) malformed++; } console.log(`file: ${file}`); console.log(`blocks: ${blocks.length}, malformed: ${malformed}`); // exhaustive t-subset coverage const covered = new Map(); let uncovered = 0; const cur = []; function* genT(arr, tt, start = 0) { if (cur.length === tt) { yield [...cur]; return; } for (let i = start; i < arr.length; i++) { cur.push(arr[i]); yield* genT(arr, tt, i + 1); cur.pop(); } } for (const b of blocks) { for (const ts of genT(b, t)) { const key = ts.join(","); covered.set(key, (covered.get(key) || 0) + 1); } } const totalT = binom(v, t); function binom(n, r) { let c = 1n; for (let i = 0; i < r; i++) c = c * BigInt(n - i) / BigInt(i + 1); return Number(c); } uncovered = totalT - covered.size; console.log(`t-subsets: ${totalT}, covered: ${covered.size}, UNCOVERED: ${uncovered}`); console.log(uncovered === 0 && malformed === 0 ? `VERDICT: VALID (${blocks.length} blocks)` : "VERDICT: INVALID");