1use std::fmt;
3
4use downcast_rs::Downcast;
5
6use dyn_clone;
7use dyn_eq::DynEq;
8
9#[macro_use]
10pub mod macros;
11#[macro_use]
12pub mod element_wise;
13#[macro_use]
14pub mod binary;
15
16pub mod array;
17pub mod cast;
18pub mod change_axes;
19pub mod cnn;
20pub mod downsample;
21pub mod dummy;
22pub mod einsum;
23pub mod fft;
24pub mod gru_cell;
25pub mod identity;
26pub mod konst;
27pub mod logic;
28pub mod lstm_cell;
29pub mod math;
30pub mod matmul;
31pub mod nn;
32pub mod quant;
33pub mod scan;
34pub mod source;
35pub mod submodel;
36pub mod unimpl;
37
38pub use downsample::Downsample;
39pub use memory::*;
40
41use crate::internal::*;
42use crate::optim::OptimizerSession;
43
44#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
46pub enum Validation {
47 Random,
49 Rounding,
51 Accurate,
53}
54
55#[derive(Clone, PartialEq, Eq, Hash, Ord, PartialOrd)]
56pub enum Cost {
57 Div(DatumType),
58 FMA(DatumType),
59 Buffer(DatumType),
60 Params(DatumType),
61 Custom(bool, String),
62}
63
64impl Cost {
65 pub fn is_compute(&self) -> bool {
66 use Cost::*;
67 match self {
68 FMA(_) | Div(_) => true,
69 Buffer(_) | Params(_) => false,
70 Custom(compute, _) => *compute,
71 }
72 }
73}
74
75impl std::fmt::Debug for Cost {
76 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
77 use Cost::*;
78 match self {
79 Div(dt) => write!(f, "Div({dt:?})"),
80 FMA(dt) => write!(f, "FMA({dt:?})"),
81 Buffer(dt) => write!(f, "Buffer({dt:?})"),
82 Params(dt) => write!(f, "Params({dt:?})"),
83 Custom(_, name) => write!(f, "{name}"),
84 }
85 }
86}
87
88pub trait OpState: fmt::Debug + dyn_clone::DynClone + Downcast + Send {
89 fn load_from(
90 &mut self,
91 _: &mut TurnState,
92 _: &mut dyn Iterator<Item = TValue>,
93 ) -> TractResult<()> {
94 Ok(())
95 }
96
97 fn save_to(&self, _: &mut Vec<TValue>) -> TractResult<()> {
98 Ok(())
99 }
100
101 fn init_tensor_fact(&self) -> Option<(String, TypedFact)> {
102 None
103 }
104
105 fn has_init_tensor_fact(&self) -> bool {
113 false
114 }
115
116 fn resolve_symbols(&mut self, _: &mut TurnState) -> TractResult<()> {
117 Ok(())
118 }
119
120 fn eval(
121 &mut self,
122 ctx: &EvalContext,
123 op: &dyn Op,
124 inputs: TVec<TValue>,
125 ) -> TractResult<TVec<TValue>>;
126
127 fn reset_lanes(&mut self, lanes: &[LaneId]) -> TractResult<()>;
133}
134dyn_clone::clone_trait_object!(OpState);
135impl_downcast!(OpState);
136
137pub trait EvalOp {
138 #[allow(unused_variables)]
144 fn eval(&self, ctx: &EvalContext, inputs: TVec<TValue>) -> TractResult<TVec<TValue>> {
145 bail!("{} has neither eval nor state", std::any::type_name::<Self>())
146 }
147
148 fn eval_out_of_plan(&self, inputs: TVec<TValue>) -> TractResult<Option<TVec<TValue>>>;
155
156 #[allow(unused_variables)]
160 fn state(&self, ctx: &EvalContext) -> TractResult<Option<Box<dyn OpState>>> {
161 Ok(None)
162 }
163
164 #[allow(unused_variables)]
168 fn drop_session(&self, session: SessionId, node_id: usize) {}
169}
170
171pub trait Op:
173 fmt::Debug + dyn_clone::DynClone + dyn_eq::DynEq + Send + Sync + 'static + Downcast + EvalOp
174{
175 fn name(&self) -> StaticName;
176
177 fn validation(&self) -> Validation {
180 Validation::Accurate
181 }
182
183 fn info(&self) -> TractResult<Vec<String>> {
186 Ok(vec![])
187 }
188
189 fn as_typed(&self) -> Option<&dyn TypedOp>;
190}
191
192impl_downcast!(Op);
193dyn_clone::clone_trait_object!(Op);
194dyn_eq::eq_trait_object!(Op);
195
196pub trait TypedOp:
197 Op + fmt::Debug + dyn_clone::DynClone + Send + Sync + 'static + Downcast + EvalOp
198{
199 fn as_op(&self) -> &dyn Op;
201
202 fn as_op_mut(&mut self) -> &mut dyn Op;
204
205 fn output_facts(&self, inputs: &[&TypedFact]) -> TractResult<TVec<TypedFact>>;
207
208 #[allow(unused_variables)]
209 fn axes_mapping(
210 &self,
211 inputs: &[&TypedFact],
212 outputs: &[&TypedFact],
213 ) -> TractResult<AxesMapping> {
214 AxesMapping::disconnected(inputs, outputs)
215 }
216
217 fn fuse(&self, _model: &TypedModel, _node: &TypedNode) -> TractResult<Option<TypedModelPatch>> {
219 Ok(None)
220 }
221
222 #[allow(unused_variables)]
224 fn declutter_with_session(
225 &self,
226 session: &mut OptimizerSession,
227 model: &TypedModel,
228 node: &TypedNode,
229 ) -> TractResult<Option<TypedModelPatch>> {
230 self.declutter(model, node)
231 }
232
233 #[allow(unused_variables)]
235 fn declutter(
236 &self,
237 model: &TypedModel,
238 node: &TypedNode,
239 ) -> TractResult<Option<TypedModelPatch>> {
240 Ok(None)
241 }
242
243 fn cost(&self, _inputs: &[&TypedFact]) -> TractResult<TVec<(Cost, TDim)>> {
247 Ok(tvec!())
248 }
249
250 #[allow(unused_variables)]
254 fn input_roi(
255 &self,
256 model: &TypedModel,
257 node: &TypedNode,
258 ) -> TractResult<Option<TVec<Option<TDim>>>> {
259 Ok(None)
260 }
261
262 #[allow(unused_variables)]
263 fn suggested_axis_changes(&self) -> TractResult<TVec<(InOut, AxisOp)>> {
264 Ok(tvec!())
265 }
266
267 #[allow(unused_variables)]
268 fn change_axes(
269 &self,
270 model: &TypedModel,
271 node: &TypedNode,
272 io: InOut,
273 change: &AxisOp,
274 ) -> TractResult<Option<AxisChangeConsequence>> {
275 Ok(None)
276 }
277
278 #[allow(unused_variables)]
279 #[allow(clippy::too_many_arguments)]
280 fn slice(
281 &self,
282 patch: &mut TypedModelPatch,
283 model: &TypedModel,
284 node: &TypedNode,
285 prefix: &str,
286 inputs: &[OutletId],
287 output_axis: usize,
288 start: &TDim,
289 end: &TDim,
290 ) -> TractResult<Option<TVec<OutletId>>> {
291 Ok(None)
292 }
293
294 #[allow(unused_variables)]
298 fn quantize(
299 &self,
300 model: &TypedModel,
301 node: &TypedNode,
302 dt: DatumType,
303 scale: f32,
304 zero_point: i32,
305 ) -> TractResult<Option<Box<dyn TypedOp>>> {
306 Ok(None)
307 }
308
309 #[allow(unused_variables)]
313 fn set_symbols(
314 &self,
315 source: &TypedModel,
316 node: &TypedNode,
317 target: &mut TypedModel,
318 mapping: &HashMap<OutletId, OutletId>,
319 subs: &HashMap<Symbol, TDim>,
320 ) -> TractResult<TVec<OutletId>> {
321 let inputs = node.inputs.iter().map(|i| mapping[i]).collect::<TVec<_>>();
322 target.wire_node(&node.name, node.op.clone(), &inputs)
323 }
324
325 #[allow(unused_variables)]
330 fn codegen(
331 &self,
332 model: &TypedModel,
333 node: &TypedNode,
334 ) -> TractResult<Option<TypedModelPatch>> {
335 Ok(None)
336 }
337
338 #[allow(unused_variables)]
340 fn nested_model_multipliers(&self, inputs: &[&TypedFact]) -> Vec<(StaticName, TDim)> {
341 vec![]
342 }
343}
344
345impl_downcast!(TypedOp);
346dyn_clone::clone_trait_object!(TypedOp);
347dyn_eq::eq_trait_object!(TypedOp);
348
349impl<O: Op> From<O> for Box<dyn Op> {
350 fn from(it: O) -> Box<dyn Op> {
351 Box::new(it)
352 }
353}
354
355impl<O: TypedOp> From<O> for Box<dyn TypedOp> {
356 fn from(it: O) -> Box<dyn TypedOp> {
357 Box::new(it)
358 }
359}
360
361impl<'a> From<&'a Box<dyn TypedOp>> for Box<dyn TypedOp> {
362 fn from(it: &'a Box<dyn TypedOp>) -> Box<dyn TypedOp> {
363 it.clone()
364 }
365}
366
367impl AsRef<dyn Op> for dyn TypedOp {
368 fn as_ref(&self) -> &dyn Op {
369 self.as_op()
370 }
371}
372
373impl AsRef<dyn Op> for Box<dyn TypedOp> {
374 fn as_ref(&self) -> &dyn Op {
375 self.as_op()
376 }
377}
378
379impl AsMut<dyn Op> for dyn TypedOp {
380 fn as_mut(&mut self) -> &mut dyn Op {
381 self.as_op_mut()
382 }
383}
384
385impl AsMut<dyn Op> for Box<dyn TypedOp> {
386 fn as_mut(&mut self) -> &mut dyn Op {
387 self.as_op_mut()
388 }
389}
390
391impl std::fmt::Display for Box<dyn Op> {
392 fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
393 write!(fmt, "{}", self.name())
394 }
395}
396
397impl std::fmt::Display for Box<dyn TypedOp> {
398 fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
399 write!(fmt, "{}", self.name())
400 }
401}