Upload 15 files
Browse files- factored.py +210 -99
- pipeline.py +101 -105
factored.py
CHANGED
|
@@ -32,7 +32,7 @@ from .analog import build_block_analogs
|
|
| 32 |
from .config import HPCConfig
|
| 33 |
from .fp16 import from_fp16_bits, fp16_ulp_neighbors, nearest_int, round_fp16, to_fp16_bits
|
| 34 |
from .q2k import NS, QK_K, codes_from_params, derive_subscales
|
| 35 |
-
from .spectral import objective, refine_codes_hadamard
|
| 36 |
|
| 37 |
N_CAND_D = 24
|
| 38 |
N_CAND_M = 24
|
|
@@ -165,6 +165,10 @@ def _factor_1d_lloyd(v: np.ndarray, w: np.ndarray, nmax: int, iters: int):
|
|
| 165 |
return best_d, best_codes
|
| 166 |
|
| 167 |
|
|
|
|
|
|
|
|
|
|
|
|
|
| 168 |
def _refine_integer_codes(v, w, d, codes, nmax, sweeps=2):
|
| 169 |
v = np.asarray(v, dtype=np.float64)
|
| 170 |
w = np.asarray(w, dtype=np.float64)
|
|
@@ -172,33 +176,46 @@ def _refine_integer_codes(v, w, d, codes, nmax, sweeps=2):
|
|
| 172 |
d = float(d)
|
| 173 |
if d <= 0.0:
|
| 174 |
return d, codes.astype(np.uint8)
|
| 175 |
-
|
| 176 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 177 |
for _ in range(sweeps):
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 178 |
improved = False
|
| 179 |
for i in range(v.size):
|
| 180 |
-
wi
|
| 181 |
-
|
| 182 |
-
sum_l2 = float(np.sum(w * codes * codes))
|
| 183 |
-
slv = sum_lv - wi * vi * li + wi * vi * options
|
| 184 |
-
sl2 = sum_l2 - wi * li * li + wi * options * options
|
| 185 |
-
valid = sl2 > 1.0e-30
|
| 186 |
-
if not np.any(valid):
|
| 187 |
continue
|
| 188 |
-
|
| 189 |
-
|
| 190 |
-
|
| 191 |
-
|
| 192 |
-
|
| 193 |
-
|
| 194 |
-
|
| 195 |
-
|
| 196 |
-
|
| 197 |
-
|
| 198 |
-
|
|
|
|
|
|
|
|
|
|
| 199 |
improved = True
|
| 200 |
if not improved:
|
| 201 |
break
|
|
|
|
| 202 |
return d, codes.astype(np.uint8)
|
| 203 |
|
| 204 |
|
|
@@ -242,28 +259,26 @@ def _factor_1d_for(v, w, nmax, cfg: HPCConfig, legacy: bool):
|
|
| 242 |
)
|
| 243 |
|
| 244 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 245 |
def _range_init(x, w, cfg: HPCConfig, legacy_1d: bool = False):
|
| 246 |
-
x = np.asarray(x, dtype=np.float64)
|
| 247 |
w = np.asarray(w, dtype=np.float64)
|
| 248 |
-
|
| 249 |
-
|
| 250 |
-
s = np.zeros(NS)
|
| 251 |
-
t = np.zeros(NS)
|
| 252 |
-
codes = np.zeros(QK_K, dtype=np.uint8)
|
| 253 |
-
for j in range(NS):
|
| 254 |
-
sub = blocks[j]
|
| 255 |
-
xmin = min(float(sub.min()), 0.0)
|
| 256 |
-
xmax = float(sub.max())
|
| 257 |
-
span = xmax - xmin
|
| 258 |
-
sj = span / 3.0 if span > 1.0e-30 else 0.0
|
| 259 |
-
tj = -xmin
|
| 260 |
-
s[j] = sj
|
| 261 |
-
t[j] = tj
|
| 262 |
-
if sj > 1.0e-30:
|
| 263 |
-
codes[16 * j : 16 * (j + 1)] = np.clip(
|
| 264 |
-
nearest_int((sub + tj) / sj), 0, 3
|
| 265 |
-
).astype(np.uint8)
|
| 266 |
-
sw = wblocks.sum(axis=1) if w is not None else np.full(NS, 16.0)
|
| 267 |
d, ls = _factor_1d_for(s, sw, 15, cfg, legacy_1d)
|
| 268 |
m, lm = _factor_1d_for(t, sw, 15, cfg, legacy_1d)
|
| 269 |
return d, m, ls, lm, codes
|
|
@@ -280,17 +295,7 @@ def _seeded_init(x, scales, mins, d_seed, m_seed):
|
|
| 280 |
def _ls_init(x, w, cfg: HPCConfig, legacy_1d: bool = False):
|
| 281 |
x = np.asarray(x, dtype=np.float64)
|
| 282 |
w = np.asarray(w, dtype=np.float64)
|
| 283 |
-
|
| 284 |
-
codes = np.zeros(QK_K, dtype=np.uint8)
|
| 285 |
-
for j in range(NS):
|
| 286 |
-
sub = blocks[j]
|
| 287 |
-
xmin = min(float(sub.min()), 0.0)
|
| 288 |
-
xmax = float(sub.max())
|
| 289 |
-
span = xmax - xmin
|
| 290 |
-
if span > 1.0e-30:
|
| 291 |
-
codes[16 * j : 16 * (j + 1)] = np.clip(
|
| 292 |
-
nearest_int((sub - xmin) * 3.0 / span), 0, 3
|
| 293 |
-
).astype(np.uint8)
|
| 294 |
s, t = _sub_ls(x, w, codes)
|
| 295 |
sw = w.reshape(NS, 16).sum(axis=1)
|
| 296 |
d, ls = _factor_1d_for(s, sw, 15, cfg, legacy_1d)
|
|
@@ -302,7 +307,7 @@ def _ls_init(x, w, cfg: HPCConfig, legacy_1d: bool = False):
|
|
| 302 |
def _analog_init(x, w, x_analog, cfg: HPCConfig):
|
| 303 |
"""Extract discrete Q2_K lattice coordinates from a geometry-preserving analog
|
| 304 |
and project continuous scales onto the true weights ``x``."""
|
| 305 |
-
_, _,
|
| 306 |
s, t = _sub_ls(x, w, analog_codes)
|
| 307 |
q = analog_codes.astype(np.float64).reshape(NS, 16)
|
| 308 |
wb = np.asarray(w, dtype=np.float64).reshape(NS, 16)
|
|
@@ -311,7 +316,7 @@ def _analog_init(x, w, x_analog, cfg: HPCConfig):
|
|
| 311 |
Swq = np.sum(wb * q, axis=1)
|
| 312 |
Sqq = np.sum(wb * q * q, axis=1)
|
| 313 |
Sx = np.sum(wb * xb, axis=1)
|
| 314 |
-
q_bar = np.where(Sw > 1.0e-30, Swq / np.maximum(Sw,
|
| 315 |
Vqq = np.maximum(Sqq - Swq * q_bar, 1.0e-12 * Sw)
|
| 316 |
d, ls = _factor_1d_for(s, Vqq, 15, cfg, False)
|
| 317 |
t_coupled = np.maximum(
|
|
@@ -474,22 +479,11 @@ def _solve(
|
|
| 474 |
m, lm = float(m_new), lm_new
|
| 475 |
|
| 476 |
codes = codes_from_params(x, d, m, ls, lm)
|
| 477 |
-
if coupled:
|
| 478 |
-
|
| 479 |
-
d, m
|
| 480 |
-
|
| 481 |
-
|
| 482 |
-
if cfg.factor_joint_subscales:
|
| 483 |
-
d_f16 = float(d) if (pin & 1) else float(round_fp16(np.float32(d)))
|
| 484 |
-
m_f16 = float(m) if (pin & 2) else float(round_fp16(np.float32(m)))
|
| 485 |
-
ls_j, lm_j = _joint_subscale_scan(x, w, d_f16, m_f16)
|
| 486 |
-
codes_j = codes_from_params(x, d_f16, m_f16, ls_j, lm_j)
|
| 487 |
-
obj_j, _ = objective(x, w, d_f16, m_f16, ls_j, lm_j, codes_j, cfg, dc_carry)
|
| 488 |
-
if obj_j < best[0] - 1.0e-15:
|
| 489 |
-
d, m, ls, lm, codes = d_f16, m_f16, ls_j, lm_j, codes_j
|
| 490 |
-
best = (obj_j, d, m, ls.copy(), lm.copy(), codes.copy())
|
| 491 |
-
stall = 0
|
| 492 |
-
continue
|
| 493 |
|
| 494 |
cur, _ = objective(x, w, d, m, ls, lm, codes, cfg, dc_carry)
|
| 495 |
if cur < best[0] - 1.0e-15:
|
|
@@ -501,6 +495,21 @@ def _solve(
|
|
| 501 |
break
|
| 502 |
|
| 503 |
obj, d, m, ls, lm, codes = best
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 504 |
return d, m, ls, lm, codes, iters
|
| 505 |
|
| 506 |
|
|
@@ -588,6 +597,7 @@ def factor_q2k_block(
|
|
| 588 |
n_starts = 0
|
| 589 |
portfolio = cfg.factor_portfolio and (starts > 1 or max_iter > 1)
|
| 590 |
for legacy_1d in ((False, True) if portfolio else (False,)):
|
|
|
|
| 591 |
for d, m, ls, lm, codes in build_candidates(legacy_1d):
|
| 592 |
n_starts += 1
|
| 593 |
solve_iters = max(max_iter, 16) if legacy_1d else max_iter
|
|
@@ -596,6 +606,15 @@ def factor_q2k_block(
|
|
| 596 |
solve_iters, dc_carry, legacy_1d,
|
| 597 |
)
|
| 598 |
total_iters += it
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 599 |
d, m, d16, m16, ls, lm, codes, sse, obj = _emit_polish(
|
| 600 |
x, w, cfg, d, m, ls, lm, codes, dc_carry
|
| 601 |
)
|
|
@@ -626,40 +645,132 @@ def factor_candidates(
|
|
| 626 |
cfg: HPCConfig,
|
| 627 |
dc_carry: float = 0.0,
|
| 628 |
) -> np.ndarray:
|
| 629 |
-
"""
|
| 630 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 631 |
nd = int(cfg.n_cand_d)
|
| 632 |
nm = int(cfg.n_cand_m)
|
| 633 |
-
|
| 634 |
-
|
| 635 |
-
|
| 636 |
-
|
| 637 |
-
|
| 638 |
-
|
| 639 |
-
|
| 640 |
-
|
| 641 |
-
|
| 642 |
-
|
| 643 |
-
|
| 644 |
-
|
| 645 |
-
|
| 646 |
-
|
| 647 |
-
|
| 648 |
-
|
| 649 |
-
|
| 650 |
-
|
| 651 |
-
|
| 652 |
-
|
| 653 |
-
|
| 654 |
-
|
| 655 |
-
|
| 656 |
-
|
| 657 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 658 |
for aa in range(4):
|
| 659 |
for bb in range(4):
|
| 660 |
idx = (cb * 4 + aa) * N_CAND_M + fb * 4 + bb
|
| 661 |
-
if
|
| 662 |
-
out[idx] =
|
| 663 |
return out
|
| 664 |
|
| 665 |
|
|
|
|
| 32 |
from .config import HPCConfig
|
| 33 |
from .fp16 import from_fp16_bits, fp16_ulp_neighbors, nearest_int, round_fp16, to_fp16_bits
|
| 34 |
from .q2k import NS, QK_K, codes_from_params, derive_subscales
|
| 35 |
+
from .spectral import fold_weights, objective, refine_codes_hadamard
|
| 36 |
|
| 37 |
N_CAND_D = 24
|
| 38 |
N_CAND_M = 24
|
|
|
|
| 165 |
return best_d, best_codes
|
| 166 |
|
| 167 |
|
| 168 |
+
_OPTS_15 = np.arange(16, dtype=np.float64)
|
| 169 |
+
_OPTS_15_SQ = _OPTS_15 * _OPTS_15
|
| 170 |
+
|
| 171 |
+
|
| 172 |
def _refine_integer_codes(v, w, d, codes, nmax, sweeps=2):
|
| 173 |
v = np.asarray(v, dtype=np.float64)
|
| 174 |
w = np.asarray(w, dtype=np.float64)
|
|
|
|
| 176 |
d = float(d)
|
| 177 |
if d <= 0.0:
|
| 178 |
return d, codes.astype(np.uint8)
|
| 179 |
+
options = _OPTS_15 if nmax == 15 else np.arange(nmax + 1, dtype=np.float64)
|
| 180 |
+
opt_sq = _OPTS_15_SQ if nmax == 15 else options * options
|
| 181 |
+
wv = w * v
|
| 182 |
+
sum_lv = float(np.dot(wv, codes))
|
| 183 |
+
sum_l2 = float(np.dot(w, codes * codes))
|
| 184 |
+
if sum_l2 <= 1.0e-30:
|
| 185 |
+
return d, codes.astype(np.uint8)
|
| 186 |
+
best_gain = (sum_lv * sum_lv) / sum_l2
|
| 187 |
+
|
| 188 |
for _ in range(sweeps):
|
| 189 |
+
c_f = codes[:, None].astype(np.float64)
|
| 190 |
+
slv_all = sum_lv + wv[:, None] * (options[None, :] - c_f)
|
| 191 |
+
sl2_all = sum_l2 + w[:, None] * (opt_sq[None, :] - c_f * c_f)
|
| 192 |
+
val_all = (sl2_all > 1.0e-30) & (slv_all > 0.0)
|
| 193 |
+
g_all = np.where(val_all, (slv_all * slv_all) / np.where(val_all, sl2_all, 1.0), -1.0)
|
| 194 |
+
if float(np.max(g_all)) <= best_gain + 1.0e-18:
|
| 195 |
+
break
|
| 196 |
improved = False
|
| 197 |
for i in range(v.size):
|
| 198 |
+
wi = w[i]
|
| 199 |
+
if wi <= 0.0:
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 200 |
continue
|
| 201 |
+
wvi = wv[i]
|
| 202 |
+
li = int(codes[i])
|
| 203 |
+
base_lv = sum_lv - wvi * li
|
| 204 |
+
base_l2 = sum_l2 - wi * (li * li)
|
| 205 |
+
slv = base_lv + wvi * options
|
| 206 |
+
sl2 = base_l2 + wi * opt_sq
|
| 207 |
+
valid = (sl2 > 1.0e-30) & (slv > 0.0)
|
| 208 |
+
gains = np.where(valid, (slv * slv) / np.where(valid, sl2, 1.0), -1.0)
|
| 209 |
+
k = int(np.argmax(gains))
|
| 210 |
+
if k != li and gains[k] > best_gain + 1.0e-18:
|
| 211 |
+
best_gain = float(gains[k])
|
| 212 |
+
sum_lv = float(slv[k])
|
| 213 |
+
sum_l2 = float(sl2[k])
|
| 214 |
+
codes[i] = k
|
| 215 |
improved = True
|
| 216 |
if not improved:
|
| 217 |
break
|
| 218 |
+
d = sum_lv / sum_l2 if sum_l2 > 1.0e-30 else d
|
| 219 |
return d, codes.astype(np.uint8)
|
| 220 |
|
| 221 |
|
|
|
|
| 259 |
)
|
| 260 |
|
| 261 |
|
| 262 |
+
def _range_codes_and_st(x: np.ndarray) -> tuple[np.ndarray, np.ndarray, np.ndarray]:
|
| 263 |
+
blocks = np.asarray(x, dtype=np.float64).reshape(NS, 16)
|
| 264 |
+
xmin = np.minimum(np.min(blocks, axis=1), 0.0)
|
| 265 |
+
xmax = np.max(blocks, axis=1)
|
| 266 |
+
span = xmax - xmin
|
| 267 |
+
s = np.where(span > 1.0e-30, span / 3.0, 0.0)
|
| 268 |
+
t = -xmin
|
| 269 |
+
safe_s = np.where(s > 1.0e-30, s, 1.0)
|
| 270 |
+
q = np.where(
|
| 271 |
+
s[:, None] > 1.0e-30,
|
| 272 |
+
np.clip(nearest_int(((blocks + t[:, None]) / safe_s[:, None]).astype(np.float32)), 0, 3),
|
| 273 |
+
0,
|
| 274 |
+
).astype(np.uint8)
|
| 275 |
+
return s, t, q.reshape(QK_K)
|
| 276 |
+
|
| 277 |
+
|
| 278 |
def _range_init(x, w, cfg: HPCConfig, legacy_1d: bool = False):
|
|
|
|
| 279 |
w = np.asarray(w, dtype=np.float64)
|
| 280 |
+
s, t, codes = _range_codes_and_st(x)
|
| 281 |
+
sw = w.reshape(NS, 16).sum(axis=1)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 282 |
d, ls = _factor_1d_for(s, sw, 15, cfg, legacy_1d)
|
| 283 |
m, lm = _factor_1d_for(t, sw, 15, cfg, legacy_1d)
|
| 284 |
return d, m, ls, lm, codes
|
|
|
|
| 295 |
def _ls_init(x, w, cfg: HPCConfig, legacy_1d: bool = False):
|
| 296 |
x = np.asarray(x, dtype=np.float64)
|
| 297 |
w = np.asarray(w, dtype=np.float64)
|
| 298 |
+
_, _, codes = _range_codes_and_st(x)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 299 |
s, t = _sub_ls(x, w, codes)
|
| 300 |
sw = w.reshape(NS, 16).sum(axis=1)
|
| 301 |
d, ls = _factor_1d_for(s, sw, 15, cfg, legacy_1d)
|
|
|
|
| 307 |
def _analog_init(x, w, x_analog, cfg: HPCConfig):
|
| 308 |
"""Extract discrete Q2_K lattice coordinates from a geometry-preserving analog
|
| 309 |
and project continuous scales onto the true weights ``x``."""
|
| 310 |
+
_, _, analog_codes = _range_codes_and_st(x_analog)
|
| 311 |
s, t = _sub_ls(x, w, analog_codes)
|
| 312 |
q = analog_codes.astype(np.float64).reshape(NS, 16)
|
| 313 |
wb = np.asarray(w, dtype=np.float64).reshape(NS, 16)
|
|
|
|
| 316 |
Swq = np.sum(wb * q, axis=1)
|
| 317 |
Sqq = np.sum(wb * q * q, axis=1)
|
| 318 |
Sx = np.sum(wb * xb, axis=1)
|
| 319 |
+
q_bar = np.where(Sw > 1.0e-30, Swq / np.maximum(Sw, 1.0e-30), 0.0)
|
| 320 |
Vqq = np.maximum(Sqq - Swq * q_bar, 1.0e-12 * Sw)
|
| 321 |
d, ls = _factor_1d_for(s, Vqq, 15, cfg, False)
|
| 322 |
t_coupled = np.maximum(
|
|
|
|
| 479 |
m, lm = float(m_new), lm_new
|
| 480 |
|
| 481 |
codes = codes_from_params(x, d, m, ls, lm)
|
| 482 |
+
if coupled and pin == 0:
|
| 483 |
+
d, m = _global_bilinear_dm_solve(
|
| 484 |
+
x, w, d, m, ls, lm, codes, cfg, dc_carry, use_spectral
|
| 485 |
+
)
|
| 486 |
+
codes = codes_from_params(x, d, m, ls, lm)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 487 |
|
| 488 |
cur, _ = objective(x, w, d, m, ls, lm, codes, cfg, dc_carry)
|
| 489 |
if cur < best[0] - 1.0e-15:
|
|
|
|
| 495 |
break
|
| 496 |
|
| 497 |
obj, d, m, ls, lm, codes = best
|
| 498 |
+
if coupled and cfg.factor_joint_subscales:
|
| 499 |
+
d_f16 = float(d) if (pin & 1) else float(round_fp16(np.float32(d)))
|
| 500 |
+
m_f16 = float(m) if (pin & 2) else float(round_fp16(np.float32(m)))
|
| 501 |
+
ls_j, lm_j = _joint_subscale_scan(x, w, d_f16, m_f16)
|
| 502 |
+
codes_j = codes_from_params(x, d_f16, m_f16, ls_j, lm_j)
|
| 503 |
+
if pin == 0:
|
| 504 |
+
d_j, m_j = _global_bilinear_dm_solve(
|
| 505 |
+
x, w, d_f16, m_f16, ls_j, lm_j, codes_j, cfg, dc_carry, use_spectral
|
| 506 |
+
)
|
| 507 |
+
d_f16 = float(round_fp16(np.float32(d_j)))
|
| 508 |
+
m_f16 = float(round_fp16(np.float32(m_j)))
|
| 509 |
+
codes_j = codes_from_params(x, d_f16, m_f16, ls_j, lm_j)
|
| 510 |
+
obj_j, _ = objective(x, w, d_f16, m_f16, ls_j, lm_j, codes_j, cfg, dc_carry)
|
| 511 |
+
if obj_j < obj - 1.0e-15:
|
| 512 |
+
obj, d, m, ls, lm, codes = obj_j, d_f16, m_f16, ls_j, lm_j, codes_j
|
| 513 |
return d, m, ls, lm, codes, iters
|
| 514 |
|
| 515 |
|
|
|
|
| 597 |
n_starts = 0
|
| 598 |
portfolio = cfg.factor_portfolio and (starts > 1 or max_iter > 1)
|
| 599 |
for legacy_1d in ((False, True) if portfolio else (False,)):
|
| 600 |
+
branch_best = None
|
| 601 |
for d, m, ls, lm, codes in build_candidates(legacy_1d):
|
| 602 |
n_starts += 1
|
| 603 |
solve_iters = max(max_iter, 16) if legacy_1d else max_iter
|
|
|
|
| 606 |
solve_iters, dc_carry, legacy_1d,
|
| 607 |
)
|
| 608 |
total_iters += it
|
| 609 |
+
d_f16 = float(round_fp16(np.float32(d)))
|
| 610 |
+
m_f16 = float(round_fp16(np.float32(m)))
|
| 611 |
+
codes_f16 = codes_from_params(x, d_f16, m_f16, ls, lm)
|
| 612 |
+
raw_obj, _ = objective(x, w, d_f16, m_f16, ls, lm, codes_f16, cfg, dc_carry)
|
| 613 |
+
if branch_best is None or raw_obj < branch_best[0] - 1.0e-15:
|
| 614 |
+
branch_best = (raw_obj, d, m, ls, lm, codes)
|
| 615 |
+
|
| 616 |
+
if branch_best is not None:
|
| 617 |
+
_, d, m, ls, lm, codes = branch_best
|
| 618 |
d, m, d16, m16, ls, lm, codes, sse, obj = _emit_polish(
|
| 619 |
x, w, cfg, d, m, ls, lm, codes, dc_carry
|
| 620 |
)
|
|
|
|
| 645 |
cfg: HPCConfig,
|
| 646 |
dc_carry: float = 0.0,
|
| 647 |
) -> np.ndarray:
|
| 648 |
+
"""Vectorized factored candidate field across the (nd x nm) lattice."""
|
| 649 |
+
x_f32 = np.asarray(x, dtype=np.float32).reshape(QK_K)
|
| 650 |
+
w_f64 = (
|
| 651 |
+
np.ones(QK_K, dtype=np.float64)
|
| 652 |
+
if w is None
|
| 653 |
+
else np.asarray(w, dtype=np.float64).reshape(QK_K)
|
| 654 |
+
)
|
| 655 |
+
scales_f32 = np.asarray(scales, dtype=np.float32).reshape(NS)
|
| 656 |
+
mins_f32 = np.asarray(mins, dtype=np.float32).reshape(NS)
|
| 657 |
+
|
| 658 |
nd = int(cfg.n_cand_d)
|
| 659 |
nm = int(cfg.n_cand_m)
|
| 660 |
+
di_idx = np.array(
|
| 661 |
+
[a if nd == N_CAND_D else (a * N_CAND_D) // nd for a in range(nd)],
|
| 662 |
+
dtype=np.int64,
|
| 663 |
+
)
|
| 664 |
+
mi_idx = np.array(
|
| 665 |
+
[b if nm == N_CAND_M else (b * N_CAND_M) // nm for b in range(nm)],
|
| 666 |
+
dtype=np.int64,
|
| 667 |
+
)
|
| 668 |
+
|
| 669 |
+
ds_vec = round_fp16(np.float32(base_d) * MULTS_D[di_idx]).astype(np.float64)
|
| 670 |
+
ms_vec = round_fp16(np.float32(base_m) * MULTS_M[mi_idx]).astype(np.float64)
|
| 671 |
+
ds = np.repeat(ds_vec, nm)
|
| 672 |
+
ms = np.tile(ms_vec, nd)
|
| 673 |
+
K = ds.size
|
| 674 |
+
|
| 675 |
+
safe_ds = np.where(ds[:, None] > 1.0e-30, ds[:, None], 1.0)
|
| 676 |
+
safe_ms = np.where(ms[:, None] > 1.0e-30, ms[:, None], 1.0)
|
| 677 |
+
ls0 = np.where(
|
| 678 |
+
ds[:, None] > 1.0e-30,
|
| 679 |
+
np.clip(nearest_int((scales_f32[None, :] / safe_ds).astype(np.float32)), 0, 15),
|
| 680 |
+
0,
|
| 681 |
+
).astype(np.uint8)
|
| 682 |
+
lm0 = np.where(
|
| 683 |
+
ms[:, None] > 1.0e-30,
|
| 684 |
+
np.clip(nearest_int((mins_f32[None, :] / safe_ms).astype(np.float32)), 0, 15),
|
| 685 |
+
0,
|
| 686 |
+
).astype(np.uint8)
|
| 687 |
+
|
| 688 |
+
def _eval_batch(ls_mat: np.ndarray, lm_mat: np.ndarray) -> tuple[np.ndarray, np.ndarray]:
|
| 689 |
+
d_sub = np.repeat(ds[:, None] * ls_mat.astype(np.float64), 16, axis=1)
|
| 690 |
+
m_sub = np.repeat(ms[:, None] * lm_mat.astype(np.float64), 16, axis=1)
|
| 691 |
+
safe = d_sub >= 1.0e-15
|
| 692 |
+
sd = np.where(safe, d_sub, 1.0)
|
| 693 |
+
q = np.where(
|
| 694 |
+
safe,
|
| 695 |
+
np.clip(nearest_int(((x_f32[None, :] + m_sub) / sd).astype(np.float32)), 0, 3),
|
| 696 |
+
0,
|
| 697 |
+
).astype(np.float64)
|
| 698 |
+
e = x_f32.astype(np.float64)[None, :] - (d_sub * q - m_sub)
|
| 699 |
+
sse = np.sum(e * e * w_f64[None, :], axis=1)
|
| 700 |
+
if cfg.use_spectral and (cfg.dc_lambda != 0.0 or cfg.vw_lambda != 0.0):
|
| 701 |
+
fw = fold_weights(QK_K, cfg)
|
| 702 |
+
pen = np.zeros(K, dtype=np.float64)
|
| 703 |
+
src = e
|
| 704 |
+
m_len = QK_K // 2
|
| 705 |
+
lvl = 0
|
| 706 |
+
while m_len >= 1:
|
| 707 |
+
dst = src[:, :m_len] + src[:, m_len : 2 * m_len]
|
| 708 |
+
if m_len == 1 and dc_carry != 0.0:
|
| 709 |
+
dst = dst + dc_carry
|
| 710 |
+
if fw[lvl] != 0.0:
|
| 711 |
+
pen += fw[lvl] * np.sum(dst * dst, axis=1)
|
| 712 |
+
src = dst
|
| 713 |
+
m_len //= 2
|
| 714 |
+
lvl += 1
|
| 715 |
+
return sse + pen, q
|
| 716 |
+
return sse, q
|
| 717 |
+
|
| 718 |
+
obj0, q0 = _eval_batch(ls0, lm0)
|
| 719 |
+
best_obj = obj0
|
| 720 |
+
|
| 721 |
+
for _ in range(max(1, int(cfg.factor_iters))):
|
| 722 |
+
q_sub = q0.reshape(K, NS, 16)
|
| 723 |
+
xb = x_f32.astype(np.float64).reshape(1, NS, 16)
|
| 724 |
+
wb = w_f64.reshape(1, NS, 16)
|
| 725 |
+
Sqq = np.sum(wb * q_sub * q_sub, axis=2)
|
| 726 |
+
Swq = np.sum(wb * q_sub, axis=2)
|
| 727 |
+
Sw = np.sum(wb, axis=2)
|
| 728 |
+
Sqx = np.sum(wb * q_sub * xb, axis=2)
|
| 729 |
+
Sx = np.sum(wb * xb, axis=2)
|
| 730 |
+
det = Sqq * Sw - Swq * Swq
|
| 731 |
+
valid = det > 1.0e-30
|
| 732 |
+
s_det = np.where(valid, det, 1.0)
|
| 733 |
+
s_sw = np.where(Sw > 1.0e-30, Sw, 1.0)
|
| 734 |
+
sj = np.maximum(np.where(valid, (Sqx * Sw - Swq * Sx) / s_det, 0.0), 0.0)
|
| 735 |
+
tj = np.where(valid, (sj * Swq - Sx) / s_sw, 0.0)
|
| 736 |
+
bad_tj = tj < 0.0
|
| 737 |
+
tj = np.where(bad_tj, 0.0, tj)
|
| 738 |
+
fallback = np.where(Sqq > 1.0e-30, Sqx / np.where(Sqq > 1.0e-30, Sqq, 1.0), 0.0)
|
| 739 |
+
sj = np.where(bad_tj, np.maximum(fallback, 0.0), sj)
|
| 740 |
+
|
| 741 |
+
ls1 = np.where(
|
| 742 |
+
ds[:, None] > 1.0e-30,
|
| 743 |
+
np.clip(nearest_int((sj / safe_ds).astype(np.float32)), 0, 15),
|
| 744 |
+
0,
|
| 745 |
+
).astype(np.uint8)
|
| 746 |
+
t_tgt = (
|
| 747 |
+
np.maximum(0.0, (ds[:, None] * ls1.astype(np.float64) * Swq - Sx) / s_sw)
|
| 748 |
+
if cfg.factor_coupled_q2k
|
| 749 |
+
else tj
|
| 750 |
+
)
|
| 751 |
+
lm1 = np.where(
|
| 752 |
+
ms[:, None] > 1.0e-30,
|
| 753 |
+
np.clip(nearest_int((t_tgt / safe_ms).astype(np.float32)), 0, 15),
|
| 754 |
+
0,
|
| 755 |
+
).astype(np.uint8)
|
| 756 |
+
obj1, q0 = _eval_batch(ls1, lm1)
|
| 757 |
+
best_obj = np.minimum(best_obj, obj1)
|
| 758 |
+
|
| 759 |
+
best_f32 = best_obj.astype(np.float32)
|
| 760 |
+
out = np.full(TOTAL_CANDIDATES, np.inf, dtype=np.float32)
|
| 761 |
+
if nd == N_CAND_D and nm == N_CAND_M:
|
| 762 |
+
out[:] = best_f32
|
| 763 |
+
else:
|
| 764 |
+
for a, di in enumerate(di_idx):
|
| 765 |
+
cb = int(di) >> 2
|
| 766 |
+
for b, mi in enumerate(mi_idx):
|
| 767 |
+
fb = int(mi) >> 2
|
| 768 |
+
val = best_f32[a * nm + b]
|
| 769 |
for aa in range(4):
|
| 770 |
for bb in range(4):
|
| 771 |
idx = (cb * 4 + aa) * N_CAND_M + fb * 4 + bb
|
| 772 |
+
if val < out[idx]:
|
| 773 |
+
out[idx] = val
|
| 774 |
return out
|
| 775 |
|
| 776 |
|
pipeline.py
CHANGED
|
@@ -442,67 +442,55 @@ def _phase2b_one(i: int) -> tuple[np.ndarray, FactorResult]:
|
|
| 442 |
return cand, fac_res
|
| 443 |
|
| 444 |
|
| 445 |
-
def _phase4_one(
|
|
|
|
| 446 |
X = _MP_STATE["X"]
|
| 447 |
W = _MP_STATE["W"]
|
| 448 |
seeds = _MP_STATE["seeds"]
|
| 449 |
base_d = _MP_STATE["base_d"]
|
| 450 |
base_m = _MP_STATE["base_m"]
|
| 451 |
-
best = _MP_STATE["best"]
|
| 452 |
-
carry = _MP_STATE["carry"]
|
| 453 |
-
standalone = _MP_STATE["standalone"]
|
| 454 |
cfg = _MP_STATE["cfg"]
|
| 455 |
|
| 456 |
wi = None if W is None else W[i]
|
| 457 |
-
d16, m16 = candidate_pair(base_d[i], base_m[i], best[i])
|
| 458 |
-
at_slot = factor_q2k_block(
|
| 459 |
-
X[i],
|
| 460 |
-
wi,
|
| 461 |
-
cfg,
|
| 462 |
-
init_s=seeds["scales"][i],
|
| 463 |
-
init_t=seeds["mins"][i],
|
| 464 |
-
d_seed=float(from_fp16_bits(d16)),
|
| 465 |
-
m_seed=float(from_fp16_bits(m16)),
|
| 466 |
-
pin=cfg.factor_pin,
|
| 467 |
-
use_spectral=cfg.use_spectral,
|
| 468 |
-
max_iter=cfg.factor_iters,
|
| 469 |
-
starts=1,
|
| 470 |
-
dc_carry=0.0,
|
| 471 |
-
)
|
| 472 |
d, m, ls, lm, codes, obj, sse = _assemble_block(
|
| 473 |
-
X[i], wi, seeds, base_d[i], base_m[i],
|
| 474 |
)
|
| 475 |
cand_hit = 0
|
| 476 |
fac_hit = 0
|
| 477 |
|
| 478 |
if cfg.use_candidate_floor:
|
| 479 |
cd, cm, cls, clm = _candidate_config(
|
| 480 |
-
seeds["scales"][i], seeds["mins"][i], base_d[i], base_m[i],
|
| 481 |
)
|
| 482 |
ccodes = codes_from_params(X[i], cd, cm, cls, clm)
|
| 483 |
cobj, csse = objective(
|
| 484 |
-
X[i], wi, cd, cm, cls, clm, ccodes, cfg,
|
| 485 |
)
|
| 486 |
if cobj < obj - 1.0e-15:
|
| 487 |
d, m, ls, lm, codes, obj, sse = cd, cm, cls, clm, ccodes, cobj, csse
|
| 488 |
cand_hit = 1
|
| 489 |
|
| 490 |
if cfg.use_factor_floor:
|
| 491 |
-
|
| 492 |
-
|
| 493 |
-
X[i], wi, fac.d, fac.dmin, fac.ls, fac.lm, fac.codes, cfg,
|
| 494 |
)
|
| 495 |
-
|
| 496 |
-
|
| 497 |
-
|
| 498 |
-
|
| 499 |
-
|
| 500 |
-
|
| 501 |
-
|
| 502 |
-
|
| 503 |
-
|
| 504 |
-
|
| 505 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 506 |
|
| 507 |
blk_obj = make_block(d, m, ls, lm, codes)
|
| 508 |
return blk_obj, cand_hit, fac_hit, blk_obj.error(X[i])
|
|
@@ -596,6 +584,11 @@ class Q2KQuantizer:
|
|
| 596 |
}
|
| 597 |
)
|
| 598 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 599 |
if n_workers > 1 and "fork" in mp.get_all_start_methods():
|
| 600 |
ctx = mp.get_context("fork")
|
| 601 |
chunksize = max(1, min(16, n_blocks // (n_workers * 4) or 1))
|
|
@@ -624,77 +617,34 @@ class Q2KQuantizer:
|
|
| 624 |
eta=eta,
|
| 625 |
sigma=sigma,
|
| 626 |
)
|
| 627 |
-
pool.close()
|
| 628 |
-
pool.join()
|
| 629 |
-
except BaseException:
|
| 630 |
-
pool.terminate()
|
| 631 |
-
pool.join()
|
| 632 |
-
raise
|
| 633 |
-
else:
|
| 634 |
-
for i in range(n_blocks):
|
| 635 |
-
_check_stop()
|
| 636 |
-
cand_row, fac_res = _phase2b_one(i)
|
| 637 |
-
candidate_errors[i] = cand_row
|
| 638 |
-
standalone.append(fac_res)
|
| 639 |
-
now = time.time()
|
| 640 |
-
if (i + 1) % step_report == 0 or (i + 1) == n_blocks or (now - last_emit) >= 0.25:
|
| 641 |
-
last_emit = now
|
| 642 |
-
elapsed = max(now - t_cand, 1.0e-6)
|
| 643 |
-
rate = (i + 1) / elapsed
|
| 644 |
-
eta = (n_blocks - (i + 1)) / max(rate, 1.0e-9)
|
| 645 |
-
_emit(
|
| 646 |
-
"Phase 2b: Analog-Guided Factored Candidate Field",
|
| 647 |
-
i + 1,
|
| 648 |
-
n_blocks,
|
| 649 |
-
f"blk {i+1}/{n_blocks} ({rate:.1f} blk/s, ETA {eta:.1f}s) "
|
| 650 |
-
f"d={float(fac_res.d):.5f} dmin={float(fac_res.dmin):.5f} "
|
| 651 |
-
f"obj={fac_res.objective:.5e} starts={fac_res.starts}",
|
| 652 |
-
rate=rate,
|
| 653 |
-
eta=eta,
|
| 654 |
-
sigma=sigma,
|
| 655 |
-
)
|
| 656 |
-
|
| 657 |
-
_check_stop()
|
| 658 |
-
_emit(
|
| 659 |
-
"Phase 3: 6-State Sieve & 36-State Viterbi DP",
|
| 660 |
-
0,
|
| 661 |
-
n_blocks,
|
| 662 |
-
f"Running Sieve + 36-state Viterbi sequence optimization ({cfg.optimizer.upper()})",
|
| 663 |
-
sigma=sigma,
|
| 664 |
-
)
|
| 665 |
-
best, temperature, _ = _phase3_select(candidate_errors, cfg)
|
| 666 |
-
carry = _compute_dc_carry(X, seeds, best, base_d, base_m, cfg, row_width)
|
| 667 |
-
_emit(
|
| 668 |
-
"Phase 3.9: Viterbi Path & Rolling DC Carry",
|
| 669 |
-
n_blocks,
|
| 670 |
-
n_blocks,
|
| 671 |
-
f"Boltzmann temp={temperature:.4e}, max |DC carry|={float(np.max(np.abs(carry))):.4e}",
|
| 672 |
-
temperature=temperature,
|
| 673 |
-
sigma=sigma,
|
| 674 |
-
)
|
| 675 |
|
| 676 |
-
|
| 677 |
-
|
| 678 |
-
|
| 679 |
-
|
| 680 |
-
|
| 681 |
-
|
| 682 |
-
|
| 683 |
-
|
| 684 |
-
|
| 685 |
-
|
| 686 |
-
|
| 687 |
-
|
| 688 |
-
|
| 689 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
| 690 |
|
| 691 |
-
|
| 692 |
-
|
| 693 |
-
|
| 694 |
-
|
| 695 |
-
|
|
|
|
| 696 |
for i, (blk_obj, cand_hit, fac_hit, blk_err) in enumerate(
|
| 697 |
-
pool.imap(_phase4_one,
|
| 698 |
):
|
| 699 |
_check_stop()
|
| 700 |
blocks.append(blk_obj)
|
|
@@ -732,7 +682,53 @@ class Q2KQuantizer:
|
|
| 732 |
else:
|
| 733 |
for i in range(n_blocks):
|
| 734 |
_check_stop()
|
| 735 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 736 |
blocks.append(blk_obj)
|
| 737 |
candidate_floor_used += cand_hit
|
| 738 |
factor_floor_used += fac_hit
|
|
|
|
| 442 |
return cand, fac_res
|
| 443 |
|
| 444 |
|
| 445 |
+
def _phase4_one(args: tuple[int, int, float, FactorResult]) -> tuple[Q2KBlock, int, int, float]:
|
| 446 |
+
i, best_i, carry_i, fac = args
|
| 447 |
X = _MP_STATE["X"]
|
| 448 |
W = _MP_STATE["W"]
|
| 449 |
seeds = _MP_STATE["seeds"]
|
| 450 |
base_d = _MP_STATE["base_d"]
|
| 451 |
base_m = _MP_STATE["base_m"]
|
|
|
|
|
|
|
|
|
|
| 452 |
cfg = _MP_STATE["cfg"]
|
| 453 |
|
| 454 |
wi = None if W is None else W[i]
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 455 |
d, m, ls, lm, codes, obj, sse = _assemble_block(
|
| 456 |
+
X[i], wi, seeds, base_d[i], base_m[i], best_i, carry_i, cfg
|
| 457 |
)
|
| 458 |
cand_hit = 0
|
| 459 |
fac_hit = 0
|
| 460 |
|
| 461 |
if cfg.use_candidate_floor:
|
| 462 |
cd, cm, cls, clm = _candidate_config(
|
| 463 |
+
seeds["scales"][i], seeds["mins"][i], base_d[i], base_m[i], best_i
|
| 464 |
)
|
| 465 |
ccodes = codes_from_params(X[i], cd, cm, cls, clm)
|
| 466 |
cobj, csse = objective(
|
| 467 |
+
X[i], wi, cd, cm, cls, clm, ccodes, cfg, carry_i
|
| 468 |
)
|
| 469 |
if cobj < obj - 1.0e-15:
|
| 470 |
d, m, ls, lm, codes, obj, sse = cd, cm, cls, clm, ccodes, cobj, csse
|
| 471 |
cand_hit = 1
|
| 472 |
|
| 473 |
if cfg.use_factor_floor:
|
| 474 |
+
fcodes = (
|
| 475 |
+
refine_codes_hadamard(
|
| 476 |
+
X[i], wi, fac.d, fac.dmin, fac.ls, fac.lm, fac.codes, cfg, carry_i
|
| 477 |
)
|
| 478 |
+
if carry_i != 0.0
|
| 479 |
+
else fac.codes
|
| 480 |
+
)
|
| 481 |
+
fobj, fsse = (
|
| 482 |
+
objective(X[i], wi, fac.d, fac.dmin, fac.ls, fac.lm, fcodes, cfg, carry_i)
|
| 483 |
+
if carry_i != 0.0
|
| 484 |
+
else (fac.objective, fac.sse)
|
| 485 |
+
)
|
| 486 |
+
if fobj < obj - 1.0e-15:
|
| 487 |
+
d = float(fac.d)
|
| 488 |
+
m = float(fac.dmin)
|
| 489 |
+
ls = fac.ls.copy()
|
| 490 |
+
lm = fac.lm.copy()
|
| 491 |
+
codes = fcodes.copy()
|
| 492 |
+
obj, sse = fobj, fsse
|
| 493 |
+
fac_hit = 1
|
| 494 |
|
| 495 |
blk_obj = make_block(d, m, ls, lm, codes)
|
| 496 |
return blk_obj, cand_hit, fac_hit, blk_obj.error(X[i])
|
|
|
|
| 584 |
}
|
| 585 |
)
|
| 586 |
|
| 587 |
+
blocks: list[Q2KBlock] = []
|
| 588 |
+
factor_floor_used = 0
|
| 589 |
+
candidate_floor_used = 0
|
| 590 |
+
running_sse = 0.0
|
| 591 |
+
|
| 592 |
if n_workers > 1 and "fork" in mp.get_all_start_methods():
|
| 593 |
ctx = mp.get_context("fork")
|
| 594 |
chunksize = max(1, min(16, n_blocks // (n_workers * 4) or 1))
|
|
|
|
| 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)
|
|
|
|
| 682 |
else:
|
| 683 |
for i in range(n_blocks):
|
| 684 |
_check_stop()
|
| 685 |
+
cand_row, fac_res = _phase2b_one(i)
|
| 686 |
+
candidate_errors[i] = cand_row
|
| 687 |
+
standalone.append(fac_res)
|
| 688 |
+
now = time.time()
|
| 689 |
+
if (i + 1) % step_report == 0 or (i + 1) == n_blocks or (now - last_emit) >= 0.25:
|
| 690 |
+
last_emit = now
|
| 691 |
+
elapsed = max(now - t_cand, 1.0e-6)
|
| 692 |
+
rate = (i + 1) / elapsed
|
| 693 |
+
eta = (n_blocks - (i + 1)) / max(rate, 1.0e-9)
|
| 694 |
+
_emit(
|
| 695 |
+
"Phase 2b: Analog-Guided Factored Candidate Field",
|
| 696 |
+
i + 1,
|
| 697 |
+
n_blocks,
|
| 698 |
+
f"blk {i+1}/{n_blocks} ({rate:.1f} blk/s, ETA {eta:.1f}s) "
|
| 699 |
+
f"d={float(fac_res.d):.5f} dmin={float(fac_res.dmin):.5f} "
|
| 700 |
+
f"obj={fac_res.objective:.5e} starts={fac_res.starts}",
|
| 701 |
+
rate=rate,
|
| 702 |
+
eta=eta,
|
| 703 |
+
sigma=sigma,
|
| 704 |
+
)
|
| 705 |
+
|
| 706 |
+
_check_stop()
|
| 707 |
+
_emit(
|
| 708 |
+
"Phase 3: 6-State Sieve & 36-State Viterbi DP",
|
| 709 |
+
0,
|
| 710 |
+
n_blocks,
|
| 711 |
+
f"Running Sieve + 36-state Viterbi sequence optimization ({cfg.optimizer.upper()})",
|
| 712 |
+
sigma=sigma,
|
| 713 |
+
)
|
| 714 |
+
best, temperature, _ = _phase3_select(candidate_errors, cfg)
|
| 715 |
+
carry = _compute_dc_carry(X, seeds, best, base_d, base_m, cfg, row_width)
|
| 716 |
+
_emit(
|
| 717 |
+
"Phase 3.9: Viterbi Path & Rolling DC Carry",
|
| 718 |
+
n_blocks,
|
| 719 |
+
n_blocks,
|
| 720 |
+
f"Boltzmann temp={temperature:.4e}, max |DC carry|={float(np.max(np.abs(carry))):.4e}",
|
| 721 |
+
temperature=temperature,
|
| 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
|