#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum BlockLayoutError {
ZeroBlockSize,
ZeroWindow,
Misaligned {
window: usize,
block_size: usize,
remainder: usize,
},
}
impl std::fmt::Display for BlockLayoutError {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
BlockLayoutError::ZeroBlockSize => write!(f, "KV block size must be positive"),
BlockLayoutError::ZeroWindow => write!(
f,
"sliding window must be positive; a model without SWA has no window at all"
),
BlockLayoutError::Misaligned {
window,
block_size,
remainder,
} => write!(
f,
"KV block size {block_size} does not divide the sliding window {window} \
({window} % {block_size} = {remainder}); a block would straddle the \
window boundary and be either kept too long or dropped too early"
),
}
}
}
impl std::error::Error for BlockLayoutError {}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub struct BlockLayout {
block_size: usize,
sliding_window: Option<usize>,
}
impl BlockLayout {
pub fn new(block_size: usize, sliding_window: Option<usize>) -> Result<Self, BlockLayoutError> {
if block_size == 0 {
return Err(BlockLayoutError::ZeroBlockSize);
}
match sliding_window {
None => Ok(BlockLayout {
block_size,
sliding_window: None,
}),
Some(0) => Err(BlockLayoutError::ZeroWindow),
Some(window) => {
let remainder = window % block_size;
if remainder != 0 {
return Err(BlockLayoutError::Misaligned {
window,
block_size,
remainder,
});
}
Ok(BlockLayout {
block_size,
sliding_window: Some(window),
})
}
}
}
pub fn full_attention(block_size: usize) -> Result<Self, BlockLayoutError> {
Self::new(block_size, None)
}
pub fn block_size(&self) -> usize {
self.block_size
}
pub fn sliding_window(&self) -> Option<usize> {
self.sliding_window
}
pub fn blocks_per_window(&self) -> Option<usize> {
self.sliding_window.map(|w| w / self.block_size)
}
}
pub fn aligned_block_size(desired: usize, window: Option<usize>) -> usize {
let desired = desired.max(1);
let Some(window) = window.filter(|w| *w > 0) else {
return desired;
};
(1..=desired.min(window))
.rev()
.find(|candidate| window.is_multiple_of(*candidate))
.unwrap_or(1)
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn a_block_size_that_does_not_divide_the_window_is_refused() {
let err = BlockLayout::new(48, Some(128)).expect_err("48 does not divide 128");
assert_eq!(
err,
BlockLayoutError::Misaligned {
window: 128,
block_size: 48,
remainder: 32,
}
);
let text = err.to_string();
assert!(text.contains("48"), "{text}");
assert!(text.contains("128"), "{text}");
}
#[test]
fn a_block_size_that_divides_the_window_is_accepted() {
let layout = BlockLayout::new(32, Some(128)).expect("32 divides 128");
assert_eq!(layout.block_size(), 32);
assert_eq!(layout.sliding_window(), Some(128));
assert_eq!(layout.blocks_per_window(), Some(4));
}
#[test]
fn a_block_larger_than_the_window_is_refused() {
assert!(matches!(
BlockLayout::new(256, Some(128)),
Err(BlockLayoutError::Misaligned { .. })
));
assert!(BlockLayout::new(128, Some(128)).is_ok());
}
#[test]
fn a_full_causal_model_constrains_nothing() {
let layout = BlockLayout::full_attention(48).expect("no window, no constraint");
assert_eq!(layout.sliding_window(), None);
assert_eq!(layout.blocks_per_window(), None);
}
#[test]
fn a_zero_window_is_not_the_same_as_no_window() {
assert_eq!(
BlockLayout::new(16, Some(0)),
Err(BlockLayoutError::ZeroWindow)
);
assert!(BlockLayout::new(16, None).is_ok());
}
#[test]
fn a_zero_block_size_is_refused_with_or_without_a_window() {
assert_eq!(
BlockLayout::new(0, None),
Err(BlockLayoutError::ZeroBlockSize)
);
assert_eq!(
BlockLayout::new(0, Some(128)),
Err(BlockLayoutError::ZeroBlockSize)
);
}
#[test]
fn the_aligned_size_is_always_a_size_the_layout_accepts() {
for window in [1usize, 2, 3, 128, 512, 1024, 4096, 4099] {
for desired in [1usize, 7, 16, 31, 32, 100, 128, 256, 5000] {
let size = aligned_block_size(desired, Some(window));
assert!(size > 0 && size <= desired, "{desired}/{window} -> {size}");
BlockLayout::new(size, Some(window)).unwrap_or_else(|e| {
panic!("aligned_block_size({desired}, {window}) = {size} is not valid: {e}")
});
}
}
}
#[test]
fn the_aligned_size_rounds_down_never_up() {
assert_eq!(aligned_block_size(256, Some(128)), 128);
assert_eq!(aligned_block_size(100, Some(512)), 64);
assert_eq!(aligned_block_size(64, Some(512)), 64);
assert_eq!(aligned_block_size(100, Some(4099)), 1);
}
#[test]
fn no_window_leaves_the_desired_size_alone() {
assert_eq!(aligned_block_size(48, None), 48);
assert_eq!(aligned_block_size(0, None), 1);
}
}