Hints — Module 21
Graduated hints, surfaced by ./grade 21 --stage K --hint J. Try the stage
first; each hint is more specific than the last.
Stage 1: Truth tables and normal forms
- The whole function is one integer: bit
ioftableisf(i), where the integeriencodes the assignmentx_j = (i >> (j-1)) & 1. Every method is a loop over0 .. 2^ndoing bit operations. Remember to mask to2^nbits son = 6(all 64 bits) does not overflow. - For
to_dnf, emit one term per 1-row; forto_cnf, one clause per 0-row. A term/clause is aVec<i32>of signed literals: for rowx, variablejcontributes+jif(x >> (j-1)) & 1 == 1else-j. A maxterm negates those literals so the clause is false exactly at that row.from_dnfORs the product terms;from_cnfANDs the clauses. - A literal
lholds atxwhen(l > 0) == ((x >> (l.abs()-1)) & 1 == 1); a product term is satisfied iff all its literals hold, a clause iff some literal holds.from_closure(n, |x| terms.iter().any(|t| all_hold(t, x))).
Stage 2: Boolean chains and combinational cost
- A gate is a 4-bit nibble; the output for
(a, b)is bit2*a + bof the op. Soapply_gate(op, a, b) = (op >> (2*(a as u8) + b as u8)) & 1 == 1. Chain values are indexed0..nfor inputs, then one per step. eval_chain: build aVec<bool>seeded with theninput bits ofx, then pushapply_gate(step.op, values[step.left], values[step.right])for each step, and returnvalues[output].chain_computescompares this tof.eval(x)for everyx in 0..2^n.gate(op, l, r)pushes aStep, setsoutputto the new indexn + steps.len() - 1, and returns it. XOR from AND/OR/NOT:t2 = OR(x1,x2); t3 = AND(x1,x2); t4 = NOTL(t3,t3); out = AND(t2,t4).
Stage 3: Median, threshold, and symmetric functions
majorityis a strict majority:2 * (count of true) > len.threshold_at_leastis(count of true) >= k. A symmetric function depends only onx.count_ones().symmetric_function(n, weights)=from_closure(n, |x| weights[popcount(x)])(assertweights.len() == n + 1).is_self_dual: for everyx, comparef(x)withf(¬x)where¬x = (!x) & (2^n - 1); self-dual means they always differ.is_monotone: for everyxand every bitbthat is 0 inx, sety = x | (1 << b)and fail iff(x) && !f(y). For the Dedekind test, looptable in 0 .. 2^(2^n), count how manyBoolFunc { n, table }are monotone, and compare with[2, 3, 6, 20, 168].
Stage 4: Optimum chains for small functions
C(f)is the fewest gates overbasis. Do NOT grow a set of "reachable functions" and combine pairs — that undercounts, because it treats a gate's two operands as jointly free (it reports 3 for majority-of-3, which truly needs 4). You must model sharing.- BFS over states, where a state is the set of functions computed so far
(a
Vec<u64>, kept sorted so equal sets compare equal). Start with the constants0and2^n - 1and thenprojection tables (all cost 0). Apply gategto two truth tables at once with bit ops:r = (g&1?!a&!b:0) | (g&2?!a&b:0) | (g&4?a&!b:0) | (g&8?a&b:0), masked. - Dequeue
(state, cost); for each ordered paira, bin the state and eachgin the basis, formt = combine(g, a, b). Iftequals the target, returncost + 1. Otherwise, iftis new to the state, push the sortedstate ∪ {t}(deduped by aHashSet) withcost + 1. Keepn <= 3.