libdpf/tools/cas_window/generate.py
Ryan Henry 0d22946a0e Checkpoint the party/runtime stack before share-program and malicious-mode work.
Ship the TLS mesh, composer, Beaver/Yao/leaf MPC, prep/online paths, apps, and docs so the tree is pushable before elevating share_expr, security_mode, and prep resume.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-28 05:59:19 -06:00

618 lines
20 KiB
Python

#!/usr/bin/env python3
"""Cubic windows for the Appendix D maps that were still cleartext-only.
Sollya builds a longest-feasible partition whose fixed-point cubic stays
within half an ulp. Mathematica (Remez), Maple (numapprox[minimax]), and
MATLAB/Chebfun (minimax) each fit the same pieces. The shipped cubic is
the one with the smallest absolute error after rounding coefficients to
2^{-(k+16)}.
"""
from __future__ import annotations
import json
import math
import re
import subprocess
import sys
from dataclasses import dataclass
from decimal import Decimal, ROUND_HALF_UP
from pathlib import Path
PREC = (8, 12, 16, 20, 24, 28, 32)
SOLLYA = "sollya"
MATH = "/home/dawkteraitch/Wolfram/15.0/Executables/math"
MAPLE = "/home/dawkteraitch/maple2025/bin/maple"
MATLAB = "/home/dawkteraitch/MATLAB/R2026a/bin/matlab"
WORK = Path("/tmp/cas-lic/window")
EXPR = {
"lecun": "(17159/10000) * tanh((2 * x) / 3)",
"hard": "expm1(x) * (x + 1) / 2",
}
NUMBER = re.compile(r"[+-]?(?:\d+\.\d*|\d+\.?\d*)(?:[eE][+-]?\d+)?")
@dataclass
class Piece:
left: int
right: int
coeffs: list[int] # c0..c3 at scale 2^q
err: float
source: str
class Sollya:
def __init__(self) -> None:
self.proc: subprocess.Popen[str] | None = None
self.start()
def start(self) -> None:
if self.proc is not None:
self.proc.kill()
self.proc.wait()
self.proc = subprocess.Popen(
["stdbuf", "-o0", "-e0", SOLLYA],
stdin=subprocess.PIPE,
stdout=subprocess.PIPE,
stderr=subprocess.STDOUT,
text=True,
bufsize=1,
)
self._run("verbosity = 0;\nprec = 120;\n", "READY")
def close(self) -> None:
if self.proc is not None:
self.proc.kill()
self.proc.wait()
self.proc = None
def _run(self, script: str, sentinel: str) -> list[str]:
assert self.proc is not None and self.proc.stdin and self.proc.stdout
self.proc.stdin.write(script)
self.proc.stdin.write(f'print("{sentinel}");\n')
self.proc.stdin.flush()
lines: list[str] = []
while True:
line = self.proc.stdout.readline()
if line == "":
raise RuntimeError("sollya exited")
if sentinel in line:
return lines
lines.append(line.rstrip("\n"))
def fit(
self, name: str, left: int, right: int, k: int, q: int, tol: float
) -> tuple[float, list[int]] | None:
# fpminimax is ill-conditioned on a tiny interval at 0 and can report
# an error above half an ulp for a one-ulp step. Taylor is the
# fallback, and the search keeps the smaller certified error.
mini = self._polynomial(name, left, right, k, q, taylor=False)
if mini is not None and mini[0] <= tol:
return mini
tay = self._polynomial(name, left, right, k, q, taylor=True)
cands = [item for item in (mini, tay) if item is not None]
if not cands:
return None
return min(cands, key=lambda item: item[0])
def _polynomial(
self, name: str, left: int, right: int, k: int, q: int, taylor: bool
) -> tuple[float, list[int]] | None:
expr = EXPR[name]
if taylor:
# taylor(f, n, t) returns p such that p(x-t) is the expansion at t.
build = (
f"t0 = (({left})+({right}))/2 * 2^(-{k});\n"
f"pshift = taylor({expr}, 3, t0);\n"
f"p = pshift(x - t0);"
)
else:
build = (
f"p = fpminimax({expr}, 3, [|80,80,80,80|], "
f"[{left}*2^(-{k}), {right}*2^(-{k})], absolute);"
)
script = f"""
{build}
qbits = {q};
i0 = nearestint(coeff(p, 0) * 2^qbits);
i1 = nearestint(coeff(p, 1) * 2^qbits);
i2 = nearestint(coeff(p, 2) * 2^qbits);
i3 = nearestint(coeff(p, 3) * 2^qbits);
pr = i0*2^(-qbits) + i1*2^(-qbits)*x + i2*2^(-qbits)*x^2 + i3*2^(-qbits)*x^3;
e = dirtyinfnorm(({expr}) - pr, [{left}*2^(-{k}), {right}*2^(-{k})]);
print(i0);
print(i1);
print(i2);
print(i3);
print(e);
"""
try:
lines = self._run(script, "FITDONE")
except RuntimeError:
self.start()
return None
if any("Error" in line or "error" in line for line in lines):
self.start()
return None
nums: list[str] = []
for line in lines:
nums.extend(NUMBER.findall(line))
if len(nums) < 5:
self.start()
return None
coeffs = [int(Decimal(nums[i]).to_integral_value(ROUND_HALF_UP)) for i in range(4)]
err = max(float(n) for n in nums[4:])
if not math.isfinite(err):
return None
return err, coeffs
def score(self, name: str, left: int, right: int, k: int, q: int, coeffs: list[int]) -> float | None:
expr = EXPR[name]
c0, c1, c2, c3 = coeffs
script = f"""
pr = ({c0})*2^(-{q}) + ({c1})*2^(-{q})*x + ({c2})*2^(-{q})*x^2 + ({c3})*2^(-{q})*x^3;
e = dirtyinfnorm(({expr}) - pr, [{left}*2^(-{k}), {right}*2^(-{k})]);
print(e);
"""
try:
lines = self._run(script, "SCOREDONE")
except RuntimeError:
self.start()
return None
if any("Error" in line or "error" in line for line in lines):
self.start()
return None
nums: list[str] = []
for line in lines:
nums.extend(NUMBER.findall(line))
if not nums:
return None
err = max(float(n) for n in nums)
return err if math.isfinite(err) else None
def half_ulp(k: int) -> float:
return 2.0 ** (-(k + 1))
def q_of(k: int) -> int:
return k + 16
def quantize(coeffs: list[str], q: int) -> list[int]:
scale = Decimal(2) ** q
out: list[int] = []
for raw in coeffs:
value = Decimal(raw) * scale
if value >= 0:
out.append(int(value.to_integral_value(ROUND_HALF_UP)))
else:
out.append(-int((-value).to_integral_value(ROUND_HALF_UP)))
return out
def lecun_tail(k: int) -> int:
num = 17159 * (1 << k)
den = 10000
return (num + den // 2) // den
def lecun_end(k: int) -> int:
"""First raw at which the constant tail is within 1/4 ulp of the asymptote gap."""
tail = lecun_tail(k) / 2**k
# f increases to 1.7159. Leave a quarter ulp for rounding the tail itself.
gap = 0.25 * (2 ** (-k))
target = 1.7159 - gap
lo, hi = 0.0, 40.0
for _ in range(80):
mid = (lo + hi) / 2
if 1.7159 * math.tanh(2 * mid / 3) >= target:
hi = mid
else:
lo = mid
return max(1, math.ceil(hi * 2**k - 1e-9))
def march(sollya: Sollya, name: str, start: int, end: int, k: int) -> list[Piece]:
q = q_of(k)
tol = half_ulp(k)
pieces: list[Piece] = []
left = start
guess = 1
while left < end:
step = max(1, guess)
last: tuple[int, float, list[int]] | None = None
fail: int | None = None
while left + step <= end:
got = sollya.fit(name, left, left + step, k, q, tol)
if got is not None and got[0] <= tol:
last = (left + step, got[0], got[1])
step *= 2
else:
fail = min(end, left + step)
break
else:
if last is None or last[0] != end:
got = sollya.fit(name, left, end, k, q, tol)
if got is not None and got[0] <= tol:
last = (end, got[0], got[1])
fail = None
else:
fail = end
if fail is None and last is not None:
right, err, coeffs = last
else:
lo = last[0] if last is not None else left
hi = fail if fail is not None else end
best = last
while hi - lo > 1:
mid = (lo + hi) // 2
got = sollya.fit(name, left, mid, k, q, tol)
if got is not None and got[0] <= tol:
best = (mid, got[0], got[1])
lo = mid
else:
hi = mid
if best is None:
got = sollya.fit(name, left, left + 1, k, q, tol)
if got is None:
raise RuntimeError(f"{name} k={k} no cubic on [{left}, {left+1}]")
best = (left + 1, got[0], got[1])
right, err, coeffs = best
pieces.append(Piece(left, right, coeffs, err, "sollya"))
guess = max(1, right - left)
left = right
print(f" {name} k={k} pieces={len(pieces)} span={right - pieces[-1].left} err={err:.3e}", flush=True)
return pieces
def write_intervals(pieces_by_key: dict[tuple[str, int], list[Piece]], path: Path) -> None:
with path.open("w") as handle:
for (name, k), pieces in pieces_by_key.items():
q = q_of(k)
for piece in pieces:
handle.write(f"{name} {k} {piece.left} {piece.right} {q}\n")
def run_maple(interval_path: Path, out_path: Path) -> None:
program = WORK / "maple_batch.mpl"
program.write_text(
f"""
Digits := 40:
with(numapprox):
fd := fopen("{out_path}", WRITE):
infd := fopen("{interval_path}", READ):
while true do
line := readline(infd);
if line = 0 then break; end if;
parts := sscanf(line, "%s %d %d %d %d");
gname := parts[1];
a := parts[3] * 2^(-parts[2]);
b := parts[4] * 2^(-parts[2]);
try
if gname = "lecun" then
p := minimax(17159/10000*tanh(2*x/3), x = a .. b, [3, 0]);
else
p := minimax((exp(x)-1)*(x+1)/2, x = a .. b, [3, 0]);
end if;
p := expand(p);
fprintf(fd, "%.25e %.25e %.25e %.25e\\n",
evalf(coeff(p, x, 0)), evalf(coeff(p, x, 1)),
evalf(coeff(p, x, 2)), evalf(coeff(p, x, 3)));
catch:
fprintf(fd, "FAIL\\n");
end try;
end do:
fclose(fd):
fclose(infd):
quit:
"""
)
subprocess.run([MAPLE, "-q", str(program)], check=True, timeout=3600)
def run_math(interval_path: Path, out_path: Path) -> None:
program = WORK / "mma_batch.wl"
program.write_text(
r"""
pow[base_, 0] := 1;
pow[base_, n_Integer] := base^n;
lecun[x_] := 17159/10000*Tanh[2*x/3];
hard[x_] := (Exp[x] - 1)*(x + 1)/2;
remez[ff_, a_, b_] := Module[
{n = 3, m = 5, mid, half, nodes, coef, mat, rhs, sol, grid, err, idx, drop, tpoly, xpoly},
mid = N[(a + b)/2, 40];
half = N[(b - a)/2, 40];
nodes = Sort[Table[N[Cos[Pi*(k + 1/2)/m], 40], {k, 0, m - 1}]];
coef = {0, 0, 0, 0};
Do[
mat = N[Table[If[j <= n + 1, pow[nodes[[i]], j - 1], -(-1)^i], {i, m}, {j, m}], 40];
rhs = N[Table[ff[mid + half*nodes[[i]]], {i, m}], 40];
sol = Quiet[Check[LinearSolve[mat, rhs], $Failed]];
If[sol === $Failed || Head[sol] =!= List, Break[]];
coef = N[sol[[1 ;; n + 1]], 40];
grid = N[Subdivide[-1, 1, 256], 40];
err = Table[
coef[[1]] + coef[[2]]*grid[[i]] + coef[[3]]*grid[[i]]^2 + coef[[4]]*grid[[i]]^3
- ff[mid + half*grid[[i]]],
{i, Length[grid]}];
idx = {1, Length[grid]};
Do[
If[Abs[err[[i]]] >= Abs[err[[i - 1]]] && Abs[err[[i]]] >= Abs[err[[i + 1]]],
AppendTo[idx, i]],
{i, 2, Length[grid] - 1}];
While[Length[idx] > m,
drop = Ordering[Abs[err[[idx]]], 1][[1]];
idx = Delete[idx, drop];
];
If[Length[idx] == m, nodes = Sort[N[grid[[idx]], 40]]];
, {8}];
tpoly = coef[[1]] + coef[[2]]*((x - mid)/half) + coef[[3]]*((x - mid)/half)^2
+ coef[[4]]*((x - mid)/half)^3;
xpoly = Expand[N[tpoly, 30]];
Table[N[Coefficient[xpoly, x, k], 20], {k, 0, 3}]
];
lines = ReadList["""
+ f'"{interval_path}"'
+ r""", String];
out = OpenWrite["""
+ f'"{out_path}"'
+ r"""];
Do[
parts = StringSplit[line];
If[Length[parts] < 5, Continue[]];
name = parts[[1]];
kk = ToExpression[parts[[2]]];
left = ToExpression[parts[[3]]];
right = ToExpression[parts[[4]]];
aa = N[left*2^(-kk), 30];
bb = N[right*2^(-kk), 30];
ff = If[name == "lecun", lecun, hard];
cs = Quiet[Check[remez[ff, aa, bb], $Failed]];
If[cs === $Failed || Head[cs] =!= List,
WriteString[out, "FAIL\n"],
WriteString[out, StringRiffle[Map[ToString[CForm[#]] &, cs], " "], "\n"]
];
, {line, lines}];
Close[out];
Exit[];
"""
)
subprocess.run([MATH, "-script", str(program)], check=True, timeout=3600)
def run_matlab(interval_path: Path, out_path: Path) -> None:
program = WORK / "matlab_batch.m"
program.write_text(
f"""
fid = fopen('{interval_path}', 'r');
out = fopen('{out_path}', 'w');
while true
line = fgetl(fid);
if ~ischar(line), break; end
parts = strsplit(strtrim(line));
if numel(parts) < 5, continue; end
name = parts{{1}};
kk = str2double(parts{{2}});
left = str2double(parts{{3}});
right = str2double(parts{{4}});
aa = left * 2^(-kk);
bb = right * 2^(-kk);
try
if strcmp(name, 'lecun')
f = chebfun(@(x) 1.7159*tanh(2*x/3), [aa, bb]);
else
f = chebfun(@(x) expm1(x).*(x+1)/2, [aa, bb]);
end
p = minimax(f, 3);
c = poly(p);
c = c(:).';
if numel(c) < 4
c = [zeros(1, 4-numel(c)), c];
end
fprintf(out, '%.20e %.20e %.20e %.20e\\n', c(4), c(3), c(2), c(1));
catch
fprintf(out, 'FAIL\\n');
end
end
fclose(fid);
fclose(out);
"""
)
subprocess.run(
[MATLAB, "-batch", f"run('{program}')"],
check=True,
timeout=7200,
)
def load_coeff_file(path: Path) -> list[list[str] | None]:
rows: list[list[str] | None] = []
for line in path.read_text().splitlines():
line = line.strip()
if not line or "FAIL" in line:
rows.append(None)
continue
parts = NUMBER.findall(line.replace("D", "E"))
if len(parts) < 4:
rows.append(None)
continue
rows.append(parts[:4])
return rows
def tournament(
sollya: Sollya,
pieces_by_key: dict[tuple[str, int], list[Piece]],
others: dict[str, list[list[str] | None]],
) -> dict[str, int]:
wins = {"sollya": 0, "mathematica": 0, "maple": 0, "matlab": 0}
index = 0
for key in pieces_by_key:
name, k = key
q = q_of(k)
for piece in pieces_by_key[key]:
best_err = piece.err
best_coeffs = piece.coeffs
best_source = "sollya"
for source in ("mathematica", "maple", "matlab"):
row = others[source][index] if index < len(others[source]) else None
if row is None:
continue
try:
coeffs = quantize(row, q)
except Exception:
continue
err = sollya.score(name, piece.left, piece.right, k, q, coeffs)
if err is not None and err < best_err:
best_err = err
best_coeffs = coeffs
best_source = source
piece.coeffs = best_coeffs
piece.err = best_err
piece.source = best_source
wins[best_source] += 1
index += 1
print(f"tournament {name} k={k} done", flush=True)
return wins
def split_i128(value: int) -> tuple[int, int]:
raw = value + (1 << 128) if value < 0 else value
lo = raw & ((1 << 64) - 1)
hi = (raw >> 64) & ((1 << 64) - 1)
if hi >= (1 << 63):
hi -= 1 << 64
return hi, lo
TAGS = {"lecun": "LECUN", "hard": "HARDELISH"}
def emit_table(name: str, k: int, pieces: list[Piece]) -> str:
knots = [pieces[0].left] + [piece.right for piece in pieces]
q = q_of(k)
tag = TAGS[name]
lines = [f"static constexpr std::int64_t {tag}_K{k}_KNOTS[] = {{"]
lines.append(" " + ", ".join(str(knot) for knot in knots) + ",")
lines.append("};")
lines.append(f"static constexpr grotto::principal_detail::cubic_bits {tag}_K{k}_PIECES[] = {{")
for piece in pieces:
his, los = [], []
for coeff in piece.coeffs:
hi, lo = split_i128(coeff)
his.append(str(hi))
los.append(f"{lo}u")
lines.append(" {{" + ", ".join(his) + "}, {" + ", ".join(los) + "}},")
lines.append("};")
lines.append(
f"static constexpr window_table {tag}_K{k}_TABLE"
f"{{{tag}_K{k}_KNOTS, {tag}_K{k}_PIECES, {len(pieces)}, {q}}};"
)
lines.append("")
return "\n".join(lines)
def emit(pieces_by_key: dict[tuple[str, int], list[Piece]], wins: dict[str, int], path: Path) -> None:
chunks = [
"// Generated on mocha2.",
"// Sollya fpminimax chose the knots (absolute error at most half an ulp).",
"// Each cubic is the best of Sollya, Mathematica Remez, Maple numapprox[minimax],",
"// and MATLAB/Chebfun minimax after rounding coefficients to 2^{-(k+16)}.",
"// Wins: " + ", ".join(f"{name} {count}" for name, count in wins.items()) + ".",
"// lecun is the positive half of an odd map; hard covers (-1, 0).",
"// Do not edit.",
"#pragma once",
"",
]
ks = [k for (name, k) in pieces_by_key if name == "lecun"]
for name in ("lecun", "hard"):
for k in ks:
chunks.append(emit_table(name, k, pieces_by_key[(name, k)]))
tag = TAGS[name]
refs = ",\n ".join(f"&{tag}_K{k}_TABLE" for k in ks)
chunks.append(
f"static constexpr window_table const* const {tag}[{len(ks)}] = {{\n {refs},\n}};"
)
chunks.append("")
tails = ", ".join(str(lecun_tail(k)) for k in ks)
chunks.append(f"static constexpr std::int64_t LECUN_TAIL[{len(ks)}] = {{\n {tails},\n}};")
chunks.append("")
path.write_text("\n".join(chunks))
def summarize(pieces_by_key: dict[tuple[str, int], list[Piece]], wins: dict[str, int]) -> None:
summary = {"wins": wins, "functions": {}}
for name in ("lecun", "hard"):
summary["functions"][name] = {}
for k in selected_precisions():
pieces = pieces_by_key[(name, k)]
summary["functions"][name][str(k)] = {
"parts": len(pieces),
"max_abs_error": max(piece.err for piece in pieces),
"half_ulp": half_ulp(k),
}
(WORK / "summary.json").write_text(json.dumps(summary, indent=2))
print(json.dumps(summary, indent=2), flush=True)
def self_test() -> None:
sollya = Sollya()
got = sollya.fit("lecun", 0, 1 << 15, 16, q_of(16), half_ulp(16))
print("sollya", got[0] if got else None)
sollya.close()
def selected_precisions() -> tuple[int, ...]:
if "--k" in sys.argv:
return (int(sys.argv[sys.argv.index("--k") + 1]),)
return PREC
def main() -> None:
if len(sys.argv) > 1 and sys.argv[1] == "--self-test":
self_test()
return
WORK.mkdir(parents=True, exist_ok=True)
sollya = Sollya()
pieces_by_key: dict[tuple[str, int], list[Piece]] = {}
for k in selected_precisions():
end = lecun_end(k)
print(f"march lecun k={k} end={end} tail={lecun_tail(k)}", flush=True)
pieces_by_key[("lecun", k)] = march(sollya, "lecun", 0, end, k)
one = 1 << k
print(f"march hard k={k}", flush=True)
pieces_by_key[("hard", k)] = march(sollya, "hard", -one, 0, k)
interval_path = WORK / "intervals.txt"
write_intervals(pieces_by_key, interval_path)
print("intervals", sum(len(v) for v in pieces_by_key.values()), flush=True)
jobs = {
"maple": (run_maple, WORK / "maple_coeffs.txt"),
"mathematica": (run_math, WORK / "mma_coeffs.txt"),
"matlab": (run_matlab, WORK / "matlab_coeffs.txt"),
}
for name, (fn, out) in jobs.items():
# Run sequentially inside this process: MATLAB and Maple both want a license,
# and a failure is easier to see one at a time. They do not share state.
print("running", name, flush=True)
if out.exists():
out.unlink()
fn(interval_path, out)
print("finished", name, out.stat().st_size, flush=True)
expected = sum(len(v) for v in pieces_by_key.values())
others = {
"maple": load_coeff_file(WORK / "maple_coeffs.txt"),
"mathematica": load_coeff_file(WORK / "mma_coeffs.txt"),
"matlab": load_coeff_file(WORK / "matlab_coeffs.txt"),
}
for source, rows in others.items():
if len(rows) != expected:
raise SystemExit(f"{source} wrote {len(rows)} rows, expected {expected}")
wins = tournament(sollya, pieces_by_key, others)
sollya.close()
emit(pieces_by_key, wins, WORK / "window_extra_tables.inc")
summarize(pieces_by_key, wins)
if __name__ == "__main__":
main()