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