/* SPDX-License-Identifier: AGPL-3.0-or-later */ /* Copyright (C) 2026 David (Corey) Herrera */ /* Differential parity test for the optimized token sampler. * * (2026-10-07: both copies take the llama.cpp/HF order — top-k renormalised before top-p.) * This test keeps a VERBATIM copy of the ORIGINAL sample_token implementation * (sample_token_ref, the pre-optimization slow path) and a copy of the new * OPTIMIZED implementation (sample_token_opt, kept textually in sync with * src/core/engine.c). For thousands of random logit vectors and random * parameter combinations (temperature including 0 for greedy, top_k, top_p, * repeat_penalty, and random recent-token windows), it feeds BOTH samplers the * exact same seeded RNG state and asserts they return the identical token id. * * The two samplers are self-contained (no engine/model dependencies), so this * builds and runs anywhere with just a C compiler and libm. * * Determinism: each sampler calls the global rand() at most once (the final * draw). Before each call we srand() to the same per-trial seed, so both draws * see the identical random value r. Test data is produced by a private xorshift * PRNG so that reseeding rand() never perturbs the generated logits/params. */ #include #include #include #include #include /* Mirror of the real sampling params struct (see include/pantheon.h). */ typedef struct { float temperature; float top_p; int top_k; float repeat_penalty; int repeat_last_n; } pn_sampling_params; static float rand_float(void) { return (float)rand() / ((float)RAND_MAX + 1.0f); } /* ================================================================== * REFERENCE: verbatim copy of the ORIGINAL sample_token (slow path). * ================================================================== */ static uint32_t sample_token_ref(float *logits, int n_vocab, pn_sampling_params *params, uint32_t *recent_tokens, int n_recent) { if (params->repeat_penalty != 1.0f && recent_tokens && n_recent > 0) { for (int i = 0; i < n_recent; i++) { uint32_t tok = recent_tokens[i]; if (tok < (uint32_t)n_vocab) { if (logits[tok] > 0.0f) logits[tok] /= params->repeat_penalty; else logits[tok] *= params->repeat_penalty; } } } if (params->temperature <= 0.0f) { int best = 0; for (int i = 1; i < n_vocab; i++) { if (logits[i] > logits[best]) best = i; } return (uint32_t)best; } float inv_temp = 1.0f / params->temperature; for (int i = 0; i < n_vocab; i++) { logits[i] *= inv_temp; } int top_k = params->top_k; if (top_k <= 0 || top_k > n_vocab) top_k = n_vocab; float max_logit = logits[0]; for (int i = 1; i < n_vocab; i++) { if (logits[i] > max_logit) max_logit = logits[i]; } float *probs = malloc(n_vocab * sizeof(float)); if (!probs) return 0; float sum = 0.0f; for (int i = 0; i < n_vocab; i++) { probs[i] = expf(logits[i] - max_logit); sum += probs[i]; } float inv_sum = 1.0f / sum; for (int i = 0; i < n_vocab; i++) { probs[i] *= inv_sum; } if (top_k < n_vocab) { float *sorted = malloc(n_vocab * sizeof(float)); memcpy(sorted, probs, n_vocab * sizeof(float)); for (int k = 0; k < top_k; k++) { float best_val = sorted[k]; int best_idx = k; for (int j = k + 1; j < n_vocab; j++) { if (sorted[j] > best_val) { best_val = sorted[j]; best_idx = j; } } float tmp = sorted[k]; sorted[k] = sorted[best_idx]; sorted[best_idx] = tmp; } float threshold = sorted[top_k - 1]; free(sorted); for (int i = 0; i < n_vocab; i++) { if (probs[i] < threshold) probs[i] = 0.0f; } /* llama.cpp / HF order (2026-10-07): renormalise within the top-k set. */ sum = 0.0f; for (int i = 0; i < n_vocab; i++) sum += probs[i]; if (sum > 0.0f) { inv_sum = 1.0f / sum; for (int i = 0; i < n_vocab; i++) probs[i] *= inv_sum; } } if (params->top_p < 1.0f) { float cum_prob = 0.0f; float top_p_threshold = 0.0f; float *probs_copy = malloc(n_vocab * sizeof(float)); memcpy(probs_copy, probs, n_vocab * sizeof(float)); while (cum_prob < params->top_p) { int best = 0; for (int i = 1; i < n_vocab; i++) { if (probs_copy[i] > probs_copy[best]) best = i; } if (probs_copy[best] <= 0.0f) break; cum_prob += probs_copy[best]; top_p_threshold = probs_copy[best]; probs_copy[best] = 0.0f; } free(probs_copy); for (int i = 0; i < n_vocab; i++) { if (probs[i] < top_p_threshold) probs[i] = 0.0f; } } sum = 0.0f; for (int i = 0; i < n_vocab; i++) sum += probs[i]; if (sum > 0.0f) { inv_sum = 1.0f / sum; for (int i = 0; i < n_vocab; i++) probs[i] *= inv_sum; } float r = rand_float(); float cum = 0.0f; for (int i = 0; i < n_vocab; i++) { cum += probs[i]; if (r < cum) { free(probs); return (uint32_t)i; } } for (int i = n_vocab - 1; i >= 0; i--) { if (probs[i] > 0.0f) { free(probs); return (uint32_t)i; } } free(probs); return 0; } /* ================================================================== * OPTIMIZED: copy kept textually in sync with src/core/engine.c. * ================================================================== */ typedef struct { float *probs; float *work; int cap; } pn_sampler_scratch; static _Thread_local pn_sampler_scratch g_sampler_scratch = {0}; static pn_sampler_scratch *sampler_scratch_get(int n) { pn_sampler_scratch *s = &g_sampler_scratch; if (s->cap < n) { free(s->probs); free(s->work); s->probs = malloc((size_t)n * sizeof(float)); s->work = malloc((size_t)n * sizeof(float)); if (!s->probs || !s->work) { free(s->probs); free(s->work); s->probs = NULL; s->work = NULL; s->cap = 0; return NULL; } s->cap = n; } return s; } static float sampler_select_kth(float *a, int n, int k) { int lo = 0, hi = n - 1; while (lo < hi) { int i = lo, j = hi; float pivot = a[lo + ((hi - lo) >> 1)]; while (i <= j) { while (a[i] < pivot) i++; while (a[j] > pivot) j--; if (i <= j) { float t = a[i]; a[i] = a[j]; a[j] = t; i++; j--; } } if (k <= j) hi = j; else if (k >= i) lo = i; else break; } return a[k]; } static int sampler_cmp_desc(const void *pa, const void *pb) { float x = *(const float *)pa, y = *(const float *)pb; return (x < y) - (x > y); } static uint32_t sample_token_opt(float *logits, int n_vocab, pn_sampling_params *params, uint32_t *recent_tokens, int n_recent) { if (params->repeat_penalty != 1.0f && recent_tokens && n_recent > 0) { for (int i = 0; i < n_recent; i++) { uint32_t tok = recent_tokens[i]; if (tok < (uint32_t)n_vocab) { if (logits[tok] > 0.0f) logits[tok] /= params->repeat_penalty; else logits[tok] *= params->repeat_penalty; } } } if (params->temperature <= 0.0f) { int best = 0; for (int i = 1; i < n_vocab; i++) { if (logits[i] > logits[best]) best = i; } return (uint32_t)best; } float inv_temp = 1.0f / params->temperature; for (int i = 0; i < n_vocab; i++) { logits[i] *= inv_temp; } int top_k = params->top_k; if (top_k <= 0 || top_k > n_vocab) top_k = n_vocab; float max_logit = logits[0]; for (int i = 1; i < n_vocab; i++) { if (logits[i] > max_logit) max_logit = logits[i]; } pn_sampler_scratch *sc = sampler_scratch_get(n_vocab); if (!sc) return 0; float *probs = sc->probs; float sum = 0.0f; for (int i = 0; i < n_vocab; i++) { probs[i] = expf(logits[i] - max_logit); sum += probs[i]; } float inv_sum = 1.0f / sum; for (int i = 0; i < n_vocab; i++) { probs[i] *= inv_sum; } if (top_k < n_vocab) { memcpy(sc->work, probs, (size_t)n_vocab * sizeof(float)); float threshold = sampler_select_kth(sc->work, n_vocab, n_vocab - top_k); for (int i = 0; i < n_vocab; i++) { if (probs[i] < threshold) probs[i] = 0.0f; } /* llama.cpp / HF order (2026-10-07): renormalise within the top-k set. */ sum = 0.0f; for (int i = 0; i < n_vocab; i++) sum += probs[i]; if (sum > 0.0f) { inv_sum = 1.0f / sum; for (int i = 0; i < n_vocab; i++) probs[i] *= inv_sum; } } if (params->top_p < 1.0f) { float *cand = sc->work; int nc = 0; for (int i = 0; i < n_vocab; i++) { if (probs[i] > 0.0f) cand[nc++] = probs[i]; } qsort(cand, (size_t)nc, sizeof(float), sampler_cmp_desc); float cum_prob = 0.0f; float top_p_threshold = 0.0f; for (int t = 0; t < nc; t++) { if (!(cum_prob < params->top_p)) break; if (cand[t] <= 0.0f) break; cum_prob += cand[t]; top_p_threshold = cand[t]; } for (int i = 0; i < n_vocab; i++) { if (probs[i] < top_p_threshold) probs[i] = 0.0f; } } sum = 0.0f; for (int i = 0; i < n_vocab; i++) sum += probs[i]; if (sum > 0.0f) { inv_sum = 1.0f / sum; for (int i = 0; i < n_vocab; i++) probs[i] *= inv_sum; } float r = rand_float(); float cum = 0.0f; for (int i = 0; i < n_vocab; i++) { cum += probs[i]; if (r < cum) return (uint32_t)i; } for (int i = n_vocab - 1; i >= 0; i--) { if (probs[i] > 0.0f) return (uint32_t)i; } return 0; } /* ================================================================== * Test driver. * ================================================================== */ /* Private xorshift PRNG for generating test data (kept independent of the * global rand() used inside the samplers). */ static uint64_t g_rng = 0x123456789abcdef0ull; static uint32_t xr(void) { uint64_t x = g_rng; x ^= x << 13; x ^= x >> 7; x ^= x << 17; g_rng = x; return (uint32_t)(x >> 32); } static float xr_uniform(float lo, float hi) { return lo + (hi - lo) * ((float)xr() / 4294967296.0f); } static int xr_range(int lo, int hi) { /* inclusive */ return lo + (int)(xr() % (uint32_t)(hi - lo + 1)); } int main(void) { const int TRIALS = 20000; int mismatches = 0; int greedy_cases = 0, topk_cases = 0, topp_cases = 0, penalty_cases = 0, tie_heavy = 0; int max_vocab = 4096; float *base = malloc(max_vocab * sizeof(float)); float *a = malloc(max_vocab * sizeof(float)); float *b = malloc(max_vocab * sizeof(float)); uint32_t *recent = malloc(max_vocab * sizeof(uint32_t)); for (int trial = 0; trial < TRIALS; trial++) { /* Vocab size: mix of tiny, small and large. */ int nv; int roll = xr_range(0, 9); if (roll < 2) nv = xr_range(1, 8); /* tiny edge cases */ else if (roll < 7) nv = xr_range(16, 512); /* small */ else nv = xr_range(1000, max_vocab); /* Decide whether this trial is "tie heavy": draw logits from a small * discrete set so lots of tokens share the exact same value. This * stresses the top-k threshold and top-p tie handling. */ int ties = (xr_range(0, 2) == 0); if (ties) tie_heavy++; for (int i = 0; i < nv; i++) { if (ties) { int levels = xr_range(2, 6); base[i] = (float)xr_range(0, levels) * xr_uniform(0.5f, 3.0f) - 4.0f; } else { base[i] = xr_uniform(-25.0f, 25.0f); } } /* Random params. Temperature 0 ~1/6 of the time (greedy). */ pn_sampling_params p; int troll = xr_range(0, 5); if (troll == 0) { p.temperature = 0.0f; greedy_cases++; } else if (troll == 1) p.temperature = 0.2f; /* production OCR */ else p.temperature = xr_uniform(0.05f, 2.0f); int kroll = xr_range(0, 4); if (kroll == 0) p.top_k = 0; /* -> all */ else if (kroll == 1) p.top_k = xr_range(nv + 1, nv + 100); /* > vocab */ else if (kroll == 2) p.top_k = 40; /* production OCR */ else p.top_k = xr_range(1, nv); if (p.top_k > 0 && p.top_k <= nv) topk_cases++; int proll = xr_range(0, 4); if (proll == 0) p.top_p = 1.0f; /* off */ else if (proll == 1) p.top_p = 0.9f; /* production OCR */ else p.top_p = xr_uniform(0.05f, 1.0f); if (p.top_p < 1.0f) topp_cases++; int rpr = xr_range(0, 3); if (rpr == 0) p.repeat_penalty = 1.0f; /* off */ else if (rpr == 1) p.repeat_penalty = 1.15f; /* production OCR */ else p.repeat_penalty = xr_uniform(1.0f, 2.0f); p.repeat_last_n = 64; /* Random recent-token window. */ int n_recent = 0; if (p.repeat_penalty != 1.0f && xr_range(0, 1)) { n_recent = xr_range(0, nv < 64 ? nv : 64); for (int i = 0; i < n_recent; i++) { /* Sometimes emit out-of-range ids to exercise the guard. */ recent[i] = (xr_range(0, 9) == 0) ? (uint32_t)(nv + xr_range(0, 5)) : (uint32_t)xr_range(0, nv - 1); } if (n_recent > 0) penalty_cases++; } memcpy(a, base, nv * sizeof(float)); memcpy(b, base, nv * sizeof(float)); unsigned seed = 0x9E3779B9u ^ (unsigned)(trial * 2654435761u); srand(seed); uint32_t tok_ref = sample_token_ref(a, nv, &p, n_recent ? recent : NULL, n_recent); srand(seed); uint32_t tok_opt = sample_token_opt(b, nv, &p, n_recent ? recent : NULL, n_recent); if (tok_ref != tok_opt) { if (mismatches < 20) { fprintf(stderr, "MISMATCH trial=%d nv=%d temp=%.4f top_k=%d top_p=%.4f rp=%.4f " "n_recent=%d ties=%d : ref=%u opt=%u\n", trial, nv, p.temperature, p.top_k, p.top_p, p.repeat_penalty, n_recent, ties, tok_ref, tok_opt); } mismatches++; } } free(base); free(a); free(b); free(recent); printf("sampler parity: %d trials\n", TRIALS); printf(" greedy=%d top_k=%d top_p=%d penalty=%d tie_heavy=%d\n", greedy_cases, topk_cases, topp_cases, penalty_cases, tie_heavy); if (mismatches == 0) { printf("PASS: 100%% token-id match (0 mismatches)\n"); return 0; } printf("FAIL: %d mismatches out of %d\n", mismatches, TRIALS); return 1; }