#[derive(Debug, Clone)]
pub struct InferenceResult {
pub text: String,
pub tokens: Vec<u32>,
pub input_token_count: usize,
pub generated_token_count: usize,
pub inference_ms: f64,
pub tok_per_sec: f64,
pub load_ms: f64,
pub format: String,
pub used_gpu: bool,
}
const VALID_MODEL_EXTENSIONS: &[&str] = &["gguf", "safetensors", "apr", "bin", "json"];
pub(crate) fn validate_model_path(path: &std::path::Path) -> Result<()> {
let path_str = path.to_string_lossy();
if path_str.contains("..") {
return Err(RealizarError::SecurityError {
reason: format!(
"Path traversal detected: '{}'. Use absolute paths or paths without '..'",
path_str
),
});
}
let extension = path
.extension()
.and_then(|e| e.to_str())
.map(str::to_lowercase)
.unwrap_or_default();
if !VALID_MODEL_EXTENSIONS.contains(&extension.as_str()) {
return Err(RealizarError::SecurityError {
reason: format!(
"Invalid model file extension: '.{}'. Expected one of: {}",
extension,
VALID_MODEL_EXTENSIONS.join(", ")
),
});
}
if !path.exists() {
return Err(RealizarError::IoError {
message: format!("File not found: {}", path.display()),
});
}
if !path.is_file() {
return Err(RealizarError::SecurityError {
reason: format!("Path is not a regular file: {}", path.display()),
});
}
Ok(())
}
pub fn run_inference(config: &InferenceConfig) -> Result<InferenceResult> {
if config.use_mock_backend {
return run_mock_inference(config);
}
let path_str = config.model_path.to_string_lossy();
if path_str.ends_with(".safetensors.index.json") {
validate_model_path(&config.model_path)?;
let format = ModelFormat::SafeTensors;
let prepared = prepare_tokens(config, &format)?;
return run_sharded_safetensors_inference(config, &prepared);
}
validate_model_path(&config.model_path)?;
let magic = {
use std::io::Read;
let mut file = std::fs::File::open(&config.model_path).map_err(|e| RealizarError::IoError {
message: format!("Failed to read model: {}", e),
})?;
let mut buf = [0u8; 8];
file.read_exact(&mut buf).map_err(|e| {
if e.kind() == std::io::ErrorKind::UnexpectedEof {
RealizarError::FormatError {
reason: "File too small for format detection".to_string(),
}
} else {
RealizarError::IoError {
message: format!("Failed to read model header: {}", e),
}
}
})?;
buf
};
let format = detect_format(&magic).map_err(|e| RealizarError::FormatError {
reason: format!("Format detection failed: {}", e),
})?;
let prepared = prepare_tokens(config, &format)?;
match format {
ModelFormat::Gguf => run_gguf_inference(config, &prepared),
ModelFormat::Apr => run_apr_inference(config, &prepared),
ModelFormat::SafeTensors => run_safetensors_inference(config, &prepared),
}
}
fn run_gguf_inference(
config: &InferenceConfig,
prepared: &PreparedTokens,
) -> Result<InferenceResult> {
use crate::gguf::{MappedGGUFModel, OwnedQuantizedModel, QuantizedGenerateConfig};
if config.verbose {
eprintln!("Loading model: {}", config.model_path.display());
}
let load_start = Instant::now();
let mapped = MappedGGUFModel::from_path(&config.model_path)?;
prefault_mmap(mapped.data());
let model = OwnedQuantizedModel::from_mapped(&mapped)?;
let load_ms = load_start.elapsed().as_secs_f64() * 1000.0;
let gguf_arch = mapped.model.architecture().unwrap_or("transformer");
if config.verbose {
print_gguf_verbose_info(gguf_arch, &model, load_ms);
}
let input_tokens = prepared.tokens().to_vec();
let input_token_count = prepared.input_count();
let model_config = model.config.clone();
let mut stop_tokens: Vec<u32> = model_config.eos_token_id.into_iter().collect();
for &t in &config.stop_tokens {
if !stop_tokens.contains(&t) {
stop_tokens.push(t);
}
}
let mut gen_config = QuantizedGenerateConfig {
max_tokens: config.max_tokens,
stop_tokens,
trace: config.trace,
..Default::default()
};
config.apply_sampling_to(&mut gen_config);
let infer_start = Instant::now();
let canonical_arch = crate::tensor_names::normalize_architecture(&model.config.architecture);
let (tokens, used_gpu) = if canonical_arch == "qwen3_moe" {
let tokens = crate::infer::qwen3_moe_generate::run_qwen3_moe_generate(
&mapped,
&model,
&input_tokens,
&gen_config,
)?;
(tokens, false) } else {
run_gguf_generate(model, &input_tokens, &gen_config, config)?
};
let inference_ms = infer_start.elapsed().as_secs_f64() * 1000.0;
let generated_tokens = &tokens[input_token_count..];
let raw_text = mapped.model.decode(generated_tokens);
if config.verbose {
eprintln!("[DEBUG] input_count={}, total_tokens={}, generated_count={}", input_token_count, tokens.len(), generated_tokens.len());
eprintln!("[DEBUG] generated token ids: {:?}", &generated_tokens[..generated_tokens.len().min(20)]);
eprintln!("[DEBUG] raw decoded: {:?}", &raw_text[..raw_text.len().min(200)]);
}
let text = clean_model_output(&raw_text);
let generated_token_count = generated_tokens.len();
let tps = tok_per_sec(generated_token_count, inference_ms);
write_gguf_trace(
config,
&model_config,
input_token_count,
generated_token_count,
load_ms,
inference_ms,
tps,
used_gpu,
);
Ok(InferenceResult {
text,
tokens,
input_token_count,
generated_token_count,
inference_ms,
tok_per_sec: tps,
load_ms,
format: "GGUF".to_string(),
used_gpu,
})
}
fn print_gguf_verbose_info(
gguf_arch: &str,
model: &crate::gguf::OwnedQuantizedModel,
load_ms: f64,
) {
let arch = match gguf_arch.to_lowercase().as_str() {
"qwen2" | "qwen" => "Qwen2",
"llama" => "LLaMA",
"mistral" => "Mistral",
"phi" | "phi3" => "Phi",
_ => "Transformer",
};
let quant_type = qtype_to_dtype_str(model.lm_head_weight.qtype);
let thread_count = rayon::current_num_threads();
eprintln!(
"Architecture: {} [GGUF: {}] ({} layers, vocab_size={})",
arch, gguf_arch, model.config.num_layers, model.config.vocab_size
);
eprintln!(
"Config: hidden_size={}, context_length={}, quant={}, threads={}",
model.config.hidden_dim, model.config.context_length, quant_type, thread_count
);
eprintln!("Model loaded in {:.1}ms", load_ms);
}
fn write_gguf_trace(
config: &InferenceConfig,
model_config: &crate::gguf::GGUFConfig,
input_token_count: usize,
generated_token_count: usize,
load_ms: f64,
inference_ms: f64,
tps: f64,
used_gpu: bool,
) {
let trace_path = match config.trace_output {
Some(ref p) => p,
None => return,
};
let trace_json = format!(
r#"{{
"version": "1.0",
"timestamp": "{}",
"model": {{
"path": "{}",
"format": "GGUF",
"num_layers": {},
"hidden_dim": {},
"vocab_size": {},
"num_heads": {}
}},
"inference": {{
"input_tokens": {},
"generated_tokens": {},
"load_ms": {:.2},
"inference_ms": {:.2},
"tok_per_sec": {:.2},
"used_gpu": {}
}},
"events": []
}}
"#,
chrono::Utc::now().to_rfc3339(),
config.model_path.display(),
model_config.num_layers,
model_config.hidden_dim,
model_config.vocab_size,
model_config.num_heads,
input_token_count,
generated_token_count,
load_ms,
inference_ms,
tps,
used_gpu
);
if let Err(e) = std::fs::write(trace_path, trace_json) {
eprintln!(
"Warning: Failed to write trace output to {}: {}",
trace_path.display(),
e
);
}
}
#[inline]
fn is_legacy_gguf_quant(qtype: u32) -> bool {
crate::gguf::gpu_unsupported_quant_qtype(qtype)
}
fn model_has_legacy_quant(model: &crate::gguf::OwnedQuantizedModel) -> bool {
model.has_gpu_unsupported_quant()
}
#[inline]
fn log_cpu_backend(verbose: bool, is_legacy: bool) {
if !verbose {
return;
}
if is_legacy {
eprintln!("Backend: CPU (Q4_0 format - GPU Q4_K kernels incompatible)");
} else {
eprintln!("Backend: CPU (SIMD-accelerated)");
}
}
#[cfg(feature = "cuda")]
fn validate_gpu_first_token(
cuda_model: &mut crate::gguf::OwnedQuantizedModelCuda,
_gen_config: &crate::gguf::QuantizedGenerateConfig,
probe_context: &[u32],
) -> bool {
use crate::gguf::OwnedQuantizedKVCache;
if std::env::var("SKIP_PARITY_GATE")
.map(|v| v == "1")
.unwrap_or(false)
{
return true;
}
const PROBE_MAX_CTX: usize = 64;
let (kv_dim, num_layers, probe): (usize, usize, Vec<u32>) = {
let model = cuda_model.model();
let kv_dim =
model.config.num_kv_heads * (model.config.hidden_dim / model.config.num_heads);
let num_layers = model.config.num_layers;
let probe: Vec<u32> = if probe_context.is_empty() {
match model.config.bos_token_id {
Some(id) => vec![id],
None => {
eprintln!("[F2-VALIDATION] no prompt context and BOS unknown — skipping GPU validation");
return true;
},
}
} else {
let start = probe_context.len().saturating_sub(PROBE_MAX_CTX);
probe_context[start..].to_vec()
};
(kv_dim, num_layers, probe)
};
if probe.len() < 2 {
return true;
}
let mut cpu_logits_per_pos: Vec<Vec<f32>> = Vec::with_capacity(probe.len());
{
let model = cuda_model.model();
let mut cpu_cache = OwnedQuantizedKVCache::new(num_layers, kv_dim, probe.len().max(2));
for (pos, &tok) in probe.iter().enumerate() {
match model.forward_single_with_cache(tok, &mut cpu_cache, pos) {
Ok(logits) => cpu_logits_per_pos.push(logits),
Err(_) => return true, }
}
}
cuda_model.executor.reset_kv_cache_gpu();
let mut gpu_logits_per_pos: Vec<Vec<f32>> = Vec::with_capacity(probe.len());
let mut gpu_cache = OwnedQuantizedKVCache::new(num_layers, kv_dim, probe.len().max(2));
for (pos, &tok) in probe.iter().enumerate() {
match cuda_model.forward_gpu_resident(tok, &mut gpu_cache, pos) {
Ok(logits) => gpu_logits_per_pos.push(logits),
Err(_) => {
cuda_model.executor.reset_kv_cache_gpu();
return false; },
}
}
cuda_model.executor.reset_kv_cache_gpu();
let report = f2_multi_position_report(&cpu_logits_per_pos, &gpu_logits_per_pos);
if report.accepted {
if report.pos0_argmax_flip {
eprintln!(
"[F2-VALIDATION] pos0 argmax flip (benign BOS near-tie) ignored; all {} real positions match (min cosine {:.4} >= {F2_GATE_COSINE_MIN}) — accepting GPU path",
probe.len() - 1,
report.min_cosine_real,
);
}
true
} else {
eprintln!(
"[F2-VALIDATION] GPU diverges from CPU at real position {} (argmax {} != {}, cosine {:.4}); min real-position cosine {:.4} — HwDp4a-class mid-context degradation, falling back to CPU",
report.first_bad_pos,
report.first_bad_gpu_argmax,
report.first_bad_cpu_argmax,
report.first_bad_cosine,
report.min_cosine_real,
);
false
}
}
pub(crate) const F2_GATE_COSINE_MIN: f32 = 0.95;
pub(crate) const F2_ARGMAX_MISMATCH_COSINE: f32 = 0.98;
pub(crate) const F2_CATASTROPHIC_COSINE: f32 = 0.90;
#[derive(Debug, Clone)]
pub(crate) struct F2PositionReport {
pub accepted: bool,
pub pos0_argmax_flip: bool,
pub min_cosine_real: f32,
pub first_bad_pos: usize,
pub first_bad_cpu_argmax: u32,
pub first_bad_gpu_argmax: u32,
pub first_bad_cosine: f32,
}
pub(crate) fn f2_multi_position_report(
cpu_per_pos: &[Vec<f32>],
gpu_per_pos: &[Vec<f32>],
) -> F2PositionReport {
let n = cpu_per_pos.len().min(gpu_per_pos.len());
let mut min_cosine_real = 1.0_f32;
let mut pos0_argmax_flip = false;
if n > 0 {
pos0_argmax_flip = argmax_u32(&cpu_per_pos[0]) != argmax_u32(&gpu_per_pos[0]);
}
if n < 2 {
return F2PositionReport {
accepted: true,
pos0_argmax_flip,
min_cosine_real: 1.0,
first_bad_pos: 0,
first_bad_cpu_argmax: 0,
first_bad_gpu_argmax: 0,
first_bad_cosine: 1.0,
};
}
for pos in 1..n {
let cpu = &cpu_per_pos[pos];
let gpu = &gpu_per_pos[pos];
let cosine = logits_cosine_similarity(cpu, gpu);
if cosine < min_cosine_real {
min_cosine_real = cosine;
}
let cpu_argmax = argmax_u32(cpu);
let gpu_argmax = argmax_u32(gpu);
let argmax_mismatch = cpu_argmax != gpu_argmax;
let bad = cosine < F2_GATE_COSINE_MIN
|| (argmax_mismatch && cosine < F2_ARGMAX_MISMATCH_COSINE);
if bad {
return F2PositionReport {
accepted: false,
pos0_argmax_flip,
min_cosine_real,
first_bad_pos: pos,
first_bad_cpu_argmax: cpu_argmax,
first_bad_gpu_argmax: gpu_argmax,
first_bad_cosine: cosine,
};
}
}
F2PositionReport {
accepted: true,
pos0_argmax_flip,
min_cosine_real,
first_bad_pos: 0,
first_bad_cpu_argmax: 0,
first_bad_gpu_argmax: 0,
first_bad_cosine: 1.0,
}
}
pub(crate) fn logits_cosine_similarity(a: &[f32], b: &[f32]) -> f32 {
let mut dot: f64 = 0.0;
let mut norm_a: f64 = 0.0;
let mut norm_b: f64 = 0.0;
for (x, y) in a.iter().zip(b.iter()) {
let x = f64::from(*x);
let y = f64::from(*y);
dot += x * y;
norm_a += x * x;
norm_b += y * y;
}
let denom = norm_a.sqrt() * norm_b.sqrt();
if denom < 1e-12 {
0.0
} else {
(dot / denom) as f32
}
}
pub(crate) fn argmax_u32(logits: &[f32]) -> u32 {
logits
.iter()
.enumerate()
.max_by(|a, b| a.1.partial_cmp(b.1).unwrap_or(std::cmp::Ordering::Equal))
.map_or(0, |(i, _)| i as u32)
}
pub(crate) const GPU_PROBE_NEAR_TIE_REL_GAP: f32 = 0.15;
pub(crate) fn cpu_logit_rel_gap(cpu_logits: &[f32], cpu_argmax: u32, token: u32) -> f32 {
let cpu_max = cpu_logits[cpu_argmax as usize];
let cpu_min = cpu_logits.iter().copied().fold(f32::INFINITY, f32::min);
let at = cpu_logits
.get(token as usize)
.copied()
.unwrap_or(f32::NEG_INFINITY);
let range = (cpu_max - cpu_min).max(f32::MIN_POSITIVE);
(cpu_max - at) / range
}
pub(crate) fn gpu_probe_token_acceptable(cpu_logits: &[f32], cpu_argmax: u32, gpu_first: u32) -> bool {
gpu_first == cpu_argmax
|| cpu_logit_rel_gap(cpu_logits, cpu_argmax, gpu_first) <= GPU_PROBE_NEAR_TIE_REL_GAP
}
#[cfg(test)]
mod pmat919_cosine_gate_tests {
use super::{
argmax_u32, f2_multi_position_report, logits_cosine_similarity, F2_ARGMAX_MISMATCH_COSINE,
F2_CATASTROPHIC_COSINE, F2_GATE_COSINE_MIN,
};
fn vocab_logits(leader: usize, seed: f32) -> Vec<f32> {
(0..256)
.map(|i| {
if i == leader {
20.0
} else {
6.0 + ((i as f32 + seed) * 0.013).sin() * 4.0
}
})
.collect()
}
#[test]
fn correct_fp32_mwv_multi_position_logits_are_accepted() {
let cpu: Vec<Vec<f32>> = vec![
vocab_logits(5, 0.0),
vocab_logits(12, 1.0),
vocab_logits(33, 2.0),
vocab_logits(71, 3.0),
];
let mut gpu = cpu.clone();
for (pos, v) in gpu.iter_mut().enumerate() {
for (i, g) in v.iter_mut().enumerate() {
*g += ((i as f32 * 0.37 + pos as f32).cos()) * (g.abs() * 0.002);
}
}
gpu[0][5] = 19.99;
gpu[0][6] = 20.01;
let report = f2_multi_position_report(&cpu, &gpu);
assert!(report.pos0_argmax_flip, "test must reproduce the benign pos0 flip");
for pos in 1..4 {
assert_eq!(
argmax_u32(&cpu[pos]),
argmax_u32(&gpu[pos]),
"real position {pos} argmax must match for the correct fp32-Mwv path"
);
}
assert!(
report.min_cosine_real >= 0.9998,
"correct fp32-Mwv min real-position cosine {} must be >= 0.9998",
report.min_cosine_real
);
assert!(
report.accepted,
"the F2 gate MUST accept the correct fp32-Mwv default despite the pos0 BOS flip"
);
}
#[test]
fn hwdp4a_mid_position_argmax_mismatch_is_rejected() {
let cpu: Vec<Vec<f32>> = vec![
vocab_logits(5, 0.0),
vocab_logits(12, 1.0),
vocab_logits(33, 2.0), vocab_logits(71, 3.0),
];
let mut gpu = cpu.clone();
gpu[2] = cpu[2]
.iter()
.enumerate()
.map(|(i, &c)| match i {
33 => 16.0, 40 => 21.0, _ => c + ((i as f32 * 1.7).sin() * 0.30 * c.abs().max(2.0)), })
.collect();
let report = f2_multi_position_report(&cpu, &gpu);
assert_ne!(
argmax_u32(&cpu[2]),
argmax_u32(&gpu[2]),
"test must reproduce the HwDp4a mid-position argmax mismatch"
);
let pos2_cos = logits_cosine_similarity(&cpu[2], &gpu[2]);
assert!(
pos2_cos > F2_CATASTROPHIC_COSINE && pos2_cos < F2_ARGMAX_MISMATCH_COSINE,
"this is a REAL-margin (degraded but not catastrophic) case: pos2 cosine {pos2_cos} \
must be in (0.90, 0.98) — argmax mismatch at degraded cosine, the 1.5B symptom"
);
assert!(
!report.accepted,
"the F2 gate MUST REJECT the degraded HwDp4a path (mid-position argmax mismatch at degraded cosine)"
);
assert_eq!(report.first_bad_pos, 2, "the reject must be attributed to pos2");
}
#[test]
fn high_cosine_late_argmax_flip_is_accepted() {
let cpu: Vec<Vec<f32>> = vec![
vocab_logits(5, 0.0),
vocab_logits(12, 1.0),
(0..256)
.map(|i| match i {
33 => 20.00,
34 => 19.99,
_ => 6.0 + ((i as f32 + 2.0) * 0.013).sin() * 4.0,
})
.collect(),
];
let mut gpu = cpu.clone();
gpu[2][33] = 19.99;
gpu[2][34] = 20.00;
let report = f2_multi_position_report(&cpu, &gpu);
assert_ne!(
argmax_u32(&cpu[2]),
argmax_u32(&gpu[2]),
"test must reproduce a late-position argmax flip"
);
let pos2_cos = logits_cosine_similarity(&cpu[2], &gpu[2]);
assert!(
pos2_cos >= F2_ARGMAX_MISMATCH_COSINE,
"benign near-tie pos2 cosine {pos2_cos} must be >= {F2_ARGMAX_MISMATCH_COSINE}"
);
assert!(
report.accepted,
"the F2 gate MUST ACCEPT a high-cosine ({pos2_cos}) argmax flip — it is a benign \
near-tie (the correct fp32-Mwv path), NOT a degradation"
);
}
#[test]
fn pos0_only_bos_near_tie_is_not_false_rejected() {
let near_flat: Vec<f32> = (0..256)
.map(|i| match i {
5 => 10.00,
6 => 9.99,
_ => 9.0 + (i as f32 * 0.5).sin() * 0.4,
})
.collect();
let mut gpu_pos0 = near_flat.clone();
gpu_pos0[5] = 9.99;
gpu_pos0[6] = 10.00;
let cpu: Vec<Vec<f32>> = vec![near_flat, vocab_logits(12, 1.0), vocab_logits(33, 2.0)];
let mut gpu = cpu.clone();
gpu[0] = gpu_pos0;
for pos in 1..3 {
for (i, g) in gpu[pos].iter_mut().enumerate() {
*g += ((i as f32 * 0.21).cos()) * (g.abs() * 0.002);
}
}
let report = f2_multi_position_report(&cpu, &gpu);
assert!(report.pos0_argmax_flip, "test must reproduce the pos0 argmax flip");
assert!(
report.accepted,
"pos0-only BOS near-tie must NOT be false-rejected (all real positions match)"
);
}
#[test]
fn orthogonal_garbage_logits_are_rejected() {
let cpu: Vec<Vec<f32>> = vec![vocab_logits(5, 0.0), vocab_logits(12, 1.0)];
let mut gpu = cpu.clone();
gpu[1] = (0..256)
.map(|i| ((i as f32 * 12.9898).sin() * 43758.547).fract() * 20.0 - 10.0)
.collect();
let pos1_cos = logits_cosine_similarity(&cpu[1], &gpu[1]);
assert!(
pos1_cos < F2_CATASTROPHIC_COSINE,
"garbage pos1 cosine {pos1_cos} must be below the catastrophic floor"
);
let report = f2_multi_position_report(&cpu, &gpu);
assert!(
!report.accepted,
"the F2 gate MUST reject orthogonal garbage (cosine ~0) — fail-closed"
);
}
#[test]
fn f2_threshold_below_load_time_gate() {
const LOAD_TIME_PARITY_GATE_COSINE_MIN: f32 = 0.98;
assert!(
F2_GATE_COSINE_MIN < LOAD_TIME_PARITY_GATE_COSINE_MIN,
"F2 tau {F2_GATE_COSINE_MIN} must be < load-time tau {LOAD_TIME_PARITY_GATE_COSINE_MIN}"
);
assert!(F2_CATASTROPHIC_COSINE < F2_GATE_COSINE_MIN);
assert!(F2_GATE_COSINE_MIN < F2_ARGMAX_MISMATCH_COSINE);
assert!(F2_ARGMAX_MISMATCH_COSINE <= LOAD_TIME_PARITY_GATE_COSINE_MIN);
}
#[test]
fn identical_multi_position_logits_are_accepted() {
let cpu: Vec<Vec<f32>> = vec![vocab_logits(5, 0.0), vocab_logits(12, 1.0), vocab_logits(33, 2.0)];
let report = f2_multi_position_report(&cpu, &cpu.clone());
assert!(report.accepted);
assert!((report.min_cosine_real - 1.0).abs() < 1e-5);
}
#[test]
fn single_token_probe_is_noop_accept() {
let cpu: Vec<Vec<f32>> = vec![vocab_logits(5, 0.0)];
let mut gpu = cpu.clone();
gpu[0][5] = 19.0;
gpu[0][6] = 21.0; let report = f2_multi_position_report(&cpu, &gpu);
assert!(report.accepted, "single-token probe must be a no-op accept");
}
}
#[cfg(test)]
mod pmat742_parity_gate_tests {
use super::{cpu_logit_rel_gap, gpu_probe_token_acceptable, GPU_PROBE_NEAR_TIE_REL_GAP};
const NEAR_FLAT: [f32; 6] = [10.00, 9.99, 9.98, 9.97, 1.00, 0.50];
#[test]
fn near_tie_argmax_flip_is_accepted() {
let rel_gap = cpu_logit_rel_gap(&NEAR_FLAT, 0, 1);
assert!(rel_gap <= GPU_PROBE_NEAR_TIE_REL_GAP, "rel_gap {rel_gap} should be a near-tie");
assert!(gpu_probe_token_acceptable(&NEAR_FLAT, 0, 1));
assert!(gpu_probe_token_acceptable(&NEAR_FLAT, 0, 3));
}
#[test]
fn exact_argmax_match_is_accepted() {
assert!(gpu_probe_token_acceptable(&NEAR_FLAT, 0, 0));
let peaked = [20.0_f32, 1.0, 0.5, 0.1];
assert!(gpu_probe_token_acceptable(&peaked, 0, 0));
}
#[test]
fn real_divergence_is_rejected() {
let peaked = [20.0_f32, 5.0, 0.5, 0.0];
let rel_gap = cpu_logit_rel_gap(&peaked, 0, 3); assert!(rel_gap > GPU_PROBE_NEAR_TIE_REL_GAP, "tail token rel_gap {rel_gap} must exceed tolerance");
assert!(!gpu_probe_token_acceptable(&peaked, 0, 3));
}
#[test]
fn rel_gap_endpoints_are_zero_and_one() {
let logits = [3.0_f32, 2.0, 1.0, 0.0];
assert!((cpu_logit_rel_gap(&logits, 0, 0) - 0.0).abs() < 1e-6); assert!((cpu_logit_rel_gap(&logits, 0, 3) - 1.0).abs() < 1e-6); }
#[test]
fn out_of_range_gpu_token_is_rejected() {
assert!(!gpu_probe_token_acceptable(&NEAR_FLAT, 0, 9999));
}
}