laddu_kernel/ir/
wrappers.rs1use super::*;
2
3fn validate_root_bounds(values: &[KernelValue], root: KernelValueId) -> Result<(), KernelIrError> {
4 if root.index() >= values.len() {
5 return Err(KernelIrError::RootOutOfBounds {
6 root: root.index(),
7 len: values.len(),
8 });
9 }
10 Ok(())
11}
12
13fn validate_scalar_root(
14 values: &[KernelValue],
15 root: KernelValueId,
16 operation: &'static str,
17 message: &'static str,
18) -> Result<(), KernelIrError> {
19 if !values[root.index()].kind.is_scalar() {
20 return Err(KernelInstruction::shape_error(
21 root.index(),
22 operation,
23 message,
24 ));
25 }
26 Ok(())
27}
28
29fn validate_cache_outputs(
30 values: &[KernelValue],
31 outputs: &[KernelValueId],
32) -> Result<(), KernelIrError> {
33 for output in outputs {
34 if output.index() >= values.len() {
35 return Err(KernelIrError::CacheOutputOutOfBounds {
36 output: output.index(),
37 len: values.len(),
38 });
39 }
40 }
41 Ok(())
42}
43
44fn validate_gradient_outputs(
45 values: &[KernelValue],
46 outputs: &[KernelValueId],
47) -> Result<(), KernelIrError> {
48 for output in outputs {
49 let Some(value) = values.get(output.index()) else {
50 return Err(KernelIrError::GradientOutOfBounds {
51 output: output.index(),
52 len: values.len(),
53 });
54 };
55 if value.kind != KernelValueKind::Real {
56 return Err(KernelIrError::GradientKindMismatch {
57 output: output.index(),
58 actual: value.kind,
59 });
60 }
61 }
62 Ok(())
63}
64
65impl ScalarKernelIr {
66 pub fn new(values: Vec<KernelValue>, root: KernelValueId) -> Result<Self, KernelIrError> {
75 let ir = Self { values, root };
76 ir.validate()?;
77 Ok(ir)
78 }
79
80 pub fn validate(&self) -> Result<(), KernelIrError> {
88 if self.values.is_empty() {
89 return validate_graph(&self.values);
90 }
91 validate_root_bounds(&self.values, self.root)?;
92 validate_graph(&self.values)?;
93 validate_scalar_root(
94 &self.values,
95 self.root,
96 "kernel root",
97 "root must be scalar",
98 )
99 }
100
101 pub fn values(&self) -> &[KernelValue] {
103 &self.values
104 }
105
106 pub fn root(&self) -> KernelValueId {
108 self.root
109 }
110}
111
112impl CacheKernelIr {
113 pub fn new(
121 values: Vec<KernelValue>,
122 outputs: Vec<KernelValueId>,
123 ) -> Result<Self, KernelIrError> {
124 if outputs.is_empty() {
125 return Err(KernelIrError::EmptyCacheOutputs);
126 }
127 validate_graph(&values)?;
128 validate_cache_outputs(&values, &outputs)?;
129 Ok(Self { values, outputs })
130 }
131
132 pub fn values(&self) -> &[KernelValue] {
134 &self.values
135 }
136
137 pub fn outputs(&self) -> &[KernelValueId] {
139 &self.outputs
140 }
141}
142
143impl GradientKernelIr {
144 pub fn new(
152 values: Vec<KernelValue>,
153 primal_root: KernelValueId,
154 outputs: Vec<KernelValueId>,
155 component: OutputComponent,
156 ) -> Result<Self, KernelIrError> {
157 let ir = Self {
158 values,
159 primal_root,
160 outputs,
161 component,
162 };
163 ir.validate()?;
164 Ok(ir)
165 }
166
167 pub fn validate(&self) -> Result<(), KernelIrError> {
175 if self.values.is_empty() {
176 return validate_graph(&self.values);
177 }
178 validate_root_bounds(&self.values, self.primal_root)?;
179 validate_graph(&self.values)?;
180 validate_scalar_root(
181 &self.values,
182 self.primal_root,
183 "gradient primal root",
184 "primal root must be scalar",
185 )?;
186 validate_gradient_outputs(&self.values, &self.outputs)
187 }
188
189 pub fn values(&self) -> &[KernelValue] {
191 &self.values
192 }
193
194 pub fn primal_root(&self) -> KernelValueId {
196 self.primal_root
197 }
198
199 pub fn outputs(&self) -> &[KernelValueId] {
201 &self.outputs
202 }
203
204 pub fn component(&self) -> OutputComponent {
206 self.component
207 }
208}