CompressedGemma commited on
Commit
a073a68
·
verified ·
1 Parent(s): b60d890

--iq2auto

Browse files
Files changed (2) hide show
  1. hexstate_quantize.c +253 -53
  2. hexstate_requantize.py +41 -2
hexstate_quantize.c CHANGED
@@ -1793,21 +1793,130 @@ void hexstate_set_spectral_params(float dc_lambda, float vw_lambda, float dc_dec
1793
  g_hex_dc_decay = dc_decay;
1794
  }
1795
 
1796
- /* Spectral penalty: (Σe + dc_carry)² + Σ vesica². dc_carry is the
1797
- * rolling residual we want this block to cancel (Σe ≈ −dc_carry).
1798
- * Reconstruction target is always the true weight; we never quantize x−bias. */
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1799
  static inline float hex_spectral_penalty_ex(const float *e, int n, float dc_carry)
1800
  {
1801
  if (HEX_DC_LAMBDA == 0.0f && HEX_VW_LAMBDA == 0.0f) return 0.0f;
1802
- float dc = dc_carry, ves = 0.0f;
1803
- int half = n / 2;
1804
- for (int i = 0; i < half; i++) {
1805
- float v = e[i] + e[i + half];
1806
- dc += v;
1807
- ves += v * v;
1808
- }
1809
- return (HEX_DC_LAMBDA / (float)n) * dc * dc
1810
- + (HEX_VW_LAMBDA / (float)n) * ves;
1811
  }
1812
 
1813
  static inline float hex_spectral_penalty(const float *e, int n)
@@ -3851,7 +3960,7 @@ static void quantize_tensor_q2k_hpc(const float *weights, int64_t n_elements,
3851
  dc_res += x - deq;
3852
  }
3853
  }
3854
- rolling_dc = dc_res;
3855
  }
3856
  }
3857
 
@@ -4946,7 +5055,9 @@ static void quantize_tensor_q2k_hpc(const float *weights, int64_t n_elements,
4946
  float dc_res = 0.0f;
4947
  for (int i = 0; i < QK_K; i++)
4948
  dc_res += bx[i] - deq[i];
4949
- rolling_dc = dc_res;
 
 
4950
  }
4951
  total_err = 0.0f;
4952
  for (int64_t blk = 0; blk < n_blocks; blk++)
@@ -5767,38 +5878,111 @@ static float iq2xs_block_at_d(const IQ2Book *bk, const float *x, const float *w,
5767
  return e;
5768
  }
5769
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
5770
  /* Greedy re-selection among top-K codewords per group on
5771
- * SSE + (λ_dc/n)(Σe + carry)² + (λ_vw/n) Σ_p (e_p + e_{p+128})²
5772
- * with a block SSE cap. This is the fold-through-codebook step. */
 
 
 
 
 
 
 
 
 
 
 
 
 
 
5773
  static void iq2xs_shape_block(const IQ2Book *bk, const float *x, const float *w, float d,
5774
  const uint8_t ls[IQ2XS_NSUB],
5775
- uint32_t code[IQ2XS_NGROUP], float dc_carry)
 
5776
  {
5777
- if (HEX_DC_LAMBDA == 0.0f && HEX_VW_LAMBDA == 0.0f) return;
 
5778
 
5779
  IQ2Cand cands[IQ2XS_NGROUP][IQ2XS_TOPK];
5780
  int ncand[IQ2XS_NGROUP], cur[IQ2XS_NGROUP];
5781
- float e[QK_K];
5782
- float sse = 0.0f, dc = dc_carry;
5783
 
5784
  for (int g = 0; g < IQ2XS_NGROUP; g++) {
5785
  float db = iq2xs_sub_db(d, ls[g >> 1]);
5786
  if (db <= 0.0f) { ncand[g] = 0; cur[g] = -1;
5787
- for (int j = 0; j < 8; j++) { e[8*g+j] = x[8*g+j]; sse += w[8*g+j]*x[8*g+j]*x[8*g+j]; dc += e[8*g+j]; }
5788
  continue; }
5789
  ncand[g] = iq2xs_group_candidates(bk, x + 8*g, w + 8*g, db, IQ2XS_TOPK, cands[g]);
5790
  cur[g] = 0;
5791
  for (int c = 0; c < ncand[g]; c++)
5792
  if (cands[g][c].code == code[g]) { cur[g] = c; break; }
5793
  const IQ2Cand *cc = &cands[g][cur[g]];
5794
- for (int j = 0; j < 8; j++) { e[8*g+j] = x[8*g+j] - cc->deq[j]; dc += e[8*g+j]; }
5795
  sse += cc->sse;
5796
  }
5797
  const float cap = sse * (1.0f + HEX_DC_SSE_BUDGET);
5798
- float v[QK_K / 2], ves = 0.0f;
5799
- for (int p = 0; p < QK_K / 2; p++) { v[p] = e[p] + e[p + QK_K/2]; ves += v[p] * v[p]; }
5800
- const float ldc = HEX_DC_LAMBDA / (float)QK_K, lvw = HEX_VW_LAMBDA / (float)QK_K;
5801
- float metric = sse + ldc * dc * dc + lvw * ves;
 
 
 
 
 
 
 
 
 
 
 
5802
 
5803
  for (int pass = 0; pass < 96; pass++) {
5804
  int best_g = -1, best_c = 0; float best_m = metric;
@@ -5810,31 +5994,31 @@ static void iq2xs_shape_block(const IQ2Book *bk, const float *x, const float *w,
5810
  const IQ2Cand *cn = &cands[g][c];
5811
  float sse2 = sse - co->sse + cn->sse;
5812
  if (sse2 > cap) continue;
5813
- float dc2 = dc, ves2 = ves;
5814
- for (int j = 0; j < 8; j++) {
5815
- int i = 8*g + j;
5816
- float de = co->deq[j] - cn->deq[j]; /* e_new − e_old */
5817
- dc2 += de;
5818
- int p = (i < QK_K/2) ? i : i - QK_K/2;
5819
- float vn = v[p] + de;
5820
- ves2 += vn * vn - v[p] * v[p];
5821
- }
5822
- float m2 = sse2 + ldc * dc2 * dc2 + lvw * ves2;
5823
  if (m2 < best_m) { best_m = m2; best_g = g; best_c = c; }
5824
  }
5825
  }
5826
  if (best_g < 0) break;
5827
  const IQ2Cand *co = &cands[best_g][cur[best_g]];
5828
  const IQ2Cand *cn = &cands[best_g][best_c];
5829
- sse += cn->sse - co->sse;
5830
- for (int j = 0; j < 8; j++) {
5831
- int i = 8*best_g + j;
5832
- float de = co->deq[j] - cn->deq[j];
5833
- e[i] += de; dc += de;
5834
- int p = (i < QK_K/2) ? i : i - QK_K/2;
5835
- ves += (v[p] + de) * (v[p] + de) - v[p] * v[p];
5836
- v[p] += de;
 
 
 
 
5837
  }
 
 
5838
  cur[best_g] = best_c;
5839
  code[best_g] = cn->code;
5840
  metric = best_m;
@@ -5990,7 +6174,7 @@ static void quantize_tensor_iq2_hpc(const IQ2Book *bk,
5990
 
5991
  /* 4. fold/DC shaping among near-equivalent codewords (carry = 0 here;
5992
  * the sequential pass below applies the true residual carry). */
5993
- iq2xs_shape_block(bk, x, w, best_d, ls, code, 0.0f);
5994
 
5995
  float d_out = best_d;
5996
  if (inflate != 0.0f)
@@ -5998,15 +6182,24 @@ static void quantize_tensor_iq2_hpc(const IQ2Book *bk,
5998
  iq2_pack(bk, output + blk * BB, d_out, ls, code);
5999
  }
6000
 
6001
- /* 5. sequential TRUE residual carry along each row */
6002
- if (HEX_DC_LAMBDA > 0.0f && g_hex_dc_decay > 0.0f) {
 
 
 
6003
  int64_t bpr = (row_width > 0 && row_width % QK_K == 0) ? row_width / QK_K : 0;
6004
- float rolling = 0.0f, w[QK_K], deq[QK_K];
 
6005
  uint8_t ls[IQ2XS_NSUB]; uint32_t code[IQ2XS_NGROUP];
 
 
6006
  for (int64_t blk = 0; blk < n_blocks; blk++) {
6007
- if (bpr > 0 && (blk % bpr) == 0) rolling = 0.0f;
6008
  const float *x = weights + blk * QK_K;
6009
  uint8_t *b = output + blk * BB;
 
 
 
6010
  float d = iq2_unpack(bk, b, ls, code);
6011
  if (d > 0.0f) {
6012
  float sigma2 = 0.0f;
@@ -6016,13 +6209,20 @@ static void quantize_tensor_iq2_hpc(const IQ2Book *bk,
6016
  float base = imat_importance ? imat_importance[blk * QK_K + i] : 1.0f;
6017
  w[i] = (wmode == 1) ? base * sqrtf(sigma2 + x[i] * x[i]) : base;
6018
  }
6019
- iq2xs_shape_block(bk, x, w, d, ls, code, g_hex_dc_decay * rolling);
6020
  iq2_pack(bk, b, d, ls, code);
6021
  }
6022
  iq2_dequant_block(bk, b, deq);
6023
- float r = 0.0f;
6024
- for (int i = 0; i < QK_K; i++) r += x[i] - deq[i];
6025
- rolling = r;
 
 
 
 
 
 
 
6026
  }
6027
  }
6028
 
 
1793
  g_hex_dc_decay = dc_decay;
1794
  }
1795
 
1796
+ /* ── Fold pyramid ─────────────────────────────────────────────────────────
1797
+ * Vesica is the block folded in half once; DC is the block folded in half
1798
+ * log2(n) times. The levels between are the rest of the same tree:
1799
+ *
1800
+ * v¹[p] = e[p] + e[p+n/2] n/2 nodes (vesica)
1801
+ * vᵏ[p] = vᵏ⁻¹[p] + vᵏ⁻¹[p+n/2ᵏ] n/2ᵏ nodes
1802
+ * vᴸ = Σ e 1 node (DC), L = log2 n
1803
+ *
1804
+ * ‖vᵏ‖² is 2ᵏ× the error energy in the subspace of n/2ᵏ-periodic patterns
1805
+ * (Walsh functions on the low 8−k index bits), so penalising level k drives
1806
+ * the error orthogonal to activations with that period. Level weights are
1807
+ * geometric, λ_k = λ_vw·γᵏ⁻¹/n for k ≤ depth (depth=1 ⇒ the classic single
1808
+ * fold), and the top level keeps λ_dc/n so DC behaviour is unchanged.
1809
+ *
1810
+ * Measured (SmolLM2 ffn_down splice, IQ2_S, λ=(16,1), budget 2e-2): depth 7
1811
+ * γ=2 pulls the level-5..7 row-lane residuals from 0.9 → 0.1–0.4 of white
1812
+ * but costs +2.7% RMSE / +1.7% wRMSE and leaves PPL inside noise. Only DC
1813
+ * is invariant to the (arbitrary) neuron ordering, so the other periodic
1814
+ * lanes have nothing in the activations to cancel against. Default depth is
1815
+ * therefore 1; the tree stays available via hexstate_set_fold_params.
1816
+ *
1817
+ * Pyramid layout: T[0..n/2) level 1, then n/4 level 2, …, T[n-2] = DC.
1818
+ * A carry pyramid C (same layout) holds the decayed cumulative residual per
1819
+ * lane along the row; the penalty is Σ_k λ_k Σ_p (Tᵏ[p] + Cᵏ[p])². */
1820
+ #define HEX_FOLD_LEVELS 8 /* log2(QK_K) */
1821
+ static int g_hex_fold_depth = 1; /* vesica levels 1..depth (7 = every level below DC) */
1822
+ static float g_hex_fold_gamma = 2.0f; /* per-level geometric weight */
1823
+ static int g_hex_carry_cumulative = 1;/* 1: S ← decay·S + Σe (row residual = last miss);
1824
+ 0: legacy, carry only the previous block's Σe */
1825
+
1826
+ void hexstate_set_fold_params(int depth, float gamma, int carry_cumulative)
1827
+ {
1828
+ if (depth >= 0 && depth <= HEX_FOLD_LEVELS - 1) g_hex_fold_depth = depth;
1829
+ if (gamma > 0.0f) g_hex_fold_gamma = gamma;
1830
+ if (carry_cumulative >= 0) g_hex_carry_cumulative = carry_cumulative ? 1 : 0;
1831
+ }
1832
+
1833
+ /* ── Activation lanes ─────────────────────────────────────────────────────
1834
+ * The fold tree is a fixed family of index patterns; DC (the root) is the
1835
+ * only member invariant to the arbitrary neuron order, and measured on the
1836
+ * ffn_down input it carries ~0.1% of E[‖a‖²]. What the output error
1837
+ * eᵀE[aaᵀ]e actually lives in is the top eigen-directions u_k of E[aaᵀ]
1838
+ * (25–80% of the trace in the top 16). So the row lanes are generalised to
1839
+ * arbitrary directions: penalty Σ_k λ·ev_k (u_k·e_row + carry_k)², with the
1840
+ * same cumulative carry along the row. ev_k are in E[a²] units, the same as
1841
+ * the imatrix weights on SSE, so λ=1 is the rank-r correction of the
1842
+ * diagonal (imatrix) objective toward the true output error. Nothing is
1843
+ * needed at inference: only the codeword choice changes. */
1844
+ #define HEX_MAX_LANES 64
1845
+ static const float *g_lane_U = NULL; /* r × cols, row-major */
1846
+ static const float *g_lane_ev = NULL; /* r */
1847
+ static int g_lane_r = 0;
1848
+ static int64_t g_lane_cols = 0;
1849
+ static float g_lane_lambda = 1.0f;
1850
+
1851
+ void hexstate_set_activation_lanes(const float *U, const float *ev, int r, int64_t cols, float lambda)
1852
+ {
1853
+ if (!U || !ev || r <= 0 || cols <= 0) { g_lane_U = NULL; g_lane_ev = NULL; g_lane_r = 0; g_lane_cols = 0; return; }
1854
+ g_lane_U = U; g_lane_ev = ev; g_lane_r = r > HEX_MAX_LANES ? HEX_MAX_LANES : r;
1855
+ g_lane_cols = cols; g_lane_lambda = lambda > 0.0f ? lambda : 1.0f;
1856
+ }
1857
+
1858
+ typedef struct {
1859
+ const float *U; /* lane k slice for this block: U + k*stride + i */
1860
+ int64_t stride;
1861
+ const float *ev;
1862
+ int r;
1863
+ const float *carry; /* r decayed cumulative lane residuals */
1864
+ float lambda;
1865
+ } IQ2LaneCtx;
1866
+
1867
+ /* Level weights for a block of n = 2^L. wk[k-1] for k = 1..L. */
1868
+ static inline void hex_fold_weights(int n, float *wk)
1869
+ {
1870
+ int L = 0; while ((1 << L) < n) L++;
1871
+ float g = 1.0f;
1872
+ for (int k = 1; k <= L; k++) {
1873
+ if (k == L) wk[k-1] = HEX_DC_LAMBDA / (float)n;
1874
+ else if (k <= g_hex_fold_depth) wk[k-1] = (HEX_VW_LAMBDA / (float)n) * g;
1875
+ else wk[k-1] = 0.0f;
1876
+ g *= g_hex_fold_gamma;
1877
+ }
1878
+ }
1879
+
1880
+ /* Build the pyramid (n-1 floats) from leaves e[n]. */
1881
+ static inline void hex_fold_build(const float *e, int n, float *T)
1882
+ {
1883
+ const float *src = e; float *dst = T;
1884
+ for (int m = n / 2; m >= 1; m >>= 1) {
1885
+ for (int p = 0; p < m; p++) dst[p] = src[p] + src[p + m];
1886
+ src = dst; dst += m;
1887
+ }
1888
+ }
1889
+
1890
+ /* Σ_k λ_k Σ_p (Tᵏ[p] + Cᵏ[p])²; C may be NULL (no carry). */
1891
+ static inline float hex_fold_energy(const float *T, const float *C, int n)
1892
+ {
1893
+ float wk[HEX_FOLD_LEVELS];
1894
+ hex_fold_weights(n, wk);
1895
+ float acc = 0.0f; int off = 0, k = 0;
1896
+ for (int m = n / 2; m >= 1; m >>= 1, k++) {
1897
+ if (wk[k] != 0.0f) {
1898
+ float s = 0.0f;
1899
+ for (int p = 0; p < m; p++) {
1900
+ float v = T[off + p] + (C ? C[off + p] : 0.0f);
1901
+ s += v * v;
1902
+ }
1903
+ acc += wk[k] * s;
1904
+ }
1905
+ off += m;
1906
+ }
1907
+ return acc;
1908
+ }
1909
+
1910
+ /* Spectral penalty with a scalar DC carry (Q2_K acceptance stages):
1911
+ * Σ_k λ_k‖vᵏ‖² with (vᴸ + dc_carry)² at the top. Reconstruction target is
1912
+ * always the true weight; we never quantize x−bias. */
1913
  static inline float hex_spectral_penalty_ex(const float *e, int n, float dc_carry)
1914
  {
1915
  if (HEX_DC_LAMBDA == 0.0f && HEX_VW_LAMBDA == 0.0f) return 0.0f;
1916
+ float T[QK_K];
1917
+ hex_fold_build(e, n, T);
1918
+ T[n - 2] += dc_carry;
1919
+ return hex_fold_energy(T, NULL, n);
 
 
 
 
 
1920
  }
1921
 
1922
  static inline float hex_spectral_penalty(const float *e, int n)
 
3960
  dc_res += x - deq;
3961
  }
3962
  }
3963
+ rolling_dc = g_hex_carry_cumulative ? block_dc_carry[blk] + dc_res : dc_res;
3964
  }
3965
  }
3966
 
 
5055
  float dc_res = 0.0f;
5056
  for (int i = 0; i < QK_K; i++)
5057
  dc_res += bx[i] - deq[i];
5058
+ /* cumulative: S ← decay·S + Σe, so the metric (Σe + carry)² is
5059
+ * S² and the row residual after each block is just its miss. */
5060
+ rolling_dc = g_hex_carry_cumulative ? carry + dc_res : dc_res;
5061
  }
5062
  total_err = 0.0f;
5063
  for (int64_t blk = 0; blk < n_blocks; blk++)
 
5878
  return e;
5879
  }
5880
 
5881
+ /* Change in fold energy if the 8 leaves of group g move by de[8].
5882
+ * Leaf i lives at node (i & (m-1)) of the level with m nodes; the 8
5883
+ * contiguous leaves of a group hit 8 distinct nodes while m ≥ 8 and fold
5884
+ * onto all m nodes below that. O(8·log n) per evaluation. */
5885
+ static inline float iq2_fold_delta(const float *T, const float *C, const float *wk,
5886
+ int g, const float de[8])
5887
+ {
5888
+ float acc = 0.0f; int off = 0, k = 0;
5889
+ for (int m = QK_K / 2; m >= 1; m >>= 1, k++) {
5890
+ if (wk[k] != 0.0f) {
5891
+ if (m >= 8) {
5892
+ int base = (8 * g) & (m - 1);
5893
+ for (int j = 0; j < 8; j++) {
5894
+ int q = off + base + j;
5895
+ float t = T[q] + (C ? C[q] : 0.0f);
5896
+ acc += wk[k] * de[j] * (2.0f * t + de[j]);
5897
+ }
5898
+ } else {
5899
+ float dn[8] = {0};
5900
+ for (int j = 0; j < 8; j++) dn[j & (m - 1)] += de[j];
5901
+ for (int p = 0; p < m; p++) {
5902
+ int q = off + p;
5903
+ float t = T[q] + (C ? C[q] : 0.0f);
5904
+ acc += wk[k] * dn[p] * (2.0f * t + dn[p]);
5905
+ }
5906
+ }
5907
+ }
5908
+ off += m;
5909
+ }
5910
+ return acc;
5911
+ }
5912
+
5913
+ static inline void iq2_fold_apply(float *T, int g, const float de[8])
5914
+ {
5915
+ int off = 0;
5916
+ for (int m = QK_K / 2; m >= 1; m >>= 1) {
5917
+ if (m >= 8) {
5918
+ int base = (8 * g) & (m - 1);
5919
+ for (int j = 0; j < 8; j++) T[off + base + j] += de[j];
5920
+ } else {
5921
+ for (int j = 0; j < 8; j++) T[off + (j & (m - 1))] += de[j];
5922
+ }
5923
+ off += m;
5924
+ }
5925
+ }
5926
+
5927
  /* Greedy re-selection among top-K codewords per group on
5928
+ * SSE + Σ_k λ_k Σ_p (vᵏ[p] + carryᵏ[p])² (fold pyramid, DC at the top)
5929
+ * with a block SSE cap. This is the fold-through-codebook step. carry is a
5930
+ * pyramid (QK_K-1 floats) of decayed cumulative lane residuals, or NULL. */
5931
+ static inline float iq2_lane_delta(const IQ2LaneCtx *lc, const float *Lv, int g, const float de[8])
5932
+ {
5933
+ float acc = 0.0f;
5934
+ for (int k = 0; k < lc->r; k++) {
5935
+ const float *u = lc->U + (int64_t)k * lc->stride + 8 * g;
5936
+ float dL = 0.0f;
5937
+ for (int j = 0; j < 8; j++) dL += u[j] * de[j];
5938
+ float t = Lv[k] + (lc->carry ? lc->carry[k] : 0.0f);
5939
+ acc += lc->lambda * lc->ev[k] * dL * (2.0f * t + dL);
5940
+ }
5941
+ return acc;
5942
+ }
5943
+
5944
  static void iq2xs_shape_block(const IQ2Book *bk, const float *x, const float *w, float d,
5945
  const uint8_t ls[IQ2XS_NSUB],
5946
+ uint32_t code[IQ2XS_NGROUP], const float *carry,
5947
+ const IQ2LaneCtx *lc)
5948
  {
5949
+ if (HEX_DC_LAMBDA == 0.0f && HEX_VW_LAMBDA == 0.0f && !(lc && lc->r > 0)) return;
5950
+ if (lc && lc->r <= 0) lc = NULL;
5951
 
5952
  IQ2Cand cands[IQ2XS_NGROUP][IQ2XS_TOPK];
5953
  int ncand[IQ2XS_NGROUP], cur[IQ2XS_NGROUP];
5954
+ float e[QK_K], T[QK_K], wk[HEX_FOLD_LEVELS], Lv[HEX_MAX_LANES];
5955
+ float sse = 0.0f;
5956
 
5957
  for (int g = 0; g < IQ2XS_NGROUP; g++) {
5958
  float db = iq2xs_sub_db(d, ls[g >> 1]);
5959
  if (db <= 0.0f) { ncand[g] = 0; cur[g] = -1;
5960
+ for (int j = 0; j < 8; j++) { e[8*g+j] = x[8*g+j]; sse += w[8*g+j]*x[8*g+j]*x[8*g+j]; }
5961
  continue; }
5962
  ncand[g] = iq2xs_group_candidates(bk, x + 8*g, w + 8*g, db, IQ2XS_TOPK, cands[g]);
5963
  cur[g] = 0;
5964
  for (int c = 0; c < ncand[g]; c++)
5965
  if (cands[g][c].code == code[g]) { cur[g] = c; break; }
5966
  const IQ2Cand *cc = &cands[g][cur[g]];
5967
+ for (int j = 0; j < 8; j++) e[8*g+j] = x[8*g+j] - cc->deq[j];
5968
  sse += cc->sse;
5969
  }
5970
  const float cap = sse * (1.0f + HEX_DC_SSE_BUDGET);
5971
+ hex_fold_weights(QK_K, wk);
5972
+ hex_fold_build(e, QK_K, T);
5973
+ float fold = hex_fold_energy(T, carry, QK_K);
5974
+ float lane = 0.0f;
5975
+ if (lc) {
5976
+ for (int k = 0; k < lc->r; k++) {
5977
+ const float *u = lc->U + (int64_t)k * lc->stride;
5978
+ float s = 0.0f;
5979
+ for (int i = 0; i < QK_K; i++) s += u[i] * e[i];
5980
+ Lv[k] = s;
5981
+ float t = s + (lc->carry ? lc->carry[k] : 0.0f);
5982
+ lane += lc->lambda * lc->ev[k] * t * t;
5983
+ }
5984
+ }
5985
+ float metric = sse + fold + lane;
5986
 
5987
  for (int pass = 0; pass < 96; pass++) {
5988
  int best_g = -1, best_c = 0; float best_m = metric;
 
5994
  const IQ2Cand *cn = &cands[g][c];
5995
  float sse2 = sse - co->sse + cn->sse;
5996
  if (sse2 > cap) continue;
5997
+ float de[8];
5998
+ for (int j = 0; j < 8; j++) de[j] = co->deq[j] - cn->deq[j]; /* e_new − e_old */
5999
+ float m2 = sse2 + fold + iq2_fold_delta(T, carry, wk, g, de)
6000
+ + lane + (lc ? iq2_lane_delta(lc, Lv, g, de) : 0.0f);
 
 
 
 
 
 
6001
  if (m2 < best_m) { best_m = m2; best_g = g; best_c = c; }
6002
  }
6003
  }
6004
  if (best_g < 0) break;
6005
  const IQ2Cand *co = &cands[best_g][cur[best_g]];
6006
  const IQ2Cand *cn = &cands[best_g][best_c];
6007
+ float de[8];
6008
+ for (int j = 0; j < 8; j++) de[j] = co->deq[j] - cn->deq[j];
6009
+ fold += iq2_fold_delta(T, carry, wk, best_g, de);
6010
+ iq2_fold_apply(T, best_g, de);
6011
+ if (lc) {
6012
+ lane += iq2_lane_delta(lc, Lv, best_g, de);
6013
+ for (int k = 0; k < lc->r; k++) {
6014
+ const float *u = lc->U + (int64_t)k * lc->stride + 8 * best_g;
6015
+ float dL = 0.0f;
6016
+ for (int j = 0; j < 8; j++) dL += u[j] * de[j];
6017
+ Lv[k] += dL;
6018
+ }
6019
  }
6020
+ for (int j = 0; j < 8; j++) e[8*best_g + j] += de[j];
6021
+ sse += cn->sse - co->sse;
6022
  cur[best_g] = best_c;
6023
  code[best_g] = cn->code;
6024
  metric = best_m;
 
6174
 
6175
  /* 4. fold/DC shaping among near-equivalent codewords (carry = 0 here;
6176
  * the sequential pass below applies the true residual carry). */
6177
+ iq2xs_shape_block(bk, x, w, best_d, ls, code, NULL, NULL);
6178
 
6179
  float d_out = best_d;
6180
  if (inflate != 0.0f)
 
6182
  iq2_pack(bk, output + blk * BB, d_out, ls, code);
6183
  }
6184
 
6185
+ /* 5. sequential TRUE residual carry along each row — one lane per
6186
+ * pyramid node (255 lanes: 128 vesica pairs … 1 DC). S ← decay·S + vᵏ,
6187
+ * carry = decay·S, so each lane's row residual is just its last miss. */
6188
+ const int use_lanes = (g_lane_r > 0 && g_lane_U && row_width > 0 && g_lane_cols == row_width);
6189
+ if ((HEX_DC_LAMBDA > 0.0f || HEX_VW_LAMBDA > 0.0f || use_lanes) && g_hex_dc_decay > 0.0f) {
6190
  int64_t bpr = (row_width > 0 && row_width % QK_K == 0) ? row_width / QK_K : 0;
6191
+ float S[QK_K], C[QK_K], T[QK_K], e[QK_K], w[QK_K], deq[QK_K];
6192
+ float LS[HEX_MAX_LANES], LC[HEX_MAX_LANES];
6193
  uint8_t ls[IQ2XS_NSUB]; uint32_t code[IQ2XS_NGROUP];
6194
+ IQ2LaneCtx lc = { NULL, g_lane_cols, g_lane_ev, use_lanes ? g_lane_r : 0, LC, g_lane_lambda };
6195
+ memset(S, 0, sizeof(S)); memset(LS, 0, sizeof(LS));
6196
  for (int64_t blk = 0; blk < n_blocks; blk++) {
6197
+ if (bpr > 0 && (blk % bpr) == 0) { memset(S, 0, sizeof(S)); memset(LS, 0, sizeof(LS)); }
6198
  const float *x = weights + blk * QK_K;
6199
  uint8_t *b = output + blk * BB;
6200
+ for (int q = 0; q < QK_K - 1; q++) C[q] = g_hex_dc_decay * S[q];
6201
+ for (int k = 0; k < lc.r; k++) LC[k] = g_hex_dc_decay * LS[k];
6202
+ if (use_lanes) lc.U = g_lane_U + (bpr > 0 ? (blk % bpr) * QK_K : 0);
6203
  float d = iq2_unpack(bk, b, ls, code);
6204
  if (d > 0.0f) {
6205
  float sigma2 = 0.0f;
 
6209
  float base = imat_importance ? imat_importance[blk * QK_K + i] : 1.0f;
6210
  w[i] = (wmode == 1) ? base * sqrtf(sigma2 + x[i] * x[i]) : base;
6211
  }
6212
+ iq2xs_shape_block(bk, x, w, d, ls, code, C, use_lanes ? &lc : NULL);
6213
  iq2_pack(bk, b, d, ls, code);
6214
  }
6215
  iq2_dequant_block(bk, b, deq);
6216
+ for (int i = 0; i < QK_K; i++) e[i] = x[i] - deq[i];
6217
+ hex_fold_build(e, QK_K, T);
6218
+ for (int q = 0; q < QK_K - 1; q++)
6219
+ S[q] = g_hex_carry_cumulative ? C[q] + T[q] : T[q];
6220
+ for (int k = 0; k < lc.r; k++) {
6221
+ const float *u = lc.U + (int64_t)k * lc.stride;
6222
+ float s = 0.0f;
6223
+ for (int i = 0; i < QK_K; i++) s += u[i] * e[i];
6224
+ LS[k] = g_hex_carry_cumulative ? LC[k] + s : s;
6225
+ }
6226
  }
6227
  }
6228
 
hexstate_requantize.py CHANGED
@@ -155,6 +155,20 @@ def _load_hexstate_lib():
155
  budget = '0.02'
156
  if budget is not None and hasattr(lib, 'hexstate_set_sse_budget'):
157
  lib.hexstate_set_sse_budget(ctypes.c_float(float(budget)))
 
 
 
 
 
 
 
 
 
 
 
 
 
 
158
  _HEXSTATE_LIB = lib
159
  return lib
160
  except Exception as e:
@@ -852,9 +866,14 @@ def _copy_bytes(fin, fout, abs_offset, n_bytes):
852
  return written
853
 
854
 
855
- def quantize_tensor_iq2_hpc(f32_data, importance=None, row_width=0, kind='iq2xs'):
856
  """IQ2_XS (74 B) or IQ2_S (82 B) per 256 weights via the HPC C library.
857
- Returns (bytes, n_blocks, dequant_f32)."""
 
 
 
 
 
858
  suffix = {'iq2xs': 'iq2_xs', 'iq2s': 'iq2_s'}[kind]
859
  block_bytes = LOWBIT_KINDS[kind][1]
860
  lib = _load_hexstate_lib()
@@ -872,6 +891,20 @@ def quantize_tensor_iq2_hpc(f32_data, importance=None, row_width=0, kind='iq2xs'
872
  imat_c = np.ascontiguousarray(importance, dtype=np.float32).reshape(-1)
873
  if imat_c.size == n:
874
  imat_ptr = imat_c.ctypes.data_as(ctypes.POINTER(ctypes.c_float))
 
 
 
 
 
 
 
 
 
 
 
 
 
 
875
  getattr(lib, f'hexstate_quantize_tensor_{suffix}_hpc')(
876
  f32.ctypes.data_as(ctypes.POINTER(ctypes.c_float)),
877
  ctypes.c_int64(n),
@@ -881,6 +914,9 @@ def quantize_tensor_iq2_hpc(f32_data, importance=None, row_width=0, kind='iq2xs'
881
  ctypes.c_int(0),
882
  ctypes.c_int64(int(row_width)),
883
  )
 
 
 
884
  deq = np.zeros(n, dtype=np.float32)
885
  getattr(lib, f'hexstate_dequant_{suffix}')(
886
  out.ctypes.data_as(ctypes.c_void_p), ctypes.c_int64(n_blocks),
@@ -1161,6 +1197,9 @@ def main():
1161
  print(" HEX_VW_LAMBDA vesica weight (default 1)")
1162
  print(" HEX_DC_DECAY rolling residual carry 0..1 (default 0.85)")
1163
  print(" HEX_SSE_BUDGET relative SSE the shaper may spend (Q2_K 5e-4, IQ2 2e-2)")
 
 
 
1164
  sys.exit(1)
1165
 
1166
  global LOWBIT_FORMAT
 
155
  budget = '0.02'
156
  if budget is not None and hasattr(lib, 'hexstate_set_sse_budget'):
157
  lib.hexstate_set_sse_budget(ctypes.c_float(float(budget)))
158
+ # Fold pyramid: HEX_FOLD_DEPTH levels below DC get vesica weight
159
+ # (1 = classic single-fold vesica [default], 7 = full tree), geometric
160
+ # per-level weight HEX_FOLD_GAMMA. HEX_CARRY_CUM=0 restores the legacy
161
+ # previous-block-only carry (default carries the cumulative residual).
162
+ fd = os.environ.get('HEX_FOLD_DEPTH')
163
+ fg = os.environ.get('HEX_FOLD_GAMMA')
164
+ fc = os.environ.get('HEX_CARRY_CUM')
165
+ if hasattr(lib, 'hexstate_set_fold_params') and (fd or fg or fc):
166
+ lib.hexstate_set_fold_params.restype = None
167
+ lib.hexstate_set_fold_params.argtypes = [ctypes.c_int, ctypes.c_float, ctypes.c_int]
168
+ lib.hexstate_set_fold_params(
169
+ ctypes.c_int(int(fd) if fd else -1),
170
+ ctypes.c_float(float(fg) if fg else 0.0),
171
+ ctypes.c_int(int(fc) if fc else -1))
172
  _HEXSTATE_LIB = lib
173
  return lib
174
  except Exception as e:
 
866
  return written
867
 
868
 
869
+ def quantize_tensor_iq2_hpc(f32_data, importance=None, row_width=0, kind='iq2xs', lanes=None):
870
  """IQ2_XS (74 B) or IQ2_S (82 B) per 256 weights via the HPC C library.
871
+ Returns (bytes, n_blocks, dequant_f32).
872
+
873
+ lanes: optional (U, ev[, lambda]) — U is (r, row_width) activation
874
+ directions over the input columns (top eigenvectors of E[a aᵀ]) and ev
875
+ their eigenvalues in E[a²] units; the sequential pass then also cancels
876
+ the row error along each u_k with a cumulative carry."""
877
  suffix = {'iq2xs': 'iq2_xs', 'iq2s': 'iq2_s'}[kind]
878
  block_bytes = LOWBIT_KINDS[kind][1]
879
  lib = _load_hexstate_lib()
 
891
  imat_c = np.ascontiguousarray(importance, dtype=np.float32).reshape(-1)
892
  if imat_c.size == n:
893
  imat_ptr = imat_c.ctypes.data_as(ctypes.POINTER(ctypes.c_float))
894
+ lane_keep = None
895
+ if lanes is not None and hasattr(lib, 'hexstate_set_activation_lanes') and row_width > 0:
896
+ U = np.ascontiguousarray(lanes[0], dtype=np.float32).reshape(-1, int(row_width))
897
+ ev = np.ascontiguousarray(lanes[1], dtype=np.float32).reshape(-1)
898
+ lam = float(lanes[2]) if len(lanes) > 2 else 1.0
899
+ lib.hexstate_set_activation_lanes.restype = None
900
+ lib.hexstate_set_activation_lanes.argtypes = [
901
+ ctypes.POINTER(ctypes.c_float), ctypes.POINTER(ctypes.c_float),
902
+ ctypes.c_int, ctypes.c_int64, ctypes.c_float]
903
+ lib.hexstate_set_activation_lanes(
904
+ U.ctypes.data_as(ctypes.POINTER(ctypes.c_float)),
905
+ ev.ctypes.data_as(ctypes.POINTER(ctypes.c_float)),
906
+ ctypes.c_int(int(min(U.shape[0], ev.size))), ctypes.c_int64(int(row_width)), ctypes.c_float(lam))
907
+ lane_keep = (U, ev)
908
  getattr(lib, f'hexstate_quantize_tensor_{suffix}_hpc')(
909
  f32.ctypes.data_as(ctypes.POINTER(ctypes.c_float)),
910
  ctypes.c_int64(n),
 
914
  ctypes.c_int(0),
915
  ctypes.c_int64(int(row_width)),
916
  )
917
+ if lane_keep is not None:
918
+ lib.hexstate_set_activation_lanes(None, None, ctypes.c_int(0), ctypes.c_int64(0), ctypes.c_float(0.0))
919
+ del lane_keep
920
  deq = np.zeros(n, dtype=np.float32)
921
  getattr(lib, f'hexstate_dequant_{suffix}')(
922
  out.ctypes.data_as(ctypes.c_void_p), ctypes.c_int64(n_blocks),
 
1197
  print(" HEX_VW_LAMBDA vesica weight (default 1)")
1198
  print(" HEX_DC_DECAY rolling residual carry 0..1 (default 0.85)")
1199
  print(" HEX_SSE_BUDGET relative SSE the shaper may spend (Q2_K 5e-4, IQ2 2e-2)")
1200
+ print(" HEX_FOLD_DEPTH fold-pyramid levels below DC to shape, 1=vesica only (default 1, 7=full tree)")
1201
+ print(" HEX_FOLD_GAMMA per-level geometric weight of the pyramid (default 2)")
1202
+ print(" HEX_CARRY_CUM 1: carry cumulative row residual (default), 0: previous block only")
1203
  sys.exit(1)
1204
 
1205
  global LOWBIT_FORMAT