Skip to main content

tract_core/ops/
submodel.rs

1use std::fmt::Debug;
2
3use tract_downcast_rs::Downcast;
4
5use crate::internal::*;
6
7#[derive(Debug, Clone)]
8pub struct SubmodelOp {
9    pub model: Box<dyn InnerModel>,
10    label: String,
11    decluttered: bool,
12    codegen: bool,
13}
14
15impl PartialEq for SubmodelOp {
16    fn eq(&self, _other: &Self) -> bool {
17        false
18    }
19}
20impl Eq for SubmodelOp {}
21
22impl SubmodelOp {
23    pub fn new(model: Box<dyn InnerModel>, label: &str) -> TractResult<Self> {
24        Ok(Self { model, label: label.to_string(), decluttered: false, codegen: false })
25    }
26
27    pub fn iteration_count(&self, _inputs: &[&TypedFact]) -> Option<TDim> {
28        None
29    }
30
31    pub fn model(&self) -> &TypedModel {
32        self.model.as_typed()
33    }
34
35    pub fn label(&self) -> &str {
36        self.label.as_str()
37    }
38}
39
40impl Op for SubmodelOp {
41    fn name(&self) -> StaticName {
42        "SubmodelOp".into()
43    }
44
45    op_as_typed_op!();
46}
47
48impl EvalOp for SubmodelOp {
49    not_out_of_plan!();
50
51    fn state(&self, ctx: &EvalContext) -> TractResult<Option<Box<dyn OpState>>> {
52        self.model.state(ctx)
53    }
54}
55
56impl TypedOp for SubmodelOp {
57    fn output_facts(&self, inputs: &[&TypedFact]) -> TractResult<TVec<TypedFact>> {
58        let facts = self.model.output_facts(inputs)?;
59        Ok(facts)
60    }
61
62    fn declutter(
63        &self,
64        model: &TypedModel,
65        node: &TypedNode,
66    ) -> TractResult<Option<TypedModelPatch>> {
67        if !self.decluttered {
68            let mut new = self.clone();
69            new.model.declutter()?;
70            new.decluttered = true;
71            Ok(Some(TypedModelPatch::replace_single_op(model, node, &node.inputs, new)?))
72        } else {
73            Ok(None)
74        }
75    }
76
77    fn codegen(
78        &self,
79        model: &TypedModel,
80        node: &TypedNode,
81    ) -> TractResult<Option<TypedModelPatch>> {
82        if !self.codegen {
83            let mut new = self.clone();
84            new.model.codegen()?;
85            new.codegen = true;
86            Ok(Some(TypedModelPatch::replace_single_op(model, node, &node.inputs, new)?))
87        } else {
88            Ok(None)
89        }
90    }
91
92    as_op!();
93}
94
95pub trait InnerModel: Debug + dyn_clone::DynClone + Downcast + Sync + Send + 'static {
96    #[allow(unused_variables)]
97    fn output_facts(&self, inputs: &[&TypedFact]) -> TractResult<TVec<TypedFact>>;
98
99    #[allow(unused_variables)]
100    fn state(&self, ctx: &EvalContext) -> TractResult<Option<Box<dyn OpState>>> {
101        Ok(None)
102    }
103
104    #[allow(unused_variables)]
105    fn declutter(&mut self) -> TractResult<()>;
106
107    fn codegen(&mut self) -> TractResult<()>;
108
109    fn as_typed(&self) -> &TypedModel;
110}
111
112dyn_clone::clone_trait_object!(InnerModel);
113downcast_rs::impl_downcast!(InnerModel);
114
115impl InnerModel for TypedModel {
116    fn output_facts(&self, _inputs: &[&TypedFact]) -> TractResult<TVec<TypedFact>> {
117        let facts = self
118            .output_outlets()?
119            .iter()
120            .map(|outlet| self.outlet_fact(*outlet).cloned())
121            .collect::<TractResult<TVec<_>>>()?;
122        Ok(facts)
123    }
124    #[allow(unused_variables)]
125    fn state(&self, ctx: &EvalContext) -> TractResult<Option<Box<dyn OpState>>> {
126        let plan = self.clone().into_runnable()?;
127        let state = plan.spawn()?;
128        Ok(Some(Box::new(state)))
129    }
130
131    #[allow(unused_variables)]
132    fn declutter(&mut self) -> TractResult<()> {
133        self.declutter()
134    }
135
136    fn codegen(&mut self) -> TractResult<()> {
137        self.optimize()
138    }
139
140    fn as_typed(&self) -> &TypedModel {
141        self
142    }
143}
144
145pub type TypedModelOpState = TypedSimpleState;
146
147impl OpState for TypedModelOpState {
148    fn eval(
149        &mut self,
150        _ctx: &EvalContext,
151        _op: &dyn Op,
152        inputs: TVec<TValue>,
153    ) -> TractResult<TVec<TValue>> {
154        let inference_out = self.run(inputs)?;
155        Ok(inference_out)
156    }
157
158    fn reset_lanes(&mut self, _lanes: &[LaneId]) -> TractResult<()> {
159        bail!("Submodel is not lane-aware: its body is a nested state")
160    }
161}