CompressedGemma commited on
Commit
02ee2c3
·
verified ·
1 Parent(s): 603ba09

Use Algebraic solver in phase 4

Browse files

Slightly less efficient but whatever, it needs to complete in a day not week

Files changed (1) hide show
  1. 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 _candidate_config(scales, mins, base_d, base_m, cidx):
376
- d16, m16 = candidate_pair(base_d, base_m, cidx)
377
- d = float(from_fp16_bits(d16))
378
- m = float(from_fp16_bits(m16))
379
- ls, lm = derive_subscales(scales, mins, d, m)
380
- return d, m, ls, lm
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
- _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
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(