Use Algebraic solver in phase 4
Browse filesSlightly less efficient but whatever, it needs to complete in a day not week
- pipeline.py +421 -111
pipeline.py
CHANGED
|
@@ -26,6 +26,8 @@ import numpy as np
|
|
| 26 |
from .config import HPCConfig
|
| 27 |
from .factored import (
|
| 28 |
CAND_TO_QUHIT,
|
|
|
|
|
|
|
| 29 |
N_CAND_M,
|
| 30 |
TOTAL_CANDIDATES,
|
| 31 |
FactorResult,
|
|
@@ -42,6 +44,7 @@ from .q2k import (
|
|
| 42 |
codes_from_params,
|
| 43 |
codes_from_params_batch,
|
| 44 |
dequantize_params,
|
|
|
|
| 45 |
derive_subscales,
|
| 46 |
make_block,
|
| 47 |
pack_codes,
|
|
@@ -51,7 +54,7 @@ from .q2k import (
|
|
| 51 |
)
|
| 52 |
from .seeds import build_seeds, seed_clamp_value
|
| 53 |
from .sieve import block_chain_edges, sieve_measure_chain, subblock_chain_edges
|
| 54 |
-
from .spectral import dc_nudge_codes, objective, refine_codes_hadamard
|
| 55 |
from .viterbi import robust_temperature, viterbi_select
|
| 56 |
|
| 57 |
|
|
@@ -372,12 +375,364 @@ def _assemble_block(x, w, seeds, base_d, base_m, cidx, dc_carry, cfg):
|
|
| 372 |
return d, m, ls, lm, codes, best[0], sse
|
| 373 |
|
| 374 |
|
| 375 |
-
def
|
| 376 |
-
|
| 377 |
-
|
| 378 |
-
|
| 379 |
-
|
| 380 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 381 |
|
| 382 |
|
| 383 |
def _apply_dc_nudge(X, W, blocks, cfg, row_width):
|
|
@@ -617,62 +972,6 @@ class Q2KQuantizer:
|
|
| 617 |
eta=eta,
|
| 618 |
sigma=sigma,
|
| 619 |
)
|
| 620 |
-
|
| 621 |
-
_check_stop()
|
| 622 |
-
_emit(
|
| 623 |
-
"Phase 3: 6-State Sieve & 36-State Viterbi DP",
|
| 624 |
-
0,
|
| 625 |
-
n_blocks,
|
| 626 |
-
f"Running Sieve + 36-state Viterbi sequence optimization ({cfg.optimizer.upper()})",
|
| 627 |
-
sigma=sigma,
|
| 628 |
-
)
|
| 629 |
-
best, temperature, _ = _phase3_select(candidate_errors, cfg)
|
| 630 |
-
carry = _compute_dc_carry(X, seeds, best, base_d, base_m, cfg, row_width)
|
| 631 |
-
_emit(
|
| 632 |
-
"Phase 3.9: Viterbi Path & Rolling DC Carry",
|
| 633 |
-
n_blocks,
|
| 634 |
-
n_blocks,
|
| 635 |
-
f"Boltzmann temp={temperature:.4e}, max |DC carry|={float(np.max(np.abs(carry))):.4e}",
|
| 636 |
-
temperature=temperature,
|
| 637 |
-
sigma=sigma,
|
| 638 |
-
)
|
| 639 |
-
|
| 640 |
-
t_asm = time.time()
|
| 641 |
-
last_emit = 0.0
|
| 642 |
-
p4_args = [
|
| 643 |
-
(i, int(best[i]), float(carry[i]), standalone[i])
|
| 644 |
-
for i in range(n_blocks)
|
| 645 |
-
]
|
| 646 |
-
for i, (blk_obj, cand_hit, fac_hit, blk_err) in enumerate(
|
| 647 |
-
pool.imap(_phase4_one, p4_args, chunksize=chunksize)
|
| 648 |
-
):
|
| 649 |
-
_check_stop()
|
| 650 |
-
blocks.append(blk_obj)
|
| 651 |
-
candidate_floor_used += cand_hit
|
| 652 |
-
factor_floor_used += fac_hit
|
| 653 |
-
running_sse += blk_err
|
| 654 |
-
now = time.time()
|
| 655 |
-
if (i + 1) % step_report == 0 or (i + 1) == n_blocks or (now - last_emit) >= 0.25:
|
| 656 |
-
last_emit = now
|
| 657 |
-
elapsed = max(now - t_asm, 1.0e-6)
|
| 658 |
-
rate = (i + 1) / elapsed
|
| 659 |
-
eta = (n_blocks - (i + 1)) / max(rate, 1.0e-9)
|
| 660 |
-
cur_rmse = float(np.sqrt(running_sse / ((i + 1) * QK_K)))
|
| 661 |
-
_emit(
|
| 662 |
-
f"Phase 4: Sub-block Sieve + ULP + Hadamard Assembly ({n_workers} workers)",
|
| 663 |
-
i + 1,
|
| 664 |
-
n_blocks,
|
| 665 |
-
f"blk {i+1}/{n_blocks} ({rate:.1f} blk/s, ETA {eta:.1f}s) "
|
| 666 |
-
f"rmse={cur_rmse:.6e} rmse/sigma={cur_rmse/max(sigma, 1e-15):.4f} "
|
| 667 |
-
f"floors(cand={candidate_floor_used}, fac={factor_floor_used})",
|
| 668 |
-
rmse=cur_rmse,
|
| 669 |
-
sigma=sigma,
|
| 670 |
-
temperature=temperature,
|
| 671 |
-
cand_floors=candidate_floor_used,
|
| 672 |
-
fac_floors=factor_floor_used,
|
| 673 |
-
rate=rate,
|
| 674 |
-
eta=eta,
|
| 675 |
-
)
|
| 676 |
pool.close()
|
| 677 |
pool.join()
|
| 678 |
except BaseException:
|
|
@@ -703,61 +1002,72 @@ class Q2KQuantizer:
|
|
| 703 |
sigma=sigma,
|
| 704 |
)
|
| 705 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 706 |
_check_stop()
|
| 707 |
-
|
| 708 |
-
|
| 709 |
-
|
| 710 |
-
|
| 711 |
-
|
| 712 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 713 |
)
|
| 714 |
-
|
| 715 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 716 |
_emit(
|
| 717 |
-
"Phase
|
| 718 |
-
|
| 719 |
n_blocks,
|
| 720 |
-
f"
|
| 721 |
-
|
|
|
|
|
|
|
| 722 |
sigma=sigma,
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 723 |
)
|
| 724 |
|
| 725 |
-
t_asm = time.time()
|
| 726 |
-
last_emit = 0.0
|
| 727 |
-
for i in range(n_blocks):
|
| 728 |
-
_check_stop()
|
| 729 |
-
blk_obj, cand_hit, fac_hit, blk_err = _phase4_one(
|
| 730 |
-
(i, int(best[i]), float(carry[i]), standalone[i])
|
| 731 |
-
)
|
| 732 |
-
blocks.append(blk_obj)
|
| 733 |
-
candidate_floor_used += cand_hit
|
| 734 |
-
factor_floor_used += fac_hit
|
| 735 |
-
running_sse += blk_err
|
| 736 |
-
now = time.time()
|
| 737 |
-
if (i + 1) % step_report == 0 or (i + 1) == n_blocks or (now - last_emit) >= 0.25:
|
| 738 |
-
last_emit = now
|
| 739 |
-
elapsed = max(now - t_asm, 1.0e-6)
|
| 740 |
-
rate = (i + 1) / elapsed
|
| 741 |
-
eta = (n_blocks - (i + 1)) / max(rate, 1.0e-9)
|
| 742 |
-
cur_rmse = float(np.sqrt(running_sse / ((i + 1) * QK_K)))
|
| 743 |
-
_emit(
|
| 744 |
-
"Phase 4: Sub-block Sieve + ULP + Hadamard Assembly",
|
| 745 |
-
i + 1,
|
| 746 |
-
n_blocks,
|
| 747 |
-
f"blk {i+1}/{n_blocks} ({rate:.1f} blk/s, ETA {eta:.1f}s) "
|
| 748 |
-
f"rmse={cur_rmse:.6e} rmse/sigma={cur_rmse/max(sigma, 1e-15):.4f} "
|
| 749 |
-
f"floors(cand={candidate_floor_used}, fac={factor_floor_used})",
|
| 750 |
-
rmse=cur_rmse,
|
| 751 |
-
sigma=sigma,
|
| 752 |
-
temperature=temperature,
|
| 753 |
-
cand_floors=candidate_floor_used,
|
| 754 |
-
fac_floors=factor_floor_used,
|
| 755 |
-
rate=rate,
|
| 756 |
-
eta=eta,
|
| 757 |
-
)
|
| 758 |
-
|
| 759 |
-
_MP_STATE.clear()
|
| 760 |
-
|
| 761 |
if cfg.apply_dc_carry and (cfg.dc_lambda > 0.0 or cfg.dc_decay > 0.0):
|
| 762 |
_check_stop()
|
| 763 |
_emit(
|
|
|
|
| 26 |
from .config import HPCConfig
|
| 27 |
from .factored import (
|
| 28 |
CAND_TO_QUHIT,
|
| 29 |
+
MULTS_D,
|
| 30 |
+
MULTS_M,
|
| 31 |
N_CAND_M,
|
| 32 |
TOTAL_CANDIDATES,
|
| 33 |
FactorResult,
|
|
|
|
| 44 |
codes_from_params,
|
| 45 |
codes_from_params_batch,
|
| 46 |
dequantize_params,
|
| 47 |
+
dequantize_params_batch,
|
| 48 |
derive_subscales,
|
| 49 |
make_block,
|
| 50 |
pack_codes,
|
|
|
|
| 54 |
)
|
| 55 |
from .seeds import build_seeds, seed_clamp_value
|
| 56 |
from .sieve import block_chain_edges, sieve_measure_chain, subblock_chain_edges
|
| 57 |
+
from .spectral import dc_nudge_codes, fold_weights, objective, refine_codes_hadamard
|
| 58 |
from .viterbi import robust_temperature, viterbi_select
|
| 59 |
|
| 60 |
|
|
|
|
| 375 |
return d, m, ls, lm, codes, best[0], sse
|
| 376 |
|
| 377 |
|
| 378 |
+
def _batch_objective(
|
| 379 |
+
X: np.ndarray,
|
| 380 |
+
W_f64: np.ndarray,
|
| 381 |
+
d: np.ndarray,
|
| 382 |
+
m: np.ndarray,
|
| 383 |
+
ls: np.ndarray,
|
| 384 |
+
lm: np.ndarray,
|
| 385 |
+
codes: np.ndarray,
|
| 386 |
+
carry: np.ndarray,
|
| 387 |
+
cfg: HPCConfig,
|
| 388 |
+
) -> tuple[np.ndarray, np.ndarray]:
|
| 389 |
+
xh = dequantize_params_batch(d, m, ls, lm, codes).astype(np.float64)
|
| 390 |
+
e = X.astype(np.float64) - xh
|
| 391 |
+
sse = np.sum(W_f64 * e * e, axis=1)
|
| 392 |
+
if not cfg.use_spectral or (cfg.dc_lambda == 0.0 and cfg.vw_lambda == 0.0):
|
| 393 |
+
return sse, sse
|
| 394 |
+
fw = fold_weights(QK_K, cfg)
|
| 395 |
+
pen = np.zeros(X.shape[0], dtype=np.float64)
|
| 396 |
+
src = e
|
| 397 |
+
m_len = QK_K // 2
|
| 398 |
+
lvl = 0
|
| 399 |
+
while m_len >= 1:
|
| 400 |
+
dst = src[:, :m_len] + src[:, m_len : 2 * m_len]
|
| 401 |
+
if m_len == 1:
|
| 402 |
+
dst = dst + carry[:, None].astype(np.float64)
|
| 403 |
+
if fw[lvl] != 0.0:
|
| 404 |
+
pen += fw[lvl] * np.sum(dst * dst, axis=1)
|
| 405 |
+
src = dst
|
| 406 |
+
m_len //= 2
|
| 407 |
+
lvl += 1
|
| 408 |
+
return sse + pen, sse
|
| 409 |
+
|
| 410 |
+
|
| 411 |
+
def _batch_extended_dm_solve_and_ulp(
|
| 412 |
+
X_f64: np.ndarray,
|
| 413 |
+
W_f64: np.ndarray,
|
| 414 |
+
ls: np.ndarray,
|
| 415 |
+
lm: np.ndarray,
|
| 416 |
+
codes: np.ndarray,
|
| 417 |
+
d_cur: np.ndarray,
|
| 418 |
+
m_cur: np.ndarray,
|
| 419 |
+
carry: np.ndarray,
|
| 420 |
+
cfg: HPCConfig,
|
| 421 |
+
) -> tuple[np.ndarray, np.ndarray]:
|
| 422 |
+
"""Closed-form 2x2 Cramer solve + O(1) quadratic ULP polish on the full extended objective."""
|
| 423 |
+
N = X_f64.shape[0]
|
| 424 |
+
A = np.repeat(ls.astype(np.float64), 16, axis=1) * codes.astype(np.float64)
|
| 425 |
+
B = np.repeat(lm.astype(np.float64), 16, axis=1)
|
| 426 |
+
Saa = np.sum(W_f64 * A * A, axis=1)
|
| 427 |
+
Sab = np.sum(W_f64 * A * B, axis=1)
|
| 428 |
+
Sbb = np.sum(W_f64 * B * B, axis=1)
|
| 429 |
+
Sxa = np.sum(W_f64 * X_f64 * A, axis=1)
|
| 430 |
+
Sxb = np.sum(W_f64 * X_f64 * B, axis=1)
|
| 431 |
+
|
| 432 |
+
if cfg.use_spectral:
|
| 433 |
+
if cfg.vw_lambda > 0.0:
|
| 434 |
+
vw_w = float(cfg.vw_lambda) / QK_K
|
| 435 |
+
half = QK_K // 2
|
| 436 |
+
Ap = A[:, :half] + A[:, half:]
|
| 437 |
+
Bp = B[:, :half] + B[:, half:]
|
| 438 |
+
Xp = X_f64[:, :half] + X_f64[:, half:]
|
| 439 |
+
Saa += vw_w * np.sum(Ap * Ap, axis=1)
|
| 440 |
+
Sab += vw_w * np.sum(Ap * Bp, axis=1)
|
| 441 |
+
Sbb += vw_w * np.sum(Bp * Bp, axis=1)
|
| 442 |
+
Sxa += vw_w * np.sum(Xp * Ap, axis=1)
|
| 443 |
+
Sxb += vw_w * np.sum(Xp * Bp, axis=1)
|
| 444 |
+
if cfg.dc_lambda > 0.0:
|
| 445 |
+
dc_w = float(cfg.dc_lambda) / QK_K
|
| 446 |
+
rA = np.sum(A, axis=1)
|
| 447 |
+
rB = np.sum(B, axis=1)
|
| 448 |
+
rS = np.sum(X_f64, axis=1) + carry.astype(np.float64)
|
| 449 |
+
Saa += dc_w * rA * rA
|
| 450 |
+
Sab += dc_w * rA * rB
|
| 451 |
+
Sbb += dc_w * rB * rB
|
| 452 |
+
Sxa += dc_w * rS * rA
|
| 453 |
+
Sxb += dc_w * rS * rB
|
| 454 |
+
|
| 455 |
+
det = Saa * Sbb - Sab * Sab
|
| 456 |
+
valid = det > 1.0e-30
|
| 457 |
+
s_det = np.where(valid, det, 1.0)
|
| 458 |
+
d_new = (Sbb * Sxa - Sab * Sxb) / s_det
|
| 459 |
+
m_new = (Sab * Sxa - Saa * Sxb) / s_det
|
| 460 |
+
d_opt = np.where(valid & (d_new > 0.0) & np.isfinite(d_new), d_new, d_cur)
|
| 461 |
+
m_opt = np.where(valid & (m_new >= 0.0) & np.isfinite(m_new), m_new, m_cur)
|
| 462 |
+
|
| 463 |
+
rad = max(int(cfg.ulp_radius), 1)
|
| 464 |
+
deltas = np.arange(-rad, rad + 1, dtype=np.int32)
|
| 465 |
+
d16_c = to_fp16_bits(d_opt.astype(np.float32)).astype(np.int32)
|
| 466 |
+
m16_c = to_fp16_bits(m_opt.astype(np.float32)).astype(np.int32)
|
| 467 |
+
d_bits = np.clip(d16_c[:, None] + deltas[None, :], 0, 0x7BFF).astype(np.uint16)
|
| 468 |
+
m_bits = np.clip(m16_c[:, None] + deltas[None, :], 0, 0x7BFF).astype(np.uint16)
|
| 469 |
+
dd = from_fp16_bits(d_bits).astype(np.float64)[:, :, None]
|
| 470 |
+
mm = from_fp16_bits(m_bits).astype(np.float64)[:, None, :]
|
| 471 |
+
|
| 472 |
+
q_form = (
|
| 473 |
+
Saa[:, None, None] * (dd * dd)
|
| 474 |
+
- 2.0 * Sab[:, None, None] * (dd * mm)
|
| 475 |
+
+ Sbb[:, None, None] * (mm * mm)
|
| 476 |
+
- 2.0 * Sxa[:, None, None] * dd
|
| 477 |
+
+ 2.0 * Sxb[:, None, None] * mm
|
| 478 |
+
).reshape(N, -1)
|
| 479 |
+
best_idx = np.argmin(q_form, axis=1)
|
| 480 |
+
K = deltas.size
|
| 481 |
+
rows = np.arange(N)
|
| 482 |
+
return dd[rows, best_idx // K, 0].astype(np.float32), mm[rows, 0, best_idx % K].astype(np.float32)
|
| 483 |
+
|
| 484 |
+
|
| 485 |
+
def _batch_algebraic_refine_codes(
|
| 486 |
+
X_f64: np.ndarray,
|
| 487 |
+
W_f64: np.ndarray,
|
| 488 |
+
d: np.ndarray,
|
| 489 |
+
m: np.ndarray,
|
| 490 |
+
ls: np.ndarray,
|
| 491 |
+
lm: np.ndarray,
|
| 492 |
+
codes: np.ndarray,
|
| 493 |
+
carry: np.ndarray,
|
| 494 |
+
cfg: HPCConfig,
|
| 495 |
+
) -> np.ndarray:
|
| 496 |
+
"""Closed-form 1D quadratic coordinate projection for Vesica + DC + weighted SSE."""
|
| 497 |
+
N = X_f64.shape[0]
|
| 498 |
+
out = codes.astype(np.int64).copy()
|
| 499 |
+
lam_vw = (float(cfg.vw_lambda) / QK_K) if cfg.use_spectral else 0.0
|
| 500 |
+
lam_dc = (float(cfg.dc_lambda) / QK_K) if cfg.use_spectral else 0.0
|
| 501 |
+
if lam_vw == 0.0 and lam_dc == 0.0:
|
| 502 |
+
return out.astype(np.uint8)
|
| 503 |
+
|
| 504 |
+
d_sub = np.repeat(d.astype(np.float64)[:, None] * ls.astype(np.float64), 16, axis=1)
|
| 505 |
+
m_sub = np.repeat(m.astype(np.float64)[:, None] * lm.astype(np.float64), 16, axis=1)
|
| 506 |
+
active = d_sub >= 1.0e-15
|
| 507 |
+
e = X_f64 - (d_sub * out - m_sub)
|
| 508 |
+
sse_live = np.sum(W_f64 * e * e, axis=1)
|
| 509 |
+
sse_cap = sse_live * (1.0 + cfg.sse_budget)
|
| 510 |
+
half = QK_K // 2
|
| 511 |
+
v = e[:, :half] + e[:, half:]
|
| 512 |
+
dc = np.sum(e, axis=1) + carry.astype(np.float64)
|
| 513 |
+
denom = (W_f64 + lam_vw + lam_dc) * (d_sub * d_sub)
|
| 514 |
+
safe_den = np.where(active & (denom > 1.0e-30), denom, 1.0)
|
| 515 |
+
|
| 516 |
+
v_full = np.concatenate([v, v], axis=1)
|
| 517 |
+
grad = d_sub * (W_f64 * e + lam_vw * v_full + lam_dc * dc[:, None])
|
| 518 |
+
dq = np.where(active, nearest_int((grad / safe_den).astype(np.float32)), 0)
|
| 519 |
+
q_new = np.clip(out + dq, 0, 3)
|
| 520 |
+
|
| 521 |
+
for b in range(N):
|
| 522 |
+
changed = np.where(q_new[b] != out[b])[0]
|
| 523 |
+
if changed.size == 0:
|
| 524 |
+
continue
|
| 525 |
+
xb, wb, dsb, msb = X_f64[b], W_f64[b], d_sub[b], m_sub[b]
|
| 526 |
+
eb, vb, dcb, sseb, capb = e[b], v[b], float(dc[b]), float(sse_live[b]), float(sse_cap[b])
|
| 527 |
+
e_cand = xb[changed] - (dsb[changed] * q_new[b, changed] - msb[changed])
|
| 528 |
+
de_cand = e_cand - eb[changed]
|
| 529 |
+
dsse_cand = wb[changed] * (e_cand * e_cand - eb[changed] * eb[changed])
|
| 530 |
+
pi_cand = np.where(changed < half, changed, changed - half)
|
| 531 |
+
v_old = vb[pi_cand]
|
| 532 |
+
v_new = v_old + de_cand
|
| 533 |
+
d_spec = lam_vw * (v_old * v_old - v_new * v_new) + lam_dc * (dcb * dcb - (dcb + de_cand) ** 2)
|
| 534 |
+
order = changed[np.argsort(-(d_spec - dsse_cand))]
|
| 535 |
+
for k in order:
|
| 536 |
+
q_try = int(q_new[b, k])
|
| 537 |
+
if q_try == int(out[b, k]):
|
| 538 |
+
continue
|
| 539 |
+
e_new = xb[k] - (dsb[k] * q_try - msb[k])
|
| 540 |
+
de = e_new - eb[k]
|
| 541 |
+
dsse = wb[k] * (e_new * e_new - eb[k] * eb[k])
|
| 542 |
+
if sseb + dsse > capb:
|
| 543 |
+
continue
|
| 544 |
+
p = k if k < half else k - half
|
| 545 |
+
v_np = vb[p] + de
|
| 546 |
+
dc_n = dcb + de
|
| 547 |
+
spec_gain = lam_vw * (vb[p] * vb[p] - v_np * v_np) + lam_dc * (dcb * dcb - dc_n * dc_n)
|
| 548 |
+
if spec_gain > dsse + 1.0e-18:
|
| 549 |
+
out[b, k] = q_try
|
| 550 |
+
eb[k] = e_new
|
| 551 |
+
vb[p] = v_np
|
| 552 |
+
dcb = dc_n
|
| 553 |
+
sseb += dsse
|
| 554 |
+
return out.astype(np.uint8)
|
| 555 |
+
|
| 556 |
+
|
| 557 |
+
def _refine_trajectory_algebraic(
|
| 558 |
+
X: np.ndarray,
|
| 559 |
+
X_f64: np.ndarray,
|
| 560 |
+
W_f64: np.ndarray,
|
| 561 |
+
Xb: np.ndarray,
|
| 562 |
+
Wb: np.ndarray,
|
| 563 |
+
Sw: np.ndarray,
|
| 564 |
+
Sx: np.ndarray,
|
| 565 |
+
safe_Sw: np.ndarray,
|
| 566 |
+
d0: np.ndarray,
|
| 567 |
+
m0: np.ndarray,
|
| 568 |
+
ls0: np.ndarray,
|
| 569 |
+
lm0: np.ndarray,
|
| 570 |
+
codes0: np.ndarray,
|
| 571 |
+
carry: np.ndarray,
|
| 572 |
+
cfg: HPCConfig,
|
| 573 |
+
):
|
| 574 |
+
N = X.shape[0]
|
| 575 |
+
best_d, best_m = d0.copy(), m0.copy()
|
| 576 |
+
best_ls, best_lm = ls0.copy(), lm0.copy()
|
| 577 |
+
best_codes = codes0.copy()
|
| 578 |
+
best_obj, best_sse = _batch_objective(X, W_f64, best_d, best_m, best_ls, best_lm, best_codes, carry, cfg)
|
| 579 |
+
d, m, ls, lm, codes = best_d.copy(), best_m.copy(), best_ls.copy(), best_lm.copy(), best_codes.copy()
|
| 580 |
+
ls_deltas = np.array([-3, -2, -1, 0, 1, 2, 3], dtype=np.int64)
|
| 581 |
+
lm_deltas = np.array([-1, 0, 1], dtype=np.int64)
|
| 582 |
+
n_idx = np.arange(N)[:, None]
|
| 583 |
+
s_idx = np.arange(NS)[None, :]
|
| 584 |
+
|
| 585 |
+
for _ in range(cfg.refine_passes):
|
| 586 |
+
d_new, m_new = _batch_extended_dm_solve_and_ulp(X_f64, W_f64, ls, lm, codes, d, m, carry, cfg)
|
| 587 |
+
obj_dm, sse_dm = _batch_objective(X, W_f64, d_new, m_new, ls, lm, codes, carry, cfg)
|
| 588 |
+
imp_dm = obj_dm < best_obj - 1.0e-15
|
| 589 |
+
if np.any(imp_dm):
|
| 590 |
+
best_obj = np.where(imp_dm, obj_dm, best_obj)
|
| 591 |
+
best_sse = np.where(imp_dm, sse_dm, best_sse)
|
| 592 |
+
best_d = np.where(imp_dm, d_new, best_d)
|
| 593 |
+
best_m = np.where(imp_dm, m_new, best_m)
|
| 594 |
+
best_ls = np.where(imp_dm[:, None], ls, best_ls)
|
| 595 |
+
best_lm = np.where(imp_dm[:, None], lm, best_lm)
|
| 596 |
+
best_codes = np.where(imp_dm[:, None], codes, best_codes)
|
| 597 |
+
d, m = best_d.copy(), best_m.copy()
|
| 598 |
+
|
| 599 |
+
codes_re = codes_from_params_batch(X, d, m, ls, lm)
|
| 600 |
+
obj_re, sse_re = _batch_objective(X, W_f64, d, m, ls, lm, codes_re, carry, cfg)
|
| 601 |
+
imp_re = obj_re < best_obj - 1.0e-15
|
| 602 |
+
if np.any(imp_re):
|
| 603 |
+
best_obj = np.where(imp_re, obj_re, best_obj)
|
| 604 |
+
best_sse = np.where(imp_re, sse_re, best_sse)
|
| 605 |
+
best_codes = np.where(imp_re[:, None], codes_re, best_codes)
|
| 606 |
+
codes = best_codes.copy()
|
| 607 |
+
|
| 608 |
+
q = codes.astype(np.float64).reshape(N, NS, 16)
|
| 609 |
+
Sqq = np.sum(Wb * q * q, axis=2)
|
| 610 |
+
Swq = np.sum(Wb * q, axis=2)
|
| 611 |
+
Sqx = np.sum(Wb * q * Xb, axis=2)
|
| 612 |
+
q_bar = Swq / safe_Sw
|
| 613 |
+
Vqq = np.maximum(Sqq - Swq * q_bar, 0.0)
|
| 614 |
+
Cqx = Sqx - Sx * q_bar
|
| 615 |
+
s_star = np.where(Vqq > 1.0e-30, np.maximum(Cqx / np.maximum(Vqq, 1.0e-30), 0.0), d[:, None] * ls)
|
| 616 |
+
sd = np.where(d[:, None] > 1.0e-15, d[:, None], 1.0)
|
| 617 |
+
sm = np.where(m[:, None] > 1.0e-15, m[:, None], 1.0)
|
| 618 |
+
ls_center = np.where(d[:, None] > 1.0e-15, np.clip(nearest_int((s_star / sd).astype(np.float32)), 0, 15), 0)
|
| 619 |
+
|
| 620 |
+
c_ls_base = np.clip(ls_center[:, :, None] + ls_deltas[None, None, :], 0, 15).astype(np.float64)
|
| 621 |
+
d_sub_base = d.astype(np.float64)[:, None, None] * c_ls_base
|
| 622 |
+
t_opt_base = np.maximum(0.0, (d_sub_base * Swq[:, :, None] - Sx[:, :, None]) / safe_Sw[:, :, None])
|
| 623 |
+
lm_center = np.where(
|
| 624 |
+
m[:, None, None] > 1.0e-15,
|
| 625 |
+
np.clip(nearest_int((t_opt_base / sm[:, :, None]).astype(np.float32)), 0, 15),
|
| 626 |
+
0,
|
| 627 |
+
)
|
| 628 |
+
|
| 629 |
+
cand_ls = np.repeat(c_ls_base, 3, axis=2)
|
| 630 |
+
cand_lm = np.clip(
|
| 631 |
+
np.repeat(lm_center, 3, axis=2) + np.tile(lm_deltas, 7)[None, None, :], 0, 15
|
| 632 |
+
).astype(np.float64)
|
| 633 |
+
|
| 634 |
+
d_sub_c = d.astype(np.float64)[:, None, None] * cand_ls
|
| 635 |
+
m_sub_c = m.astype(np.float64)[:, None, None] * cand_lm
|
| 636 |
+
safe_dc = d_sub_c >= 1.0e-15
|
| 637 |
+
sd_c = np.where(safe_dc, d_sub_c, 1.0)
|
| 638 |
+
q_c = np.where(
|
| 639 |
+
safe_dc[:, :, :, None],
|
| 640 |
+
np.clip(
|
| 641 |
+
nearest_int(((Xb[:, :, None, :] + m_sub_c[:, :, :, None]) / sd_c[:, :, :, None]).astype(np.float32)),
|
| 642 |
+
0,
|
| 643 |
+
3,
|
| 644 |
+
),
|
| 645 |
+
0,
|
| 646 |
+
).astype(np.float64)
|
| 647 |
+
e_c = Xb[:, :, None, :] - (d_sub_c[:, :, :, None] * q_c - m_sub_c[:, :, :, None])
|
| 648 |
+
err_c = np.sum(Wb[:, :, None, :] * e_c * e_c, axis=3)
|
| 649 |
+
pick = np.argmin(err_c, axis=2)
|
| 650 |
+
ls_try = cand_ls[n_idx, s_idx, pick].astype(np.uint8)
|
| 651 |
+
lm_try = cand_lm[n_idx, s_idx, pick].astype(np.uint8)
|
| 652 |
+
codes_try = codes_from_params_batch(X, d, m, ls_try, lm_try)
|
| 653 |
+
d_try, m_try = _batch_extended_dm_solve_and_ulp(X_f64, W_f64, ls_try, lm_try, codes_try, d, m, carry, cfg)
|
| 654 |
+
obj_try, sse_try = _batch_objective(X, W_f64, d_try, m_try, ls_try, lm_try, codes_try, carry, cfg)
|
| 655 |
+
imp_sub = obj_try < best_obj - 1.0e-15
|
| 656 |
+
if np.any(imp_sub):
|
| 657 |
+
best_obj = np.where(imp_sub, obj_try, best_obj)
|
| 658 |
+
best_sse = np.where(imp_sub, sse_try, best_sse)
|
| 659 |
+
best_d = np.where(imp_sub, d_try, best_d)
|
| 660 |
+
best_m = np.where(imp_sub, m_try, best_m)
|
| 661 |
+
best_ls = np.where(imp_sub[:, None], ls_try, best_ls)
|
| 662 |
+
best_lm = np.where(imp_sub[:, None], lm_try, best_lm)
|
| 663 |
+
best_codes = np.where(imp_sub[:, None], codes_try, best_codes)
|
| 664 |
+
d, m, ls, lm, codes = best_d.copy(), best_m.copy(), best_ls.copy(), best_lm.copy(), best_codes.copy()
|
| 665 |
+
|
| 666 |
+
refined = _batch_algebraic_refine_codes(X_f64, W_f64, best_d, best_m, best_ls, best_lm, best_codes, carry, cfg)
|
| 667 |
+
d_r, m_r = _batch_extended_dm_solve_and_ulp(X_f64, W_f64, best_ls, best_lm, refined, best_d, best_m, carry, cfg)
|
| 668 |
+
obj_r, sse_r = _batch_objective(X, W_f64, d_r, m_r, best_ls, best_lm, refined, carry, cfg)
|
| 669 |
+
imp_r = obj_r < best_obj - 1.0e-15
|
| 670 |
+
if np.any(imp_r):
|
| 671 |
+
best_obj = np.where(imp_r, obj_r, best_obj)
|
| 672 |
+
best_sse = np.where(imp_r, sse_r, best_sse)
|
| 673 |
+
best_d = np.where(imp_r, d_r, best_d)
|
| 674 |
+
best_m = np.where(imp_r, m_r, best_m)
|
| 675 |
+
best_codes = np.where(imp_r[:, None], refined, best_codes)
|
| 676 |
+
|
| 677 |
+
return best_d, best_m, best_ls, best_lm, best_codes, best_obj, best_sse
|
| 678 |
+
|
| 679 |
+
|
| 680 |
+
def _phase4_algebraic_batch(
|
| 681 |
+
X: np.ndarray,
|
| 682 |
+
W: np.ndarray | None,
|
| 683 |
+
scales_seed: np.ndarray,
|
| 684 |
+
mins_seed: np.ndarray,
|
| 685 |
+
base_d: np.ndarray,
|
| 686 |
+
base_m: np.ndarray,
|
| 687 |
+
best: np.ndarray,
|
| 688 |
+
carry: np.ndarray,
|
| 689 |
+
standalone: list[FactorResult],
|
| 690 |
+
cfg: HPCConfig,
|
| 691 |
+
) -> tuple[np.ndarray, np.ndarray, np.ndarray, np.ndarray, np.ndarray, int, int]:
|
| 692 |
+
"""Batched algebraic Phase-4 solver across N blocks (replaces brute-force 16x16 & ULP grids)."""
|
| 693 |
+
N = X.shape[0]
|
| 694 |
+
X_f64 = X.astype(np.float64)
|
| 695 |
+
W_f64 = np.ones_like(X_f64) if W is None else W.astype(np.float64)
|
| 696 |
+
Xb = X_f64.reshape(N, NS, 16)
|
| 697 |
+
Wb = W_f64.reshape(N, NS, 16)
|
| 698 |
+
Sw = np.sum(Wb, axis=2)
|
| 699 |
+
Sx = np.sum(Wb * Xb, axis=2)
|
| 700 |
+
safe_Sw = np.maximum(Sw, 1.0e-30)
|
| 701 |
+
|
| 702 |
+
di = best // N_CAND_M
|
| 703 |
+
mi = best % N_CAND_M
|
| 704 |
+
d_v = round_fp16(base_d * MULTS_D[di])
|
| 705 |
+
m_v = round_fp16(base_m * MULTS_M[mi])
|
| 706 |
+
sd_v = np.where(d_v[:, None] > 1.0e-15, d_v[:, None], 1.0)
|
| 707 |
+
sm_v = np.where(m_v[:, None] > 1.0e-15, m_v[:, None], 1.0)
|
| 708 |
+
ls_v = np.where(d_v[:, None] > 1.0e-15, np.clip(nearest_int(scales_seed / sd_v), 0, 15), 0).astype(np.uint8)
|
| 709 |
+
lm_v = np.where(m_v[:, None] > 1.0e-15, np.clip(nearest_int(mins_seed / sm_v), 0, 15), 0).astype(np.uint8)
|
| 710 |
+
codes_v = codes_from_params_batch(X, d_v, m_v, ls_v, lm_v)
|
| 711 |
+
|
| 712 |
+
d1, m1, ls1, lm1, c1, obj1, _ = _refine_trajectory_algebraic(
|
| 713 |
+
X, X_f64, W_f64, Xb, Wb, Sw, Sx, safe_Sw, d_v, m_v, ls_v, lm_v, codes_v, carry, cfg
|
| 714 |
+
)
|
| 715 |
+
cand_hits = 0
|
| 716 |
+
fac_hits = 0
|
| 717 |
+
|
| 718 |
+
if cfg.use_factor_floor:
|
| 719 |
+
d_f = np.array([f.d for f in standalone], dtype=np.float32)
|
| 720 |
+
m_f = np.array([f.dmin for f in standalone], dtype=np.float32)
|
| 721 |
+
ls_f = np.stack([f.ls for f in standalone], axis=0)
|
| 722 |
+
lm_f = np.stack([f.lm for f in standalone], axis=0)
|
| 723 |
+
codes_f = np.stack([f.codes for f in standalone], axis=0)
|
| 724 |
+
d2, m2, ls2, lm2, c2, obj2, _ = _refine_trajectory_algebraic(
|
| 725 |
+
X, X_f64, W_f64, Xb, Wb, Sw, Sx, safe_Sw, d_f, m_f, ls_f, lm_f, codes_f, carry, cfg
|
| 726 |
+
)
|
| 727 |
+
take2 = obj2 < obj1 - 1.0e-15
|
| 728 |
+
fac_hits = int(np.sum(take2))
|
| 729 |
+
d1 = np.where(take2, d2, d1)
|
| 730 |
+
m1 = np.where(take2, m2, m1)
|
| 731 |
+
ls1 = np.where(take2[:, None], ls2, ls1)
|
| 732 |
+
lm1 = np.where(take2[:, None], lm2, lm1)
|
| 733 |
+
c1 = np.where(take2[:, None], c2, c1)
|
| 734 |
+
|
| 735 |
+
return d1, m1, ls1, lm1, c1, cand_hits, fac_hits
|
| 736 |
|
| 737 |
|
| 738 |
def _apply_dc_nudge(X, W, blocks, cfg, row_width):
|
|
|
|
| 972 |
eta=eta,
|
| 973 |
sigma=sigma,
|
| 974 |
)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 975 |
pool.close()
|
| 976 |
pool.join()
|
| 977 |
except BaseException:
|
|
|
|
| 1002 |
sigma=sigma,
|
| 1003 |
)
|
| 1004 |
|
| 1005 |
+
_MP_STATE.clear()
|
| 1006 |
+
_check_stop()
|
| 1007 |
+
_emit(
|
| 1008 |
+
"Phase 3: 6-State Sieve & 36-State Viterbi DP",
|
| 1009 |
+
0,
|
| 1010 |
+
n_blocks,
|
| 1011 |
+
f"Running Sieve + 36-state Viterbi sequence optimization ({cfg.optimizer.upper()})",
|
| 1012 |
+
sigma=sigma,
|
| 1013 |
+
)
|
| 1014 |
+
best, temperature, _ = _phase3_select(candidate_errors, cfg)
|
| 1015 |
+
carry = _compute_dc_carry(X, seeds, best, base_d, base_m, cfg, row_width)
|
| 1016 |
+
_emit(
|
| 1017 |
+
"Phase 3.9: Viterbi Path & Rolling DC Carry",
|
| 1018 |
+
n_blocks,
|
| 1019 |
+
n_blocks,
|
| 1020 |
+
f"Boltzmann temp={temperature:.4e}, max |DC carry|={float(np.max(np.abs(carry))):.4e}",
|
| 1021 |
+
temperature=temperature,
|
| 1022 |
+
sigma=sigma,
|
| 1023 |
+
)
|
| 1024 |
+
|
| 1025 |
+
t_asm = time.time()
|
| 1026 |
+
batch_sz = 256
|
| 1027 |
+
for start in range(0, n_blocks, batch_sz):
|
| 1028 |
_check_stop()
|
| 1029 |
+
stop = min(start + batch_sz, n_blocks)
|
| 1030 |
+
W_chunk = None if W is None else W[start:stop]
|
| 1031 |
+
d_b, m_b, ls_b, lm_b, codes_b, c_hits, f_hits = _phase4_algebraic_batch(
|
| 1032 |
+
X[start:stop],
|
| 1033 |
+
W_chunk,
|
| 1034 |
+
seeds["scales"][start:stop],
|
| 1035 |
+
seeds["mins"][start:stop],
|
| 1036 |
+
base_d[start:stop],
|
| 1037 |
+
base_m[start:stop],
|
| 1038 |
+
best[start:stop],
|
| 1039 |
+
carry[start:stop],
|
| 1040 |
+
standalone[start:stop],
|
| 1041 |
+
cfg,
|
| 1042 |
)
|
| 1043 |
+
candidate_floor_used += c_hits
|
| 1044 |
+
factor_floor_used += f_hits
|
| 1045 |
+
for k in range(stop - start):
|
| 1046 |
+
blk_obj = make_block(d_b[k], m_b[k], ls_b[k], lm_b[k], codes_b[k])
|
| 1047 |
+
blocks.append(blk_obj)
|
| 1048 |
+
running_sse += blk_obj.error(X[start + k])
|
| 1049 |
+
|
| 1050 |
+
now = time.time()
|
| 1051 |
+
elapsed = max(now - t_asm, 1.0e-6)
|
| 1052 |
+
rate = stop / elapsed
|
| 1053 |
+
eta = (n_blocks - stop) / max(rate, 1.0e-9)
|
| 1054 |
+
cur_rmse = float(np.sqrt(running_sse / (stop * QK_K)))
|
| 1055 |
_emit(
|
| 1056 |
+
"Phase 4: Algebraic Coupled Bilinear Assembly",
|
| 1057 |
+
stop,
|
| 1058 |
n_blocks,
|
| 1059 |
+
f"blk {stop}/{n_blocks} ({rate:.1f} blk/s, ETA {eta:.1f}s) "
|
| 1060 |
+
f"rmse={cur_rmse:.6e} rmse/sigma={cur_rmse/max(sigma, 1e-15):.4f} "
|
| 1061 |
+
f"floors(cand={candidate_floor_used}, fac={factor_floor_used})",
|
| 1062 |
+
rmse=cur_rmse,
|
| 1063 |
sigma=sigma,
|
| 1064 |
+
temperature=temperature,
|
| 1065 |
+
cand_floors=candidate_floor_used,
|
| 1066 |
+
fac_floors=factor_floor_used,
|
| 1067 |
+
rate=rate,
|
| 1068 |
+
eta=eta,
|
| 1069 |
)
|
| 1070 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1071 |
if cfg.apply_dc_carry and (cfg.dc_lambda > 0.0 or cfg.dc_decay > 0.0):
|
| 1072 |
_check_stop()
|
| 1073 |
_emit(
|