Skip to main content

tract_core/ops/array/
broadcast.rs

1use crate::internal::*;
2
3#[derive(Debug, Clone, new, Hash, PartialEq, Eq)]
4pub struct MultiBroadcastTo {
5    pub shape: ShapeFact,
6}
7
8impl Op for MultiBroadcastTo {
9    fn name(&self) -> StaticName {
10        "MultiBroadcastTo".into()
11    }
12
13    op_as_typed_op!();
14}
15
16impl EvalOp for MultiBroadcastTo {
17    fn is_stateless(&self) -> bool {
18        true
19    }
20
21    fn eval_with_session(
22        &self,
23        _node_id: usize,
24        session: &TurnState,
25        inputs: TVec<TValue>,
26    ) -> TractResult<TVec<TValue>> {
27        let shape = self.shape.eval_to_usize(&session.resolved_symbols)?;
28        Ok(tvec!(inputs[0].broadcast_to_shape(&shape)?.into_tvalue()))
29    }
30}
31
32impl TypedOp for MultiBroadcastTo {
33    fn output_facts(&self, inputs: &[&TypedFact]) -> TractResult<TVec<TypedFact>> {
34        ensure!(inputs.len() == 1);
35        let mut fact = inputs[0].datum_type.fact(self.shape.clone());
36        fact.uniform.clone_from(&inputs[0].uniform);
37        fact.uniform_tdim = inputs[0].uniform_tdim.clone();
38        Ok(tvec!(fact))
39    }
40
41    fn input_roi(
42        &self,
43        model: &TypedModel,
44        node: &TypedNode,
45    ) -> TractResult<Option<TVec<Option<TDim>>>> {
46        crate::optim::propagate_roi::bubble_roi(model, node)
47    }
48
49    fn concretize_dims(
50        &self,
51        _source: &TypedModel,
52        node: &TypedNode,
53        target: &mut TypedModel,
54        mapping: &HashMap<OutletId, OutletId>,
55        values: &SymbolValues,
56    ) -> TractResult<TVec<OutletId>> {
57        let input = mapping[&node.inputs[0]];
58        let op =
59            Self { shape: self.shape.iter().map(|d| d.eval(values)).collect::<TVec<_>>().into() };
60        target.wire_node(&node.name, op, &[input])
61    }
62
63    fn declutter(
64        &self,
65        model: &TypedModel,
66        node: &TypedNode,
67    ) -> TractResult<Option<TypedModelPatch>> {
68        let input_fact = model.outlet_fact(node.inputs[0])?;
69        if input_fact.shape == self.shape {
70            TypedModelPatch::shunt_one_op(model, node)
71        } else {
72            Ok(None)
73        }
74    }
75
76    as_op!();
77}