use ferrox_moe::{GatingFunction, MoeLayerConfig};
pub const MODEL_LEVEL_TENSORS_READ_BY_CONFIG: &[&str] = &[
"rope_freqs.weight",
"rope_factors_long.weight",
"rope_factors_short.weight",
];
#[derive(Debug, Clone)]
pub enum AttentionKind {
Gqa,
KimiHybrid(KimiHybridAttention),
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum LayerAttentionKind {
Gqa,
KimiKda,
KimiMla,
}
#[derive(Debug, Clone)]
pub struct KimiHybridAttention {
pub kda_layers: Vec<usize>,
pub full_attn_layers: Vec<usize>,
pub mla: MlaConfig,
pub kda: KdaConfig,
}
#[derive(Debug, Clone)]
pub struct MlaConfig {
pub num_heads: usize,
pub q_lora_rank: usize,
pub kv_lora_rank: usize,
pub qk_nope_head_dim: usize,
pub qk_rope_head_dim: usize,
pub v_head_dim: usize,
pub use_output_gate: bool,
pub rope: Option<MlaRopeConfig>,
}
#[derive(Debug, Clone, Copy)]
pub struct MlaRopeConfig {
pub theta: f32,
}
#[derive(Debug, Clone)]
pub struct KdaConfig {
pub num_heads: usize,
pub head_dim: usize,
pub short_conv_kernel_size: usize,
pub gate_lower_bound: f32,
pub use_full_rank_gate: bool,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum RopeLayout {
Norm,
Neox,
}
impl RopeLayout {
pub fn for_gguf_architecture(arch: &str) -> Self {
match crate::capability::resolve_profile(arch) {
Some(p) => p.rope,
None => RopeLayout::Neox,
}
}
}
#[derive(Debug, Clone)]
pub struct ModelConfig {
pub name: &'static str,
pub n_layers: usize,
pub hidden_dim: usize,
pub n_heads: usize,
pub n_kv_heads: usize,
pub head_dim: usize,
pub vocab_size: usize,
pub rope_theta: f32,
pub rms_norm_eps: f32,
pub moe: MoeLayerConfig,
pub attention: AttentionKind,
pub sliding_window: Option<usize>,
pub n_dense_leading_layers: usize,
pub rope_freqs: Option<Vec<f32>>,
pub rope_freqs_long: Option<Vec<f32>>,
pub rope_freqs_short: Option<Vec<f32>>,
pub rope_orig_ctx: Option<usize>,
pub rope_dim: Option<usize>,
pub rope_attn_factor: f32,
pub rope_layout: RopeLayout,
pub qk_norm_style: crate::capability::QkNormStyle,
pub swa_pattern: Option<usize>,
pub attn_logit_softcap: Option<f32>,
pub final_logit_softcap: Option<f32>,
pub embedding_scale: Option<f32>,
pub attention_scale: Option<f32>,
pub rope_theta_swa: Option<f32>,
pub ffn_activation: FfnActivation,
pub best_effort_fields: &'static [&'static str],
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
pub enum FfnActivation {
#[default]
Swiglu,
SwigluFused,
Gelu,
}
impl ModelConfig {
pub fn apply_runtime_context(&mut self, ctx: usize) {
let (Some(orig), true) = (
self.rope_orig_ctx,
self.rope_freqs_long.is_some() || self.rope_freqs_short.is_some(),
) else {
return;
};
let picked = if ctx > orig {
self.rope_freqs_long.as_ref()
} else {
self.rope_freqs_short.as_ref()
};
if let Some(f) = picked
.or(self.rope_freqs_long.as_ref())
.or(self.rope_freqs_short.as_ref())
{
self.rope_freqs = Some(f.clone());
}
}
pub fn layer_is_dense(&self, layer_idx: usize) -> bool {
layer_idx < self.n_dense_leading_layers
}
pub fn layer_sliding_window(&self, layer_idx: usize) -> Option<usize> {
let window = self.sliding_window?;
match self.swa_pattern {
None => Some(window),
Some(period) if period > 1 => {
if (layer_idx + 1).is_multiple_of(period) {
None
} else {
Some(window)
}
}
Some(_) => Some(window),
}
}
pub fn kv_block_window(&self) -> Option<usize> {
(0..self.n_layers).find_map(|il| self.layer_sliding_window(il))
}
pub fn kv_block_layout(&self, desired_block_size: usize) -> ferrox_core::BlockLayout {
let window = self.kv_block_window();
let block_size = ferrox_core::aligned_block_size(desired_block_size, window);
ferrox_core::BlockLayout::new(block_size, window)
.expect("aligned_block_size returns a size BlockLayout accepts")
}
pub fn layer_rope_theta(&self, layer_idx: usize) -> f32 {
match (self.layer_sliding_window(layer_idx), self.rope_theta_swa) {
(Some(_), Some(theta)) => theta,
_ => self.rope_theta,
}
}
pub fn layer_attention_kind(&self, layer_idx: usize) -> LayerAttentionKind {
match &self.attention {
AttentionKind::Gqa => LayerAttentionKind::Gqa,
AttentionKind::KimiHybrid(hybrid) => {
let one_indexed = layer_idx + 1;
if hybrid.kda_layers.contains(&one_indexed) {
LayerAttentionKind::KimiKda
} else if hybrid.full_attn_layers.contains(&one_indexed) {
LayerAttentionKind::KimiMla
} else {
panic!(
"layer {layer_idx} (1-indexed {one_indexed}) is in neither \
kda_layers nor full_attn_layers"
)
}
}
}
}
pub fn approx_active_params_per_token(&self) -> usize {
let attn_params_per_layer = 4 * self.hidden_dim * self.hidden_dim; let active_experts = self.moe.n_experts_active + self.moe.n_shared_experts;
let expert_params = active_experts * 3 * self.moe.hidden_dim * self.moe.expert_ffn_dim; self.n_layers * (attn_params_per_layer + expert_params)
}
}
pub fn glm_5_2() -> ModelConfig {
ModelConfig {
sliding_window: None,
name: "glm-5.2",
attention: AttentionKind::Gqa,
n_layers: 92,
hidden_dim: 6144,
n_heads: 48,
n_kv_heads: 8,
head_dim: 128,
vocab_size: 151552,
rope_theta: 1_000_000.0,
rms_norm_eps: 1e-5,
moe: MoeLayerConfig {
expert_weights_scale: 1.0,
n_experts: 256,
n_experts_active: 8,
n_shared_experts: 1,
hidden_dim: 6144,
expert_ffn_dim: 2048,
gating: GatingFunction::Sigmoid,
norm_topk_prob: true,
expert_group_count: None, expert_group_used_count: None,},
n_dense_leading_layers: 0,
rope_freqs: None,
rope_attn_factor: 1.0,
rope_dim: None,
rope_freqs_long: None,
rope_freqs_short: None,
rope_orig_ctx: None,
rope_layout: RopeLayout::Neox,
qk_norm_style: crate::capability::QkNormStyle::WholeVector,
swa_pattern: None,
attn_logit_softcap: None,
final_logit_softcap: None,
embedding_scale: None,
attention_scale: None,
rope_theta_swa: None,
ffn_activation: FfnActivation::Swiglu,
best_effort_fields: &[
"n_layers",
"hidden_dim",
"n_heads",
"n_kv_heads",
"head_dim",
"rope_theta",
"moe.expert_ffn_dim",
"moe.n_shared_experts",
"moe.gating (sigmoid assumed from GLM4-MoE-family convention found in ik_llama.cpp source, not confirmed for GLM-5.2 specifically)",
],
}
}
pub fn deepseek_v4_pro() -> ModelConfig {
ModelConfig {
sliding_window: None,
name: "deepseek-v4-pro",
attention: AttentionKind::Gqa,
n_layers: 96,
hidden_dim: 7168,
n_heads: 56,
n_kv_heads: 8,
head_dim: 128,
vocab_size: 129280,
rope_theta: 1_000_000.0,
rms_norm_eps: 1e-6,
moe: MoeLayerConfig {
expert_weights_scale: 1.0,
n_experts: 385,
n_experts_active: 6,
n_shared_experts: 1,
hidden_dim: 7168,
expert_ffn_dim: 2048,
gating: GatingFunction::Sigmoid,
norm_topk_prob: true,
expert_group_count: None, expert_group_used_count: None,},
n_dense_leading_layers: 3,
rope_freqs: None,
rope_attn_factor: 1.0,
rope_dim: None,
rope_freqs_long: None,
rope_freqs_short: None,
rope_orig_ctx: None,
rope_layout: RopeLayout::Norm,
qk_norm_style: crate::capability::QkNormStyle::WholeVector,
swa_pattern: None,
attn_logit_softcap: None,
final_logit_softcap: None,
embedding_scale: None,
attention_scale: None,
rope_theta_swa: None,
ffn_activation: FfnActivation::Swiglu,
best_effort_fields: &[
"n_layers",
"hidden_dim",
"n_heads",
"n_kv_heads",
"head_dim",
"moe.expert_ffn_dim",
"attention_variant (CSA/HCA hybrid NOT implemented, GQA fallback in use)",
"moe.gating (sqrtsoftplus: confirmed for real V4 in llama.cpp PR #24162; this preset still uses Sigmoid on the wrong GQA sketch path)",
"n_dense_leading_layers (3: same confidence basis as gating above, DeepSeek-V3 technical report + ik_llama.cpp source, not confirmed for V4 Pro)",
],
}
}
pub fn kimi_k3() -> ModelConfig {
ModelConfig {
sliding_window: None,
name: "kimi-k3",
n_layers: 93,
hidden_dim: 7168,
n_heads: 96,
n_kv_heads: 96,
head_dim: 192,
vocab_size: 163840,
rope_theta: 1_000_000.0,
rms_norm_eps: 1e-5,
moe: MoeLayerConfig {
expert_weights_scale: 1.0,
n_experts: 896,
n_experts_active: 16,
n_shared_experts: 2,
hidden_dim: 7168,
expert_ffn_dim: 3072,
gating: GatingFunction::Sigmoid,
norm_topk_prob: true,
expert_group_count: None, expert_group_used_count: None,},
n_dense_leading_layers: 1,
attention: AttentionKind::KimiHybrid(KimiHybridAttention {
kda_layers: vec![
1, 2, 3, 5, 6, 7, 9, 10, 11, 13, 14, 15, 17, 18, 19, 21, 22, 23, 25, 26, 27, 29,
30, 31, 33, 34, 35, 37, 38, 39, 41, 42, 43, 45, 46, 47, 49, 50, 51, 53, 54, 55,
57, 58, 59, 61, 62, 63, 65, 66, 67, 69, 70, 71, 73, 74, 75, 77, 78, 79, 81, 82,
83, 85, 86, 87, 89, 90, 91,
],
full_attn_layers: vec![
4, 8, 12, 16, 20, 24, 28, 32, 36, 40, 44, 48, 52, 56, 60, 64, 68, 72, 76, 80, 84,
88, 92, 93,
],
mla: MlaConfig {
num_heads: 96,
q_lora_rank: 1536,
kv_lora_rank: 512,
qk_nope_head_dim: 128,
qk_rope_head_dim: 64,
v_head_dim: 128,
use_output_gate: true,
rope: None,
},
kda: KdaConfig {
num_heads: 96,
head_dim: 128,
short_conv_kernel_size: 4,
gate_lower_bound: -5.0,
use_full_rank_gate: true,
},
}),
rope_freqs: None,
rope_attn_factor: 1.0,
rope_dim: None,
rope_freqs_long: None,
rope_freqs_short: None,
rope_orig_ctx: None,
rope_layout: RopeLayout::Neox,
qk_norm_style: crate::capability::QkNormStyle::WholeVector,
swa_pattern: None,
attn_logit_softcap: None,
final_logit_softcap: None,
embedding_scale: None,
attention_scale: None,
rope_theta_swa: None,
ffn_activation: FfnActivation::Swiglu,
best_effort_fields: &[
"n_heads/n_kv_heads/head_dim (describe the unimplemented Gqa placeholder, not Kimi K3's real MLA/KDA attention -- see `attention` field)",
"rope_theta (not present in the published config; real architecture only applies RoPE to Gated MLA's qk_rope_head_dim slice, which Decoder doesn't implement)",
"entire preset beyond hyperparameters (the real 2.8T-parameter checkpoint has not been run end to end; only real slices have, via the dedicated kimi_decoder/kimi_loader stack -- see docs/MODELS.md)",
],
}
}
pub fn test_dense_fixture() -> ModelConfig {
ModelConfig {
sliding_window: None,
name: "ferrox-test-dense",
attention: AttentionKind::Gqa,
n_layers: 2,
hidden_dim: 32,
n_heads: 4,
n_kv_heads: 2,
head_dim: 8,
vocab_size: 32,
rope_theta: 10000.0,
rms_norm_eps: 1e-5,
moe: MoeLayerConfig {
expert_weights_scale: 1.0,
n_experts: 1,
n_experts_active: 1,
n_shared_experts: 0,
hidden_dim: 32,
expert_ffn_dim: 32,
gating: GatingFunction::Softmax,
norm_topk_prob: true,
expert_group_count: None,
expert_group_used_count: None,
},
n_dense_leading_layers: 0,
rope_freqs: None,
rope_attn_factor: 1.0,
rope_dim: None,
rope_freqs_long: None,
rope_freqs_short: None,
rope_orig_ctx: None,
rope_layout: RopeLayout::Neox,
qk_norm_style: crate::capability::QkNormStyle::WholeVector,
swa_pattern: None,
attn_logit_softcap: None,
final_logit_softcap: None,
embedding_scale: None,
attention_scale: None,
rope_theta_swa: None,
ffn_activation: FfnActivation::Swiglu,
best_effort_fields: &["this is a synthetic test fixture, not a real model"],
}
}
pub fn test_moe_fixture() -> ModelConfig {
ModelConfig {
sliding_window: None,
name: "ferrox-test-moe",
attention: AttentionKind::Gqa,
n_layers: 2,
hidden_dim: 32,
n_heads: 4,
n_kv_heads: 2,
head_dim: 8,
vocab_size: 32,
rope_theta: 10000.0,
rms_norm_eps: 1e-5,
moe: MoeLayerConfig {
expert_weights_scale: 1.0,
n_experts: 4,
n_experts_active: 2,
n_shared_experts: 1,
hidden_dim: 32,
expert_ffn_dim: 32,
gating: GatingFunction::Softmax,
norm_topk_prob: true,
expert_group_count: None,
expert_group_used_count: None,
},
n_dense_leading_layers: 0,
rope_freqs: None,
rope_attn_factor: 1.0,
rope_dim: None,
rope_freqs_long: None,
rope_freqs_short: None,
rope_orig_ctx: None,
rope_layout: RopeLayout::Neox,
qk_norm_style: crate::capability::QkNormStyle::WholeVector,
swa_pattern: None,
attn_logit_softcap: None,
final_logit_softcap: None,
embedding_scale: None,
attention_scale: None,
rope_theta_swa: None,
ffn_activation: FfnActivation::Swiglu,
best_effort_fields: &["this is a synthetic multi-expert test fixture, not a real model"],
}
}
pub fn test_mixed_fixture() -> ModelConfig {
ModelConfig {
sliding_window: None,
name: "ferrox-test-mixed",
attention: AttentionKind::Gqa,
n_layers: 3,
hidden_dim: 32,
n_heads: 4,
n_kv_heads: 2,
head_dim: 8,
vocab_size: 32,
rope_theta: 10000.0,
rms_norm_eps: 1e-5,
moe: MoeLayerConfig {
expert_weights_scale: 1.0,
n_experts: 3,
n_experts_active: 1,
n_shared_experts: 1,
hidden_dim: 32,
expert_ffn_dim: 32,
gating: GatingFunction::Softmax,
norm_topk_prob: true,
expert_group_count: None,
expert_group_used_count: None,
},
n_dense_leading_layers: 1,
rope_freqs: None,
rope_attn_factor: 1.0,
rope_dim: None,
rope_freqs_long: None,
rope_freqs_short: None,
rope_orig_ctx: None,
rope_layout: RopeLayout::Neox,
qk_norm_style: crate::capability::QkNormStyle::WholeVector,
swa_pattern: None,
attn_logit_softcap: None,
final_logit_softcap: None,
embedding_scale: None,
attention_scale: None,
rope_theta_swa: None,
ffn_activation: FfnActivation::Swiglu,
best_effort_fields: &["this is a synthetic mixed dense/MoE test fixture, not a real model"],
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn rope_layout_for_gguf_architecture_matches_llama_cpp() {
assert_eq!(RopeLayout::for_gguf_architecture("llama"), RopeLayout::Norm);
assert_eq!(
RopeLayout::for_gguf_architecture("llama4"),
RopeLayout::Norm
);
assert_eq!(
RopeLayout::for_gguf_architecture("deepseek2"),
RopeLayout::Norm
);
assert_eq!(RopeLayout::for_gguf_architecture("olmoe"), RopeLayout::Neox);
assert_eq!(RopeLayout::for_gguf_architecture("qwen2"), RopeLayout::Neox);
assert_eq!(
RopeLayout::for_gguf_architecture("qwen2moe"),
RopeLayout::Neox
);
assert_eq!(RopeLayout::for_gguf_architecture("qwen3"), RopeLayout::Neox);
assert_eq!(RopeLayout::for_gguf_architecture("phi3"), RopeLayout::Neox);
assert_eq!(
RopeLayout::for_gguf_architecture("gemma3"),
RopeLayout::Neox
);
assert_eq!(
RopeLayout::for_gguf_architecture("totally-unknown-arch"),
RopeLayout::Neox
);
}
#[test]
fn an_alternating_swa_model_constrains_the_block_layout() {
let mut cfg = test_dense_fixture();
cfg.n_layers = 24;
cfg.sliding_window = Some(128);
cfg.swa_pattern = Some(2);
assert!(cfg.layer_sliding_window(1).is_none() || cfg.layer_sliding_window(0).is_none());
assert_eq!(cfg.kv_block_window(), Some(128));
let layout = cfg.kv_block_layout(256);
assert_eq!(layout.block_size(), 128, "256 must round down, not up");
assert_eq!(layout.sliding_window(), Some(128));
assert_eq!(layout.blocks_per_window(), Some(1));
assert_eq!(cfg.kv_block_layout(48).block_size(), 32);
assert_eq!(cfg.kv_block_layout(32).block_size(), 32);
}
#[test]
fn a_gemma3_shaped_model_takes_its_window_from_the_sliding_layers() {
let mut cfg = test_dense_fixture();
cfg.n_layers = 30;
cfg.sliding_window = Some(512);
cfg.swa_pattern = Some(6);
assert!(
cfg.layer_sliding_window(5).is_none(),
"every 6th layer is full-attention"
);
assert_eq!(cfg.kv_block_window(), Some(512));
assert_eq!(cfg.kv_block_layout(100).block_size(), 64);
assert_eq!(cfg.kv_block_layout(64).blocks_per_window(), Some(8));
}
#[test]
fn a_full_causal_model_keeps_the_block_size_it_was_given() {
let mut cfg = test_dense_fixture();
cfg.sliding_window = None;
cfg.swa_pattern = None;
assert_eq!(cfg.kv_block_window(), None);
let layout = cfg.kv_block_layout(48);
assert_eq!(layout.block_size(), 48);
assert_eq!(layout.sliding_window(), None);
}
#[test]
fn all_presets_have_consistent_moe_hidden_dim() {
for cfg in [glm_5_2(), deepseek_v4_pro(), kimi_k3()] {
assert_eq!(
cfg.hidden_dim, cfg.moe.hidden_dim,
"{}: attention hidden_dim and MoE hidden_dim must match",
cfg.name
);
}
}
#[test]
fn all_presets_route_fewer_experts_than_total() {
for cfg in [glm_5_2(), deepseek_v4_pro(), kimi_k3()] {
assert!(
cfg.moe.n_experts_active < cfg.moe.n_experts,
"{}: active experts must be a sparse subset of total experts",
cfg.name
);
}
}
#[test]
fn all_presets_have_divisible_heads() {
for cfg in [glm_5_2(), deepseek_v4_pro(), kimi_k3()] {
assert_eq!(
cfg.n_heads % cfg.n_kv_heads,
0,
"{}: n_heads must be a multiple of n_kv_heads for GQA grouping",
cfg.name
);
}
}
#[test]
fn every_preset_declares_its_uncertain_fields() {
for cfg in [glm_5_2(), deepseek_v4_pro(), kimi_k3()] {
assert!(
!cfg.best_effort_fields.is_empty(),
"{}: must disclose which fields are unconfirmed estimates",
cfg.name
);
}
}
#[test]
fn kimi_k3_hybrid_attention_layers_partition_every_layer_exactly_once() {
let cfg = kimi_k3();
let AttentionKind::KimiHybrid(hybrid) = &cfg.attention else {
panic!("kimi_k3() must use AttentionKind::KimiHybrid");
};
let mut seen = std::collections::HashSet::new();
for &l in hybrid
.kda_layers
.iter()
.chain(hybrid.full_attn_layers.iter())
{
assert!(
(1..=cfg.n_layers).contains(&l),
"layer {l} is out of the published 1..={} range",
cfg.n_layers
);
assert!(
seen.insert(l),
"layer {l} appears in both/either list twice"
);
}
assert_eq!(
hybrid.kda_layers.len() + hybrid.full_attn_layers.len(),
cfg.n_layers,
"every layer must be assigned exactly one of KDA or Gated MLA"
);
assert_eq!(
hybrid.kda_layers.len(),
69,
"expected 69 KDA layers per the published config"
);
assert_eq!(
hybrid.full_attn_layers.len(),
24,
"expected 24 Gated MLA layers per the published config"
);
}
#[test]
fn layer_attention_kind_is_gqa_for_every_layer_of_a_gqa_model() {
let cfg = glm_5_2();
for l in 0..cfg.n_layers {
assert_eq!(cfg.layer_attention_kind(l), LayerAttentionKind::Gqa);
}
}
#[test]
fn layer_attention_kind_classifies_every_kimi_k3_layer_without_panicking() {
let cfg = kimi_k3();
let AttentionKind::KimiHybrid(hybrid) = &cfg.attention else {
panic!("kimi_k3() must use AttentionKind::KimiHybrid");
};
for l in 0..cfg.n_layers {
let kind = cfg.layer_attention_kind(l);
let one_indexed = l + 1;
if hybrid.kda_layers.contains(&one_indexed) {
assert_eq!(kind, LayerAttentionKind::KimiKda);
} else {
assert_eq!(kind, LayerAttentionKind::KimiMla);
}
}
}
#[test]
fn layer_attention_kind_matches_the_real_published_layer_1_and_4() {
let cfg = kimi_k3();
assert_eq!(cfg.layer_attention_kind(0), LayerAttentionKind::KimiKda);
assert_eq!(cfg.layer_attention_kind(3), LayerAttentionKind::KimiMla);
}
#[test]
fn kimi_k3_mla_q_head_dim_matches_gqa_placeholder_head_dim() {
let cfg = kimi_k3();
let AttentionKind::KimiHybrid(hybrid) = &cfg.attention else {
panic!("kimi_k3() must use AttentionKind::KimiHybrid");
};
assert_eq!(
cfg.head_dim,
hybrid.mla.qk_nope_head_dim + hybrid.mla.qk_rope_head_dim
);
}
#[test]
fn approx_active_params_is_nonzero_and_finite_order_of_magnitude() {
for cfg in [glm_5_2(), deepseek_v4_pro(), kimi_k3()] {
let approx = cfg.approx_active_params_per_token();
assert!(
approx > 1_000_000_000 && approx < 1_000_000_000_000,
"{}: approx_active_params_per_token={approx} is outside a plausible range",
cfg.name
);
}
}
}
#[cfg(test)]
mod longrope_tests {
use super::*;
fn cfg_with_factors() -> ModelConfig {
let mut c = test_dense_fixture();
c.rope_orig_ctx = Some(4096);
c.rope_freqs_short = Some(vec![1.0; 48]);
c.rope_freqs_long = Some((0..48).map(|i| 1.0 + i as f32).collect());
c.rope_freqs = None;
c
}
#[test]
fn long_set_only_above_the_original_context() {
let mut c = cfg_with_factors();
c.apply_runtime_context(4096);
assert_eq!(
c.rope_freqs.as_ref().unwrap()[1],
1.0,
"at the threshold, short"
);
let mut c = cfg_with_factors();
c.apply_runtime_context(4097);
assert_eq!(c.rope_freqs.as_ref().unwrap()[1], 2.0, "above it, long");
let mut c = cfg_with_factors();
c.apply_runtime_context(1024);
assert_eq!(c.rope_freqs.as_ref().unwrap()[1], 1.0, "below it, short");
}
#[test]
fn an_explicit_rope_freqs_tensor_is_never_overridden() {
let mut c = test_dense_fixture();
c.rope_freqs = Some(vec![7.0; 48]);
c.rope_orig_ctx = Some(4096);
c.rope_freqs_long = None;
c.rope_freqs_short = None;
c.apply_runtime_context(131072);
assert_eq!(c.rope_freqs.as_ref().unwrap()[0], 7.0);
}
#[test]
fn models_without_longrope_are_untouched() {
let mut c = test_dense_fixture();
c.rope_freqs = None;
c.apply_runtime_context(8192);
assert!(c.rope_freqs.is_none());
assert!(c.rope_orig_ctx.is_none());
}
}