use std::rc::Rc;
use crate::{DType, Engine, Error, Matrix, Result};
use super::{Embedding, Mamba3, Mamba3Config, Mamba3State};
use crate::ml::{Module, ModuleRegistry};
pub struct Empyrealm {
registry: ModuleRegistry,
embedding: Rc<Embedding>,
mixer: Rc<Mamba3>,
model_width: usize,
}
impl Empyrealm {
pub fn with_seed(
engine: &Engine,
vocab_size: usize,
config: Mamba3Config,
seed: u64,
) -> Result<Self> {
let embedding = Rc::new(Embedding::with_seed(
engine,
vocab_size,
config.model_width,
seed,
)?);
let mixer = Rc::new(Mamba3::with_seed(engine, config, seed.wrapping_add(1))?);
let mut registry = ModuleRegistry::new();
registry.register_module("embed", embedding.clone())?;
registry.register_module("mixer", mixer.clone())?;
Ok(Self {
registry,
embedding,
mixer,
model_width: config.model_width,
})
}
pub fn forward(&self, tokens: &Matrix) -> Result<Matrix> {
let [batch, sequence] = tokens.shape() else {
return Err(Error::invalid_argument(
"Empyrealm tokens must have shape [batch, sequence]",
));
};
if !matches!(tokens.dtype(), DType::U8 | DType::U32) || *batch == 0 || *sequence == 0 {
return Err(Error::invalid_argument(
"Empyrealm tokens must be a nonempty U8/U32 Matrix",
));
}
let embedded = self.embedding.forward(tokens)?;
self.forward_embedded(&embedded)
}
pub fn forward_embedded(&self, embedded: &Matrix) -> Result<Matrix> {
let [batch, sequence, width] = embedded.shape() else {
return Err(Error::invalid_argument(
"Empyrealm embedded input must have shape [B, S, D]",
));
};
if embedded.dtype() != DType::F32 || *batch == 0 || *sequence == 0 || *width != self.model_width
{
return Err(Error::invalid_argument(format!(
"Empyrealm requires nonempty F32 [B, S, {}]; found {:?} {}",
self.model_width,
embedded.shape(),
embedded.dtype().token()
)));
}
let mixed = self.mixer.forward(embedded)?;
crate::matrix::add(&mixed, embedded)
}
pub fn new_state(&self, batch_size: usize) -> Result<Mamba3State> {
self.mixer.new_state(batch_size)
}
pub fn step_embedded(&self, embedded: &Matrix, state: &mut Mamba3State) -> Result<Matrix> {
let mixed = self.mixer.step(embedded, state)?;
crate::matrix::add(&mixed, embedded)
}
pub fn mixer(&self) -> &Mamba3 {
&self.mixer
}
}
impl Module for Empyrealm {
fn forward(&self, input: &Matrix) -> Result<Matrix> {
Empyrealm::forward(self, input)
}
fn registry(&self) -> &ModuleRegistry {
&self.registry
}
}