1use crate::q_hash;
7
8#[repr(u8)]
9#[derive(Debug, Clone, Copy, PartialEq, Eq)]
10pub enum ScalarType {
11 F32 = 1,
12 F64 = 2,
13 Complex64 = 3,
14}
15
16#[repr(u8)]
17#[derive(Debug, Clone, Copy, PartialEq, Eq)]
18pub enum AccuracyModel {
19 ExactAlgebraic = 1,
20 FixedOrder = 2,
21 EmbeddedEstimate = 3,
22 ResidualControlled = 4,
23 DiagnosticOnly = 5,
24}
25
26#[repr(u8)]
27#[derive(Debug, Clone, Copy, PartialEq, Eq)]
28pub enum StepControl {
29 NotApplicable = 0,
30 Fixed = 1,
31 Adaptive = 2,
32}
33
34#[repr(u8)]
35#[derive(Debug, Clone, Copy, PartialEq, Eq)]
36pub enum AllocationClass {
37 ZeroHeap = 0,
38 CallerWorkspace = 1,
39 ColdHeap = 2,
40}
41
42#[repr(u8)]
43#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
44pub enum Maturity {
45 Foundation = 0,
46 Verified = 1,
47 Certified = 2,
48}
49
50#[repr(transparent)]
51#[derive(Debug, Clone, Copy, PartialEq, Eq)]
52pub struct BackendSet(pub u8);
53
54impl BackendSet {
55 pub const SCALAR_CPU: u8 = 1 << 0;
56 pub const SIMD_CPU: u8 = 1 << 1;
57 pub const GPU: u8 = 1 << 2;
58 pub const WASM: u8 = 1 << 3;
59
60 pub const fn new(bits: u8) -> Self {
61 Self(bits)
62 }
63
64 pub const fn contains(self, backend: u8) -> bool {
65 self.0 & backend == backend
66 }
67}
68
69#[repr(C)]
70#[derive(Debug, Clone, Copy, PartialEq, Eq)]
71pub struct CalculusCapability {
72 pub operation_id: u64,
73 pub name: &'static str,
74 pub minimum_dimension: u16,
75 pub maximum_dimension: u16,
77 pub scalar: ScalarType,
78 pub accuracy: AccuracyModel,
79 pub formal_order: u8,
80 pub step_control: StepControl,
81 pub allocation: AllocationClass,
82 pub backends: BackendSet,
83 pub maturity: Maturity,
84}
85
86const CPU: BackendSet = BackendSet::new(BackendSet::SCALAR_CPU | BackendSet::WASM);
87const SIMD_CPU: BackendSet =
88 BackendSet::new(BackendSet::SCALAR_CPU | BackendSet::SIMD_CPU | BackendSet::WASM);
89const PORTABLE_GPU: BackendSet =
90 BackendSet::new(BackendSet::SCALAR_CPU | BackendSet::GPU | BackendSet::WASM);
91
92pub const CALCULUS_CAPABILITIES: &[CalculusCapability] = &[
93 CalculusCapability {
94 operation_id: q_hash("q42:calculus:simpson-1-3"),
95 name: "composite Simpson 1/3 quadrature",
96 minimum_dimension: 1,
97 maximum_dimension: 1,
98 scalar: ScalarType::F64,
99 accuracy: AccuracyModel::FixedOrder,
100 formal_order: 4,
101 step_control: StepControl::Fixed,
102 allocation: AllocationClass::ZeroHeap,
103 backends: SIMD_CPU,
104 maturity: Maturity::Verified,
105 },
106 CalculusCapability {
107 operation_id: q_hash("q42:calculus:trapezoid"),
108 name: "composite trapezoidal quadrature",
109 minimum_dimension: 1,
110 maximum_dimension: 1,
111 scalar: ScalarType::F64,
112 accuracy: AccuracyModel::FixedOrder,
113 formal_order: 2,
114 step_control: StepControl::Fixed,
115 allocation: AllocationClass::ZeroHeap,
116 backends: CPU,
117 maturity: Maturity::Verified,
118 },
119 CalculusCapability {
120 operation_id: q_hash("q42:calculus:gpu-simpson-1-3-f32"),
121 name: "portable GPU Simpson 1/3 quadrature",
122 minimum_dimension: 1,
123 maximum_dimension: 1,
124 scalar: ScalarType::F32,
125 accuracy: AccuracyModel::FixedOrder,
126 formal_order: 4,
127 step_control: StepControl::Fixed,
128 allocation: AllocationClass::ColdHeap,
129 backends: PORTABLE_GPU,
130 maturity: Maturity::Foundation,
131 },
132 CalculusCapability {
133 operation_id: q_hash("q42:calculus:rk4-static"),
134 name: "fixed-state classical Runge-Kutta",
135 minimum_dimension: 4,
136 maximum_dimension: 4,
137 scalar: ScalarType::F64,
138 accuracy: AccuracyModel::FixedOrder,
139 formal_order: 4,
140 step_control: StepControl::Fixed,
141 allocation: AllocationClass::ZeroHeap,
142 backends: CPU,
143 maturity: Maturity::Verified,
144 },
145 CalculusCapability {
146 operation_id: q_hash("q42:calculus:rk4-dense"),
147 name: "dynamic classical Runge-Kutta",
148 minimum_dimension: 1,
149 maximum_dimension: 0,
150 scalar: ScalarType::F64,
151 accuracy: AccuracyModel::FixedOrder,
152 formal_order: 4,
153 step_control: StepControl::Fixed,
154 allocation: AllocationClass::ColdHeap,
155 backends: CPU,
156 maturity: Maturity::Verified,
157 },
158 CalculusCapability {
159 operation_id: q_hash("q42:calculus:shooting-newton-static"),
160 name: "fixed-state Newton shooting BVP",
161 minimum_dimension: 4,
162 maximum_dimension: 4,
163 scalar: ScalarType::F64,
164 accuracy: AccuracyModel::ResidualControlled,
165 formal_order: 4,
166 step_control: StepControl::Fixed,
167 allocation: AllocationClass::ZeroHeap,
168 backends: CPU,
169 maturity: Maturity::Verified,
170 },
171 CalculusCapability {
172 operation_id: q_hash("q42:calculus:bdf1"),
173 name: "scalar backward Euler",
174 minimum_dimension: 1,
175 maximum_dimension: 1,
176 scalar: ScalarType::F64,
177 accuracy: AccuracyModel::ResidualControlled,
178 formal_order: 1,
179 step_control: StepControl::Fixed,
180 allocation: AllocationClass::ZeroHeap,
181 backends: CPU,
182 maturity: Maturity::Foundation,
183 },
184 CalculusCapability {
185 operation_id: q_hash("q42:calculus:bdf2"),
186 name: "scalar BDF2",
187 minimum_dimension: 1,
188 maximum_dimension: 1,
189 scalar: ScalarType::F64,
190 accuracy: AccuracyModel::ResidualControlled,
191 formal_order: 2,
192 step_control: StepControl::Fixed,
193 allocation: AllocationClass::ZeroHeap,
194 backends: CPU,
195 maturity: Maturity::Foundation,
196 },
197 CalculusCapability {
198 operation_id: q_hash("q42:calculus:symplectic-separable"),
199 name: "scalar separable symplectic integration",
200 minimum_dimension: 2,
201 maximum_dimension: 2,
202 scalar: ScalarType::F64,
203 accuracy: AccuracyModel::FixedOrder,
204 formal_order: 4,
205 step_control: StepControl::Fixed,
206 allocation: AllocationClass::ColdHeap,
207 backends: CPU,
208 maturity: Maturity::Verified,
209 },
210 CalculusCapability {
211 operation_id: q_hash("q42:calculus:forward-sensitivity-scalar"),
212 name: "scalar forward sensitivity",
213 minimum_dimension: 1,
214 maximum_dimension: 1,
215 scalar: ScalarType::F64,
216 accuracy: AccuracyModel::FixedOrder,
217 formal_order: 4,
218 step_control: StepControl::Fixed,
219 allocation: AllocationClass::ColdHeap,
220 backends: CPU,
221 maturity: Maturity::Verified,
222 },
223 CalculusCapability {
224 operation_id: q_hash("q42:calculus:symbolic-multivariable"),
225 name: "symbolic gradient Jacobian and Hessian",
226 minimum_dimension: 1,
227 maximum_dimension: 0,
228 scalar: ScalarType::F64,
229 accuracy: AccuracyModel::ExactAlgebraic,
230 formal_order: 0,
231 step_control: StepControl::NotApplicable,
232 allocation: AllocationClass::ColdHeap,
233 backends: CPU,
234 maturity: Maturity::Verified,
235 },
236];
237
238pub fn capability(operation_id: u64) -> Option<&'static CalculusCapability> {
239 CALCULUS_CAPABILITIES
240 .iter()
241 .find(|entry| entry.operation_id == operation_id)
242}
243
244#[cfg(test)]
245mod tests {
246 use super::*;
247
248 #[test]
249 fn capability_ids_are_unique_and_backend_claims_are_nonempty() {
250 for (index, capability) in CALCULUS_CAPABILITIES.iter().enumerate() {
251 assert_ne!(capability.operation_id, 0);
252 assert_ne!(capability.backends.0, 0);
253 for other in &CALCULUS_CAPABILITIES[index + 1..] {
254 assert_ne!(capability.operation_id, other.operation_id);
255 }
256 }
257 }
258
259 #[test]
260 fn capability_lookup_is_allocation_free_static_discovery() {
261 let id = q_hash("q42:calculus:simpson-1-3");
262 let descriptor = capability(id).unwrap();
263 assert_eq!(descriptor.formal_order, 4);
264 assert_eq!(descriptor.maturity, Maturity::Verified);
265 assert!(descriptor.backends.contains(BackendSet::SIMD_CPU));
266 }
267}