use crate::error::{InferenceError, InferenceResult};
use crate::pool::TensorPool;
use kizzasi_core::HiddenState;
use scirs2_core::ndarray::Array1;
use std::collections::VecDeque;
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
pub struct ContextConfig {
pub max_context: usize,
pub store_history: bool,
pub num_layers: usize,
pub hidden_dim: usize,
pub state_dim: usize,
}
impl Default for ContextConfig {
fn default() -> Self {
Self {
max_context: 8192,
store_history: false,
num_layers: 4,
hidden_dim: 256,
state_dim: 16,
}
}
}
impl ContextConfig {
pub fn new() -> Self {
Self::default()
}
pub fn max_context(mut self, size: usize) -> Self {
self.max_context = size;
self
}
pub fn store_history(mut self, store: bool) -> Self {
self.store_history = store;
self
}
pub fn num_layers(mut self, n: usize) -> Self {
self.num_layers = n;
self
}
}
pub struct InferenceContext {
config: ContextConfig,
history: VecDeque<Array1<f32>>,
states: Vec<HiddenState>,
step_count: usize,
pool: Option<TensorPool>,
}
impl InferenceContext {
pub fn new(config: ContextConfig) -> Self {
let states = (0..config.num_layers)
.map(|_| HiddenState::new(config.hidden_dim, config.state_dim))
.collect();
Self {
config,
history: VecDeque::new(),
states,
step_count: 0,
pool: None,
}
}
pub fn with_pool(config: ContextConfig, pool: TensorPool) -> Self {
let states = (0..config.num_layers)
.map(|_| HiddenState::new(config.hidden_dim, config.state_dim))
.collect();
Self {
config,
history: VecDeque::new(),
states,
step_count: 0,
pool: Some(pool),
}
}
pub fn pool(&self) -> Option<&TensorPool> {
self.pool.as_ref()
}
pub fn enable_pooling(&mut self, pool: TensorPool) {
self.pool = Some(pool);
}
pub fn disable_pooling(&mut self) {
self.pool = None;
}
pub fn reset(&mut self) {
self.history.clear();
for state in &mut self.states {
state.reset();
}
self.step_count = 0;
}
pub fn push(&mut self, input: Array1<f32>) {
if self.config.store_history {
if self.history.len() >= self.config.max_context {
self.history.pop_front();
}
self.history.push_back(input);
}
self.step_count += 1;
}
pub fn step_count(&self) -> usize {
self.step_count
}
pub fn history_len(&self) -> usize {
self.history.len()
}
pub fn recent_history(&self, n: usize) -> Vec<&Array1<f32>> {
self.history.iter().rev().take(n).collect()
}
pub fn states(&self) -> &[HiddenState] {
&self.states
}
pub fn states_mut(&mut self) -> &mut [HiddenState] {
&mut self.states
}
pub fn update_state(&mut self, layer: usize, state: HiddenState) -> InferenceResult<()> {
if layer >= self.states.len() {
return Err(InferenceError::DimensionMismatch {
expected: self.states.len(),
got: layer + 1,
});
}
self.states[layer] = state;
Ok(())
}
pub fn config(&self) -> &ContextConfig {
&self.config
}
pub fn is_full(&self) -> bool {
self.step_count >= self.config.max_context
}
pub fn history(&self) -> &VecDeque<Array1<f32>> {
&self.history
}
pub fn trim_history(&mut self, max_len: usize) {
while self.history.len() > max_len {
self.history.pop_front();
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_context_creation() {
let config = ContextConfig::new().max_context(100).num_layers(2);
let ctx = InferenceContext::new(config);
assert_eq!(ctx.step_count(), 0);
assert_eq!(ctx.states().len(), 2);
}
#[test]
fn test_context_push() {
let config = ContextConfig::new().store_history(true).max_context(5);
let mut ctx = InferenceContext::new(config);
for i in 0..10 {
ctx.push(Array1::from_vec(vec![i as f32]));
}
assert_eq!(ctx.step_count(), 10);
assert_eq!(ctx.history_len(), 5); }
#[test]
fn test_context_reset() {
let config = ContextConfig::new().store_history(true);
let mut ctx = InferenceContext::new(config);
ctx.push(Array1::from_vec(vec![1.0]));
ctx.push(Array1::from_vec(vec![2.0]));
assert_eq!(ctx.step_count(), 2);
ctx.reset();
assert_eq!(ctx.step_count(), 0);
assert_eq!(ctx.history_len(), 0);
}
}