"""Equality in the counting argument: does every best layout have to lie in a
hyperplane (n <= 27) or contain a whole one (n >= 28)?

A layout S lies in a hyperplane exactly when some parallel class splits it
(n, 0, 0); for n >= 28 it contains a whole hyperplane exactly when some class
has a part of 27. So run the same exact search as bound.py at L = f(n), with
those splits forbidden. If no assignment of the remaining allowed splits to the
40 classes meets the pair and triple counts, every best layout has that shape.

  python3 classify.py > out/classify.txt
"""
from math import comb
import numpy as np
from bound import G3, built


def feasible_without_full(n, L):
    big = min(n, 27)
    ok = [(a, b, n - a - b) for a in range(n + 1) for b in range(n - a + 1)
          if a >= b >= n - a - b and a <= 27 and a != big
          and G3[a] + G3[b] + G3[n - a - b] + min(a * b, b * (n - a - b), a * (n - a - b)) >= L]
    if not ok:
        return False, []
    need_p, need_t = 13 * comb(n, 2), 4 * comb(n, 3) + 9 * L
    P = [sum(comb(k, 2) for k in p) for p in ok]
    T = [sum(comb(k, 3) for k in p) for p in ok]
    row = np.full(need_p + 1, -1, dtype=np.int64)
    row[0] = 0
    for _ in range(40):
        nxt = np.full(need_p + 1, -1, dtype=np.int64)
        for Pp, Tp in zip(P, T):
            if Pp <= need_p:
                src = row[:need_p + 1 - Pp]
                np.maximum(nxt[Pp:], np.where(src >= 0, src + Tp, -1), out=nxt[Pp:])
        row = nxt
    return int(row[need_p]) >= need_t, ok


for n in range(3, 48):
    f = built(n)
    feas, ok = feasible_without_full(n, f)
    shape = 'in a hyperplane' if n <= 27 else 'contains a hyperplane'
    print(f'n={n:2d} f={f:3d}  every best layout {shape}: {"NOT PROVED" if feas else "yes"}'
          + (f'  (other splits allowed: {len(ok)})' if feas else ''), flush=True)
