metrale_circuit/checkpoint/
states.rs1use std::collections::BTreeMap;
15
16use super::{ARCHES, BLOCKS, config_maps};
17use crate::circuit_toml::{CircuitError, parse_file};
18use crate::instantiate::state_decl;
19use crate::ir::Section;
20use crate::state::{StateDecl, StateKind};
21
22pub fn recurrent_states(
28 model_type: &str,
29 dims: &BTreeMap<String, u64>,
30) -> Result<Option<Vec<StateDecl>>, CircuitError> {
31 let maps = config_maps().map_err(|e| CircuitError::Parse(e.to_string()))?;
32 let Some(i) = maps
33 .iter()
34 .position(|m| m.serves_engine_model_type(model_type))
35 else {
36 return Ok(None);
37 };
38 let file = parse_file(ARCHES[i].circuit, &BLOCKS)?;
39 let mut templates: Vec<&String> = file
40 .layout
41 .blocks
42 .values()
43 .flatten()
44 .filter(|t| {
45 file.block
46 .get(*t)
47 .is_some_and(|b| b.state.iter().any(|s| s.kind == "recurrent"))
48 })
49 .collect();
50 templates.sort();
51 templates.dedup();
52 let template = match templates.as_slice() {
53 [] => return Ok(Some(Vec::new())),
54 [one] => *one,
55 many => {
56 return Err(CircuitError::Layout(format!(
57 "circuit `{}`: recurrent state in more than one layer block ({many:?})",
58 file.arch
59 )));
60 }
61 };
62 let mut out = Vec::new();
63 let block = &file.block[template].state;
64 for sf in block {
65 let d = state_decl(template, template, None, Section::Main, sf, block, dims)?;
66 if d.kind == StateKind::Recurrent {
67 out.push(d);
68 }
69 }
70 Ok(Some(out))
71}