tract_core/ops/array/
broadcast.rs1use 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}