1use anyhow::{Result, ensure};
2use boow::Bow;
3use std::fmt::{Debug, Display};
4use std::path::Path;
5
6#[macro_use]
7pub mod macros;
8pub mod transform;
9
10pub use transform::{FloatPrecision, Pulse, SetSymbols, TransformConfig, TransformSpec};
11
12pub trait NnefInterface: Debug + Sized {
16 type Model: ModelInterface;
17 fn load(&self, path: impl AsRef<Path>) -> Result<Self::Model>;
21
22 fn load_buffer(&self, data: &[u8]) -> Result<Self::Model>;
26
27 fn disable_tract_core(&mut self) -> Result<()>;
30
31 fn enable_tract_extra(&mut self) -> Result<()>;
33
34 fn enable_tract_transformers(&mut self) -> Result<()>;
36
37 fn enable_onnx(&mut self) -> Result<()>;
40
41 fn enable_pulse(&mut self) -> Result<()>;
43
44 fn enable_extended_identifier_syntax(&mut self) -> Result<()>;
49
50 fn without_tract_core(mut self) -> Result<Self> {
52 self.disable_tract_core()?;
53 Ok(self)
54 }
55
56 fn with_tract_extra(mut self) -> Result<Self> {
58 self.enable_tract_extra()?;
59 Ok(self)
60 }
61
62 fn with_tract_transformers(mut self) -> Result<Self> {
64 self.enable_tract_transformers()?;
65 Ok(self)
66 }
67
68 fn with_onnx(mut self) -> Result<Self> {
70 self.enable_onnx()?;
71 Ok(self)
72 }
73
74 fn with_pulse(mut self) -> Result<Self> {
76 self.enable_pulse()?;
77 Ok(self)
78 }
79
80 fn with_extended_identifier_syntax(mut self) -> Result<Self> {
82 self.enable_extended_identifier_syntax()?;
83 Ok(self)
84 }
85
86 fn write_model_to_dir(&self, path: impl AsRef<Path>, model: &Self::Model) -> Result<()>;
90
91 fn write_model_to_tar(&self, path: impl AsRef<Path>, model: &Self::Model) -> Result<()>;
97 fn write_model_to_tar_gz(&self, path: impl AsRef<Path>, model: &Self::Model) -> Result<()>;
98}
99
100#[derive(Debug, Clone, Default, PartialEq, serde::Serialize, serde::Deserialize)]
109#[serde(default, deny_unknown_fields)]
110pub struct OnnxOptions {
111 pub ignore_value_info: bool,
113 pub assertions: Vec<String>,
117}
118
119impl OnnxOptions {
120 pub fn new() -> Self {
121 Self::default()
122 }
123
124 pub fn ignore_value_info(mut self, ignore: bool) -> Self {
126 self.ignore_value_info = ignore;
127 self
128 }
129
130 pub fn assertion(mut self, assertion: impl Into<String>) -> Self {
132 self.assertions.push(assertion.into());
133 self
134 }
135
136 pub fn to_json(&self) -> String {
138 serde_json::to_string(self).expect("OnnxOptions serialization cannot fail")
139 }
140}
141
142#[derive(Debug, Clone)]
144pub struct OnnxOptionsSpec(String);
145
146impl OnnxOptionsSpec {
147 pub fn to_json(&self) -> String {
149 self.0.clone()
150 }
151
152 pub fn parse(&self) -> Result<OnnxOptions> {
154 Ok(serde_json::from_str(&self.0)?)
155 }
156}
157
158impl From<OnnxOptions> for OnnxOptionsSpec {
159 fn from(o: OnnxOptions) -> Self {
160 OnnxOptionsSpec(o.to_json())
161 }
162}
163
164impl From<&str> for OnnxOptionsSpec {
165 fn from(s: &str) -> Self {
166 OnnxOptionsSpec(s.to_string())
167 }
168}
169
170impl From<String> for OnnxOptionsSpec {
171 fn from(s: String) -> Self {
172 OnnxOptionsSpec(s)
173 }
174}
175
176pub trait OnnxInterface: Debug {
177 type InferenceModel: InferenceModelInterface;
178
179 fn load(&self, path: impl AsRef<Path>) -> Result<Self::InferenceModel> {
181 self.load_with_options(path, OnnxOptions::new())
182 }
183
184 fn load_buffer(&self, data: &[u8]) -> Result<Self::InferenceModel> {
186 self.load_buffer_with_options(data, OnnxOptions::new())
187 }
188
189 fn load_with_options(
193 &self,
194 path: impl AsRef<Path>,
195 options: impl Into<OnnxOptionsSpec>,
196 ) -> Result<Self::InferenceModel>;
197
198 fn load_buffer_with_options(
202 &self,
203 data: &[u8],
204 options: impl Into<OnnxOptionsSpec>,
205 ) -> Result<Self::InferenceModel>;
206}
207
208pub trait InferenceModelInterface: Debug + Sized {
209 type Model: ModelInterface;
210 type InferenceFact: InferenceFactInterface;
211 fn input_count(&self) -> Result<usize>;
212 fn output_count(&self) -> Result<usize>;
213 fn input_name(&self, id: usize) -> Result<String>;
214 fn output_name(&self, id: usize) -> Result<String>;
215
216 fn input_fact(&self, id: usize) -> Result<Self::InferenceFact>;
217
218 fn set_input_fact(
219 &mut self,
220 id: usize,
221 fact: impl AsFact<Self, Self::InferenceFact>,
222 ) -> Result<()>;
223
224 fn output_fact(&self, id: usize) -> Result<Self::InferenceFact>;
225
226 fn set_output_fact(
227 &mut self,
228 id: usize,
229 fact: impl AsFact<Self, Self::InferenceFact>,
230 ) -> Result<()>;
231
232 fn analyse(&mut self) -> Result<()>;
233
234 fn into_model(self) -> Result<Self::Model>;
235}
236
237pub trait ModelInterface: Debug + Sized {
238 type Fact: FactInterface;
239 type Runnable: RunnableInterface;
240 type Tensor: TensorInterface;
241 fn input_count(&self) -> Result<usize>;
242
243 fn output_count(&self) -> Result<usize>;
244
245 fn input_name(&self, id: usize) -> Result<String>;
246
247 fn output_name(&self, id: usize) -> Result<String>;
248
249 fn input_fact(&self, id: usize) -> Result<Self::Fact>;
250
251 fn output_fact(&self, id: usize) -> Result<Self::Fact>;
252
253 fn into_runnable(self) -> Result<Self::Runnable>;
254
255 fn transform(&mut self, spec: impl Into<TransformSpec>) -> Result<()>;
256
257 fn property_keys(&self) -> Result<Vec<String>>;
258
259 fn property(&self, name: impl AsRef<str>) -> Result<Self::Tensor>;
260
261 fn parse_fact(&self, spec: &str) -> Result<Self::Fact>;
262
263 fn input_facts(&self) -> Result<impl Iterator<Item = Self::Fact>> {
264 Ok((0..self.input_count()?)
265 .map(|ix| self.input_fact(ix))
266 .collect::<Result<Vec<_>>>()?
267 .into_iter())
268 }
269
270 fn output_facts(&self) -> Result<impl Iterator<Item = Self::Fact>> {
271 Ok((0..self.output_count()?)
272 .map(|ix| self.output_fact(ix))
273 .collect::<Result<Vec<_>>>()?
274 .into_iter())
275 }
276}
277
278pub trait RuntimeInterface: Debug {
279 type Runnable: RunnableInterface;
280 type Model: ModelInterface;
281 fn name(&self) -> Result<String>;
282 fn prepare(&self, model: Self::Model) -> Result<Self::Runnable>;
283}
284
285pub trait RunnableInterface: Debug + Send + Sync {
286 type Tensor: TensorInterface;
287 type Fact: FactInterface;
288 type State: StateInterface<Tensor = Self::Tensor>;
289 fn run(&self, inputs: impl IntoInputs<Self::Tensor>) -> Result<Vec<Self::Tensor>> {
290 self.spawn_state()?.run(inputs.into_inputs()?)
291 }
292
293 fn input_count(&self) -> Result<usize>;
294 fn output_count(&self) -> Result<usize>;
295 fn input_fact(&self, id: usize) -> Result<Self::Fact>;
296
297 fn output_fact(&self, id: usize) -> Result<Self::Fact>;
298
299 fn input_facts(&self) -> Result<impl Iterator<Item = Self::Fact>> {
300 Ok((0..self.input_count()?)
301 .map(|ix| self.input_fact(ix))
302 .collect::<Result<Vec<_>>>()?
303 .into_iter())
304 }
305
306 fn output_facts(&self) -> Result<impl Iterator<Item = Self::Fact>> {
307 Ok((0..self.output_count()?)
308 .map(|ix| self.output_fact(ix))
309 .collect::<Result<Vec<_>>>()?
310 .into_iter())
311 }
312
313 fn property_keys(&self) -> Result<Vec<String>>;
314 fn property(&self, name: impl AsRef<str>) -> Result<Self::Tensor>;
315
316 fn spawn_state(&self) -> Result<Self::State>;
317
318 fn cost_json(&self) -> Result<String>;
319
320 fn profile_json<I, IV, IE>(&self, inputs: Option<I>) -> Result<String>
321 where
322 I: IntoIterator<Item = IV>,
323 IV: TryInto<Self::Tensor, Error = IE>,
324 IE: Into<anyhow::Error> + Debug;
325}
326
327pub trait StateInterface: Debug + Clone + Send {
328 type Fact: FactInterface;
329 type Tensor: TensorInterface;
330
331 fn input_count(&self) -> Result<usize>;
332 fn output_count(&self) -> Result<usize>;
333
334 fn run(&mut self, inputs: impl IntoInputs<Self::Tensor>) -> Result<Vec<Self::Tensor>>;
335}
336
337pub trait TensorInterface: Debug + Sized + Clone + PartialEq + Send + Sync {
338 fn datum_type(&self) -> Result<DatumType>;
339 fn from_bytes(dt: DatumType, shape: &[usize], data: &[u8]) -> Result<Self>;
340 fn as_bytes(&self) -> Result<(DatumType, &[usize], &[u8])>;
341
342 fn from_slice<T: Datum>(shape: &[usize], data: &[T]) -> Result<Self> {
343 let data = unsafe {
344 std::slice::from_raw_parts(data.as_ptr() as *const u8, std::mem::size_of_val(data))
345 };
346 Self::from_bytes(T::datum_type(), shape, data)
347 }
348
349 fn as_slice<T: Datum>(&self) -> Result<&[T]> {
350 let (dt, _shape, data) = self.as_bytes()?;
351 ensure!(T::datum_type() == dt);
352 let data = unsafe {
353 std::slice::from_raw_parts(
354 data.as_ptr() as *const T,
355 data.len() / std::mem::size_of::<T>(),
356 )
357 };
358 Ok(data)
359 }
360
361 fn as_shape_and_slice<T: Datum>(&self) -> Result<(&[usize], &[T])> {
362 let (_, shape, _) = self.as_bytes()?;
363 let data = self.as_slice()?;
364 Ok((shape, data))
365 }
366
367 fn shape(&self) -> Result<&[usize]> {
368 let (_, shape, _) = self.as_bytes()?;
369 Ok(shape)
370 }
371
372 fn convert_to(&self, to: DatumType) -> Result<Self>;
373}
374
375pub trait FactInterface: Debug + Display + Clone {
376 type Dim: DimInterface;
377 fn datum_type(&self) -> Result<DatumType>;
378 fn rank(&self) -> Result<usize>;
379 fn dim(&self, axis: usize) -> Result<Self::Dim>;
380
381 fn dims(&self) -> Result<impl Iterator<Item = Self::Dim>> {
382 Ok((0..self.rank()?).map(|axis| self.dim(axis)).collect::<Result<Vec<_>>>()?.into_iter())
383 }
384}
385
386pub trait DimInterface: Debug + Display + Clone {
387 fn eval(&self, values: impl IntoIterator<Item = (impl AsRef<str>, i64)>) -> Result<Self>;
388 fn to_int64(&self) -> Result<i64>;
389}
390
391pub trait InferenceFactInterface: Debug + Display + Default + Clone {
392 fn empty() -> Result<Self>;
393}
394
395pub trait AsFact<M, F>: Debug {
396 fn as_fact(&self, model: &M) -> Result<Bow<'_, F>>;
397}
398
399#[repr(C)]
400#[derive(Debug, PartialEq, Eq, Copy, Clone)]
401pub enum DatumType {
402 Bool = 0x01,
403 U8 = 0x11,
404 U16 = 0x12,
405 U32 = 0x14,
406 U64 = 0x18,
407 I8 = 0x21,
408 I16 = 0x22,
409 I32 = 0x24,
410 I64 = 0x28,
411 F16 = 0x32,
412 F32 = 0x34,
413 F64 = 0x38,
414 #[cfg(feature = "complex")]
415 ComplexI16 = 0x42,
416 #[cfg(feature = "complex")]
417 ComplexI32 = 0x44,
418 #[cfg(feature = "complex")]
419 ComplexI64 = 0x48,
420 #[cfg(feature = "complex")]
421 ComplexF16 = 0x52,
422 #[cfg(feature = "complex")]
423 ComplexF32 = 0x54,
424 #[cfg(feature = "complex")]
425 ComplexF64 = 0x58,
426}
427
428impl DatumType {
429 pub fn size_of(&self) -> usize {
430 use DatumType::*;
431 match &self {
432 Bool | U8 | I8 => 1,
433 U16 | I16 | F16 => 2,
434 U32 | I32 | F32 => 4,
435 U64 | I64 | F64 => 8,
436 #[cfg(feature = "complex")]
437 ComplexI16 | ComplexF16 => 4,
438 #[cfg(feature = "complex")]
439 ComplexI32 | ComplexF32 => 8,
440 #[cfg(feature = "complex")]
441 ComplexI64 | ComplexF64 => 16,
442 }
443 }
444
445 pub fn is_bool(&self) -> bool {
446 *self == DatumType::Bool
447 }
448
449 pub fn is_number(&self) -> bool {
450 *self != DatumType::Bool
451 }
452
453 pub fn is_unsigned(&self) -> bool {
454 use DatumType::*;
455 *self == U8 || *self == U16 || *self == U32 || *self == U64
456 }
457
458 pub fn is_signed(&self) -> bool {
459 use DatumType::*;
460 *self == I8 || *self == I16 || *self == I32 || *self == I64
461 }
462
463 pub fn is_float(&self) -> bool {
464 use DatumType::*;
465 *self == F16 || *self == F32 || *self == F64
466 }
467}
468
469pub trait Datum {
470 fn datum_type() -> DatumType;
471}
472
473pub trait IntoInputs<V: TensorInterface> {
475 fn into_inputs(self) -> Result<Vec<V>>;
476}
477
478impl<V, T, E, const N: usize> IntoInputs<V> for [T; N]
480where
481 V: TensorInterface,
482 T: TryInto<V, Error = E>,
483 E: Into<anyhow::Error>,
484{
485 fn into_inputs(self) -> Result<Vec<V>> {
486 self.into_iter().map(|v| v.try_into().map_err(|e| e.into())).collect()
487 }
488}
489
490impl<V: TensorInterface> IntoInputs<V> for Vec<V> {
492 fn into_inputs(self) -> Result<Vec<V>> {
493 Ok(self)
494 }
495}
496
497macro_rules! impl_into_inputs_tuple {
499 ($($idx:tt : $T:ident),+) => {
500 impl<V, $($T),+> IntoInputs<V> for ($($T,)+)
501 where
502 V: TensorInterface,
503 $($T: TryInto<V>,
504 <$T as TryInto<V>>::Error: Into<anyhow::Error>,)+
505 {
506 fn into_inputs(self) -> Result<Vec<V>> {
507 Ok(vec![$(self.$idx.try_into().map_err(|e| e.into())?),+])
508 }
509 }
510 };
511}
512
513impl_into_inputs_tuple!(0: A);
514impl_into_inputs_tuple!(0: A, 1: B);
515impl_into_inputs_tuple!(0: A, 1: B, 2: C);
516impl_into_inputs_tuple!(0: A, 1: B, 2: C, 3: D);
517impl_into_inputs_tuple!(0: A, 1: B, 2: C, 3: D, 4: E_);
518impl_into_inputs_tuple!(0: A, 1: B, 2: C, 3: D, 4: E_, 5: F);
519impl_into_inputs_tuple!(0: A, 1: B, 2: C, 3: D, 4: E_, 5: F, 6: G);
520impl_into_inputs_tuple!(0: A, 1: B, 2: C, 3: D, 4: E_, 5: F, 6: G, 7: H);
521
522pub fn tensor<V, T, E>(v: T) -> Result<V>
524where
525 V: TensorInterface,
526 T: TryInto<V, Error = E>,
527 E: Into<anyhow::Error>,
528{
529 v.try_into().map_err(|e| e.into())
530}
531
532macro_rules! impl_datum_type {
533 ($ty:ty, $c_repr:expr) => {
534 impl Datum for $ty {
535 fn datum_type() -> DatumType {
536 $c_repr
537 }
538 }
539 };
540}
541
542impl_datum_type!(bool, DatumType::Bool);
543impl_datum_type!(u8, DatumType::U8);
544impl_datum_type!(u16, DatumType::U16);
545impl_datum_type!(u32, DatumType::U32);
546impl_datum_type!(u64, DatumType::U64);
547impl_datum_type!(i8, DatumType::I8);
548impl_datum_type!(i16, DatumType::I16);
549impl_datum_type!(i32, DatumType::I32);
550impl_datum_type!(i64, DatumType::I64);
551impl_datum_type!(half::f16, DatumType::F16);
552impl_datum_type!(f32, DatumType::F32);
553impl_datum_type!(f64, DatumType::F64);