Skip to main content

burn_ir/
operation.rs

1use burn_backend::ops::AttentionModuleOptions;
2use burn_backend::tensor::IndexingUpdateOp;
3use core::hash::Hash;
4use serde::{Deserialize, Serialize};
5
6use alloc::borrow::ToOwned;
7use alloc::boxed::Box;
8use alloc::{string::String, vec::Vec};
9
10use burn_backend::{
11    DType, Distribution, Slice,
12    ops::{
13        ConvOptions, ConvTransposeOptions, DeformConvOptions, GridSampleOptions,
14        GridSamplePaddingMode, InterpolateMode, InterpolateOptions, PadMode,
15    },
16    quantization::QuantScheme,
17};
18
19use crate::{ScalarIr, TensorId, TensorIr, TensorStatus};
20
21/// Visitor for mutating the components of an [`OperationIr`] in place.
22pub trait IrVisitorMut {
23    /// Visit a [`TensorIr`] mutably.
24    fn visit_tensor_mut(&mut self, _tensor: &mut TensorIr) {}
25    /// Visit a [`ScalarIr`] mutably.
26    fn visit_scalar_mut(&mut self, _scalar: &mut ScalarIr) {}
27    /// Visit a slice range mutably.
28    fn visit_range_mut(&mut self, _range: &mut Slice) {}
29}
30
31/// Custom operation in fusion stream, declaring its inputs, outputs and scalar arguments.
32#[derive(Clone, Debug, Hash, PartialEq, Serialize, Deserialize)]
33pub struct CustomOpIr {
34    /// Unique identifier of the operation.
35    pub id: String,
36    /// Input tensors used in the custom operation.
37    pub inputs: Vec<TensorIr>,
38    /// Output tensors used in the custom operation.
39    pub outputs: Vec<TensorIr>,
40    /// Non-tensor scalar arguments, in declaration order.
41    ///
42    /// Carried through fusion's relativization like any other scalar (see the
43    /// `RelativeOps for CustomOpIr` impl), so a cached graph replays with fresh scalar values. The
44    /// remote backend relies on these to ship a custom op's scalar arguments to the server, where
45    /// the registered handler reads them back with [`ScalarIr::elem`].
46    pub scalars: Vec<ScalarIr>,
47}
48
49impl CustomOpIr {
50    /// Create a new custom operation intermediate representation (without scalar arguments).
51    pub fn new(id: &'static str, inputs: &[TensorIr], outputs: &[TensorIr]) -> Self {
52        Self {
53            id: id.to_owned(),
54            inputs: inputs.to_vec(),
55            outputs: outputs.to_vec(),
56            scalars: Vec::new(),
57        }
58    }
59
60    /// Create a new custom operation intermediate representation with scalar arguments.
61    pub fn with_scalars(
62        id: &'static str,
63        inputs: &[TensorIr],
64        outputs: &[TensorIr],
65        scalars: Vec<ScalarIr>,
66    ) -> Self {
67        Self {
68            id: id.to_owned(),
69            inputs: inputs.to_vec(),
70            outputs: outputs.to_vec(),
71            scalars,
72        }
73    }
74
75    /// Cast the intermediate representation, and get the in and output tensors.
76    pub fn as_fixed<const N_IN: usize, const N_OUT: usize>(
77        &self,
78    ) -> (&[TensorIr; N_IN], &[TensorIr; N_OUT]) {
79        (
80            self.inputs.as_slice().try_into().expect(
81                "Wrong number of inputs expected (expected {D}, is {}), check your implementation",
82            ),
83            self.outputs.as_slice().try_into().expect(
84                "Wrong number of outputs expected (expected {D}, is {}), check your implementation",
85            ),
86        )
87    }
88
89    fn inputs(&self) -> Box<dyn Iterator<Item = &TensorIr> + '_> {
90        Box::new(self.inputs.iter())
91    }
92
93    fn outputs(&self) -> Box<dyn Iterator<Item = &TensorIr> + '_> {
94        Box::new(self.outputs.iter())
95    }
96
97    fn visit_mut(&mut self, v: &mut impl IrVisitorMut) {
98        for t in self.inputs.iter_mut() {
99            v.visit_tensor_mut(t);
100        }
101        for t in self.outputs.iter_mut() {
102            v.visit_tensor_mut(t);
103        }
104        for s in self.scalars.iter_mut() {
105            v.visit_scalar_mut(s);
106        }
107    }
108}
109
110/// Describe all tensor operations possible.
111#[derive(Clone, Debug, Hash, PartialEq, Serialize, Deserialize)]
112#[allow(clippy::large_enum_variant)]
113pub enum OperationIr {
114    /// Basic operation on a float tensor.
115    BaseFloat(BaseOperationIr),
116    /// Basic operation on an int tensor.
117    BaseInt(BaseOperationIr),
118    /// Basic operation on a bool tensor.
119    BaseBool(BaseOperationIr),
120    /// Numeric operation on a float tensor.
121    NumericFloat(DType, NumericOperationIr),
122    /// Numeric operation on an int tensor.
123    NumericInt(DType, NumericOperationIr),
124    /// Operation specific to a bool tensor.
125    Bool(BoolOperationIr),
126    /// Operation specific to an int tensor.
127    Int(IntOperationIr),
128    /// Operation specific to a float tensor.
129    Float(DType, FloatOperationIr),
130    /// Module operation.
131    Module(ModuleOperationIr),
132    /// Initialize operation.
133    Init(InitOperationIr),
134    /// A custom operation.
135    Custom(CustomOpIr),
136    /// A tensor is dropped.
137    Drop(TensorIr),
138    /// Operation specific to a distributed tensor.
139    Distributed(DistributedOperationIr),
140    /// Activation function operation (relu, gelu, sigmoid, softmax, …).
141    Activation(ActivationOperationIr),
142}
143
144/// Operation intermediate representation specific to a float tensor.
145#[derive(Clone, Debug, Hash, PartialEq, Serialize, Deserialize)]
146pub enum FloatOperationIr {
147    /// Operation corresponding to [exp](burn_backend::ops::FloatTensorOps::float_exp).
148    Exp(UnaryOpIr),
149    /// Operation corresponding to [log](burn_backend::ops::FloatTensorOps::float_log).
150    Log(UnaryOpIr),
151    /// Operation corresponding to [log1p](burn_backend::ops::FloatTensorOps::float_log1p).
152    Log1p(UnaryOpIr),
153    /// Operation corresponding to [erf](burn_backend::ops::FloatTensorOps::float_erf).
154    Erf(UnaryOpIr),
155    /// Operation corresponding to [powf_scalar](burn_backend::ops::FloatTensorOps::float_powf_scalar).
156    PowfScalar(ScalarOpIr),
157    /// Operation corresponding to [sqrt](burn_backend::ops::FloatTensorOps::float_sqrt).
158    Sqrt(UnaryOpIr),
159    /// Operation corresponding to [cos](burn_backend::ops::FloatTensorOps::float_cos).
160    Cos(UnaryOpIr),
161    /// Operation corresponding to [cosh](burn_backend::ops::FloatTensorOps::float_cosh).
162    Cosh(UnaryOpIr),
163    /// Operation corresponding to [sin](burn_backend::ops::FloatTensorOps::float_sin).
164    Sin(UnaryOpIr),
165    /// Operation corresponding to [sin](burn_backend::ops::FloatTensorOps::float_sinh).
166    Sinh(UnaryOpIr),
167    /// Operation corresponding to [tan](burn_backend::ops::FloatTensorOps::float_tan).
168    Tan(UnaryOpIr),
169    /// Operation corresponding to [tanh](burn_backend::ops::FloatTensorOps::float_tanh).
170    Tanh(UnaryOpIr),
171    /// Operation corresponding to [acos](burn_backend::ops::FloatTensorOps::float_acos).
172    ArcCos(UnaryOpIr),
173    /// Operation corresponding to [acosh](burn_backend::ops::FloatTensorOps::float_acosh).
174    ArcCosh(UnaryOpIr),
175    /// Operation corresponding to [asin](burn_backend::ops::FloatTensorOps::float_asin).
176    ArcSin(UnaryOpIr),
177    /// Operation corresponding to [asinh](burn_backend::ops::FloatTensorOps::float_asinh).
178    ArcSinh(UnaryOpIr),
179    /// Operation corresponding to [atan](burn_backend::ops::FloatTensorOps::float_atan).
180    ArcTan(UnaryOpIr),
181    /// Operation corresponding to [atanh](burn_backend::ops::FloatTensorOps::float_atanh).
182    ArcTanh(UnaryOpIr),
183    /// Operation corresponding to [atan2](burn_backend::ops::FloatTensorOps::float_atan2).
184    ArcTan2(BinaryOpIr),
185    /// Operation corresponding to [round](burn_backend::ops::FloatTensorOps::float_round).
186    Round(UnaryOpIr),
187    /// Operation corresponding to [floor](burn_backend::ops::FloatTensorOps::float_floor).
188    Floor(UnaryOpIr),
189    /// Operation corresponding to [ceil](burn_backend::ops::FloatTensorOps::float_ceil).
190    Ceil(UnaryOpIr),
191    /// Operation corresponding to [trunc](burn_backend::ops::FloatTensorOps::float_trunc).
192    Trunc(UnaryOpIr),
193    /// Operation corresponding to [into_int](burn_backend::ops::FloatTensorOps::float_into_int).
194    IntoInt(CastOpIr),
195    /// Operation corresponding to [matmul](burn_backend::ops::FloatTensorOps::float_matmul).
196    Matmul(MatmulOpIr),
197    /// Operation corresponding to [cross](burn_backend::ops::FloatTensorOps::float_cross).
198    Cross(CrossOpIr),
199    /// Operation corresponding to [random](burn_backend::ops::FloatTensorOps::float_random).
200    Random(RandomOpIr),
201    /// Operation corresponding to [recip](burn_backend::ops::FloatTensorOps::float_recip).
202    Recip(UnaryOpIr),
203    /// Operation corresponding to [is_nan](burn_backend::ops::FloatTensorOps::float_is_nan).
204    IsNan(UnaryOpIr),
205    /// Operation corresponding to [is_nan](burn_backend::ops::FloatTensorOps::float_is_inf).
206    IsInf(UnaryOpIr),
207    /// Operation corresponding to [quantize](burn_backend::ops::QTensorOps::quantize).
208    Quantize(QuantizeOpIr),
209    /// Operation corresponding to [dequantize](burn_backend::ops::QTensorOps::dequantize).
210    Dequantize(DequantizeOpIr),
211    /// Operation corresponding to [grid_sample_2d](burn_backend::ops::FloatTensorOps::float_grid_sample_2d).
212    GridSample2d(GridSample2dOpIr),
213    /// Operation corresponding to [powf](burn_backend::ops::FloatTensorOps::float_powi).
214    Powf(BinaryOpIr),
215    /// Operation corresponding to [hypot](burn_backend::ops::FloatTensorOps::float_hypot).
216    Hypot(BinaryOpIr),
217}
218
219/// Operation intermediate representation specific to module.
220#[derive(Clone, Debug, Hash, PartialEq, Serialize, Deserialize)]
221pub enum ModuleOperationIr {
222    /// Batch normalization with explicitly supplied statistics, corresponding
223    /// to [batch_norm](burn_backend::ops::ModuleOps::batch_norm).
224    BatchNorm(BatchNormOpIr),
225    /// Operation corresponding to [embedding](burn_backend::ops::ModuleOps::embedding).
226    Embedding(EmbeddingOpIr),
227    /// Operation corresponding to [embedding_backward](burn_backend::ops::ModuleOps::embedding_backward).
228    EmbeddingBackward(EmbeddingBackwardOpIr),
229    /// Operation corresponding to [linear](burn_backend::ops::ModuleOps::linear).
230    Linear(LinearOpIr),
231    /// Operation corresponding to [linear_x_backward](burn_backend::ops::ModuleOps::linear_x_backward).
232    LinearXBackward(LinearXBackwardOpIr),
233    /// Operation corresponding to [linear_weight_backward](burn_backend::ops::ModuleOps::linear_weight_backward).
234    LinearWeightBackward(LinearWeightBackwardOpIr),
235    /// Operation corresponding to [linear_bias_backward](burn_backend::ops::ModuleOps::linear_bias_backward).
236    LinearBiasBackward(LinearBiasBackwardOpIr),
237    /// Operation corresponding to [conv1d](burn_backend::ops::ModuleOps::conv1d).
238    Conv1d(Conv1dOpIr),
239    /// Operation corresponding to [conv1d_x_backward](burn_backend::ops::ModuleOps::conv1d_x_backward).
240    Conv1dXBackward(Conv1dXBackwardOpIr),
241    /// Operation corresponding to [conv1d_weight_backward](burn_backend::ops::ModuleOps::conv1d_weight_backward).
242    Conv1dWeightBackward(Conv1dWeightBackwardOpIr),
243    /// Operation corresponding to [conv1d_bias_backward](burn_backend::ops::ModuleOps::conv1d_bias_backward).
244    Conv1dBiasBackward(Conv1dBiasBackwardOpIr),
245    /// Operation corresponding to [conv2d](burn_backend::ops::ModuleOps::conv2d).
246    Conv2d(Conv2dOpIr),
247    /// Operation corresponding to [conv2d_x_backward](burn_backend::ops::ModuleOps::conv2d_x_backward).
248    Conv2dXBackward(Conv2dXBackwardOpIr),
249    /// Operation corresponding to [conv2d_weight_backward](burn_backend::ops::ModuleOps::conv2d_weight_backward).
250    Conv2dWeightBackward(Conv2dWeightBackwardOpIr),
251    /// Operation corresponding to [conv2d_bias_backward](burn_backend::ops::ModuleOps::conv2d_bias_backward).
252    Conv2dBiasBackward(Conv2dBiasBackwardOpIr),
253    /// Operation corresponding to [conv3d](burn_backend::ops::ModuleOps::conv3d).
254    Conv3d(Conv3dOpIr),
255    /// Operation corresponding to [conv3d_x_backward](burn_backend::ops::ModuleOps::conv3d_x_backward).
256    Conv3dXBackward(Conv3dXBackwardOpIr),
257    /// Operation corresponding to [conv3d_weight_backward](burn_backend::ops::ModuleOps::conv3d_weight_backward).
258    Conv3dWeightBackward(Conv3dWeightBackwardOpIr),
259    /// Operation corresponding to [conv3d_bias_backward](burn_backend::ops::ModuleOps::conv3d_bias_backward).
260    Conv3dBiasBackward(Conv3dBiasBackwardOpIr),
261    /// Operation corresponding to [deform_conv2d](burn_backend::ops::ModuleOps::deform_conv2d)
262    DeformableConv2d(Box<DeformConv2dOpIr>),
263    /// Operation corresponding to [deform_conv2d_backward](burn_backend::ops::ModuleOps::deform_conv2d_backward)
264    DeformableConv2dBackward(Box<DeformConv2dBackwardOpIr>),
265    /// Operation corresponding to [conv transpose 1d](burn_backend::ops::ModuleOps::conv_transpose1d).
266    ConvTranspose1d(ConvTranspose1dOpIr),
267    /// Operation corresponding to [conv transpose 2d](burn_backend::ops::ModuleOps::conv_transpose2d).
268    ConvTranspose2d(ConvTranspose2dOpIr),
269    /// Operation corresponding to [conv transpose 3d](burn_backend::ops::ModuleOps::conv_transpose3d).
270    ConvTranspose3d(ConvTranspose3dOpIr),
271    /// Operation corresponding to [avg pool 1d](burn_backend::ops::ModuleOps::avg_pool1d).
272    AvgPool1d(AvgPool1dOpIr),
273    /// Operation corresponding to [avg pool 2d](burn_backend::ops::ModuleOps::avg_pool2d).
274    AvgPool2d(AvgPool2dOpIr),
275    /// Operation corresponding to
276    /// [avg pool 1d backward](burn_backend::ops::ModuleOps::avg_pool1d_backward).
277    AvgPool1dBackward(AvgPool1dBackwardOpIr),
278    /// Operation corresponding to
279    /// [avg pool 2d backward](burn_backend::ops::ModuleOps::avg_pool2d_backward).
280    AvgPool2dBackward(AvgPool2dBackwardOpIr),
281    /// Operation corresponding to
282    /// [adaptive avg pool 1d](burn_backend::ops::ModuleOps::adaptive_avg_pool1d).
283    AdaptiveAvgPool1d(AdaptiveAvgPool1dOpIr),
284    /// Operation corresponding to
285    /// [adaptive avg pool 2d](burn_backend::ops::ModuleOps::adaptive_avg_pool2d).
286    AdaptiveAvgPool2d(AdaptiveAvgPool2dOpIr),
287    /// Operation corresponding to
288    /// [adaptive avg pool 1d backward](burn_backend::ops::ModuleOps::adaptive_avg_pool1d_backward).
289    AdaptiveAvgPool1dBackward(AdaptiveAvgPool1dBackwardOpIr),
290    /// Operation corresponding to
291    /// [adaptive avg pool 2d backward](burn_backend::ops::ModuleOps::adaptive_avg_pool2d_backward).
292    AdaptiveAvgPool2dBackward(AdaptiveAvgPool2dBackwardOpIr),
293    /// Operation corresponding to
294    /// [adaptive avg pool 3d](burn_backend::ops::ModuleOps::adaptive_avg_pool3d).
295    AdaptiveAvgPool3d(AdaptiveAvgPool3dOpIr),
296    /// Operation corresponding to
297    /// [adaptive avg pool 3d backward](burn_backend::ops::ModuleOps::adaptive_avg_pool3d_backward).
298    AdaptiveAvgPool3dBackward(AdaptiveAvgPool3dBackwardOpIr),
299    /// Operation corresponding to
300    /// [max pool 1d](burn_backend::ops::ModuleOps::max_pool1d).
301    MaxPool1d(MaxPool1dOpIr),
302    /// Operation corresponding to
303    /// [max pool 1d with indices](burn_backend::ops::ModuleOps::max_pool1d_with_indices).
304    MaxPool1dWithIndices(MaxPool1dWithIndicesOpIr),
305    /// Operation corresponding to
306    /// [max pool 1d with indices backward](burn_backend::ops::ModuleOps::max_pool1d_with_indices_backward).
307    MaxPool1dWithIndicesBackward(MaxPool1dWithIndicesBackwardOpIr),
308    /// Operation corresponding to
309    /// [max pool 2d](burn_backend::ops::ModuleOps::max_pool1d).
310    MaxPool2d(MaxPool2dOpIr),
311    /// Operation corresponding to
312    /// [max pool 2d with indices](burn_backend::ops::ModuleOps::max_pool2d_with_indices).
313    MaxPool2dWithIndices(MaxPool2dWithIndicesOpIr),
314    /// Operation corresponding to
315    /// [max pool 2d with indices backward](burn_backend::ops::ModuleOps::max_pool2d_with_indices_backward).
316    MaxPool2dWithIndicesBackward(MaxPool2dWithIndicesBackwardOpIr),
317    /// Operation corresponding to [interpolate](burn_backend::ops::ModuleOps::interpolate).
318    Interpolate(InterpolateOpIr),
319    /// Operation corresponding to [interpolate backward](burn_backend::ops::ModuleOps::interpolate_backward).
320    InterpolateBackward(InterpolateBackwardOpIr),
321    /// Operation corresponding to [attention](burn_backend::ops::ModuleOps::attention).
322    Attention(AttentionOpIr),
323    /// Operation corresponding to [ctc_loss](burn_backend::ops::ModuleOps::ctc_loss).
324    CtcLoss(CtcLossOpIr),
325    /// Operation corresponding to
326    /// [ctc_loss_backward](burn_backend::ops::ModuleOps::ctc_loss_backward).
327    CtcLossBackward(CtcLossBackwardOpIr),
328    /// Operation corresponding to [layer_norm](burn_backend::ops::ModuleOps::layer_norm).
329    LayerNorm(LayerNormOpIr),
330    /// Operation corresponding to [unfold4d](burn_backend::ops::ModuleOps::unfold4d).
331    Unfold4d(Unfold4dOpIr),
332    /// Operation corresponding to
333    /// [conv_transpose1d_weight_backward](burn_backend::ops::ModuleOps::conv_transpose1d_weight_backward).
334    ConvTranspose1dWeightBackward(ConvTranspose1dWeightBackwardOpIr),
335    /// Operation corresponding to
336    /// [conv_transpose1d_bias_backward](burn_backend::ops::ModuleOps::conv_transpose1d_bias_backward).
337    ConvTranspose1dBiasBackward(ConvTranspose1dBiasBackwardOpIr),
338    /// Operation corresponding to
339    /// [conv_transpose2d_weight_backward](burn_backend::ops::ModuleOps::conv_transpose2d_weight_backward).
340    ConvTranspose2dWeightBackward(ConvTranspose2dWeightBackwardOpIr),
341    /// Operation corresponding to
342    /// [conv_transpose2d_bias_backward](burn_backend::ops::ModuleOps::conv_transpose2d_bias_backward).
343    ConvTranspose2dBiasBackward(ConvTranspose2dBiasBackwardOpIr),
344    /// Operation corresponding to
345    /// [conv_transpose3d_weight_backward](burn_backend::ops::ModuleOps::conv_transpose3d_weight_backward).
346    ConvTranspose3dWeightBackward(ConvTranspose3dWeightBackwardOpIr),
347    /// Operation corresponding to
348    /// [conv_transpose3d_bias_backward](burn_backend::ops::ModuleOps::conv_transpose3d_bias_backward).
349    ConvTranspose3dBiasBackward(ConvTranspose3dBiasBackwardOpIr),
350}
351
352/// Basic operations that can be done on any tensor type.
353#[derive(Clone, Debug, Hash, PartialEq, Serialize, Deserialize)]
354pub enum BaseOperationIr {
355    /// Operation corresponding to:
356    ///
357    /// Float => [reshape](burn_backend::ops::FloatTensorOps::float_reshape).
358    /// Int => [reshape](burn_backend::ops::IntTensorOps::int_reshape).
359    /// Bool => [reshape](burn_backend::ops::BoolTensorOps::bool_reshape).
360    Reshape(ShapeOpIr),
361
362    /// Operation corresponding to:
363    ///
364    /// Float => [swap_dims](burn_backend::ops::FloatTensorOps::float_swap_dims).
365    /// Int => [swap_dims](burn_backend::ops::IntTensorOps::int_swap_dims).
366    /// Bool => [swap_dims](burn_backend::ops::BoolTensorOps::bool_swap_dims).
367    SwapDims(SwapDimsOpIr),
368
369    /// Operation corresponding to:
370    ///
371    /// Float => [permute](burn_backend::ops::FloatTensorOps::float_permute).
372    /// Int => [permute](burn_backend::ops::IntTensorOps::int_permute).
373    /// Bool => [permute](burn_backend::ops::BoolTensorOps::bool_permute).
374    Permute(PermuteOpIr),
375
376    /// Operation corresponding to:
377    /// Float => [flip](burn_backend::ops::FloatTensorOps::float_flip).
378    /// Int => [flip](burn_backend::ops::IntTensorOps::int_flip).
379    /// Bool => [flip](burn_backend::ops::BoolTensorOps::bool_flip).
380    Flip(FlipOpIr),
381
382    /// Operation corresponding to:
383    ///
384    /// Float => [expand](burn_backend::ops::FloatTensorOps::float_expand).
385    /// Int => [expand](burn_backend::ops::IntTensorOps::int_expand).
386    /// Bool => [expand](burn_backend::ops::BoolTensorOps::bool_expand).
387    Expand(ShapeOpIr),
388
389    /// Unfold windows along an axis.
390    ///
391    Unfold(UnfoldOpIr),
392
393    /// Operation corresponding to:
394    ///
395    /// Float => [slice](burn_backend::ops::FloatTensorOps::float_slice).
396    /// Int => [slice](burn_backend::ops::IntTensorOps::int_slice).
397    /// Bool => [slice](burn_backend::ops::BoolTensorOps::bool_slice).
398    Slice(SliceOpIr),
399    /// Operation corresponding to:
400    ///
401    /// Float => [slice assign](burn_backend::ops::FloatTensorOps::float_slice_assign).
402    /// Int => [slice assign](burn_backend::ops::IntTensorOps::int_slice_assign).
403    /// Bool => [slice assign](burn_backend::ops::BoolTensorOps::bool_slice_assign).
404    SliceAssign(SliceAssignOpIr),
405    /// Operation corresponding to:
406    ///
407    /// Float => [select](burn_backend::ops::FloatTensorOps::float_select).
408    /// Int => [select](burn_backend::ops::IntTensorOps::int_select).
409    /// Bool => [select](burn_backend::ops::BoolTensorOps::bool_select).
410    Select(SelectOpIr),
411    /// Operation corresponding to:
412    ///
413    /// Float => [select assign](burn_backend::ops::FloatTensorOps::float_select_assign).
414    /// Int => [select assign](burn_backend::ops::IntTensorOps::int_select_assign).
415    /// Bool => [select assign](burn_backend::ops::BoolTensorOps::bool_select_or).
416    SelectAssign(SelectAssignOpIr),
417    /// Operation corresponding to:
418    ///
419    /// Float => [mask where](burn_backend::ops::FloatTensorOps::float_mask_where).
420    /// Int => [mask where](burn_backend::ops::IntTensorOps::int_mask_where).
421    /// Bool => [mask where](burn_backend::ops::BoolTensorOps::bool_mask_where).
422    MaskWhere(MaskWhereOpIr),
423    /// Operation corresponding to:
424    ///
425    /// Float => [mask fill](burn_backend::ops::FloatTensorOps::float_mask_fill).
426    /// Int => [mask fill](burn_backend::ops::IntTensorOps::int_mask_fill).
427    /// Bool => [mask fill](burn_backend::ops::BoolTensorOps::bool_mask_fill).
428    MaskFill(MaskFillOpIr),
429    /// Operation corresponding to:
430    ///
431    /// Float => [gather](burn_backend::ops::FloatTensorOps::float_gather).
432    /// Int => [gather](burn_backend::ops::IntTensorOps::int_gather).
433    /// Bool => [gather](burn_backend::ops::BoolTensorOps::bool_gather).
434    Gather(GatherOpIr),
435    /// Operation corresponding to:
436    ///
437    /// Float => [scatter](burn_backend::ops::FloatTensorOps::float_scatter).
438    /// Int => [scatter](burn_backend::ops::IntTensorOps::int_scatter).
439    /// Bool => [scatter](burn_backend::ops::BoolTensorOps::bool_scatter_or).
440    Scatter(ScatterOpIr),
441    /// Multi-dimensional scatter operation.
442    ScatterNd(ScatterNdOpIr),
443    /// Multi-dimensional gather operation.
444    GatherNd(GatherNdOpIr),
445    /// Operation corresponding to:
446    ///
447    /// Float => [equal](burn_backend::ops::FloatTensorOps::float_equal).
448    /// Int => [equal](burn_backend::ops::IntTensorOps::int_equal).
449    /// Bool => [equal](burn_backend::ops::BoolTensorOps::bool_equal).
450    Equal(BinaryOpIr),
451    /// Operation corresponding to:
452    ///
453    /// Float => [equal elem](burn_backend::ops::FloatTensorOps::float_equal_elem).
454    /// Int => [equal elem](burn_backend::ops::IntTensorOps::int_equal_elem).
455    /// Bool => [equal elem](burn_backend::ops::BoolTensorOps::bool_equal_elem).
456    EqualElem(ScalarOpIr),
457    /// Operation corresponding to:
458    ///
459    /// Float => [repeat dim](burn_backend::ops::FloatTensorOps::float_repeat_dim).
460    /// Int => [repeat dim](burn_backend::ops::IntTensorOps::int_repeat_dim).
461    /// Bool => [repeat dim](burn_backend::ops::BoolTensorOps::bool_repeat_dim).
462    RepeatDim(RepeatDimOpIr),
463    /// Operation corresponding to:
464    ///
465    /// Float => [cat](burn_backend::ops::FloatTensorOps::float_cat).
466    /// Int => [cat](burn_backend::ops::IntTensorOps::int_cat).
467    /// Bool => [cat](burn_backend::ops::BoolTensorOps::bool_cat).
468    Cat(CatOpIr),
469    /// Cast operation, no direct operation and should be supported by fusion backend.
470    Cast(CastOpIr),
471    /// Operation corresponding to:
472    ///
473    /// Float => [empty](burn_backend::ops::FloatTensorOps::float_empty).
474    /// Int => [empty](burn_backend::ops::IntTensorOps::int_empty).
475    /// Bool => [empty](burn_backend::ops::BoolTensorOps::bool_empty).
476    Empty(CreationOpIr),
477    /// Operation corresponding to:
478    ///
479    /// Float => [ones](burn_backend::ops::FloatTensorOps::float_ones).
480    /// Int => [ones](burn_backend::ops::IntTensorOps::int_ones).
481    /// Bool => [ones](burn_backend::ops::BoolTensorOps::bool_ones).
482    Ones(CreationOpIr),
483    /// Operation corresponding to:
484    ///
485    /// Float => [zeros](burn_backend::ops::FloatTensorOps::float_zeros).
486    /// Int => [zeros](burn_backend::ops::IntTensorOps::int_zeros).
487    /// Bool => [zeros](burn_backend::ops::BoolTensorOps::bool_zeros).
488    Zeros(CreationOpIr),
489    /// Operation corresponding to:
490    ///
491    /// Float => [not_equal](burn_backend::ops::FloatTensorOps::float_not_equal).
492    /// Int => [not_equal](burn_backend::ops::IntTensorOps::int_not_equal).
493    /// Bool => [not_equal](burn_backend::ops::BoolTensorOps::bool_not_equal).
494    NotEqual(BinaryOpIr),
495    /// Operation corresponding to:
496    ///
497    /// Float => [not_equal_elem](burn_backend::ops::FloatTensorOps::float_not_equal_elem).
498    /// Int => [not_equal_elem](burn_backend::ops::IntTensorOps::int_not_equal_elem).
499    /// Bool => [not_equal_elem](burn_backend::ops::BoolTensorOps::bool_not_equal_elem).
500    NotEqualElem(ScalarOpIr),
501    /// Reduce-`all` over the input tensor.
502    ///
503    /// Float/Int input is treated as a non-zero check; bool input is the value itself.
504    /// Output is a single-element bool tensor.
505    All(ReduceOpIr),
506    /// Reduce-`any` over the input tensor.
507    Any(ReduceOpIr),
508    /// Reduce-`all` along a dim.
509    AllDim(ReduceDimOpIr),
510    /// Reduce-`any` along a dim.
511    AnyDim(ReduceDimOpIr),
512}
513
514/// Numeric operations on int and float tensors.
515#[derive(Clone, Debug, Hash, PartialEq, Serialize, Deserialize)]
516pub enum NumericOperationIr {
517    /// Operation corresponding to:
518    ///
519    /// Float => [add](burn_backend::ops::FloatTensorOps::float_add).
520    /// Int => [add](burn_backend::ops::IntTensorOps::int_add).
521    Add(BinaryOpIr),
522    /// Operation corresponding to:
523    ///
524    /// Float => [add scalar](burn_backend::ops::FloatTensorOps::float_add_scalar).
525    /// Int => [add scalar](burn_backend::ops::IntTensorOps::int_add_scalar).
526    AddScalar(ScalarOpIr),
527    /// Operation corresponding to:
528    ///
529    /// Float => [sub](burn_backend::ops::FloatTensorOps::float_sub).
530    /// Int => [sub](burn_backend::ops::IntTensorOps::int_sub).
531    Sub(BinaryOpIr),
532    /// Operation corresponding to:
533    ///
534    /// Float => [sub scalar](burn_backend::ops::FloatTensorOps::float_sub_scalar).
535    /// Int => [sub scalar](burn_backend::ops::IntTensorOps::int_sub_scalar).
536    SubScalar(ScalarOpIr),
537    /// Operation corresponding to:
538    ///
539    /// Float => [div](burn_backend::ops::FloatTensorOps::float_div).
540    /// Int => [div](burn_backend::ops::IntTensorOps::int_div).
541    Div(BinaryOpIr),
542    /// Operation corresponding to:
543    ///
544    /// Float => [div scalar](burn_backend::ops::FloatTensorOps::float_div_scalar).
545    /// Int => [div scalar](burn_backend::ops::IntTensorOps::int_div_scalar).
546    DivScalar(ScalarOpIr),
547    /// Operation corresponding to:
548    ///
549    /// Float => [rem](burn_backend::ops::FloatTensorOps::float_remainder).
550    /// Int => [rem](burn_backend::ops::IntTensorOps::int_remainder).
551    Rem(BinaryOpIr),
552    /// Operation corresponding to:
553    ///
554    /// Float => [rem scalar](burn_backend::ops::FloatTensorOps::float_remainder_scalar).
555    /// Int => [rem scalar](burn_backend::ops::IntTensorOps::int_remainder_scalar).
556    RemScalar(ScalarOpIr),
557    /// Operation corresponding to:
558    ///
559    /// Float => [mul](burn_backend::ops::FloatTensorOps::float_mul).
560    /// Int => [mul](burn_backend::ops::IntTensorOps::int_mul).
561    Mul(BinaryOpIr),
562    /// Operation corresponding to:
563    ///
564    /// Float => [mul scalar](burn_backend::ops::FloatTensorOps::float_mul_scalar).
565    /// Int => [mul scalar](burn_backend::ops::IntTensorOps::int_mul_scalar).
566    MulScalar(ScalarOpIr),
567    /// Operation corresponding to:
568    ///
569    /// Float => [abs](burn_backend::ops::FloatTensorOps::float_abs).
570    /// Int => [abs](burn_backend::ops::IntTensorOps::int_abs).
571    Abs(UnaryOpIr),
572    /// Operation corresponding to:
573    ///
574    /// Float => [full](burn_backend::ops::FloatTensorOps::float_full).
575    /// Int => [full](burn_backend::ops::IntTensorOps::int_full).
576    Full(FullOpIr),
577    /// Operation corresponding to:
578    ///
579    /// Float => [mean dim](burn_backend::ops::FloatTensorOps::float_mean_dim).
580    /// Int => [mean dim](burn_backend::ops::IntTensorOps::int_mean_dim).
581    MeanDim(ReduceDimOpIr),
582    /// Operation corresponding to:
583    ///
584    /// Float => [mean](burn_backend::ops::FloatTensorOps::float_mean).
585    /// Int => [mean](burn_backend::ops::IntTensorOps::int_mean).
586    Mean(ReduceOpIr),
587    /// Operation corresponding to:
588    ///
589    /// Float => [sum](burn_backend::ops::FloatTensorOps::float_sum).
590    /// Int => [sum](burn_backend::ops::IntTensorOps::int_sum).
591    Sum(ReduceOpIr),
592    /// Operation corresponding to:
593    ///
594    /// Float => [sum dim](burn_backend::ops::FloatTensorOps::float_sum_dim).
595    /// Int => [sum dim](burn_backend::ops::IntTensorOps::int_sum_dim).
596    SumDim(ReduceDimOpIr),
597    /// Operation corresponding to summing several dimensions at once.
598    SumDims(ReduceDimsOpIr),
599    /// Operation corresponding to:
600    ///
601    /// Float => [prod](burn_backend::ops::FloatTensorOps::float_prod).
602    /// Int => [prod](burn_backend::ops::IntTensorOps::int_prod).
603    Prod(ReduceOpIr),
604    /// Operation corresponding to:
605    ///
606    /// Float => [prod dim](burn_backend::ops::FloatTensorOps::float_prod_dim).
607    /// Int => [prod dim](burn_backend::ops::IntTensorOps::int_prod_dim).
608    ProdDim(ReduceDimOpIr),
609    /// Operation corresponding to:
610    ///
611    /// Float => [greater](burn_backend::ops::FloatTensorOps::float_greater).
612    /// Int => [greater](burn_backend::ops::IntTensorOps::int_greater).
613    Greater(BinaryOpIr),
614    /// Operation corresponding to:
615    ///
616    /// Float => [greater elem](burn_backend::ops::FloatTensorOps::float_greater_elem).
617    /// Int => [greater elem](burn_backend::ops::IntTensorOps::int_greater_elem).
618    GreaterElem(ScalarOpIr),
619    /// Operation corresponding to:
620    ///
621    /// Float => [greater equal](burn_backend::ops::FloatTensorOps::float_greater_elem).
622    /// Int => [greater elem](burn_backend::ops::IntTensorOps::int_greater_elem).
623    GreaterEqual(BinaryOpIr),
624    /// Operation corresponding to:
625    ///
626    /// Float => [greater equal elem](burn_backend::ops::FloatTensorOps::float_greater_equal_elem).
627    /// Int => [greater equal elem](burn_backend::ops::IntTensorOps::int_greater_equal_elem).
628    GreaterEqualElem(ScalarOpIr),
629    /// Operation corresponding to:
630    ///
631    /// Float => [lower](burn_backend::ops::FloatTensorOps::float_lower).
632    /// Int => [lower](burn_backend::ops::IntTensorOps::int_lower).
633    Lower(BinaryOpIr),
634    /// Operation corresponding to:
635    ///
636    /// Float => [lower elem](burn_backend::ops::FloatTensorOps::float_lower_elem).
637    /// Int => [lower elem](burn_backend::ops::IntTensorOps::int_lower_elem).
638    LowerElem(ScalarOpIr),
639    /// Operation corresponding to:
640    ///
641    /// Float => [lower equal](burn_backend::ops::FloatTensorOps::float_lower_equal).
642    /// Int => [lower equal](burn_backend::ops::IntTensorOps::int_lower_equal).
643    LowerEqual(BinaryOpIr),
644    /// Operation corresponding to:
645    ///
646    /// Float => [lower equal elem](burn_backend::ops::FloatTensorOps::float_lower_equal_elem).
647    /// Int => [lower equal elem](burn_backend::ops::IntTensorOps::int_lower_equal_elem).
648    LowerEqualElem(ScalarOpIr),
649    /// Operation corresponding to:
650    ///
651    /// Float => [argmax](burn_backend::ops::FloatTensorOps::float_argmax).
652    /// Int => [argmax](burn_backend::ops::IntTensorOps::int_argmax).
653    ArgMax(ReduceDimOpIr),
654    /// Operation corresponding to:
655    ///
656    /// Float => [argtopk](burn_backend::ops::FloatTensorOps::float_argtopk).
657    /// Int => [argtopk](burn_backend::ops::IntTensorOps::int_argtopk).
658    ArgTopK(ReduceDimOpIr),
659    /// Operation corresponding to:
660    ///
661    /// Float => [topk](burn_backend::ops::FloatTensorOps::float_topk).
662    /// Int => [topk](burn_backend::ops::IntTensorOps::int_topk).
663    TopK(ReduceDimOpIr),
664    /// Operation corresponding to:
665    ///
666    /// Float => [topk with indices](burn_backend::ops::FloatTensorOps::float_topk_with_indices).
667    /// Int => [topk with indices](burn_backend::ops::IntTensorOps::int_topk_with_indices).
668    TopKWithIndices(TopKWithIndicesOpIr),
669    /// Operation corresponding to:
670    ///
671    /// Float => [argmin](burn_backend::ops::FloatTensorOps::float_argmin).
672    /// Int => [argmin](burn_backend::ops::IntTensorOps::int_argmin).
673    ArgMin(ReduceDimOpIr),
674    /// Operation corresponding to:
675    ///
676    /// Float => [max](burn_backend::ops::FloatTensorOps::float_max).
677    /// Int => [max](burn_backend::ops::IntTensorOps::int_max).
678    Max(ReduceOpIr),
679    /// Operation corresponding to:
680    ///
681    /// Float => [max dim with indices](burn_backend::ops::FloatTensorOps::float_max_dim_with_indices).
682    /// Int => [max dim with indices](burn_backend::ops::IntTensorOps::int_max_dim_with_indices).
683    MaxDimWithIndices(ReduceDimWithIndicesOpIr),
684    /// Operation corresponding to:
685    ///
686    /// Float => [min dim with indices](burn_backend::ops::FloatTensorOps::float_min_dim_with_indices).
687    /// Int => [min dim with indices](burn_backend::ops::IntTensorOps::int_min_dim_with_indices).
688    MinDimWithIndices(ReduceDimWithIndicesOpIr),
689    /// Operation corresponding to:
690    ///
691    /// Float => [min](burn_backend::ops::FloatTensorOps::float_min).
692    /// Int => [min](burn_backend::ops::IntTensorOps::int_min).
693    Min(ReduceOpIr),
694    /// Operation corresponding to:
695    ///
696    /// Float => [max dim](burn_backend::ops::FloatTensorOps::float_max_dim).
697    /// Int => [max dim](burn_backend::ops::IntTensorOps::int_max_dim).
698    MaxDim(ReduceDimOpIr),
699    /// Operation corresponding to:
700    ///
701    /// Float => [min dim](burn_backend::ops::FloatTensorOps::float_min_dim).
702    /// Int => [min dim](burn_backend::ops::IntTensorOps::int_min_dim).
703    MinDim(ReduceDimOpIr),
704    /// Operation corresponding to:
705    ///
706    /// Float => [max_abs](burn_backend::ops::FloatTensorOps::float_max_abs).
707    /// Int => [max_abs](burn_backend::ops::IntTensorOps::int_max_abs).
708    MaxAbs(ReduceOpIr),
709    /// Operation corresponding to:
710    ///
711    /// Float => [max_abs dim](burn_backend::ops::FloatTensorOps::float_max_abs_dim).
712    /// Int => [max_abs dim](burn_backend::ops::IntTensorOps::int_max_abs_dim).
713    MaxAbsDim(ReduceDimOpIr),
714    /// Operation corresponding to:
715    ///
716    /// Float => [clamp](burn_backend::ops::FloatTensorOps::float_clamp).
717    /// Int => [clamp](burn_backend::ops::IntTensorOps::int_clamp).
718    Clamp(ClampOpIr),
719    /// Operation corresponding to:
720    ///
721    /// Int => [random](burn_backend::ops::IntTensorOps::int_random).
722    IntRandom(RandomOpIr),
723    /// Operation corresponding to:
724    ///
725    /// Float => [powf](burn_backend::ops::FloatTensorOps::float_powi).
726    /// Int => [powf](burn_backend::ops::IntTensorOps::int_powi).
727    Powi(BinaryOpIr),
728    /// Operation corresponding to:
729    ///
730    /// Float => [powi_scalar](burn_backend::ops::FloatTensorOps::float_powi_scalar).
731    /// Int => [powi_scalar](burn_backend::ops::IntTensorOps::int_powi_scalar).
732    PowiScalar(ScalarOpIr),
733    /// Operation corresponding to:
734    ///
735    /// Float => [cumsum](burn_backend::ops::FloatTensorOps::float_cumsum).
736    /// Int => [cumsum](burn_backend::ops::IntTensorOps::int_cumsum).
737    CumSum(DimOpIr),
738    /// Operation corresponding to:
739    ///
740    /// Float => [cumprod](burn_backend::ops::FloatTensorOps::float_cumprod).
741    /// Int => [cumprod](burn_backend::ops::IntTensorOps::int_cumprod).
742    CumProd(DimOpIr),
743    /// Operation corresponding to:
744    ///
745    /// Float => [cummin](burn_backend::ops::FloatTensorOps::float_cummin).
746    /// Int => [cummin](burn_backend::ops::IntTensorOps::int_cummin).
747    CumMin(DimOpIr),
748    /// Operation corresponding to:
749    ///
750    /// Float => [cummax](burn_backend::ops::FloatTensorOps::float_cummax).
751    /// Int => [cummax](burn_backend::ops::IntTensorOps::int_cummax).
752    CumMax(DimOpIr),
753    /// Operation corresponding to:
754    ///
755    /// Float => [neg](burn_backend::ops::FloatTensorOps::float_neg).
756    /// Int => [neg](burn_backend::ops::IntTensorOps::int_neg).
757    Neg(UnaryOpIr),
758    /// Operation corresponding to:
759    ///
760    /// Float => [sign](burn_backend::ops::FloatTensorOps::float_sign).
761    /// Int => [sign](burn_backend::ops::IntTensorOps::int_sign).
762    Sign(UnaryOpIr),
763    /// Operation corresponding to:
764    ///
765    /// Float => [clamp_min](burn_backend::ops::FloatTensorOps::float_clamp_min).
766    /// Int => [clamp_min](burn_backend::ops::IntTensorOps::int_clamp_min).
767    ClampMin(ScalarOpIr),
768    /// Operation corresponding to:
769    ///
770    /// Float => [clamp_max](burn_backend::ops::FloatTensorOps::float_clamp_max).
771    /// Int => [clamp_max](burn_backend::ops::IntTensorOps::int_clamp_max).
772    ClampMax(ScalarOpIr),
773    /// Sort along a dim. Output shares the input's shape and dtype.
774    Sort(SortOpIr),
775    /// Sort along a dim, also returning the source indices.
776    SortWithIndices(SortWithIndicesOpIr),
777    /// Sort along a dim and return only the indices (i.e., the argsort).
778    ///
779    /// Shares [`SortOpIr`] with [`Sort`](Self::Sort); only the output dtype differs.
780    ArgSort(SortOpIr),
781    /// Operation corresponding to:
782    ///
783    /// Float => [pad](burn_backend::ops::FloatTensorOps::float_pad).
784    /// Int => [pad](burn_backend::ops::IntTensorOps::int_pad).
785    Pad(PadOpIr),
786}
787
788/// Operation intermediate representation specific to an int tensor.
789#[derive(Clone, Debug, Hash, PartialEq, Serialize, Deserialize)]
790pub enum IntOperationIr {
791    /// Operation corresponding to [into float](burn_backend::ops::IntTensorOps::int_into_float).
792    IntoFloat(CastOpIr),
793    /// Operation corresponding to:
794    ///
795    /// Int => [bitwise and](burn_backend::ops::IntTensorOps::bitwise_and).
796    BitwiseAnd(BinaryOpIr),
797    /// Operation corresponding to:
798    ///
799    /// Int => [bitwise and scalar](burn_backend::ops::IntTensorOps::bitwise_and_scalar).
800    BitwiseAndScalar(ScalarOpIr),
801    /// Operation corresponding to:
802    ///
803    /// Int => [bitwise or](burn_backend::ops::IntTensorOps::bitwise_or).
804    BitwiseOr(BinaryOpIr),
805    /// Operation corresponding to:
806    ///
807    /// Int => [bitwise or scalar](burn_backend::ops::IntTensorOps::bitwise_or_scalar).
808    BitwiseOrScalar(ScalarOpIr),
809    /// Operation corresponding to:
810    ///
811    /// Int => [bitwise xor](burn_backend::ops::IntTensorOps::bitwise_xor).
812    BitwiseXor(BinaryOpIr),
813    /// Operation corresponding to:
814    ///
815    /// Int => [bitwise xor scalar](burn_backend::ops::IntTensorOps::bitwise_xor_scalar).
816    BitwiseXorScalar(ScalarOpIr),
817    /// Operation corresponding to:
818    ///
819    /// Int => [bitwise not](burn_backend::ops::IntTensorOps::bitwise_not).
820    BitwiseNot(UnaryOpIr),
821    /// Operation corresponding to:
822    ///
823    /// Int => [bitwise left shift](burn_backend::ops::IntTensorOps::bitwise_left_shift).
824    BitwiseLeftShift(BinaryOpIr),
825    /// Operation corresponding to:
826    ///
827    /// Int => [bitwise left shift scalar](burn_backend::ops::IntTensorOps::bitwise_left_shift_scalar).
828    BitwiseLeftShiftScalar(ScalarOpIr),
829    /// Operation corresponding to:
830    ///
831    /// Int => [bitwise right shift](burn_backend::ops::IntTensorOps::bitwise_right_shift).
832    BitwiseRightShift(BinaryOpIr),
833    /// Operation corresponding to:
834    ///
835    /// Int => [bitwise right shift scalar](burn_backend::ops::IntTensorOps::bitwise_right_shift_scalar).
836    BitwiseRightShiftScalar(ScalarOpIr),
837    /// Operation corresponding to [matmul](burn_backend::ops::IntTensorOps::int_matmul).
838    Matmul(MatmulOpIr),
839}
840
841/// Operation intermediate representation specific to a bool tensor.
842#[derive(Clone, Debug, Hash, PartialEq, Serialize, Deserialize)]
843pub enum BoolOperationIr {
844    /// Operation corresponding to [into float](burn_backend::ops::BoolTensorOps::bool_into_float).
845    IntoFloat(CastOpIr),
846    /// Operation corresponding to [into int](burn_backend::ops::BoolTensorOps::bool_into_int).
847    IntoInt(CastOpIr),
848    /// Operation corresponding to [not](burn_backend::ops::BoolTensorOps::bool_not).
849    Not(UnaryOpIr),
850    /// Operation corresponding to [and](burn_backend::ops::BoolTensorOps::bool_and).
851    And(BinaryOpIr),
852    /// Operation corresponding to [or](burn_backend::ops::BoolTensorOps::bool_or).
853    Or(BinaryOpIr),
854    /// Operation corresponding to [xor](burn_backend::ops::BoolTensorOps::bool_xor).
855    Xor(BinaryOpIr),
856}
857
858/// Operations that can be done on distributed tensors.
859#[derive(Clone, Debug, Hash, PartialEq, Serialize, Deserialize)]
860#[allow(clippy::large_enum_variant)]
861pub enum DistributedOperationIr {
862    /// Operation corresponding to:
863    /// [all_reduce](burn_backend::distributed::DistributedOps::all_reduce).
864    AllReduce(AllReduceOpIr),
865    /// Resolve the pending collective operations on the executing device. Corresponds to
866    /// [sync_collective](burn_backend::distributed::DistributedOps::sync_collective).
867    ///
868    /// Fire-and-forget and payload-free: it syncs whichever device the interpreter is bound to.
869    /// Modeled as an operation (not a side-channel call) so it travels the normal op stream
870    /// alongside [`AllReduce`](DistributedOperationIr::AllReduce) and is ordered against it.
871    SyncCollective,
872}
873
874/// Swap dim operation intermediate representation.
875#[derive(Clone, Debug, Hash, PartialEq, Serialize, Deserialize)]
876pub struct SwapDimsOpIr {
877    /// Input tensor intermediate representation.
878    pub input: TensorIr,
879    /// Output tensor intermediate representation.
880    pub out: TensorIr,
881    /// The first dim to swap.
882    pub dim1: usize,
883    /// The second dim to swap.
884    pub dim2: usize,
885}
886
887/// Permute operation intermediate representation.
888#[derive(Clone, Debug, Hash, PartialEq, Serialize, Deserialize)]
889pub struct PermuteOpIr {
890    /// Input tensor intermediate representation.
891    pub input: TensorIr,
892    /// Output tensor intermediate representation.
893    pub out: TensorIr,
894    /// The new order of the dimensions.
895    pub axes: Vec<usize>,
896}
897
898/// Shape operation intermediate representation.
899#[derive(Clone, Debug, Hash, PartialEq, Serialize, Deserialize)]
900pub struct ShapeOpIr {
901    /// Input tensor intermediate representation.
902    pub input: TensorIr,
903    /// Output tensor intermediate representation with the new shape.
904    pub out: TensorIr,
905}
906
907/// Unfold operation intermediate representation.
908#[derive(Clone, Debug, Hash, PartialEq, Serialize, Deserialize)]
909pub struct UnfoldOpIr {
910    /// Input tensor intermediate representation.
911    pub input: TensorIr,
912    /// Output tensor intermediate representation.
913    pub out: TensorIr,
914
915    /// The selected dim.
916    pub dim: usize,
917    /// The window size.
918    pub size: usize,
919    /// The window step along dim.
920    pub step: usize,
921}
922
923/// Flip operation intermediate representation.
924#[derive(Clone, Debug, Hash, PartialEq, Serialize, Deserialize)]
925pub struct FlipOpIr {
926    /// Input tensor intermediate representation.
927    pub input: TensorIr,
928    /// Output tensor intermediate representation.
929    pub out: TensorIr,
930    /// The dimensions to flip.
931    pub axes: Vec<usize>,
932}
933
934/// Padding operation intermediate representation.
935#[derive(Clone, Debug, Hash, PartialEq, Serialize, Deserialize)]
936pub struct PadOpIr {
937    /// Input tensor intermediate representation.
938    pub input: TensorIr,
939    /// Output tensor intermediate representation.
940    pub out: TensorIr,
941    /// One `(before, after)` padding pair per dimension.
942    pub padding: Vec<(usize, usize)>,
943    /// Padding mode.
944    pub mode: PadModeIr,
945}
946
947/// Serializable padding mode intermediate representation.
948#[derive(Clone, Copy, Debug, Hash, PartialEq, Serialize, Deserialize)]
949pub enum PadModeIr {
950    /// Fill padded regions with a constant value.
951    Constant(ScalarIr),
952    /// Reflect values at the boundary, excluding the edge value.
953    Reflect,
954    /// Replicate boundary values.
955    Edge,
956}
957
958impl From<PadMode> for PadModeIr {
959    fn from(value: PadMode) -> Self {
960        match value {
961            PadMode::Constant(value) => Self::Constant(ScalarIr::Float(value as f64)),
962            PadMode::Reflect => Self::Reflect,
963            PadMode::Edge => Self::Edge,
964        }
965    }
966}
967
968impl From<PadModeIr> for PadMode {
969    fn from(value: PadModeIr) -> Self {
970        match value {
971            PadModeIr::Constant(value) => Self::Constant(value.elem()),
972            PadModeIr::Reflect => Self::Reflect,
973            PadModeIr::Edge => Self::Edge,
974        }
975    }
976}
977
978#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
979#[allow(missing_docs)]
980pub struct RandomOpIr {
981    pub out: TensorIr,
982    pub distribution: Distribution,
983}
984
985/// Creation operation intermediate representation.
986/// As opposed to [InitOperationIr], creation operations are lazy initialized.
987#[derive(Clone, Debug, Hash, PartialEq, Serialize, Deserialize)]
988pub struct CreationOpIr {
989    /// Output tensor intermediate representation.
990    pub out: TensorIr,
991}
992
993/// Full operation intermediate representation.
994#[derive(Clone, Debug, Hash, PartialEq, Serialize, Deserialize)]
995pub struct FullOpIr {
996    /// Output tensor intermediate representation.
997    pub out: TensorIr,
998    /// Fill value.
999    pub value: ScalarIr,
1000}
1001
1002#[derive(Clone, Debug, Hash, PartialEq, Serialize, Deserialize)]
1003/// Declares a tensor has been initialized.
1004///
1005/// It is necessary to register for proper orphan detection and avoid memory leak.
1006pub struct InitOperationIr {
1007    /// The initialized tensor.
1008    pub out: TensorIr,
1009}
1010
1011#[derive(Clone, Debug, Hash, PartialEq, Serialize, Deserialize)]
1012#[allow(missing_docs)]
1013pub struct BinaryOpIr {
1014    pub lhs: TensorIr,
1015    pub rhs: TensorIr,
1016    pub out: TensorIr,
1017}
1018
1019#[derive(Clone, Debug, Hash, PartialEq, Serialize, Deserialize)]
1020#[allow(missing_docs)]
1021pub struct MatmulOpIr {
1022    pub lhs: TensorIr,
1023    pub rhs: TensorIr,
1024    pub out: TensorIr,
1025}
1026
1027#[derive(Clone, Debug, Hash, PartialEq, Serialize, Deserialize)]
1028#[allow(missing_docs)]
1029pub struct CrossOpIr {
1030    pub lhs: TensorIr,
1031    pub rhs: TensorIr,
1032    pub out: TensorIr,
1033    pub dim: usize,
1034}
1035
1036#[derive(Clone, Debug, Hash, PartialEq, Serialize, Deserialize)]
1037#[allow(missing_docs)]
1038pub struct UnaryOpIr {
1039    pub input: TensorIr,
1040    pub out: TensorIr,
1041}
1042
1043#[derive(Clone, Debug, Hash, PartialEq, Serialize, Deserialize)]
1044#[allow(missing_docs)]
1045pub struct ScalarOpIr {
1046    pub lhs: TensorIr,
1047    // TODO: Make that an enum with `Value` and `Id` variants for relative/global
1048    // conversion.
1049    pub rhs: ScalarIr,
1050    pub out: TensorIr,
1051}
1052
1053#[derive(Clone, Debug, PartialEq, Serialize, Deserialize, Hash)]
1054#[allow(missing_docs)]
1055pub struct ReduceOpIr {
1056    pub input: TensorIr,
1057    pub out: TensorIr,
1058}
1059
1060#[derive(Clone, Debug, PartialEq, Serialize, Deserialize, Hash)]
1061#[allow(missing_docs)]
1062pub struct ReduceDimOpIr {
1063    pub input: TensorIr,
1064    pub out: TensorIr,
1065    pub axis: usize,
1066    pub accumulator_len: usize,
1067}
1068
1069/// A reduction over several dimensions at once, each kept with length one.
1070#[derive(Clone, Debug, PartialEq, Serialize, Deserialize, Hash)]
1071#[allow(missing_docs)]
1072pub struct ReduceDimsOpIr {
1073    pub input: TensorIr,
1074    pub out: TensorIr,
1075    pub axes: Vec<usize>,
1076}
1077
1078#[allow(missing_docs)]
1079impl ReduceDimsOpIr {
1080    pub fn create<F>(input: TensorIr, axes: Vec<usize>, mut new_id: F) -> Self
1081    where
1082        F: FnMut() -> crate::TensorId,
1083    {
1084        let mut shape = input.shape.clone();
1085        for axis in &axes {
1086            shape[*axis] = 1;
1087        }
1088        let dtype = input.dtype;
1089
1090        Self {
1091            out: TensorIr::uninit(new_id(), shape, dtype),
1092            input,
1093            axes,
1094        }
1095    }
1096}
1097
1098#[derive(Clone, Debug, Hash, PartialEq, Serialize, Deserialize)]
1099#[allow(missing_docs)]
1100pub struct CastOpIr {
1101    pub input: TensorIr,
1102    pub out: TensorIr,
1103}
1104
1105/// IR for operations that operate along a dimension without reducing it.
1106/// Unlike `ReduceDimOpIr`, the output shape is the same as the input shape.
1107#[derive(Clone, Debug, PartialEq, Serialize, Deserialize, Hash)]
1108#[allow(missing_docs)]
1109pub struct DimOpIr {
1110    pub input: TensorIr,
1111    pub out: TensorIr,
1112    pub axis: usize,
1113}
1114
1115#[derive(Clone, Debug, Hash, PartialEq, Serialize, Deserialize)]
1116#[allow(missing_docs)]
1117pub struct GatherOpIr {
1118    pub tensor: TensorIr,
1119    pub dim: usize,
1120    pub indices: TensorIr,
1121    pub out: TensorIr,
1122}
1123
1124#[derive(Clone, Debug, Hash, PartialEq, Serialize, Deserialize)]
1125#[allow(missing_docs)]
1126pub struct ScatterOpIr {
1127    pub tensor: TensorIr,
1128    pub dim: usize,
1129    pub indices: TensorIr,
1130    pub value: TensorIr,
1131    pub update: IndexingUpdateOp,
1132    pub out: TensorIr,
1133}
1134
1135#[derive(Clone, Debug, Hash, PartialEq, Serialize, Deserialize)]
1136#[allow(missing_docs)]
1137pub struct ScatterNdOpIr {
1138    pub data: TensorIr,
1139    pub indices: TensorIr,
1140    pub values: TensorIr,
1141    pub reduction: IndexingUpdateOp,
1142    pub out: TensorIr,
1143}
1144
1145#[derive(Clone, Debug, Hash, PartialEq, Serialize, Deserialize)]
1146#[allow(missing_docs)]
1147pub struct GatherNdOpIr {
1148    pub data: TensorIr,
1149    pub indices: TensorIr,
1150    pub out: TensorIr,
1151}
1152
1153#[derive(Clone, Debug, Hash, PartialEq, Serialize, Deserialize)]
1154#[allow(missing_docs)]
1155pub struct SelectOpIr {
1156    pub tensor: TensorIr,
1157    pub dim: usize,
1158    pub indices: TensorIr,
1159    pub out: TensorIr,
1160}
1161
1162#[derive(Clone, Debug, Hash, PartialEq, Serialize, Deserialize)]
1163#[allow(missing_docs)]
1164pub struct SelectAssignOpIr {
1165    pub tensor: TensorIr,
1166    pub dim: usize,
1167    pub indices: TensorIr,
1168    pub value: TensorIr,
1169    pub update: IndexingUpdateOp,
1170    pub out: TensorIr,
1171}
1172
1173#[derive(Clone, Debug, Hash, PartialEq, Serialize, Deserialize)]
1174#[allow(missing_docs)]
1175pub struct SliceOpIr {
1176    pub tensor: TensorIr,
1177    pub ranges: Vec<Slice>,
1178    pub out: TensorIr,
1179}
1180
1181#[derive(Clone, Debug, Hash, PartialEq, Serialize, Deserialize)]
1182#[allow(missing_docs)]
1183pub struct SliceAssignOpIr {
1184    pub tensor: TensorIr,
1185    pub ranges: Vec<burn_backend::Slice>,
1186    pub value: TensorIr,
1187    pub out: TensorIr,
1188}
1189
1190#[derive(Clone, Debug, Hash, PartialEq, Serialize, Deserialize)]
1191#[allow(missing_docs)]
1192pub struct MaskWhereOpIr {
1193    pub tensor: TensorIr,
1194    pub mask: TensorIr,
1195    pub value: TensorIr,
1196    pub out: TensorIr,
1197}
1198
1199#[derive(Clone, Debug, Hash, PartialEq, Serialize, Deserialize)]
1200#[allow(missing_docs)]
1201pub struct MaskFillOpIr {
1202    pub tensor: TensorIr,
1203    pub mask: TensorIr,
1204    pub value: ScalarIr,
1205    pub out: TensorIr,
1206}
1207
1208#[derive(Clone, Debug, Hash, PartialEq, Serialize, Deserialize)]
1209#[allow(missing_docs)]
1210pub struct ClampOpIr {
1211    pub tensor: TensorIr,
1212    pub min: ScalarIr,
1213    pub max: ScalarIr,
1214    pub out: TensorIr,
1215}
1216
1217#[derive(Clone, Debug, Hash, PartialEq, Serialize, Deserialize)]
1218#[allow(missing_docs)]
1219pub struct RepeatDimOpIr {
1220    pub tensor: TensorIr,
1221    pub dim: usize,
1222    pub times: usize,
1223    pub out: TensorIr,
1224}
1225
1226#[derive(Clone, Debug, Hash, PartialEq, Serialize, Deserialize)]
1227#[allow(missing_docs)]
1228pub struct CatOpIr {
1229    pub tensors: Vec<TensorIr>,
1230    pub dim: usize,
1231    pub out: TensorIr,
1232}
1233
1234#[derive(Clone, Debug, Hash, PartialEq, Serialize, Deserialize)]
1235#[allow(missing_docs)]
1236pub struct AllReduceOpIr {
1237    pub tensor: TensorIr,
1238    pub out: TensorIr,
1239    /// How to reduce the values across the participating devices.
1240    pub op: burn_backend::distributed::ReduceOperation,
1241    /// The devices participating in the collective operation.
1242    pub device_ids: Vec<DeviceIdIr>,
1243}
1244
1245/// Serializable representation of a [device id](burn_backend::DeviceId).
1246///
1247/// The intermediate representation is part of the wire protocol (e.g. the remote backend), so it
1248/// cannot store `burn_backend::DeviceId` directly since that type is not serializable.
1249#[derive(Clone, Copy, Debug, Hash, PartialEq, Eq, Serialize, Deserialize)]
1250pub struct DeviceIdIr {
1251    /// Identifies the type of the device.
1252    pub type_id: u16,
1253    /// Identifies the device number.
1254    pub index_id: u16,
1255}
1256
1257impl From<burn_backend::DeviceId> for DeviceIdIr {
1258    fn from(value: burn_backend::DeviceId) -> Self {
1259        Self {
1260            type_id: value.type_id,
1261            index_id: value.index_id,
1262        }
1263    }
1264}
1265
1266impl From<DeviceIdIr> for burn_backend::DeviceId {
1267    fn from(value: DeviceIdIr) -> Self {
1268        burn_backend::DeviceId::new(value.type_id, value.index_id)
1269    }
1270}
1271
1272#[derive(Clone, Debug, Hash, PartialEq, Serialize, Deserialize)]
1273#[allow(missing_docs)]
1274pub struct ReduceDimWithIndicesOpIr {
1275    pub tensor: TensorIr,
1276    pub dim: usize,
1277    pub out: TensorIr,
1278    pub out_indices: TensorIr,
1279}
1280
1281#[derive(Clone, Debug, Hash, PartialEq, Serialize, Deserialize)]
1282#[allow(missing_docs)]
1283/// Like [`ReduceDimWithIndicesOpIr`], but for a top-k: the reduced axis keeps `k` entries
1284/// instead of collapsing to 1, so `k` has to be carried explicitly.
1285pub struct TopKWithIndicesOpIr {
1286    pub tensor: TensorIr,
1287    pub dim: usize,
1288    pub k: usize,
1289    pub out: TensorIr,
1290    pub out_indices: TensorIr,
1291}
1292
1293#[derive(Clone, Debug, Hash, PartialEq, Serialize, Deserialize)]
1294#[allow(missing_docs)]
1295pub struct EmbeddingOpIr {
1296    pub weights: TensorIr,
1297    pub indices: TensorIr,
1298    pub out: TensorIr,
1299}
1300
1301#[derive(Clone, Debug, Hash, PartialEq, Serialize, Deserialize)]
1302#[allow(missing_docs)]
1303pub struct EmbeddingBackwardOpIr {
1304    pub weights: TensorIr,
1305    pub out_grad: TensorIr,
1306    pub indices: TensorIr,
1307    pub out: TensorIr,
1308}
1309
1310/// Batch normalization using explicitly supplied channel statistics.
1311///
1312/// This operation neither calculates nor updates the supplied statistics.
1313#[derive(Clone, Debug, Hash, PartialEq, Serialize, Deserialize)]
1314#[allow(missing_docs)]
1315pub struct BatchNormOpIr {
1316    pub x: TensorIr,
1317    pub gamma: TensorIr,
1318    pub beta: TensorIr,
1319    pub mean: TensorIr,
1320    pub variance: TensorIr,
1321    pub epsilon: ScalarIr,
1322    pub out: TensorIr,
1323}
1324
1325#[derive(Clone, Debug, Hash, PartialEq, Serialize, Deserialize)]
1326#[allow(missing_docs)]
1327pub struct LinearOpIr {
1328    pub x: TensorIr,
1329    pub weight: TensorIr,
1330    pub bias: Option<TensorIr>,
1331    pub out: TensorIr,
1332}
1333
1334#[derive(Clone, Debug, Hash, PartialEq, Serialize, Deserialize)]
1335#[allow(missing_docs)]
1336pub struct LinearXBackwardOpIr {
1337    pub weight: TensorIr,
1338    pub output_grad: TensorIr,
1339    pub out: TensorIr,
1340}
1341
1342#[derive(Clone, Debug, Hash, PartialEq, Serialize, Deserialize)]
1343#[allow(missing_docs)]
1344pub struct LinearWeightBackwardOpIr {
1345    pub x: TensorIr,
1346    pub output_grad: TensorIr,
1347    pub out: TensorIr,
1348}
1349
1350#[derive(Clone, Debug, Hash, PartialEq, Serialize, Deserialize)]
1351#[allow(missing_docs)]
1352pub struct LinearBiasBackwardOpIr {
1353    pub output_grad: TensorIr,
1354    pub out: TensorIr,
1355}
1356
1357#[derive(Clone, Debug, Hash, PartialEq, Serialize, Deserialize)]
1358#[allow(missing_docs)]
1359pub struct Conv1dOpIr {
1360    pub x: TensorIr,
1361    pub weight: TensorIr,
1362    pub bias: Option<TensorIr>,
1363    pub options: Conv1dOptionsIr,
1364    pub out: TensorIr,
1365}
1366
1367#[derive(Clone, Debug, Hash, PartialEq, Serialize, Deserialize)]
1368#[allow(missing_docs)]
1369pub struct Conv1dXBackwardOpIr {
1370    pub x: TensorIr,
1371    pub weight: TensorIr,
1372    pub output_grad: TensorIr,
1373    pub options: Conv1dOptionsIr,
1374    pub out: TensorIr,
1375}
1376
1377#[derive(Clone, Debug, Hash, PartialEq, Serialize, Deserialize)]
1378#[allow(missing_docs)]
1379pub struct Conv1dWeightBackwardOpIr {
1380    pub x: TensorIr,
1381    pub weight: TensorIr,
1382    pub output_grad: TensorIr,
1383    pub options: Conv1dOptionsIr,
1384    pub out: TensorIr,
1385}
1386
1387#[derive(Clone, Debug, Hash, PartialEq, Serialize, Deserialize)]
1388#[allow(missing_docs)]
1389pub struct Conv1dBiasBackwardOpIr {
1390    pub x: TensorIr,
1391    pub bias: TensorIr,
1392    pub output_grad: TensorIr,
1393    pub out: TensorIr,
1394}
1395
1396#[derive(Clone, Debug, Hash, PartialEq, Serialize, Deserialize)]
1397#[allow(missing_docs)]
1398pub struct Conv2dOpIr {
1399    pub x: TensorIr,
1400    pub weight: TensorIr,
1401    pub bias: Option<TensorIr>,
1402    pub options: Conv2dOptionsIr,
1403    pub out: TensorIr,
1404}
1405
1406#[derive(Clone, Debug, Hash, PartialEq, Serialize, Deserialize)]
1407#[allow(missing_docs)]
1408pub struct Conv2dXBackwardOpIr {
1409    pub x: TensorIr,
1410    pub weight: TensorIr,
1411    pub output_grad: TensorIr,
1412    pub options: Conv2dOptionsIr,
1413    pub out: TensorIr,
1414}
1415
1416#[derive(Clone, Debug, Hash, PartialEq, Serialize, Deserialize)]
1417#[allow(missing_docs)]
1418pub struct Conv2dWeightBackwardOpIr {
1419    pub x: TensorIr,
1420    pub weight: TensorIr,
1421    pub output_grad: TensorIr,
1422    pub options: Conv2dOptionsIr,
1423    pub out: TensorIr,
1424}
1425
1426#[derive(Clone, Debug, Hash, PartialEq, Serialize, Deserialize)]
1427#[allow(missing_docs)]
1428pub struct Conv2dBiasBackwardOpIr {
1429    pub x: TensorIr,
1430    pub bias: TensorIr,
1431    pub output_grad: TensorIr,
1432    pub out: TensorIr,
1433}
1434
1435#[derive(Clone, Debug, Hash, PartialEq, Serialize, Deserialize)]
1436#[allow(missing_docs)]
1437pub struct DeformConv2dOpIr {
1438    pub x: TensorIr,
1439    pub offset: TensorIr,
1440    pub weight: TensorIr,
1441    pub mask: Option<TensorIr>,
1442    pub bias: Option<TensorIr>,
1443    pub options: DeformableConv2dOptionsIr,
1444    pub out: TensorIr,
1445}
1446
1447#[derive(Clone, Debug, Hash, PartialEq, Serialize, Deserialize)]
1448#[allow(missing_docs)]
1449pub struct DeformConv2dBackwardOpIr {
1450    pub x: TensorIr,
1451    pub offset: TensorIr,
1452    pub weight: TensorIr,
1453    pub mask: Option<TensorIr>,
1454    pub bias: Option<TensorIr>,
1455    pub out_grad: TensorIr,
1456    pub options: DeformableConv2dOptionsIr,
1457    pub input_grad: TensorIr,
1458    pub offset_grad: TensorIr,
1459    pub weight_grad: TensorIr,
1460    pub mask_grad: Option<TensorIr>,
1461    pub bias_grad: Option<TensorIr>,
1462}
1463
1464#[derive(Clone, Debug, Hash, PartialEq, Serialize, Deserialize)]
1465#[allow(missing_docs)]
1466pub struct Conv3dOpIr {
1467    pub x: TensorIr,
1468    pub weight: TensorIr,
1469    pub bias: Option<TensorIr>,
1470    pub options: Conv3dOptionsIr,
1471    pub out: TensorIr,
1472}
1473
1474#[derive(Clone, Debug, Hash, PartialEq, Serialize, Deserialize)]
1475#[allow(missing_docs)]
1476pub struct Conv3dXBackwardOpIr {
1477    pub x: TensorIr,
1478    pub weight: TensorIr,
1479    pub output_grad: TensorIr,
1480    pub options: Conv3dOptionsIr,
1481    pub out: TensorIr,
1482}
1483
1484#[derive(Clone, Debug, Hash, PartialEq, Serialize, Deserialize)]
1485#[allow(missing_docs)]
1486pub struct Conv3dWeightBackwardOpIr {
1487    pub x: TensorIr,
1488    pub weight: TensorIr,
1489    pub output_grad: TensorIr,
1490    pub options: Conv3dOptionsIr,
1491    pub out: TensorIr,
1492}
1493
1494#[derive(Clone, Debug, Hash, PartialEq, Serialize, Deserialize)]
1495#[allow(missing_docs)]
1496pub struct Conv3dBiasBackwardOpIr {
1497    pub x: TensorIr,
1498    pub bias: TensorIr,
1499    pub output_grad: TensorIr,
1500    pub out: TensorIr,
1501}
1502
1503#[derive(Clone, Debug, Hash, PartialEq, Serialize, Deserialize)]
1504#[allow(missing_docs)]
1505pub struct ConvTranspose1dOpIr {
1506    pub x: TensorIr,
1507    pub weight: TensorIr,
1508    pub bias: Option<TensorIr>,
1509    pub options: ConvTranspose1dOptionsIr,
1510    pub out: TensorIr,
1511}
1512
1513#[derive(Clone, Debug, Hash, PartialEq, Serialize, Deserialize)]
1514#[allow(missing_docs)]
1515pub struct ConvTranspose2dOpIr {
1516    pub x: TensorIr,
1517    pub weight: TensorIr,
1518    pub bias: Option<TensorIr>,
1519    pub options: ConvTranspose2dOptionsIr,
1520    pub out: TensorIr,
1521}
1522
1523#[derive(Clone, Debug, Hash, PartialEq, Serialize, Deserialize)]
1524#[allow(missing_docs)]
1525pub struct ConvTranspose3dOpIr {
1526    pub x: TensorIr,
1527    pub weight: TensorIr,
1528    pub bias: Option<TensorIr>,
1529    pub options: ConvTranspose3dOptionsIr,
1530    pub out: TensorIr,
1531}
1532
1533#[derive(Clone, Debug, Hash, PartialEq, Serialize, Deserialize)]
1534#[allow(missing_docs)]
1535pub struct Conv1dOptionsIr {
1536    pub stride: [usize; 1],
1537    pub padding: [(usize, usize); 1],
1538    pub dilation: [usize; 1],
1539    pub groups: usize,
1540}
1541
1542#[derive(Clone, Debug, Hash, PartialEq, Serialize, Deserialize)]
1543#[allow(missing_docs)]
1544pub struct Conv2dOptionsIr {
1545    pub stride: [usize; 2],
1546    pub padding: [(usize, usize); 2],
1547    pub dilation: [usize; 2],
1548    pub groups: usize,
1549}
1550
1551#[derive(Clone, Debug, Hash, PartialEq, Serialize, Deserialize)]
1552#[allow(missing_docs)]
1553pub struct DeformableConv2dOptionsIr {
1554    pub stride: [usize; 2],
1555    pub padding: [usize; 2],
1556    pub dilation: [usize; 2],
1557    pub weight_groups: usize,
1558    pub offset_groups: usize,
1559}
1560
1561#[derive(Clone, Debug, Hash, PartialEq, Serialize, Deserialize)]
1562#[allow(missing_docs)]
1563pub struct Conv3dOptionsIr {
1564    pub stride: [usize; 3],
1565    pub padding: [usize; 3],
1566    pub dilation: [usize; 3],
1567    pub groups: usize,
1568}
1569
1570#[derive(Clone, Debug, Hash, PartialEq, Serialize, Deserialize)]
1571#[allow(missing_docs)]
1572pub struct ConvTranspose1dOptionsIr {
1573    pub stride: [usize; 1],
1574    pub padding: [usize; 1],
1575    pub padding_out: [usize; 1],
1576    pub dilation: [usize; 1],
1577    pub groups: usize,
1578}
1579
1580#[derive(Clone, Debug, Hash, PartialEq, Serialize, Deserialize)]
1581#[allow(missing_docs)]
1582pub struct ConvTranspose2dOptionsIr {
1583    pub stride: [usize; 2],
1584    pub padding: [usize; 2],
1585    pub padding_out: [usize; 2],
1586    pub dilation: [usize; 2],
1587    pub groups: usize,
1588}
1589
1590#[derive(Clone, Debug, Hash, PartialEq, Serialize, Deserialize)]
1591#[allow(missing_docs)]
1592pub struct ConvTranspose3dOptionsIr {
1593    pub stride: [usize; 3],
1594    pub padding: [usize; 3],
1595    pub padding_out: [usize; 3],
1596    pub dilation: [usize; 3],
1597    pub groups: usize,
1598}
1599
1600/// Quantization parameters intermediate representation.
1601#[derive(Debug, Clone, Hash, PartialEq, Eq, Serialize, Deserialize)]
1602pub struct QuantizationParametersIr {
1603    /// The scaling factor, one per block or a single one for a per-tensor level.
1604    pub scales: TensorIr,
1605    /// The per-tensor scale that [`scales`](Self::scales) are expressed relative to, for a
1606    /// two-level scheme.
1607    pub global: Option<TensorIr>,
1608}
1609
1610#[derive(Clone, Debug, Hash, PartialEq, Serialize, Deserialize)]
1611#[allow(missing_docs)]
1612pub struct QuantizeOpIr {
1613    pub tensor: TensorIr,
1614    pub qparams: QuantizationParametersIr,
1615    pub scheme: QuantScheme,
1616    pub out: TensorIr,
1617}
1618
1619#[derive(Clone, Debug, Hash, PartialEq, Serialize, Deserialize)]
1620#[allow(missing_docs)]
1621pub struct DequantizeOpIr {
1622    pub input: TensorIr,
1623    pub out: TensorIr,
1624}
1625
1626impl From<ConvOptions<1>> for Conv1dOptionsIr {
1627    fn from(value: ConvOptions<1>) -> Self {
1628        Self {
1629            stride: value.stride,
1630            padding: value.padding,
1631            dilation: value.dilation,
1632            groups: value.groups,
1633        }
1634    }
1635}
1636
1637impl From<ConvOptions<2>> for Conv2dOptionsIr {
1638    fn from(value: ConvOptions<2>) -> Self {
1639        Self {
1640            stride: value.stride,
1641            padding: value.padding,
1642            dilation: value.dilation,
1643            groups: value.groups,
1644        }
1645    }
1646}
1647
1648impl From<ConvOptions<3>> for Conv3dOptionsIr {
1649    fn from(value: ConvOptions<3>) -> Self {
1650        Self {
1651            stride: value.stride,
1652            padding: value.symmetric_padding(),
1653            dilation: value.dilation,
1654            groups: value.groups,
1655        }
1656    }
1657}
1658
1659impl From<DeformConvOptions<2>> for DeformableConv2dOptionsIr {
1660    fn from(value: DeformConvOptions<2>) -> Self {
1661        Self {
1662            stride: value.stride,
1663            padding: value.padding,
1664            dilation: value.dilation,
1665            weight_groups: value.weight_groups,
1666            offset_groups: value.offset_groups,
1667        }
1668    }
1669}
1670
1671impl From<ConvTransposeOptions<1>> for ConvTranspose1dOptionsIr {
1672    fn from(value: ConvTransposeOptions<1>) -> Self {
1673        Self {
1674            stride: value.stride,
1675            padding: value.padding,
1676            padding_out: value.padding_out,
1677            dilation: value.dilation,
1678            groups: value.groups,
1679        }
1680    }
1681}
1682
1683impl From<ConvTransposeOptions<2>> for ConvTranspose2dOptionsIr {
1684    fn from(value: ConvTransposeOptions<2>) -> Self {
1685        Self {
1686            stride: value.stride,
1687            padding: value.padding,
1688            padding_out: value.padding_out,
1689            dilation: value.dilation,
1690            groups: value.groups,
1691        }
1692    }
1693}
1694
1695impl From<ConvTransposeOptions<3>> for ConvTranspose3dOptionsIr {
1696    fn from(value: ConvTransposeOptions<3>) -> Self {
1697        Self {
1698            stride: value.stride,
1699            padding: value.padding,
1700            padding_out: value.padding_out,
1701            dilation: value.dilation,
1702            groups: value.groups,
1703        }
1704    }
1705}
1706
1707impl From<Conv1dOptionsIr> for ConvOptions<1> {
1708    fn from(val: Conv1dOptionsIr) -> Self {
1709        ConvOptions {
1710            stride: val.stride,
1711            padding: val.padding,
1712            dilation: val.dilation,
1713            groups: val.groups,
1714        }
1715    }
1716}
1717
1718impl From<Conv2dOptionsIr> for ConvOptions<2> {
1719    fn from(val: Conv2dOptionsIr) -> Self {
1720        ConvOptions {
1721            stride: val.stride,
1722            padding: val.padding,
1723            dilation: val.dilation,
1724            groups: val.groups,
1725        }
1726    }
1727}
1728
1729impl From<Conv3dOptionsIr> for ConvOptions<3> {
1730    fn from(val: Conv3dOptionsIr) -> Self {
1731        ConvOptions {
1732            stride: val.stride,
1733            padding: val.padding.map(|padding| (padding, padding)),
1734            dilation: val.dilation,
1735            groups: val.groups,
1736        }
1737    }
1738}
1739
1740impl From<DeformableConv2dOptionsIr> for DeformConvOptions<2> {
1741    fn from(value: DeformableConv2dOptionsIr) -> Self {
1742        DeformConvOptions {
1743            stride: value.stride,
1744            padding: value.padding,
1745            dilation: value.dilation,
1746            weight_groups: value.weight_groups,
1747            offset_groups: value.offset_groups,
1748        }
1749    }
1750}
1751
1752impl From<ConvTranspose1dOptionsIr> for ConvTransposeOptions<1> {
1753    fn from(val: ConvTranspose1dOptionsIr) -> Self {
1754        ConvTransposeOptions {
1755            stride: val.stride,
1756            padding: val.padding,
1757            padding_out: val.padding_out,
1758            dilation: val.dilation,
1759            groups: val.groups,
1760        }
1761    }
1762}
1763
1764impl From<ConvTranspose2dOptionsIr> for ConvTransposeOptions<2> {
1765    fn from(val: ConvTranspose2dOptionsIr) -> Self {
1766        ConvTransposeOptions {
1767            stride: val.stride,
1768            padding: val.padding,
1769            padding_out: val.padding_out,
1770            dilation: val.dilation,
1771            groups: val.groups,
1772        }
1773    }
1774}
1775
1776impl From<ConvTranspose3dOptionsIr> for ConvTransposeOptions<3> {
1777    fn from(val: ConvTranspose3dOptionsIr) -> Self {
1778        ConvTransposeOptions {
1779            stride: val.stride,
1780            padding: val.padding,
1781            padding_out: val.padding_out,
1782            dilation: val.dilation,
1783            groups: val.groups,
1784        }
1785    }
1786}
1787
1788#[derive(Clone, Debug, Hash, PartialEq, Serialize, Deserialize)]
1789#[allow(missing_docs)]
1790pub struct AvgPool1dOpIr {
1791    pub x: TensorIr,
1792    pub kernel_size: usize,
1793    pub stride: usize,
1794    pub padding: usize,
1795    pub count_include_pad: bool,
1796    pub ceil_mode: bool,
1797    pub out: TensorIr,
1798}
1799
1800#[derive(Clone, Debug, Hash, PartialEq, Serialize, Deserialize)]
1801#[allow(missing_docs)]
1802pub struct AvgPool2dOpIr {
1803    pub x: TensorIr,
1804    pub kernel_size: [usize; 2],
1805    pub stride: [usize; 2],
1806    pub padding: [usize; 2],
1807    pub count_include_pad: bool,
1808    pub ceil_mode: bool,
1809    pub out: TensorIr,
1810}
1811
1812#[derive(Clone, Debug, Hash, PartialEq, Serialize, Deserialize)]
1813#[allow(missing_docs)]
1814pub struct AvgPool1dBackwardOpIr {
1815    pub x: TensorIr,
1816    pub grad: TensorIr,
1817    pub kernel_size: usize,
1818    pub stride: usize,
1819    pub padding: usize,
1820    pub count_include_pad: bool,
1821    pub ceil_mode: bool,
1822    pub out: TensorIr,
1823}
1824
1825#[derive(Clone, Debug, Hash, PartialEq, Serialize, Deserialize)]
1826#[allow(missing_docs)]
1827pub struct AvgPool2dBackwardOpIr {
1828    pub x: TensorIr,
1829    pub grad: TensorIr,
1830    pub kernel_size: [usize; 2],
1831    pub stride: [usize; 2],
1832    pub padding: [usize; 2],
1833    pub count_include_pad: bool,
1834    pub ceil_mode: bool,
1835    pub out: TensorIr,
1836}
1837
1838#[derive(Clone, Debug, Hash, PartialEq, Serialize, Deserialize)]
1839#[allow(missing_docs)]
1840pub struct AdaptiveAvgPool1dOpIr {
1841    pub x: TensorIr,
1842    pub output_size: usize,
1843    pub out: TensorIr,
1844}
1845
1846#[derive(Clone, Debug, Hash, PartialEq, Serialize, Deserialize)]
1847#[allow(missing_docs)]
1848pub struct AdaptiveAvgPool2dOpIr {
1849    pub x: TensorIr,
1850    pub output_size: [usize; 2],
1851    pub out: TensorIr,
1852}
1853
1854#[derive(Clone, Debug, Hash, PartialEq, Serialize, Deserialize)]
1855#[allow(missing_docs)]
1856pub struct AdaptiveAvgPool1dBackwardOpIr {
1857    pub x: TensorIr,
1858    pub grad: TensorIr,
1859    pub out: TensorIr,
1860}
1861
1862#[derive(Clone, Debug, Hash, PartialEq, Serialize, Deserialize)]
1863#[allow(missing_docs)]
1864pub struct AdaptiveAvgPool2dBackwardOpIr {
1865    pub x: TensorIr,
1866    pub grad: TensorIr,
1867    pub out: TensorIr,
1868}
1869
1870#[derive(Clone, Debug, Hash, PartialEq, Serialize, Deserialize)]
1871#[allow(missing_docs)]
1872pub struct AdaptiveAvgPool3dOpIr {
1873    pub x: TensorIr,
1874    pub output_size: [usize; 3],
1875    pub out: TensorIr,
1876}
1877
1878#[derive(Clone, Debug, Hash, PartialEq, Serialize, Deserialize)]
1879#[allow(missing_docs)]
1880pub struct AdaptiveAvgPool3dBackwardOpIr {
1881    pub x: TensorIr,
1882    pub grad: TensorIr,
1883    pub out: TensorIr,
1884}
1885
1886#[derive(Clone, Debug, Hash, PartialEq, Serialize, Deserialize)]
1887#[allow(missing_docs)]
1888pub struct MaxPool1dOpIr {
1889    pub x: TensorIr,
1890    pub kernel_size: usize,
1891    pub stride: usize,
1892    pub padding: usize,
1893    pub dilation: usize,
1894    pub ceil_mode: bool,
1895    pub out: TensorIr,
1896}
1897
1898#[derive(Clone, Debug, Hash, PartialEq, Serialize, Deserialize)]
1899#[allow(missing_docs)]
1900pub struct MaxPool1dWithIndicesOpIr {
1901    pub x: TensorIr,
1902    pub kernel_size: usize,
1903    pub stride: usize,
1904    pub padding: usize,
1905    pub dilation: usize,
1906    pub ceil_mode: bool,
1907    pub out: TensorIr,
1908    pub out_indices: TensorIr,
1909}
1910
1911#[derive(Clone, Debug, Hash, PartialEq, Serialize, Deserialize)]
1912#[allow(missing_docs)]
1913pub struct MaxPool1dWithIndicesBackwardOpIr {
1914    pub x: TensorIr,
1915    pub grad: TensorIr,
1916    pub indices: TensorIr,
1917    pub kernel_size: usize,
1918    pub stride: usize,
1919    pub padding: usize,
1920    pub dilation: usize,
1921    pub ceil_mode: bool,
1922    pub out: TensorIr,
1923}
1924
1925#[derive(Clone, Debug, Hash, PartialEq, Serialize, Deserialize)]
1926#[allow(missing_docs)]
1927pub struct MaxPool2dOpIr {
1928    pub x: TensorIr,
1929    pub kernel_size: [usize; 2],
1930    pub stride: [usize; 2],
1931    pub padding: [usize; 2],
1932    pub dilation: [usize; 2],
1933    pub ceil_mode: bool,
1934    pub out: TensorIr,
1935}
1936
1937#[allow(missing_docs)]
1938#[derive(Clone, Debug, Hash, PartialEq, Serialize, Deserialize)]
1939pub struct MaxPool2dWithIndicesOpIr {
1940    pub x: TensorIr,
1941    pub kernel_size: [usize; 2],
1942    pub stride: [usize; 2],
1943    pub padding: [usize; 2],
1944    pub dilation: [usize; 2],
1945    pub ceil_mode: bool,
1946    pub out: TensorIr,
1947    pub out_indices: TensorIr,
1948}
1949
1950#[derive(Clone, Debug, Hash, PartialEq, Serialize, Deserialize)]
1951#[allow(missing_docs)]
1952pub struct MaxPool2dWithIndicesBackwardOpIr {
1953    pub x: TensorIr,
1954    pub grad: TensorIr,
1955    pub indices: TensorIr,
1956    pub kernel_size: [usize; 2],
1957    pub stride: [usize; 2],
1958    pub padding: [usize; 2],
1959    pub dilation: [usize; 2],
1960    pub ceil_mode: bool,
1961    pub out: TensorIr,
1962}
1963
1964#[derive(Clone, Debug, Hash, PartialEq, Serialize, Deserialize)]
1965#[allow(missing_docs)]
1966pub enum InterpolateModeIr {
1967    Nearest,
1968    NearestExact,
1969    Bilinear,
1970    Bicubic,
1971    Lanczos3,
1972}
1973
1974#[derive(Clone, Debug, Hash, PartialEq, Serialize, Deserialize)]
1975#[allow(missing_docs)]
1976pub struct InterpolateOptionsIr {
1977    pub mode: InterpolateModeIr,
1978    pub align_corners: bool,
1979}
1980
1981#[derive(Clone, Debug, Hash, PartialEq, Serialize, Deserialize)]
1982#[allow(missing_docs)]
1983pub struct InterpolateOpIr {
1984    pub x: TensorIr,
1985    pub output_size: [usize; 2],
1986    pub options: InterpolateOptionsIr,
1987    pub out: TensorIr,
1988}
1989
1990#[derive(Clone, Debug, Hash, PartialEq, Serialize, Deserialize)]
1991#[allow(missing_docs)]
1992pub struct AttentionOptionsIr {
1993    pub scale: Option<ScalarIr>,
1994    pub softcap: Option<ScalarIr>,
1995    pub is_causal: bool,
1996}
1997
1998impl From<AttentionOptionsIr> for AttentionModuleOptions {
1999    fn from(ir: AttentionOptionsIr) -> Self {
2000        AttentionModuleOptions {
2001            scale: ir.scale.map(|s| s.elem()),
2002            softcap: ir.softcap.map(|s| s.elem()),
2003            is_causal: ir.is_causal,
2004        }
2005    }
2006}
2007
2008impl From<AttentionModuleOptions> for AttentionOptionsIr {
2009    fn from(ir: AttentionModuleOptions) -> Self {
2010        AttentionOptionsIr {
2011            scale: ir.scale.map(ScalarIr::Float),
2012            softcap: ir.softcap.map(ScalarIr::Float),
2013            is_causal: ir.is_causal,
2014        }
2015    }
2016}
2017
2018#[derive(Clone, Debug, Hash, PartialEq, Serialize, Deserialize)]
2019#[allow(missing_docs)]
2020pub struct AttentionOpIr {
2021    pub query: TensorIr,
2022    pub key: TensorIr,
2023    pub value: TensorIr,
2024    pub mask: Option<TensorIr>,
2025    pub attn_bias: Option<TensorIr>,
2026    pub options: AttentionOptionsIr,
2027    pub out: TensorIr,
2028}
2029
2030#[derive(Clone, Debug, Hash, PartialEq, Serialize, Deserialize)]
2031#[allow(missing_docs)]
2032pub struct CtcLossOpIr {
2033    pub log_probs: TensorIr,
2034    pub targets: TensorIr,
2035    pub input_lengths: TensorIr,
2036    pub target_lengths: TensorIr,
2037    pub blank: usize,
2038    pub out: TensorIr,
2039}
2040
2041#[derive(Clone, Debug, Hash, PartialEq, Serialize, Deserialize)]
2042#[allow(missing_docs)]
2043pub struct CtcLossBackwardOpIr {
2044    pub log_probs: TensorIr,
2045    pub targets: TensorIr,
2046    pub input_lengths: TensorIr,
2047    pub target_lengths: TensorIr,
2048    pub grad_loss: TensorIr,
2049    pub blank: usize,
2050    pub out: TensorIr,
2051}
2052
2053impl From<InterpolateModeIr> for InterpolateMode {
2054    fn from(val: InterpolateModeIr) -> Self {
2055        match val {
2056            InterpolateModeIr::Nearest => Self::Nearest,
2057            InterpolateModeIr::NearestExact => Self::NearestExact,
2058            InterpolateModeIr::Bilinear => Self::Bilinear,
2059            InterpolateModeIr::Bicubic => Self::Bicubic,
2060            InterpolateModeIr::Lanczos3 => Self::Lanczos3,
2061        }
2062    }
2063}
2064
2065impl From<InterpolateOptionsIr> for InterpolateOptions {
2066    fn from(val: InterpolateOptionsIr) -> Self {
2067        Self::new(val.mode.into()).with_align_corners(val.align_corners)
2068    }
2069}
2070
2071impl From<InterpolateMode> for InterpolateModeIr {
2072    fn from(val: InterpolateMode) -> Self {
2073        match val {
2074            InterpolateMode::Nearest => Self::Nearest,
2075            InterpolateMode::NearestExact => Self::NearestExact,
2076            InterpolateMode::Bilinear => Self::Bilinear,
2077            InterpolateMode::Bicubic => Self::Bicubic,
2078            InterpolateMode::Lanczos3 => Self::Lanczos3,
2079        }
2080    }
2081}
2082
2083impl From<InterpolateOptions> for InterpolateOptionsIr {
2084    fn from(val: InterpolateOptions) -> Self {
2085        Self {
2086            mode: val.mode.into(),
2087            align_corners: val.align_corners,
2088        }
2089    }
2090}
2091
2092#[derive(Clone, Debug, Hash, PartialEq, Serialize, Deserialize)]
2093#[allow(missing_docs)]
2094pub struct InterpolateBackwardOpIr {
2095    pub x: TensorIr,
2096    pub grad: TensorIr,
2097    pub output_size: [usize; 2],
2098    pub options: InterpolateOptionsIr,
2099    pub out: TensorIr,
2100}
2101
2102#[derive(Clone, Debug, Hash, PartialEq, Serialize, Deserialize)]
2103#[allow(missing_docs)]
2104pub enum GridSamplePaddingModeIr {
2105    Zeros,
2106    Border,
2107    Reflection,
2108}
2109
2110#[derive(Clone, Debug, Hash, PartialEq, Serialize, Deserialize)]
2111#[allow(missing_docs)]
2112pub struct GridSampleOptionsIr {
2113    pub mode: InterpolateModeIr,
2114    pub padding_mode: GridSamplePaddingModeIr,
2115    pub align_corners: bool,
2116}
2117
2118#[derive(Clone, Debug, Hash, PartialEq, Serialize, Deserialize)]
2119#[allow(missing_docs)]
2120pub struct GridSample2dOpIr {
2121    pub tensor: TensorIr,
2122    pub grid: TensorIr,
2123    pub options: GridSampleOptionsIr,
2124    pub out: TensorIr,
2125}
2126
2127impl From<GridSamplePaddingModeIr> for GridSamplePaddingMode {
2128    fn from(val: GridSamplePaddingModeIr) -> Self {
2129        match val {
2130            GridSamplePaddingModeIr::Zeros => Self::Zeros,
2131            GridSamplePaddingModeIr::Border => Self::Border,
2132            GridSamplePaddingModeIr::Reflection => Self::Reflection,
2133        }
2134    }
2135}
2136
2137impl From<GridSamplePaddingMode> for GridSamplePaddingModeIr {
2138    fn from(val: GridSamplePaddingMode) -> Self {
2139        match val {
2140            GridSamplePaddingMode::Zeros => Self::Zeros,
2141            GridSamplePaddingMode::Border => Self::Border,
2142            GridSamplePaddingMode::Reflection => Self::Reflection,
2143        }
2144    }
2145}
2146
2147impl From<GridSampleOptionsIr> for GridSampleOptions {
2148    fn from(val: GridSampleOptionsIr) -> Self {
2149        Self {
2150            mode: val.mode.into(),
2151            padding_mode: val.padding_mode.into(),
2152            align_corners: val.align_corners,
2153        }
2154    }
2155}
2156
2157impl From<GridSampleOptions> for GridSampleOptionsIr {
2158    fn from(val: GridSampleOptions) -> Self {
2159        Self {
2160            mode: val.mode.into(),
2161            padding_mode: val.padding_mode.into(),
2162            align_corners: val.align_corners,
2163        }
2164    }
2165}
2166
2167impl OperationIr {
2168    /// Get all input [tensors](TensorIr) involved with the current operation.
2169    pub fn inputs(&self) -> impl Iterator<Item = &TensorIr> {
2170        match self {
2171            OperationIr::BaseFloat(repr) => repr.inputs(),
2172            OperationIr::BaseInt(repr) => repr.inputs(),
2173            OperationIr::BaseBool(repr) => repr.inputs(),
2174            OperationIr::NumericFloat(_dtype, repr) => repr.inputs(),
2175            OperationIr::NumericInt(_dtype, repr) => repr.inputs(),
2176            OperationIr::Bool(repr) => repr.inputs(),
2177            OperationIr::Int(repr) => repr.inputs(),
2178            OperationIr::Float(_dtype, repr) => repr.inputs(),
2179            OperationIr::Module(repr) => repr.inputs(),
2180            OperationIr::Init(repr) => repr.inputs(),
2181            OperationIr::Custom(repr) => repr.inputs(),
2182            OperationIr::Drop(repr) => Box::new([repr].into_iter()),
2183            OperationIr::Distributed(repr) => repr.inputs(),
2184            OperationIr::Activation(repr) => repr.inputs(),
2185        }
2186    }
2187
2188    /// Get all output [tensors](TensorIr) involved with the current operation.
2189    pub fn outputs(&self) -> impl Iterator<Item = &TensorIr> {
2190        match self {
2191            OperationIr::BaseFloat(repr) => repr.outputs(),
2192            OperationIr::BaseInt(repr) => repr.outputs(),
2193            OperationIr::BaseBool(repr) => repr.outputs(),
2194            OperationIr::NumericFloat(_dtype, repr) => repr.outputs(),
2195            OperationIr::NumericInt(_dtype, repr) => repr.outputs(),
2196            OperationIr::Bool(repr) => repr.outputs(),
2197            OperationIr::Int(repr) => repr.outputs(),
2198            OperationIr::Float(_dtype, repr) => repr.outputs(),
2199            OperationIr::Module(repr) => repr.outputs(),
2200            OperationIr::Init(repr) => repr.outputs(),
2201            OperationIr::Custom(repr) => repr.outputs(),
2202            OperationIr::Drop(_repr) => Box::new([].into_iter()),
2203            OperationIr::Distributed(repr) => repr.outputs(),
2204            OperationIr::Activation(repr) => repr.outputs(),
2205        }
2206    }
2207
2208    /// Get all [tensor](TensorIr) involved with the current operation.
2209    pub fn nodes(&self) -> Vec<&TensorIr> {
2210        self.inputs().chain(self.outputs()).collect()
2211    }
2212
2213    /// Set the given nodes that are [read write](super::TensorStatus::ReadWrite) to
2214    /// [read only](super::TensorStatus::ReadOnly) in the current operation.
2215    ///
2216    /// Returns the tensor that were updated with their original representation.
2217    pub fn mark_read_only(&mut self, nodes: &[TensorId]) -> Vec<TensorIr> {
2218        match self {
2219            OperationIr::BaseFloat(repr) => repr.mark_read_only(nodes),
2220            OperationIr::BaseInt(repr) => repr.mark_read_only(nodes),
2221            OperationIr::BaseBool(repr) => repr.mark_read_only(nodes),
2222            OperationIr::NumericFloat(_dtype, repr) => repr.mark_read_only(nodes),
2223            OperationIr::NumericInt(_dtype, repr) => repr.mark_read_only(nodes),
2224            OperationIr::Bool(repr) => repr.mark_read_only(nodes),
2225            OperationIr::Int(repr) => repr.mark_read_only(nodes),
2226            OperationIr::Float(_dtype, repr) => repr.mark_read_only(nodes),
2227            OperationIr::Module(repr) => repr.mark_read_only(nodes),
2228            OperationIr::Init(_) => Vec::new(),
2229            OperationIr::Drop(repr) => {
2230                let mut output = Vec::new();
2231                repr.mark_read_only(nodes, &mut output);
2232                output
2233            }
2234            OperationIr::Custom(repr) => {
2235                let mut output = Vec::new();
2236
2237                for input in repr.inputs.iter_mut() {
2238                    input.mark_read_only(nodes, &mut output);
2239                }
2240
2241                output
2242            }
2243            OperationIr::Distributed(repr) => repr.mark_read_only(nodes),
2244            OperationIr::Activation(repr) => repr.mark_read_only(nodes),
2245        }
2246    }
2247
2248    /// Visit every mutable component of this operation in place.
2249    ///
2250    /// For each variant, visits its [tensors](TensorIr) (in the same order as
2251    /// [`inputs`](Self::inputs) then [`outputs`](Self::outputs) combined), then its
2252    /// [scalars](ScalarIr), then its slice ranges. Only `Slice`/`SliceAssign` (under the `Base*`
2253    /// variants) carry ranges; every other category visits no ranges.
2254    pub fn visit_mut(&mut self, v: &mut impl IrVisitorMut) {
2255        match self {
2256            OperationIr::BaseFloat(repr) => repr.visit_mut(v),
2257            OperationIr::BaseInt(repr) => repr.visit_mut(v),
2258            OperationIr::BaseBool(repr) => repr.visit_mut(v),
2259            OperationIr::NumericFloat(_dtype, repr) => repr.visit_mut(v),
2260            OperationIr::NumericInt(_dtype, repr) => repr.visit_mut(v),
2261            OperationIr::Bool(repr) => repr.visit_mut(v),
2262            OperationIr::Int(repr) => repr.visit_mut(v),
2263            OperationIr::Float(_dtype, repr) => repr.visit_mut(v),
2264            OperationIr::Module(repr) => repr.visit_mut(v),
2265            OperationIr::Init(repr) => repr.visit_mut(v),
2266            OperationIr::Custom(repr) => repr.visit_mut(v),
2267            OperationIr::Drop(repr) => v.visit_tensor_mut(repr),
2268            OperationIr::Distributed(repr) => repr.visit_mut(v),
2269            OperationIr::Activation(repr) => repr.visit_mut(v),
2270        }
2271    }
2272}
2273
2274impl BaseOperationIr {
2275    fn inputs(&self) -> Box<dyn Iterator<Item = &TensorIr> + '_> {
2276        match self {
2277            BaseOperationIr::Reshape(repr) => Box::new([&repr.input].into_iter()),
2278            BaseOperationIr::SwapDims(repr) => Box::new([&repr.input].into_iter()),
2279            BaseOperationIr::Permute(repr) => Box::new([&repr.input].into_iter()),
2280            BaseOperationIr::Expand(repr) => Box::new([&repr.input].into_iter()),
2281            BaseOperationIr::Flip(repr) => Box::new([&repr.input].into_iter()),
2282            BaseOperationIr::Slice(repr) => Box::new([&repr.tensor].into_iter()),
2283            BaseOperationIr::SliceAssign(repr) => Box::new([&repr.tensor, &repr.value].into_iter()),
2284            BaseOperationIr::Gather(repr) => Box::new([&repr.tensor, &repr.indices].into_iter()),
2285            BaseOperationIr::Scatter(repr) => {
2286                Box::new([&repr.tensor, &repr.indices, &repr.value].into_iter())
2287            }
2288            BaseOperationIr::ScatterNd(repr) => {
2289                Box::new([&repr.data, &repr.indices, &repr.values].into_iter())
2290            }
2291            BaseOperationIr::GatherNd(repr) => Box::new([&repr.data, &repr.indices].into_iter()),
2292            BaseOperationIr::Select(repr) => Box::new([&repr.tensor, &repr.indices].into_iter()),
2293            BaseOperationIr::SelectAssign(repr) => {
2294                Box::new([&repr.tensor, &repr.indices, &repr.value].into_iter())
2295            }
2296            BaseOperationIr::MaskWhere(repr) => {
2297                Box::new([&repr.tensor, &repr.mask, &repr.value].into_iter())
2298            }
2299            BaseOperationIr::MaskFill(repr) => Box::new([&repr.tensor, &repr.mask].into_iter()),
2300            BaseOperationIr::Equal(repr) => Box::new([&repr.lhs, &repr.rhs].into_iter()),
2301            BaseOperationIr::EqualElem(repr) => Box::new([&repr.lhs].into_iter()),
2302            BaseOperationIr::RepeatDim(repr) => Box::new([&repr.tensor].into_iter()),
2303            BaseOperationIr::Cat(repr) => Box::new(repr.tensors.iter()),
2304            BaseOperationIr::Cast(repr) => Box::new([&repr.input].into_iter()),
2305            BaseOperationIr::Unfold(repr) => Box::new([&repr.input].into_iter()),
2306            BaseOperationIr::Empty(_repr) => Box::new([].into_iter()),
2307            BaseOperationIr::Ones(_repr) => Box::new([].into_iter()),
2308            BaseOperationIr::Zeros(_repr) => Box::new([].into_iter()),
2309            BaseOperationIr::NotEqual(repr) => Box::new([&repr.lhs, &repr.rhs].into_iter()),
2310            BaseOperationIr::NotEqualElem(repr) => Box::new([&repr.lhs].into_iter()),
2311            BaseOperationIr::All(repr) => Box::new([&repr.input].into_iter()),
2312            BaseOperationIr::Any(repr) => Box::new([&repr.input].into_iter()),
2313            BaseOperationIr::AllDim(repr) => Box::new([&repr.input].into_iter()),
2314            BaseOperationIr::AnyDim(repr) => Box::new([&repr.input].into_iter()),
2315        }
2316    }
2317
2318    fn outputs(&self) -> Box<dyn Iterator<Item = &TensorIr> + '_> {
2319        match self {
2320            BaseOperationIr::Reshape(repr) => Box::new([&repr.out].into_iter()),
2321            BaseOperationIr::SwapDims(repr) => Box::new([&repr.out].into_iter()),
2322            BaseOperationIr::Permute(repr) => Box::new([&repr.out].into_iter()),
2323            BaseOperationIr::Expand(repr) => Box::new([&repr.out].into_iter()),
2324            BaseOperationIr::Flip(repr) => Box::new([&repr.out].into_iter()),
2325            BaseOperationIr::Slice(repr) => Box::new([&repr.out].into_iter()),
2326            BaseOperationIr::SliceAssign(repr) => Box::new([&repr.out].into_iter()),
2327            BaseOperationIr::Gather(repr) => Box::new([&repr.out].into_iter()),
2328            BaseOperationIr::Scatter(repr) => Box::new([&repr.out].into_iter()),
2329            BaseOperationIr::ScatterNd(repr) => Box::new([&repr.out].into_iter()),
2330            BaseOperationIr::GatherNd(repr) => Box::new([&repr.out].into_iter()),
2331            BaseOperationIr::Select(repr) => Box::new([&repr.out].into_iter()),
2332            BaseOperationIr::SelectAssign(repr) => Box::new([&repr.out].into_iter()),
2333            BaseOperationIr::MaskWhere(repr) => Box::new([&repr.out].into_iter()),
2334            BaseOperationIr::MaskFill(repr) => Box::new([&repr.out].into_iter()),
2335            BaseOperationIr::Equal(repr) => Box::new([&repr.out].into_iter()),
2336            BaseOperationIr::EqualElem(repr) => Box::new([&repr.out].into_iter()),
2337            BaseOperationIr::RepeatDim(repr) => Box::new([&repr.out].into_iter()),
2338            BaseOperationIr::Cat(repr) => Box::new([&repr.out].into_iter()),
2339            BaseOperationIr::Cast(repr) => Box::new([&repr.out].into_iter()),
2340            BaseOperationIr::Unfold(repr) => Box::new([&repr.out].into_iter()),
2341            BaseOperationIr::Empty(repr) => Box::new([&repr.out].into_iter()),
2342            BaseOperationIr::Ones(repr) => Box::new([&repr.out].into_iter()),
2343            BaseOperationIr::Zeros(repr) => Box::new([&repr.out].into_iter()),
2344            BaseOperationIr::NotEqual(repr) => Box::new([&repr.out].into_iter()),
2345            BaseOperationIr::NotEqualElem(repr) => Box::new([&repr.out].into_iter()),
2346            BaseOperationIr::All(repr) => Box::new([&repr.out].into_iter()),
2347            BaseOperationIr::Any(repr) => Box::new([&repr.out].into_iter()),
2348            BaseOperationIr::AllDim(repr) => Box::new([&repr.out].into_iter()),
2349            BaseOperationIr::AnyDim(repr) => Box::new([&repr.out].into_iter()),
2350        }
2351    }
2352
2353    fn mark_read_only(&mut self, nodes: &[TensorId]) -> Vec<TensorIr> {
2354        let mut output = Vec::new();
2355
2356        match self {
2357            BaseOperationIr::Reshape(repr) => {
2358                repr.input.mark_read_only(nodes, &mut output);
2359            }
2360            BaseOperationIr::SwapDims(repr) => {
2361                repr.input.mark_read_only(nodes, &mut output);
2362            }
2363            BaseOperationIr::Permute(repr) => {
2364                repr.input.mark_read_only(nodes, &mut output);
2365            }
2366
2367            BaseOperationIr::Expand(repr) => {
2368                repr.input.mark_read_only(nodes, &mut output);
2369            }
2370
2371            BaseOperationIr::Flip(repr) => {
2372                repr.input.mark_read_only(nodes, &mut output);
2373            }
2374            BaseOperationIr::Slice(repr) => {
2375                repr.tensor.mark_read_only(nodes, &mut output);
2376            }
2377            BaseOperationIr::SliceAssign(repr) => {
2378                repr.tensor.mark_read_only(nodes, &mut output);
2379                repr.value.mark_read_only(nodes, &mut output);
2380            }
2381            BaseOperationIr::Gather(repr) => {
2382                repr.tensor.mark_read_only(nodes, &mut output);
2383                repr.indices.mark_read_only(nodes, &mut output);
2384            }
2385            BaseOperationIr::Scatter(repr) => {
2386                repr.tensor.mark_read_only(nodes, &mut output);
2387                repr.indices.mark_read_only(nodes, &mut output);
2388                repr.value.mark_read_only(nodes, &mut output);
2389            }
2390            BaseOperationIr::ScatterNd(repr) => {
2391                repr.data.mark_read_only(nodes, &mut output);
2392                repr.indices.mark_read_only(nodes, &mut output);
2393                repr.values.mark_read_only(nodes, &mut output);
2394            }
2395            BaseOperationIr::GatherNd(repr) => {
2396                repr.data.mark_read_only(nodes, &mut output);
2397                repr.indices.mark_read_only(nodes, &mut output);
2398            }
2399            BaseOperationIr::Select(repr) => {
2400                repr.tensor.mark_read_only(nodes, &mut output);
2401                repr.indices.mark_read_only(nodes, &mut output);
2402            }
2403            BaseOperationIr::SelectAssign(repr) => {
2404                repr.tensor.mark_read_only(nodes, &mut output);
2405                repr.indices.mark_read_only(nodes, &mut output);
2406                repr.value.mark_read_only(nodes, &mut output);
2407            }
2408            BaseOperationIr::MaskWhere(repr) => {
2409                repr.tensor.mark_read_only(nodes, &mut output);
2410                repr.mask.mark_read_only(nodes, &mut output);
2411                repr.value.mark_read_only(nodes, &mut output);
2412            }
2413            BaseOperationIr::MaskFill(repr) => {
2414                repr.tensor.mark_read_only(nodes, &mut output);
2415                repr.mask.mark_read_only(nodes, &mut output);
2416            }
2417            BaseOperationIr::Equal(repr) => {
2418                repr.lhs.mark_read_only(nodes, &mut output);
2419                repr.rhs.mark_read_only(nodes, &mut output);
2420            }
2421            BaseOperationIr::EqualElem(repr) => {
2422                repr.lhs.mark_read_only(nodes, &mut output);
2423            }
2424            BaseOperationIr::RepeatDim(repr) => {
2425                repr.tensor.mark_read_only(nodes, &mut output);
2426            }
2427            BaseOperationIr::Cat(repr) => {
2428                for t in repr.tensors.iter_mut() {
2429                    t.mark_read_only(nodes, &mut output);
2430                }
2431            }
2432            BaseOperationIr::Cast(repr) => {
2433                repr.input.mark_read_only(nodes, &mut output);
2434            }
2435            BaseOperationIr::Unfold(repr) => {
2436                repr.input.mark_read_only(nodes, &mut output);
2437            }
2438            BaseOperationIr::Empty(_) => {}
2439            BaseOperationIr::Zeros(_) => {}
2440            BaseOperationIr::Ones(_) => {}
2441            BaseOperationIr::NotEqual(repr) => {
2442                repr.lhs.mark_read_only(nodes, &mut output);
2443                repr.rhs.mark_read_only(nodes, &mut output);
2444            }
2445            BaseOperationIr::NotEqualElem(repr) => {
2446                repr.lhs.mark_read_only(nodes, &mut output);
2447            }
2448            BaseOperationIr::All(repr) => {
2449                repr.input.mark_read_only(nodes, &mut output);
2450            }
2451            BaseOperationIr::Any(repr) => {
2452                repr.input.mark_read_only(nodes, &mut output);
2453            }
2454            BaseOperationIr::AllDim(repr) => {
2455                repr.input.mark_read_only(nodes, &mut output);
2456            }
2457            BaseOperationIr::AnyDim(repr) => {
2458                repr.input.mark_read_only(nodes, &mut output);
2459            }
2460        };
2461
2462        output
2463    }
2464
2465    fn visit_mut(&mut self, v: &mut impl IrVisitorMut) {
2466        match self {
2467            BaseOperationIr::Reshape(repr) => {
2468                v.visit_tensor_mut(&mut repr.input);
2469                v.visit_tensor_mut(&mut repr.out);
2470            }
2471            BaseOperationIr::SwapDims(repr) => {
2472                v.visit_tensor_mut(&mut repr.input);
2473                v.visit_tensor_mut(&mut repr.out);
2474            }
2475            BaseOperationIr::Permute(repr) => {
2476                v.visit_tensor_mut(&mut repr.input);
2477                v.visit_tensor_mut(&mut repr.out);
2478            }
2479            BaseOperationIr::Expand(repr) => {
2480                v.visit_tensor_mut(&mut repr.input);
2481                v.visit_tensor_mut(&mut repr.out);
2482            }
2483            BaseOperationIr::Flip(repr) => {
2484                v.visit_tensor_mut(&mut repr.input);
2485                v.visit_tensor_mut(&mut repr.out);
2486            }
2487            BaseOperationIr::Slice(repr) => {
2488                v.visit_tensor_mut(&mut repr.tensor);
2489                v.visit_tensor_mut(&mut repr.out);
2490                repr.ranges.iter_mut().for_each(|r| v.visit_range_mut(r));
2491            }
2492            BaseOperationIr::SliceAssign(repr) => {
2493                v.visit_tensor_mut(&mut repr.tensor);
2494                v.visit_tensor_mut(&mut repr.value);
2495                v.visit_tensor_mut(&mut repr.out);
2496                repr.ranges.iter_mut().for_each(|r| v.visit_range_mut(r));
2497            }
2498            BaseOperationIr::Gather(repr) => {
2499                v.visit_tensor_mut(&mut repr.tensor);
2500                v.visit_tensor_mut(&mut repr.indices);
2501                v.visit_tensor_mut(&mut repr.out);
2502            }
2503            BaseOperationIr::Scatter(repr) => {
2504                v.visit_tensor_mut(&mut repr.tensor);
2505                v.visit_tensor_mut(&mut repr.indices);
2506                v.visit_tensor_mut(&mut repr.value);
2507                v.visit_tensor_mut(&mut repr.out);
2508            }
2509            BaseOperationIr::ScatterNd(repr) => {
2510                v.visit_tensor_mut(&mut repr.data);
2511                v.visit_tensor_mut(&mut repr.indices);
2512                v.visit_tensor_mut(&mut repr.values);
2513                v.visit_tensor_mut(&mut repr.out);
2514            }
2515            BaseOperationIr::GatherNd(repr) => {
2516                v.visit_tensor_mut(&mut repr.data);
2517                v.visit_tensor_mut(&mut repr.indices);
2518                v.visit_tensor_mut(&mut repr.out);
2519            }
2520            BaseOperationIr::Select(repr) => {
2521                v.visit_tensor_mut(&mut repr.tensor);
2522                v.visit_tensor_mut(&mut repr.indices);
2523                v.visit_tensor_mut(&mut repr.out);
2524            }
2525            BaseOperationIr::SelectAssign(repr) => {
2526                v.visit_tensor_mut(&mut repr.tensor);
2527                v.visit_tensor_mut(&mut repr.indices);
2528                v.visit_tensor_mut(&mut repr.value);
2529                v.visit_tensor_mut(&mut repr.out);
2530            }
2531            BaseOperationIr::MaskWhere(repr) => {
2532                v.visit_tensor_mut(&mut repr.tensor);
2533                v.visit_tensor_mut(&mut repr.mask);
2534                v.visit_tensor_mut(&mut repr.value);
2535                v.visit_tensor_mut(&mut repr.out);
2536            }
2537            BaseOperationIr::MaskFill(repr) => {
2538                v.visit_tensor_mut(&mut repr.tensor);
2539                v.visit_tensor_mut(&mut repr.mask);
2540                v.visit_tensor_mut(&mut repr.out);
2541                v.visit_scalar_mut(&mut repr.value);
2542            }
2543            BaseOperationIr::Equal(repr) => {
2544                v.visit_tensor_mut(&mut repr.lhs);
2545                v.visit_tensor_mut(&mut repr.rhs);
2546                v.visit_tensor_mut(&mut repr.out);
2547            }
2548            BaseOperationIr::EqualElem(repr) => {
2549                v.visit_tensor_mut(&mut repr.lhs);
2550                v.visit_tensor_mut(&mut repr.out);
2551                v.visit_scalar_mut(&mut repr.rhs);
2552            }
2553            BaseOperationIr::RepeatDim(repr) => {
2554                v.visit_tensor_mut(&mut repr.tensor);
2555                v.visit_tensor_mut(&mut repr.out);
2556            }
2557            BaseOperationIr::Cat(repr) => {
2558                for t in repr.tensors.iter_mut() {
2559                    v.visit_tensor_mut(t);
2560                }
2561                v.visit_tensor_mut(&mut repr.out);
2562            }
2563            BaseOperationIr::Cast(repr) => {
2564                v.visit_tensor_mut(&mut repr.input);
2565                v.visit_tensor_mut(&mut repr.out);
2566            }
2567            BaseOperationIr::Unfold(repr) => {
2568                v.visit_tensor_mut(&mut repr.input);
2569                v.visit_tensor_mut(&mut repr.out);
2570            }
2571            BaseOperationIr::Empty(repr) => {
2572                v.visit_tensor_mut(&mut repr.out);
2573            }
2574            BaseOperationIr::Ones(repr) => {
2575                v.visit_tensor_mut(&mut repr.out);
2576            }
2577            BaseOperationIr::Zeros(repr) => {
2578                v.visit_tensor_mut(&mut repr.out);
2579            }
2580            BaseOperationIr::NotEqual(repr) => {
2581                v.visit_tensor_mut(&mut repr.lhs);
2582                v.visit_tensor_mut(&mut repr.rhs);
2583                v.visit_tensor_mut(&mut repr.out);
2584            }
2585            BaseOperationIr::NotEqualElem(repr) => {
2586                v.visit_tensor_mut(&mut repr.lhs);
2587                v.visit_tensor_mut(&mut repr.out);
2588                v.visit_scalar_mut(&mut repr.rhs);
2589            }
2590            BaseOperationIr::All(repr) => {
2591                v.visit_tensor_mut(&mut repr.input);
2592                v.visit_tensor_mut(&mut repr.out);
2593            }
2594            BaseOperationIr::Any(repr) => {
2595                v.visit_tensor_mut(&mut repr.input);
2596                v.visit_tensor_mut(&mut repr.out);
2597            }
2598            BaseOperationIr::AllDim(repr) => {
2599                v.visit_tensor_mut(&mut repr.input);
2600                v.visit_tensor_mut(&mut repr.out);
2601            }
2602            BaseOperationIr::AnyDim(repr) => {
2603                v.visit_tensor_mut(&mut repr.input);
2604                v.visit_tensor_mut(&mut repr.out);
2605            }
2606        }
2607    }
2608}
2609
2610impl NumericOperationIr {
2611    fn inputs(&self) -> Box<dyn Iterator<Item = &TensorIr> + '_> {
2612        match self {
2613            NumericOperationIr::Add(repr) => Box::new([&repr.lhs, &repr.rhs].into_iter()),
2614            NumericOperationIr::AddScalar(repr) => Box::new([&repr.lhs].into_iter()),
2615            NumericOperationIr::Sub(repr) => Box::new([&repr.lhs, &repr.rhs].into_iter()),
2616            NumericOperationIr::SubScalar(repr) => Box::new([&repr.lhs].into_iter()),
2617            NumericOperationIr::Mul(repr) => Box::new([&repr.lhs, &repr.rhs].into_iter()),
2618            NumericOperationIr::MulScalar(repr) => Box::new([&repr.lhs].into_iter()),
2619            NumericOperationIr::Div(repr) => Box::new([&repr.lhs, &repr.rhs].into_iter()),
2620            NumericOperationIr::DivScalar(repr) => Box::new([&repr.lhs].into_iter()),
2621            NumericOperationIr::Rem(repr) => Box::new([&repr.lhs, &repr.rhs].into_iter()),
2622            NumericOperationIr::RemScalar(repr) => Box::new([&repr.lhs].into_iter()),
2623            NumericOperationIr::GreaterElem(repr) => Box::new([&repr.lhs].into_iter()),
2624            NumericOperationIr::GreaterEqualElem(repr) => Box::new([&repr.lhs].into_iter()),
2625            NumericOperationIr::LowerElem(repr) => Box::new([&repr.lhs].into_iter()),
2626            NumericOperationIr::LowerEqualElem(repr) => Box::new([&repr.lhs].into_iter()),
2627            NumericOperationIr::Greater(repr) => Box::new([&repr.lhs, &repr.rhs].into_iter()),
2628            NumericOperationIr::GreaterEqual(repr) => Box::new([&repr.lhs, &repr.rhs].into_iter()),
2629            NumericOperationIr::Lower(repr) => Box::new([&repr.lhs, &repr.rhs].into_iter()),
2630            NumericOperationIr::LowerEqual(repr) => Box::new([&repr.lhs, &repr.rhs].into_iter()),
2631            NumericOperationIr::ArgMax(repr) => Box::new([&repr.input].into_iter()),
2632            NumericOperationIr::ArgTopK(repr) => Box::new([&repr.input].into_iter()),
2633            NumericOperationIr::TopK(repr) => Box::new([&repr.input].into_iter()),
2634            NumericOperationIr::ArgMin(repr) => Box::new([&repr.input].into_iter()),
2635            NumericOperationIr::Clamp(repr) => Box::new([&repr.tensor].into_iter()),
2636            NumericOperationIr::Abs(repr) => Box::new([&repr.input].into_iter()),
2637            NumericOperationIr::Full(_repr) => Box::new([].into_iter()),
2638            NumericOperationIr::MeanDim(repr) => Box::new([&repr.input].into_iter()),
2639            NumericOperationIr::Mean(repr) => Box::new([&repr.input].into_iter()),
2640            NumericOperationIr::Sum(repr) => Box::new([&repr.input].into_iter()),
2641            NumericOperationIr::SumDim(repr) => Box::new([&repr.input].into_iter()),
2642            NumericOperationIr::SumDims(repr) => Box::new([&repr.input].into_iter()),
2643            NumericOperationIr::Prod(repr) => Box::new([&repr.input].into_iter()),
2644            NumericOperationIr::ProdDim(repr) => Box::new([&repr.input].into_iter()),
2645            NumericOperationIr::Max(repr) => Box::new([&repr.input].into_iter()),
2646            NumericOperationIr::MaxDimWithIndices(repr) => Box::new([&repr.tensor].into_iter()),
2647            NumericOperationIr::TopKWithIndices(repr) => Box::new([&repr.tensor].into_iter()),
2648            NumericOperationIr::MinDimWithIndices(repr) => Box::new([&repr.tensor].into_iter()),
2649            NumericOperationIr::Min(repr) => Box::new([&repr.input].into_iter()),
2650            NumericOperationIr::MaxDim(repr) => Box::new([&repr.input].into_iter()),
2651            NumericOperationIr::MinDim(repr) => Box::new([&repr.input].into_iter()),
2652            NumericOperationIr::MaxAbs(repr) => Box::new([&repr.input].into_iter()),
2653            NumericOperationIr::MaxAbsDim(repr) => Box::new([&repr.input].into_iter()),
2654            NumericOperationIr::IntRandom(_repr) => Box::new([].into_iter()),
2655            NumericOperationIr::Powi(repr) => Box::new([&repr.lhs, &repr.rhs].into_iter()),
2656            NumericOperationIr::PowiScalar(repr) => Box::new([&repr.lhs].into_iter()),
2657            NumericOperationIr::CumMin(repr) => Box::new([&repr.input].into_iter()),
2658            NumericOperationIr::CumMax(repr) => Box::new([&repr.input].into_iter()),
2659            NumericOperationIr::CumProd(repr) => Box::new([&repr.input].into_iter()),
2660            NumericOperationIr::CumSum(repr) => Box::new([&repr.input].into_iter()),
2661            NumericOperationIr::Neg(repr) => Box::new([&repr.input].into_iter()),
2662            NumericOperationIr::Sign(repr) => Box::new([&repr.input].into_iter()),
2663            NumericOperationIr::ClampMin(repr) => Box::new([&repr.lhs].into_iter()),
2664            NumericOperationIr::ClampMax(repr) => Box::new([&repr.lhs].into_iter()),
2665            NumericOperationIr::Sort(repr) => Box::new([&repr.input].into_iter()),
2666            NumericOperationIr::SortWithIndices(repr) => Box::new([&repr.input].into_iter()),
2667            NumericOperationIr::ArgSort(repr) => Box::new([&repr.input].into_iter()),
2668            NumericOperationIr::Pad(repr) => Box::new([&repr.input].into_iter()),
2669        }
2670    }
2671
2672    fn outputs(&self) -> Box<dyn Iterator<Item = &TensorIr> + '_> {
2673        match self {
2674            NumericOperationIr::Add(repr) => Box::new([&repr.out].into_iter()),
2675            NumericOperationIr::AddScalar(repr) => Box::new([&repr.out].into_iter()),
2676            NumericOperationIr::Sub(repr) => Box::new([&repr.out].into_iter()),
2677            NumericOperationIr::SubScalar(repr) => Box::new([&repr.out].into_iter()),
2678            NumericOperationIr::Mul(repr) => Box::new([&repr.out].into_iter()),
2679            NumericOperationIr::MulScalar(repr) => Box::new([&repr.out].into_iter()),
2680            NumericOperationIr::Div(repr) => Box::new([&repr.out].into_iter()),
2681            NumericOperationIr::DivScalar(repr) => Box::new([&repr.out].into_iter()),
2682            NumericOperationIr::Rem(repr) => Box::new([&repr.out].into_iter()),
2683            NumericOperationIr::RemScalar(repr) => Box::new([&repr.out].into_iter()),
2684            NumericOperationIr::GreaterElem(repr) => Box::new([&repr.out].into_iter()),
2685            NumericOperationIr::GreaterEqualElem(repr) => Box::new([&repr.out].into_iter()),
2686            NumericOperationIr::LowerElem(repr) => Box::new([&repr.out].into_iter()),
2687            NumericOperationIr::LowerEqualElem(repr) => Box::new([&repr.out].into_iter()),
2688            NumericOperationIr::Greater(repr) => Box::new([&repr.out].into_iter()),
2689            NumericOperationIr::GreaterEqual(repr) => Box::new([&repr.out].into_iter()),
2690            NumericOperationIr::Lower(repr) => Box::new([&repr.out].into_iter()),
2691            NumericOperationIr::LowerEqual(repr) => Box::new([&repr.out].into_iter()),
2692            NumericOperationIr::ArgMax(repr) => Box::new([&repr.out].into_iter()),
2693            NumericOperationIr::ArgTopK(repr) => Box::new([&repr.out].into_iter()),
2694            NumericOperationIr::TopK(repr) => Box::new([&repr.out].into_iter()),
2695            NumericOperationIr::ArgMin(repr) => Box::new([&repr.out].into_iter()),
2696            NumericOperationIr::Clamp(repr) => Box::new([&repr.out].into_iter()),
2697            NumericOperationIr::Abs(repr) => Box::new([&repr.out].into_iter()),
2698            NumericOperationIr::Full(repr) => Box::new([&repr.out].into_iter()),
2699            NumericOperationIr::MeanDim(repr) => Box::new([&repr.out].into_iter()),
2700            NumericOperationIr::Mean(repr) => Box::new([&repr.out].into_iter()),
2701            NumericOperationIr::Sum(repr) => Box::new([&repr.out].into_iter()),
2702            NumericOperationIr::SumDim(repr) => Box::new([&repr.out].into_iter()),
2703            NumericOperationIr::SumDims(repr) => Box::new([&repr.out].into_iter()),
2704            NumericOperationIr::Prod(repr) => Box::new([&repr.out].into_iter()),
2705            NumericOperationIr::ProdDim(repr) => Box::new([&repr.out].into_iter()),
2706            NumericOperationIr::Max(repr) => Box::new([&repr.out].into_iter()),
2707            NumericOperationIr::MaxDimWithIndices(repr) => {
2708                Box::new([&repr.out, &repr.out_indices].into_iter())
2709            }
2710            NumericOperationIr::TopKWithIndices(repr) => {
2711                Box::new([&repr.out, &repr.out_indices].into_iter())
2712            }
2713            NumericOperationIr::MinDimWithIndices(repr) => {
2714                Box::new([&repr.out, &repr.out_indices].into_iter())
2715            }
2716            NumericOperationIr::Min(repr) => Box::new([&repr.out].into_iter()),
2717            NumericOperationIr::MaxDim(repr) => Box::new([&repr.out].into_iter()),
2718            NumericOperationIr::MinDim(repr) => Box::new([&repr.out].into_iter()),
2719            NumericOperationIr::MaxAbs(repr) => Box::new([&repr.out].into_iter()),
2720            NumericOperationIr::MaxAbsDim(repr) => Box::new([&repr.out].into_iter()),
2721            NumericOperationIr::IntRandom(repr) => Box::new([&repr.out].into_iter()),
2722            NumericOperationIr::Powi(repr) => Box::new([&repr.out].into_iter()),
2723            NumericOperationIr::PowiScalar(repr) => Box::new([&repr.out].into_iter()),
2724            NumericOperationIr::CumMin(repr) => Box::new([&repr.out].into_iter()),
2725            NumericOperationIr::CumMax(repr) => Box::new([&repr.out].into_iter()),
2726            NumericOperationIr::CumProd(repr) => Box::new([&repr.out].into_iter()),
2727            NumericOperationIr::CumSum(repr) => Box::new([&repr.out].into_iter()),
2728            NumericOperationIr::Neg(repr) => Box::new([&repr.out].into_iter()),
2729            NumericOperationIr::Sign(repr) => Box::new([&repr.out].into_iter()),
2730            NumericOperationIr::ClampMin(repr) => Box::new([&repr.out].into_iter()),
2731            NumericOperationIr::ClampMax(repr) => Box::new([&repr.out].into_iter()),
2732            NumericOperationIr::Sort(repr) => Box::new([&repr.out].into_iter()),
2733            NumericOperationIr::SortWithIndices(repr) => {
2734                Box::new([&repr.out, &repr.out_indices].into_iter())
2735            }
2736            NumericOperationIr::ArgSort(repr) => Box::new([&repr.out].into_iter()),
2737            NumericOperationIr::Pad(repr) => Box::new([&repr.out].into_iter()),
2738        }
2739    }
2740    fn mark_read_only(&mut self, nodes: &[TensorId]) -> Vec<TensorIr> {
2741        let mut output = Vec::new();
2742
2743        match self {
2744            NumericOperationIr::Add(repr) => {
2745                repr.lhs.mark_read_only(nodes, &mut output);
2746                repr.rhs.mark_read_only(nodes, &mut output);
2747            }
2748            NumericOperationIr::AddScalar(repr) => {
2749                repr.lhs.mark_read_only(nodes, &mut output);
2750            }
2751            NumericOperationIr::Sub(repr) => {
2752                repr.lhs.mark_read_only(nodes, &mut output);
2753                repr.rhs.mark_read_only(nodes, &mut output);
2754            }
2755            NumericOperationIr::SubScalar(repr) => {
2756                repr.lhs.mark_read_only(nodes, &mut output);
2757            }
2758            NumericOperationIr::Mul(repr) => {
2759                repr.lhs.mark_read_only(nodes, &mut output);
2760                repr.rhs.mark_read_only(nodes, &mut output);
2761            }
2762            NumericOperationIr::MulScalar(repr) => {
2763                repr.lhs.mark_read_only(nodes, &mut output);
2764            }
2765            NumericOperationIr::Div(repr) => {
2766                repr.lhs.mark_read_only(nodes, &mut output);
2767                repr.rhs.mark_read_only(nodes, &mut output);
2768            }
2769            NumericOperationIr::DivScalar(repr) => {
2770                repr.lhs.mark_read_only(nodes, &mut output);
2771            }
2772            NumericOperationIr::Rem(repr) => {
2773                repr.lhs.mark_read_only(nodes, &mut output);
2774                repr.rhs.mark_read_only(nodes, &mut output);
2775            }
2776            NumericOperationIr::RemScalar(repr) => {
2777                repr.lhs.mark_read_only(nodes, &mut output);
2778            }
2779            NumericOperationIr::GreaterElem(repr) => {
2780                repr.lhs.mark_read_only(nodes, &mut output);
2781            }
2782            NumericOperationIr::GreaterEqualElem(repr) => {
2783                repr.lhs.mark_read_only(nodes, &mut output);
2784            }
2785            NumericOperationIr::LowerElem(repr) => {
2786                repr.lhs.mark_read_only(nodes, &mut output);
2787            }
2788            NumericOperationIr::LowerEqualElem(repr) => {
2789                repr.lhs.mark_read_only(nodes, &mut output);
2790            }
2791            NumericOperationIr::Greater(repr) => {
2792                repr.lhs.mark_read_only(nodes, &mut output);
2793                repr.rhs.mark_read_only(nodes, &mut output);
2794            }
2795            NumericOperationIr::GreaterEqual(repr) => {
2796                repr.lhs.mark_read_only(nodes, &mut output);
2797                repr.rhs.mark_read_only(nodes, &mut output);
2798            }
2799            NumericOperationIr::Lower(repr) => {
2800                repr.lhs.mark_read_only(nodes, &mut output);
2801                repr.rhs.mark_read_only(nodes, &mut output);
2802            }
2803            NumericOperationIr::LowerEqual(repr) => {
2804                repr.lhs.mark_read_only(nodes, &mut output);
2805                repr.rhs.mark_read_only(nodes, &mut output);
2806            }
2807            NumericOperationIr::ArgMax(repr) => {
2808                repr.input.mark_read_only(nodes, &mut output);
2809            }
2810            NumericOperationIr::ArgTopK(repr) => {
2811                repr.input.mark_read_only(nodes, &mut output);
2812            }
2813            NumericOperationIr::TopK(repr) => {
2814                repr.input.mark_read_only(nodes, &mut output);
2815            }
2816            NumericOperationIr::ArgMin(repr) => {
2817                repr.input.mark_read_only(nodes, &mut output);
2818            }
2819            NumericOperationIr::Clamp(repr) => {
2820                repr.tensor.mark_read_only(nodes, &mut output);
2821            }
2822            NumericOperationIr::Abs(repr) => {
2823                repr.input.mark_read_only(nodes, &mut output);
2824            }
2825            NumericOperationIr::Full(_) => {}
2826            NumericOperationIr::MeanDim(repr) => {
2827                repr.input.mark_read_only(nodes, &mut output);
2828            }
2829            NumericOperationIr::Mean(repr) => {
2830                repr.input.mark_read_only(nodes, &mut output);
2831            }
2832            NumericOperationIr::Sum(repr) => {
2833                repr.input.mark_read_only(nodes, &mut output);
2834            }
2835            NumericOperationIr::SumDim(repr) => {
2836                repr.input.mark_read_only(nodes, &mut output);
2837            }
2838            NumericOperationIr::SumDims(repr) => {
2839                repr.input.mark_read_only(nodes, &mut output);
2840            }
2841            NumericOperationIr::Prod(repr) => {
2842                repr.input.mark_read_only(nodes, &mut output);
2843            }
2844            NumericOperationIr::ProdDim(repr) => {
2845                repr.input.mark_read_only(nodes, &mut output);
2846            }
2847            NumericOperationIr::Max(repr) => {
2848                repr.input.mark_read_only(nodes, &mut output);
2849            }
2850            NumericOperationIr::MaxDimWithIndices(repr) => {
2851                repr.tensor.mark_read_only(nodes, &mut output);
2852            }
2853            NumericOperationIr::TopKWithIndices(repr) => {
2854                repr.tensor.mark_read_only(nodes, &mut output);
2855            }
2856            NumericOperationIr::MinDimWithIndices(repr) => {
2857                repr.tensor.mark_read_only(nodes, &mut output);
2858            }
2859            NumericOperationIr::Min(repr) => {
2860                repr.input.mark_read_only(nodes, &mut output);
2861            }
2862            NumericOperationIr::MaxDim(repr) => {
2863                repr.input.mark_read_only(nodes, &mut output);
2864            }
2865            NumericOperationIr::MinDim(repr) => {
2866                repr.input.mark_read_only(nodes, &mut output);
2867            }
2868            NumericOperationIr::MaxAbs(repr) => {
2869                repr.input.mark_read_only(nodes, &mut output);
2870            }
2871            NumericOperationIr::MaxAbsDim(repr) => {
2872                repr.input.mark_read_only(nodes, &mut output);
2873            }
2874            NumericOperationIr::IntRandom(_) => {}
2875            NumericOperationIr::Powi(repr) => {
2876                repr.lhs.mark_read_only(nodes, &mut output);
2877                repr.rhs.mark_read_only(nodes, &mut output);
2878            }
2879            NumericOperationIr::PowiScalar(repr) => {
2880                repr.lhs.mark_read_only(nodes, &mut output);
2881            }
2882            NumericOperationIr::CumSum(repr) => {
2883                repr.input.mark_read_only(nodes, &mut output);
2884            }
2885            NumericOperationIr::CumProd(repr) => {
2886                repr.input.mark_read_only(nodes, &mut output);
2887            }
2888            NumericOperationIr::CumMin(repr) => {
2889                repr.input.mark_read_only(nodes, &mut output);
2890            }
2891            NumericOperationIr::CumMax(repr) => {
2892                repr.input.mark_read_only(nodes, &mut output);
2893            }
2894            NumericOperationIr::Neg(repr) => {
2895                repr.input.mark_read_only(nodes, &mut output);
2896            }
2897            NumericOperationIr::Sign(repr) => {
2898                repr.input.mark_read_only(nodes, &mut output);
2899            }
2900            NumericOperationIr::ClampMin(repr) => {
2901                repr.lhs.mark_read_only(nodes, &mut output);
2902            }
2903            NumericOperationIr::ClampMax(repr) => {
2904                repr.lhs.mark_read_only(nodes, &mut output);
2905            }
2906            NumericOperationIr::Sort(repr) => {
2907                repr.input.mark_read_only(nodes, &mut output);
2908            }
2909            NumericOperationIr::SortWithIndices(repr) => {
2910                repr.input.mark_read_only(nodes, &mut output);
2911            }
2912            NumericOperationIr::ArgSort(repr) => {
2913                repr.input.mark_read_only(nodes, &mut output);
2914            }
2915            NumericOperationIr::Pad(repr) => {
2916                repr.input.mark_read_only(nodes, &mut output);
2917            }
2918        };
2919
2920        output
2921    }
2922
2923    fn visit_mut(&mut self, v: &mut impl IrVisitorMut) {
2924        match self {
2925            NumericOperationIr::Add(repr) => {
2926                v.visit_tensor_mut(&mut repr.lhs);
2927                v.visit_tensor_mut(&mut repr.rhs);
2928                v.visit_tensor_mut(&mut repr.out);
2929            }
2930            NumericOperationIr::AddScalar(repr) => {
2931                v.visit_tensor_mut(&mut repr.lhs);
2932                v.visit_tensor_mut(&mut repr.out);
2933                v.visit_scalar_mut(&mut repr.rhs);
2934            }
2935            NumericOperationIr::Sub(repr) => {
2936                v.visit_tensor_mut(&mut repr.lhs);
2937                v.visit_tensor_mut(&mut repr.rhs);
2938                v.visit_tensor_mut(&mut repr.out);
2939            }
2940            NumericOperationIr::SubScalar(repr) => {
2941                v.visit_tensor_mut(&mut repr.lhs);
2942                v.visit_tensor_mut(&mut repr.out);
2943                v.visit_scalar_mut(&mut repr.rhs);
2944            }
2945            NumericOperationIr::Mul(repr) => {
2946                v.visit_tensor_mut(&mut repr.lhs);
2947                v.visit_tensor_mut(&mut repr.rhs);
2948                v.visit_tensor_mut(&mut repr.out);
2949            }
2950            NumericOperationIr::MulScalar(repr) => {
2951                v.visit_tensor_mut(&mut repr.lhs);
2952                v.visit_tensor_mut(&mut repr.out);
2953                v.visit_scalar_mut(&mut repr.rhs);
2954            }
2955            NumericOperationIr::Div(repr) => {
2956                v.visit_tensor_mut(&mut repr.lhs);
2957                v.visit_tensor_mut(&mut repr.rhs);
2958                v.visit_tensor_mut(&mut repr.out);
2959            }
2960            NumericOperationIr::DivScalar(repr) => {
2961                v.visit_tensor_mut(&mut repr.lhs);
2962                v.visit_tensor_mut(&mut repr.out);
2963                v.visit_scalar_mut(&mut repr.rhs);
2964            }
2965            NumericOperationIr::Rem(repr) => {
2966                v.visit_tensor_mut(&mut repr.lhs);
2967                v.visit_tensor_mut(&mut repr.rhs);
2968                v.visit_tensor_mut(&mut repr.out);
2969            }
2970            NumericOperationIr::RemScalar(repr) => {
2971                v.visit_tensor_mut(&mut repr.lhs);
2972                v.visit_tensor_mut(&mut repr.out);
2973                v.visit_scalar_mut(&mut repr.rhs);
2974            }
2975            NumericOperationIr::GreaterElem(repr) => {
2976                v.visit_tensor_mut(&mut repr.lhs);
2977                v.visit_tensor_mut(&mut repr.out);
2978                v.visit_scalar_mut(&mut repr.rhs);
2979            }
2980            NumericOperationIr::GreaterEqualElem(repr) => {
2981                v.visit_tensor_mut(&mut repr.lhs);
2982                v.visit_tensor_mut(&mut repr.out);
2983                v.visit_scalar_mut(&mut repr.rhs);
2984            }
2985            NumericOperationIr::LowerElem(repr) => {
2986                v.visit_tensor_mut(&mut repr.lhs);
2987                v.visit_tensor_mut(&mut repr.out);
2988                v.visit_scalar_mut(&mut repr.rhs);
2989            }
2990            NumericOperationIr::LowerEqualElem(repr) => {
2991                v.visit_tensor_mut(&mut repr.lhs);
2992                v.visit_tensor_mut(&mut repr.out);
2993                v.visit_scalar_mut(&mut repr.rhs);
2994            }
2995            NumericOperationIr::Greater(repr) => {
2996                v.visit_tensor_mut(&mut repr.lhs);
2997                v.visit_tensor_mut(&mut repr.rhs);
2998                v.visit_tensor_mut(&mut repr.out);
2999            }
3000            NumericOperationIr::GreaterEqual(repr) => {
3001                v.visit_tensor_mut(&mut repr.lhs);
3002                v.visit_tensor_mut(&mut repr.rhs);
3003                v.visit_tensor_mut(&mut repr.out);
3004            }
3005            NumericOperationIr::Lower(repr) => {
3006                v.visit_tensor_mut(&mut repr.lhs);
3007                v.visit_tensor_mut(&mut repr.rhs);
3008                v.visit_tensor_mut(&mut repr.out);
3009            }
3010            NumericOperationIr::LowerEqual(repr) => {
3011                v.visit_tensor_mut(&mut repr.lhs);
3012                v.visit_tensor_mut(&mut repr.rhs);
3013                v.visit_tensor_mut(&mut repr.out);
3014            }
3015            NumericOperationIr::ArgMax(repr) => {
3016                v.visit_tensor_mut(&mut repr.input);
3017                v.visit_tensor_mut(&mut repr.out);
3018            }
3019            NumericOperationIr::ArgTopK(repr) => {
3020                v.visit_tensor_mut(&mut repr.input);
3021                v.visit_tensor_mut(&mut repr.out);
3022            }
3023            NumericOperationIr::TopK(repr) => {
3024                v.visit_tensor_mut(&mut repr.input);
3025                v.visit_tensor_mut(&mut repr.out);
3026            }
3027            NumericOperationIr::ArgMin(repr) => {
3028                v.visit_tensor_mut(&mut repr.input);
3029                v.visit_tensor_mut(&mut repr.out);
3030            }
3031            NumericOperationIr::Clamp(repr) => {
3032                v.visit_tensor_mut(&mut repr.tensor);
3033                v.visit_tensor_mut(&mut repr.out);
3034                v.visit_scalar_mut(&mut repr.min);
3035                v.visit_scalar_mut(&mut repr.max);
3036            }
3037            NumericOperationIr::Abs(repr) => {
3038                v.visit_tensor_mut(&mut repr.input);
3039                v.visit_tensor_mut(&mut repr.out);
3040            }
3041            NumericOperationIr::Full(repr) => {
3042                v.visit_tensor_mut(&mut repr.out);
3043                v.visit_scalar_mut(&mut repr.value);
3044            }
3045            NumericOperationIr::MeanDim(repr) => {
3046                v.visit_tensor_mut(&mut repr.input);
3047                v.visit_tensor_mut(&mut repr.out);
3048            }
3049            NumericOperationIr::Mean(repr) => {
3050                v.visit_tensor_mut(&mut repr.input);
3051                v.visit_tensor_mut(&mut repr.out);
3052            }
3053            NumericOperationIr::Sum(repr) => {
3054                v.visit_tensor_mut(&mut repr.input);
3055                v.visit_tensor_mut(&mut repr.out);
3056            }
3057            NumericOperationIr::SumDim(repr) => {
3058                v.visit_tensor_mut(&mut repr.input);
3059                v.visit_tensor_mut(&mut repr.out);
3060            }
3061            NumericOperationIr::SumDims(repr) => {
3062                v.visit_tensor_mut(&mut repr.input);
3063                v.visit_tensor_mut(&mut repr.out);
3064            }
3065            NumericOperationIr::Prod(repr) => {
3066                v.visit_tensor_mut(&mut repr.input);
3067                v.visit_tensor_mut(&mut repr.out);
3068            }
3069            NumericOperationIr::ProdDim(repr) => {
3070                v.visit_tensor_mut(&mut repr.input);
3071                v.visit_tensor_mut(&mut repr.out);
3072            }
3073            NumericOperationIr::Max(repr) => {
3074                v.visit_tensor_mut(&mut repr.input);
3075                v.visit_tensor_mut(&mut repr.out);
3076            }
3077            NumericOperationIr::MaxDimWithIndices(repr) => {
3078                v.visit_tensor_mut(&mut repr.tensor);
3079                v.visit_tensor_mut(&mut repr.out);
3080                v.visit_tensor_mut(&mut repr.out_indices);
3081            }
3082            NumericOperationIr::TopKWithIndices(repr) => {
3083                v.visit_tensor_mut(&mut repr.tensor);
3084                v.visit_tensor_mut(&mut repr.out);
3085                v.visit_tensor_mut(&mut repr.out_indices);
3086            }
3087            NumericOperationIr::MinDimWithIndices(repr) => {
3088                v.visit_tensor_mut(&mut repr.tensor);
3089                v.visit_tensor_mut(&mut repr.out);
3090                v.visit_tensor_mut(&mut repr.out_indices);
3091            }
3092            NumericOperationIr::Min(repr) => {
3093                v.visit_tensor_mut(&mut repr.input);
3094                v.visit_tensor_mut(&mut repr.out);
3095            }
3096            NumericOperationIr::MaxDim(repr) => {
3097                v.visit_tensor_mut(&mut repr.input);
3098                v.visit_tensor_mut(&mut repr.out);
3099            }
3100            NumericOperationIr::MinDim(repr) => {
3101                v.visit_tensor_mut(&mut repr.input);
3102                v.visit_tensor_mut(&mut repr.out);
3103            }
3104            NumericOperationIr::MaxAbs(repr) => {
3105                v.visit_tensor_mut(&mut repr.input);
3106                v.visit_tensor_mut(&mut repr.out);
3107            }
3108            NumericOperationIr::MaxAbsDim(repr) => {
3109                v.visit_tensor_mut(&mut repr.input);
3110                v.visit_tensor_mut(&mut repr.out);
3111            }
3112            NumericOperationIr::IntRandom(repr) => {
3113                v.visit_tensor_mut(&mut repr.out);
3114            }
3115            NumericOperationIr::Powi(repr) => {
3116                v.visit_tensor_mut(&mut repr.lhs);
3117                v.visit_tensor_mut(&mut repr.rhs);
3118                v.visit_tensor_mut(&mut repr.out);
3119            }
3120            NumericOperationIr::PowiScalar(repr) => {
3121                v.visit_tensor_mut(&mut repr.lhs);
3122                v.visit_tensor_mut(&mut repr.out);
3123                v.visit_scalar_mut(&mut repr.rhs);
3124            }
3125            NumericOperationIr::CumMin(repr) => {
3126                v.visit_tensor_mut(&mut repr.input);
3127                v.visit_tensor_mut(&mut repr.out);
3128            }
3129            NumericOperationIr::CumMax(repr) => {
3130                v.visit_tensor_mut(&mut repr.input);
3131                v.visit_tensor_mut(&mut repr.out);
3132            }
3133            NumericOperationIr::CumProd(repr) => {
3134                v.visit_tensor_mut(&mut repr.input);
3135                v.visit_tensor_mut(&mut repr.out);
3136            }
3137            NumericOperationIr::CumSum(repr) => {
3138                v.visit_tensor_mut(&mut repr.input);
3139                v.visit_tensor_mut(&mut repr.out);
3140            }
3141            NumericOperationIr::Neg(repr) => {
3142                v.visit_tensor_mut(&mut repr.input);
3143                v.visit_tensor_mut(&mut repr.out);
3144            }
3145            NumericOperationIr::Sign(repr) => {
3146                v.visit_tensor_mut(&mut repr.input);
3147                v.visit_tensor_mut(&mut repr.out);
3148            }
3149            NumericOperationIr::ClampMin(repr) => {
3150                v.visit_tensor_mut(&mut repr.lhs);
3151                v.visit_tensor_mut(&mut repr.out);
3152                v.visit_scalar_mut(&mut repr.rhs);
3153            }
3154            NumericOperationIr::ClampMax(repr) => {
3155                v.visit_tensor_mut(&mut repr.lhs);
3156                v.visit_tensor_mut(&mut repr.out);
3157                v.visit_scalar_mut(&mut repr.rhs);
3158            }
3159            NumericOperationIr::Sort(repr) => {
3160                v.visit_tensor_mut(&mut repr.input);
3161                v.visit_tensor_mut(&mut repr.out);
3162            }
3163            NumericOperationIr::SortWithIndices(repr) => {
3164                v.visit_tensor_mut(&mut repr.input);
3165                v.visit_tensor_mut(&mut repr.out);
3166                v.visit_tensor_mut(&mut repr.out_indices);
3167            }
3168            NumericOperationIr::ArgSort(repr) => {
3169                v.visit_tensor_mut(&mut repr.input);
3170                v.visit_tensor_mut(&mut repr.out);
3171            }
3172            NumericOperationIr::Pad(repr) => {
3173                v.visit_tensor_mut(&mut repr.input);
3174                v.visit_tensor_mut(&mut repr.out);
3175                if let PadModeIr::Constant(value) = &mut repr.mode {
3176                    v.visit_scalar_mut(value);
3177                }
3178            }
3179        }
3180    }
3181}
3182
3183impl FloatOperationIr {
3184    fn inputs(&self) -> Box<dyn Iterator<Item = &TensorIr> + '_> {
3185        match self {
3186            FloatOperationIr::Matmul(repr) => Box::new([&repr.lhs, &repr.rhs].into_iter()),
3187            FloatOperationIr::Cross(repr) => Box::new([&repr.lhs, &repr.rhs].into_iter()),
3188            FloatOperationIr::Random(_repr) => Box::new([].into_iter()),
3189            FloatOperationIr::Exp(repr) => Box::new([&repr.input].into_iter()),
3190            FloatOperationIr::Log(repr) => Box::new([&repr.input].into_iter()),
3191            FloatOperationIr::Log1p(repr) => Box::new([&repr.input].into_iter()),
3192            FloatOperationIr::Erf(repr) => Box::new([&repr.input].into_iter()),
3193            FloatOperationIr::Recip(repr) => Box::new([&repr.input].into_iter()),
3194            FloatOperationIr::PowfScalar(repr) => Box::new([&repr.lhs].into_iter()),
3195            FloatOperationIr::Sqrt(repr) => Box::new([&repr.input].into_iter()),
3196            FloatOperationIr::Cos(repr) => Box::new([&repr.input].into_iter()),
3197            FloatOperationIr::Sin(repr) => Box::new([&repr.input].into_iter()),
3198            FloatOperationIr::Tanh(repr) => Box::new([&repr.input].into_iter()),
3199            FloatOperationIr::Round(repr) => Box::new([&repr.input].into_iter()),
3200            FloatOperationIr::Floor(repr) => Box::new([&repr.input].into_iter()),
3201            FloatOperationIr::Ceil(repr) => Box::new([&repr.input].into_iter()),
3202            FloatOperationIr::Trunc(repr) => Box::new([&repr.input].into_iter()),
3203            FloatOperationIr::IntoInt(repr) => Box::new([&repr.input].into_iter()),
3204            FloatOperationIr::Quantize(repr) => Box::new(
3205                [&repr.tensor, &repr.qparams.scales]
3206                    .into_iter()
3207                    .chain(repr.qparams.global.iter()),
3208            ),
3209            FloatOperationIr::Dequantize(repr) => Box::new([&repr.input].into_iter()),
3210            FloatOperationIr::IsNan(repr) => Box::new([&repr.input].into_iter()),
3211            FloatOperationIr::IsInf(repr) => Box::new([&repr.input].into_iter()),
3212            FloatOperationIr::GridSample2d(repr) => {
3213                Box::new([&repr.tensor, &repr.grid].into_iter())
3214            }
3215            FloatOperationIr::Tan(repr) => Box::new([&repr.input].into_iter()),
3216            FloatOperationIr::Cosh(repr) => Box::new([&repr.input].into_iter()),
3217            FloatOperationIr::Sinh(repr) => Box::new([&repr.input].into_iter()),
3218            FloatOperationIr::ArcCos(repr) => Box::new([&repr.input].into_iter()),
3219            FloatOperationIr::ArcCosh(repr) => Box::new([&repr.input].into_iter()),
3220            FloatOperationIr::ArcSin(repr) => Box::new([&repr.input].into_iter()),
3221            FloatOperationIr::ArcSinh(repr) => Box::new([&repr.input].into_iter()),
3222            FloatOperationIr::ArcTan(repr) => Box::new([&repr.input].into_iter()),
3223            FloatOperationIr::ArcTanh(repr) => Box::new([&repr.input].into_iter()),
3224            FloatOperationIr::ArcTan2(repr) => Box::new([&repr.lhs, &repr.rhs].into_iter()),
3225            FloatOperationIr::Powf(repr) => Box::new([&repr.lhs, &repr.rhs].into_iter()),
3226            FloatOperationIr::Hypot(repr) => Box::new([&repr.lhs, &repr.rhs].into_iter()),
3227        }
3228    }
3229    fn outputs(&self) -> Box<dyn Iterator<Item = &TensorIr> + '_> {
3230        match self {
3231            FloatOperationIr::Matmul(repr) => Box::new([&repr.out].into_iter()),
3232            FloatOperationIr::Cross(repr) => Box::new([&repr.out].into_iter()),
3233            FloatOperationIr::Random(repr) => Box::new([&repr.out].into_iter()),
3234            FloatOperationIr::Exp(repr) => Box::new([&repr.out].into_iter()),
3235            FloatOperationIr::Log(repr) => Box::new([&repr.out].into_iter()),
3236            FloatOperationIr::Log1p(repr) => Box::new([&repr.out].into_iter()),
3237            FloatOperationIr::Erf(repr) => Box::new([&repr.out].into_iter()),
3238            FloatOperationIr::Recip(repr) => Box::new([&repr.out].into_iter()),
3239            FloatOperationIr::PowfScalar(repr) => Box::new([&repr.out].into_iter()),
3240            FloatOperationIr::Sqrt(repr) => Box::new([&repr.out].into_iter()),
3241            FloatOperationIr::Cos(repr) => Box::new([&repr.out].into_iter()),
3242            FloatOperationIr::Sin(repr) => Box::new([&repr.out].into_iter()),
3243            FloatOperationIr::Tanh(repr) => Box::new([&repr.out].into_iter()),
3244            FloatOperationIr::Round(repr) => Box::new([&repr.out].into_iter()),
3245            FloatOperationIr::Floor(repr) => Box::new([&repr.out].into_iter()),
3246            FloatOperationIr::Ceil(repr) => Box::new([&repr.out].into_iter()),
3247            FloatOperationIr::Trunc(repr) => Box::new([&repr.out].into_iter()),
3248            FloatOperationIr::IntoInt(repr) => Box::new([&repr.out].into_iter()),
3249            FloatOperationIr::Quantize(repr) => Box::new([&repr.out].into_iter()),
3250            FloatOperationIr::Dequantize(repr) => Box::new([&repr.out].into_iter()),
3251            FloatOperationIr::IsNan(repr) => Box::new([&repr.out].into_iter()),
3252            FloatOperationIr::IsInf(repr) => Box::new([&repr.out].into_iter()),
3253            FloatOperationIr::GridSample2d(repr) => Box::new([&repr.out].into_iter()),
3254            FloatOperationIr::Tan(repr) => Box::new([&repr.out].into_iter()),
3255            FloatOperationIr::Cosh(repr) => Box::new([&repr.out].into_iter()),
3256            FloatOperationIr::Sinh(repr) => Box::new([&repr.out].into_iter()),
3257            FloatOperationIr::ArcCos(repr) => Box::new([&repr.out].into_iter()),
3258            FloatOperationIr::ArcCosh(repr) => Box::new([&repr.out].into_iter()),
3259            FloatOperationIr::ArcSin(repr) => Box::new([&repr.out].into_iter()),
3260            FloatOperationIr::ArcSinh(repr) => Box::new([&repr.out].into_iter()),
3261            FloatOperationIr::ArcTan(repr) => Box::new([&repr.out].into_iter()),
3262            FloatOperationIr::ArcTanh(repr) => Box::new([&repr.out].into_iter()),
3263            FloatOperationIr::ArcTan2(repr) => Box::new([&repr.out].into_iter()),
3264            FloatOperationIr::Powf(repr) => Box::new([&repr.out].into_iter()),
3265            FloatOperationIr::Hypot(repr) => Box::new([&repr.out].into_iter()),
3266        }
3267    }
3268
3269    fn mark_read_only(&mut self, nodes: &[TensorId]) -> Vec<TensorIr> {
3270        let mut output = Vec::new();
3271
3272        match self {
3273            FloatOperationIr::Matmul(repr) => {
3274                repr.lhs.mark_read_only(nodes, &mut output);
3275                repr.rhs.mark_read_only(nodes, &mut output);
3276            }
3277            FloatOperationIr::Cross(repr) => {
3278                repr.lhs.mark_read_only(nodes, &mut output);
3279                repr.rhs.mark_read_only(nodes, &mut output);
3280            }
3281            FloatOperationIr::Random(_) => {}
3282            FloatOperationIr::Exp(repr) => {
3283                repr.input.mark_read_only(nodes, &mut output);
3284            }
3285            FloatOperationIr::Log(repr) => {
3286                repr.input.mark_read_only(nodes, &mut output);
3287            }
3288            FloatOperationIr::Log1p(repr) => {
3289                repr.input.mark_read_only(nodes, &mut output);
3290            }
3291            FloatOperationIr::Erf(repr) => {
3292                repr.input.mark_read_only(nodes, &mut output);
3293            }
3294            FloatOperationIr::Recip(repr) => {
3295                repr.input.mark_read_only(nodes, &mut output);
3296            }
3297            FloatOperationIr::PowfScalar(repr) => {
3298                repr.lhs.mark_read_only(nodes, &mut output);
3299            }
3300            FloatOperationIr::Sqrt(repr) => {
3301                repr.input.mark_read_only(nodes, &mut output);
3302            }
3303            FloatOperationIr::Cos(repr) => {
3304                repr.input.mark_read_only(nodes, &mut output);
3305            }
3306            FloatOperationIr::Sin(repr) => {
3307                repr.input.mark_read_only(nodes, &mut output);
3308            }
3309            FloatOperationIr::Tanh(repr) => {
3310                repr.input.mark_read_only(nodes, &mut output);
3311            }
3312            FloatOperationIr::Round(repr) => {
3313                repr.input.mark_read_only(nodes, &mut output);
3314            }
3315            FloatOperationIr::Floor(repr) => {
3316                repr.input.mark_read_only(nodes, &mut output);
3317            }
3318            FloatOperationIr::Ceil(repr) => {
3319                repr.input.mark_read_only(nodes, &mut output);
3320            }
3321            FloatOperationIr::Trunc(repr) => {
3322                repr.input.mark_read_only(nodes, &mut output);
3323            }
3324            FloatOperationIr::Quantize(repr) => {
3325                repr.tensor.mark_read_only(nodes, &mut output);
3326                repr.qparams.scales.mark_read_only(nodes, &mut output);
3327                if let Some(global) = &mut repr.qparams.global {
3328                    global.mark_read_only(nodes, &mut output);
3329                }
3330            }
3331            FloatOperationIr::Dequantize(repr) => {
3332                repr.input.mark_read_only(nodes, &mut output);
3333            }
3334            FloatOperationIr::IntoInt(repr) => {
3335                repr.input.mark_read_only(nodes, &mut output);
3336            }
3337            FloatOperationIr::IsNan(repr) => {
3338                repr.input.mark_read_only(nodes, &mut output);
3339            }
3340            FloatOperationIr::IsInf(repr) => {
3341                repr.input.mark_read_only(nodes, &mut output);
3342            }
3343            FloatOperationIr::GridSample2d(repr) => {
3344                repr.tensor.mark_read_only(nodes, &mut output);
3345                repr.grid.mark_read_only(nodes, &mut output);
3346            }
3347            FloatOperationIr::Tan(repr) => repr.input.mark_read_only(nodes, &mut output),
3348            FloatOperationIr::Cosh(repr) => repr.input.mark_read_only(nodes, &mut output),
3349            FloatOperationIr::Sinh(repr) => repr.input.mark_read_only(nodes, &mut output),
3350            FloatOperationIr::ArcCos(repr) => repr.input.mark_read_only(nodes, &mut output),
3351            FloatOperationIr::ArcCosh(repr) => repr.input.mark_read_only(nodes, &mut output),
3352            FloatOperationIr::ArcSin(repr) => repr.input.mark_read_only(nodes, &mut output),
3353            FloatOperationIr::ArcSinh(repr) => repr.input.mark_read_only(nodes, &mut output),
3354            FloatOperationIr::ArcTan(repr) => repr.input.mark_read_only(nodes, &mut output),
3355            FloatOperationIr::ArcTanh(repr) => repr.input.mark_read_only(nodes, &mut output),
3356            FloatOperationIr::ArcTan2(repr) => {
3357                repr.lhs.mark_read_only(nodes, &mut output);
3358                repr.rhs.mark_read_only(nodes, &mut output);
3359            }
3360            FloatOperationIr::Powf(repr) => {
3361                repr.lhs.mark_read_only(nodes, &mut output);
3362                repr.rhs.mark_read_only(nodes, &mut output);
3363            }
3364            FloatOperationIr::Hypot(repr) => {
3365                repr.lhs.mark_read_only(nodes, &mut output);
3366                repr.rhs.mark_read_only(nodes, &mut output);
3367            }
3368        };
3369
3370        output
3371    }
3372
3373    fn visit_mut(&mut self, v: &mut impl IrVisitorMut) {
3374        match self {
3375            FloatOperationIr::Matmul(repr) => {
3376                v.visit_tensor_mut(&mut repr.lhs);
3377                v.visit_tensor_mut(&mut repr.rhs);
3378                v.visit_tensor_mut(&mut repr.out);
3379            }
3380            FloatOperationIr::Cross(repr) => {
3381                v.visit_tensor_mut(&mut repr.lhs);
3382                v.visit_tensor_mut(&mut repr.rhs);
3383                v.visit_tensor_mut(&mut repr.out);
3384            }
3385            FloatOperationIr::Random(repr) => {
3386                v.visit_tensor_mut(&mut repr.out);
3387            }
3388            FloatOperationIr::Exp(repr) => {
3389                v.visit_tensor_mut(&mut repr.input);
3390                v.visit_tensor_mut(&mut repr.out);
3391            }
3392            FloatOperationIr::Log(repr) => {
3393                v.visit_tensor_mut(&mut repr.input);
3394                v.visit_tensor_mut(&mut repr.out);
3395            }
3396            FloatOperationIr::Log1p(repr) => {
3397                v.visit_tensor_mut(&mut repr.input);
3398                v.visit_tensor_mut(&mut repr.out);
3399            }
3400            FloatOperationIr::Erf(repr) => {
3401                v.visit_tensor_mut(&mut repr.input);
3402                v.visit_tensor_mut(&mut repr.out);
3403            }
3404            FloatOperationIr::Recip(repr) => {
3405                v.visit_tensor_mut(&mut repr.input);
3406                v.visit_tensor_mut(&mut repr.out);
3407            }
3408            FloatOperationIr::PowfScalar(repr) => {
3409                v.visit_tensor_mut(&mut repr.lhs);
3410                v.visit_tensor_mut(&mut repr.out);
3411                v.visit_scalar_mut(&mut repr.rhs);
3412            }
3413            FloatOperationIr::Sqrt(repr) => {
3414                v.visit_tensor_mut(&mut repr.input);
3415                v.visit_tensor_mut(&mut repr.out);
3416            }
3417            FloatOperationIr::Cos(repr) => {
3418                v.visit_tensor_mut(&mut repr.input);
3419                v.visit_tensor_mut(&mut repr.out);
3420            }
3421            FloatOperationIr::Sin(repr) => {
3422                v.visit_tensor_mut(&mut repr.input);
3423                v.visit_tensor_mut(&mut repr.out);
3424            }
3425            FloatOperationIr::Tanh(repr) => {
3426                v.visit_tensor_mut(&mut repr.input);
3427                v.visit_tensor_mut(&mut repr.out);
3428            }
3429            FloatOperationIr::Round(repr) => {
3430                v.visit_tensor_mut(&mut repr.input);
3431                v.visit_tensor_mut(&mut repr.out);
3432            }
3433            FloatOperationIr::Floor(repr) => {
3434                v.visit_tensor_mut(&mut repr.input);
3435                v.visit_tensor_mut(&mut repr.out);
3436            }
3437            FloatOperationIr::Ceil(repr) => {
3438                v.visit_tensor_mut(&mut repr.input);
3439                v.visit_tensor_mut(&mut repr.out);
3440            }
3441            FloatOperationIr::Trunc(repr) => {
3442                v.visit_tensor_mut(&mut repr.input);
3443                v.visit_tensor_mut(&mut repr.out);
3444            }
3445            FloatOperationIr::IntoInt(repr) => {
3446                v.visit_tensor_mut(&mut repr.input);
3447                v.visit_tensor_mut(&mut repr.out);
3448            }
3449            FloatOperationIr::Quantize(repr) => {
3450                v.visit_tensor_mut(&mut repr.tensor);
3451                v.visit_tensor_mut(&mut repr.qparams.scales);
3452                if let Some(global) = &mut repr.qparams.global {
3453                    v.visit_tensor_mut(global);
3454                }
3455                v.visit_tensor_mut(&mut repr.out);
3456            }
3457            FloatOperationIr::Dequantize(repr) => {
3458                v.visit_tensor_mut(&mut repr.input);
3459                v.visit_tensor_mut(&mut repr.out);
3460            }
3461            FloatOperationIr::IsNan(repr) => {
3462                v.visit_tensor_mut(&mut repr.input);
3463                v.visit_tensor_mut(&mut repr.out);
3464            }
3465            FloatOperationIr::IsInf(repr) => {
3466                v.visit_tensor_mut(&mut repr.input);
3467                v.visit_tensor_mut(&mut repr.out);
3468            }
3469            FloatOperationIr::GridSample2d(repr) => {
3470                v.visit_tensor_mut(&mut repr.tensor);
3471                v.visit_tensor_mut(&mut repr.grid);
3472                v.visit_tensor_mut(&mut repr.out);
3473            }
3474            FloatOperationIr::Tan(repr) => {
3475                v.visit_tensor_mut(&mut repr.input);
3476                v.visit_tensor_mut(&mut repr.out);
3477            }
3478            FloatOperationIr::Cosh(repr) => {
3479                v.visit_tensor_mut(&mut repr.input);
3480                v.visit_tensor_mut(&mut repr.out);
3481            }
3482            FloatOperationIr::Sinh(repr) => {
3483                v.visit_tensor_mut(&mut repr.input);
3484                v.visit_tensor_mut(&mut repr.out);
3485            }
3486            FloatOperationIr::ArcCos(repr) => {
3487                v.visit_tensor_mut(&mut repr.input);
3488                v.visit_tensor_mut(&mut repr.out);
3489            }
3490            FloatOperationIr::ArcCosh(repr) => {
3491                v.visit_tensor_mut(&mut repr.input);
3492                v.visit_tensor_mut(&mut repr.out);
3493            }
3494            FloatOperationIr::ArcSin(repr) => {
3495                v.visit_tensor_mut(&mut repr.input);
3496                v.visit_tensor_mut(&mut repr.out);
3497            }
3498            FloatOperationIr::ArcSinh(repr) => {
3499                v.visit_tensor_mut(&mut repr.input);
3500                v.visit_tensor_mut(&mut repr.out);
3501            }
3502            FloatOperationIr::ArcTan(repr) => {
3503                v.visit_tensor_mut(&mut repr.input);
3504                v.visit_tensor_mut(&mut repr.out);
3505            }
3506            FloatOperationIr::ArcTanh(repr) => {
3507                v.visit_tensor_mut(&mut repr.input);
3508                v.visit_tensor_mut(&mut repr.out);
3509            }
3510            FloatOperationIr::ArcTan2(repr) => {
3511                v.visit_tensor_mut(&mut repr.lhs);
3512                v.visit_tensor_mut(&mut repr.rhs);
3513                v.visit_tensor_mut(&mut repr.out);
3514            }
3515            FloatOperationIr::Powf(repr) => {
3516                v.visit_tensor_mut(&mut repr.lhs);
3517                v.visit_tensor_mut(&mut repr.rhs);
3518                v.visit_tensor_mut(&mut repr.out);
3519            }
3520            FloatOperationIr::Hypot(repr) => {
3521                v.visit_tensor_mut(&mut repr.lhs);
3522                v.visit_tensor_mut(&mut repr.rhs);
3523                v.visit_tensor_mut(&mut repr.out);
3524            }
3525        }
3526    }
3527}
3528
3529impl IntOperationIr {
3530    fn inputs(&self) -> Box<dyn Iterator<Item = &TensorIr> + '_> {
3531        match self {
3532            IntOperationIr::Matmul(repr) => Box::new([&repr.lhs, &repr.rhs].into_iter()),
3533            IntOperationIr::IntoFloat(repr) => Box::new([&repr.input].into_iter()),
3534            IntOperationIr::BitwiseAnd(repr) => Box::new([&repr.lhs, &repr.rhs].into_iter()),
3535            IntOperationIr::BitwiseAndScalar(repr) => Box::new([&repr.lhs].into_iter()),
3536            IntOperationIr::BitwiseOr(repr) => Box::new([&repr.lhs, &repr.rhs].into_iter()),
3537            IntOperationIr::BitwiseOrScalar(repr) => Box::new([&repr.lhs].into_iter()),
3538            IntOperationIr::BitwiseXor(repr) => Box::new([&repr.lhs, &repr.rhs].into_iter()),
3539            IntOperationIr::BitwiseXorScalar(repr) => Box::new([&repr.lhs].into_iter()),
3540            IntOperationIr::BitwiseNot(repr) => Box::new([&repr.input].into_iter()),
3541            IntOperationIr::BitwiseLeftShift(repr) => Box::new([&repr.lhs, &repr.rhs].into_iter()),
3542            IntOperationIr::BitwiseLeftShiftScalar(repr) => Box::new([&repr.lhs].into_iter()),
3543            IntOperationIr::BitwiseRightShift(repr) => Box::new([&repr.lhs, &repr.rhs].into_iter()),
3544            IntOperationIr::BitwiseRightShiftScalar(repr) => Box::new([&repr.lhs].into_iter()),
3545        }
3546    }
3547
3548    fn outputs(&self) -> Box<dyn Iterator<Item = &TensorIr> + '_> {
3549        match self {
3550            IntOperationIr::Matmul(repr) => Box::new([&repr.out].into_iter()),
3551            IntOperationIr::IntoFloat(repr) => Box::new([&repr.out].into_iter()),
3552            IntOperationIr::BitwiseAnd(repr) => Box::new([&repr.out].into_iter()),
3553            IntOperationIr::BitwiseAndScalar(repr) => Box::new([&repr.out].into_iter()),
3554            IntOperationIr::BitwiseOr(repr) => Box::new([&repr.out].into_iter()),
3555            IntOperationIr::BitwiseOrScalar(repr) => Box::new([&repr.out].into_iter()),
3556            IntOperationIr::BitwiseXor(repr) => Box::new([&repr.out].into_iter()),
3557            IntOperationIr::BitwiseXorScalar(repr) => Box::new([&repr.out].into_iter()),
3558            IntOperationIr::BitwiseNot(repr) => Box::new([&repr.out].into_iter()),
3559            IntOperationIr::BitwiseLeftShift(repr) => Box::new([&repr.out].into_iter()),
3560            IntOperationIr::BitwiseLeftShiftScalar(repr) => Box::new([&repr.out].into_iter()),
3561            IntOperationIr::BitwiseRightShift(repr) => Box::new([&repr.out].into_iter()),
3562            IntOperationIr::BitwiseRightShiftScalar(repr) => Box::new([&repr.out].into_iter()),
3563        }
3564    }
3565
3566    fn mark_read_only(&mut self, nodes: &[TensorId]) -> Vec<TensorIr> {
3567        let mut output = Vec::new();
3568
3569        match self {
3570            IntOperationIr::Matmul(repr) => {
3571                repr.lhs.mark_read_only(nodes, &mut output);
3572                repr.rhs.mark_read_only(nodes, &mut output);
3573            }
3574            IntOperationIr::IntoFloat(repr) => {
3575                repr.input.mark_read_only(nodes, &mut output);
3576            }
3577            IntOperationIr::BitwiseAnd(repr) => {
3578                repr.lhs.mark_read_only(nodes, &mut output);
3579                repr.rhs.mark_read_only(nodes, &mut output);
3580            }
3581            IntOperationIr::BitwiseAndScalar(repr) => {
3582                repr.lhs.mark_read_only(nodes, &mut output);
3583            }
3584            IntOperationIr::BitwiseOr(repr) => {
3585                repr.lhs.mark_read_only(nodes, &mut output);
3586                repr.rhs.mark_read_only(nodes, &mut output);
3587            }
3588            IntOperationIr::BitwiseOrScalar(repr) => {
3589                repr.lhs.mark_read_only(nodes, &mut output);
3590            }
3591            IntOperationIr::BitwiseXor(repr) => {
3592                repr.lhs.mark_read_only(nodes, &mut output);
3593                repr.rhs.mark_read_only(nodes, &mut output);
3594            }
3595            IntOperationIr::BitwiseXorScalar(repr) => {
3596                repr.lhs.mark_read_only(nodes, &mut output);
3597            }
3598            IntOperationIr::BitwiseNot(repr) => {
3599                repr.input.mark_read_only(nodes, &mut output);
3600            }
3601            IntOperationIr::BitwiseLeftShift(repr) => {
3602                repr.lhs.mark_read_only(nodes, &mut output);
3603                repr.rhs.mark_read_only(nodes, &mut output);
3604            }
3605            IntOperationIr::BitwiseLeftShiftScalar(repr) => {
3606                repr.lhs.mark_read_only(nodes, &mut output);
3607            }
3608            IntOperationIr::BitwiseRightShift(repr) => {
3609                repr.lhs.mark_read_only(nodes, &mut output);
3610                repr.rhs.mark_read_only(nodes, &mut output);
3611            }
3612            IntOperationIr::BitwiseRightShiftScalar(repr) => {
3613                repr.lhs.mark_read_only(nodes, &mut output);
3614            }
3615        };
3616
3617        output
3618    }
3619
3620    fn visit_mut(&mut self, v: &mut impl IrVisitorMut) {
3621        match self {
3622            IntOperationIr::Matmul(repr) => {
3623                v.visit_tensor_mut(&mut repr.lhs);
3624                v.visit_tensor_mut(&mut repr.rhs);
3625                v.visit_tensor_mut(&mut repr.out);
3626            }
3627            IntOperationIr::IntoFloat(repr) => {
3628                v.visit_tensor_mut(&mut repr.input);
3629                v.visit_tensor_mut(&mut repr.out);
3630            }
3631            IntOperationIr::BitwiseAnd(repr) => {
3632                v.visit_tensor_mut(&mut repr.lhs);
3633                v.visit_tensor_mut(&mut repr.rhs);
3634                v.visit_tensor_mut(&mut repr.out);
3635            }
3636            IntOperationIr::BitwiseAndScalar(repr) => {
3637                v.visit_tensor_mut(&mut repr.lhs);
3638                v.visit_tensor_mut(&mut repr.out);
3639                v.visit_scalar_mut(&mut repr.rhs);
3640            }
3641            IntOperationIr::BitwiseOr(repr) => {
3642                v.visit_tensor_mut(&mut repr.lhs);
3643                v.visit_tensor_mut(&mut repr.rhs);
3644                v.visit_tensor_mut(&mut repr.out);
3645            }
3646            IntOperationIr::BitwiseOrScalar(repr) => {
3647                v.visit_tensor_mut(&mut repr.lhs);
3648                v.visit_tensor_mut(&mut repr.out);
3649                v.visit_scalar_mut(&mut repr.rhs);
3650            }
3651            IntOperationIr::BitwiseXor(repr) => {
3652                v.visit_tensor_mut(&mut repr.lhs);
3653                v.visit_tensor_mut(&mut repr.rhs);
3654                v.visit_tensor_mut(&mut repr.out);
3655            }
3656            IntOperationIr::BitwiseXorScalar(repr) => {
3657                v.visit_tensor_mut(&mut repr.lhs);
3658                v.visit_tensor_mut(&mut repr.out);
3659                v.visit_scalar_mut(&mut repr.rhs);
3660            }
3661            IntOperationIr::BitwiseNot(repr) => {
3662                v.visit_tensor_mut(&mut repr.input);
3663                v.visit_tensor_mut(&mut repr.out);
3664            }
3665            IntOperationIr::BitwiseLeftShift(repr) => {
3666                v.visit_tensor_mut(&mut repr.lhs);
3667                v.visit_tensor_mut(&mut repr.rhs);
3668                v.visit_tensor_mut(&mut repr.out);
3669            }
3670            IntOperationIr::BitwiseLeftShiftScalar(repr) => {
3671                v.visit_tensor_mut(&mut repr.lhs);
3672                v.visit_tensor_mut(&mut repr.out);
3673                v.visit_scalar_mut(&mut repr.rhs);
3674            }
3675            IntOperationIr::BitwiseRightShift(repr) => {
3676                v.visit_tensor_mut(&mut repr.lhs);
3677                v.visit_tensor_mut(&mut repr.rhs);
3678                v.visit_tensor_mut(&mut repr.out);
3679            }
3680            IntOperationIr::BitwiseRightShiftScalar(repr) => {
3681                v.visit_tensor_mut(&mut repr.lhs);
3682                v.visit_tensor_mut(&mut repr.out);
3683                v.visit_scalar_mut(&mut repr.rhs);
3684            }
3685        }
3686    }
3687}
3688
3689impl BoolOperationIr {
3690    fn inputs(&self) -> Box<dyn Iterator<Item = &TensorIr> + '_> {
3691        match self {
3692            BoolOperationIr::IntoFloat(repr) => Box::new([&repr.input].into_iter()),
3693            BoolOperationIr::IntoInt(repr) => Box::new([&repr.input].into_iter()),
3694            BoolOperationIr::Not(repr) => Box::new([&repr.input].into_iter()),
3695            BoolOperationIr::And(repr) => Box::new([&repr.lhs, &repr.rhs].into_iter()),
3696            BoolOperationIr::Or(repr) => Box::new([&repr.lhs, &repr.rhs].into_iter()),
3697            BoolOperationIr::Xor(repr) => Box::new([&repr.lhs, &repr.rhs].into_iter()),
3698        }
3699    }
3700    fn outputs(&self) -> Box<dyn Iterator<Item = &TensorIr> + '_> {
3701        match self {
3702            BoolOperationIr::IntoFloat(repr) => Box::new([&repr.out].into_iter()),
3703            BoolOperationIr::IntoInt(repr) => Box::new([&repr.out].into_iter()),
3704            BoolOperationIr::Not(repr) => Box::new([&repr.out].into_iter()),
3705            BoolOperationIr::And(repr) => Box::new([&repr.out].into_iter()),
3706            BoolOperationIr::Or(repr) => Box::new([&repr.out].into_iter()),
3707            BoolOperationIr::Xor(repr) => Box::new([&repr.out].into_iter()),
3708        }
3709    }
3710    fn mark_read_only(&mut self, nodes: &[TensorId]) -> Vec<TensorIr> {
3711        let mut output = Vec::new();
3712
3713        match self {
3714            BoolOperationIr::IntoFloat(repr) => {
3715                repr.input.mark_read_only(nodes, &mut output);
3716            }
3717            BoolOperationIr::IntoInt(repr) => {
3718                repr.input.mark_read_only(nodes, &mut output);
3719            }
3720            BoolOperationIr::Not(repr) => {
3721                repr.input.mark_read_only(nodes, &mut output);
3722            }
3723            BoolOperationIr::And(repr) => {
3724                repr.lhs.mark_read_only(nodes, &mut output);
3725                repr.rhs.mark_read_only(nodes, &mut output);
3726            }
3727            BoolOperationIr::Or(repr) => {
3728                repr.lhs.mark_read_only(nodes, &mut output);
3729                repr.rhs.mark_read_only(nodes, &mut output);
3730            }
3731            BoolOperationIr::Xor(repr) => {
3732                repr.lhs.mark_read_only(nodes, &mut output);
3733                repr.rhs.mark_read_only(nodes, &mut output);
3734            }
3735        };
3736
3737        output
3738    }
3739
3740    fn visit_mut(&mut self, v: &mut impl IrVisitorMut) {
3741        match self {
3742            BoolOperationIr::IntoFloat(repr) => {
3743                v.visit_tensor_mut(&mut repr.input);
3744                v.visit_tensor_mut(&mut repr.out);
3745            }
3746            BoolOperationIr::IntoInt(repr) => {
3747                v.visit_tensor_mut(&mut repr.input);
3748                v.visit_tensor_mut(&mut repr.out);
3749            }
3750            BoolOperationIr::Not(repr) => {
3751                v.visit_tensor_mut(&mut repr.input);
3752                v.visit_tensor_mut(&mut repr.out);
3753            }
3754            BoolOperationIr::And(repr) => {
3755                v.visit_tensor_mut(&mut repr.lhs);
3756                v.visit_tensor_mut(&mut repr.rhs);
3757                v.visit_tensor_mut(&mut repr.out);
3758            }
3759            BoolOperationIr::Or(repr) => {
3760                v.visit_tensor_mut(&mut repr.lhs);
3761                v.visit_tensor_mut(&mut repr.rhs);
3762                v.visit_tensor_mut(&mut repr.out);
3763            }
3764            BoolOperationIr::Xor(repr) => {
3765                v.visit_tensor_mut(&mut repr.lhs);
3766                v.visit_tensor_mut(&mut repr.rhs);
3767                v.visit_tensor_mut(&mut repr.out);
3768            }
3769        }
3770    }
3771}
3772
3773impl ModuleOperationIr {
3774    fn inputs(&self) -> Box<dyn Iterator<Item = &TensorIr> + '_> {
3775        match self {
3776            ModuleOperationIr::BatchNorm(repr) => {
3777                Box::new([&repr.x, &repr.gamma, &repr.beta, &repr.mean, &repr.variance].into_iter())
3778            }
3779            ModuleOperationIr::Embedding(repr) => {
3780                Box::new([&repr.weights, &repr.indices].into_iter())
3781            }
3782            ModuleOperationIr::EmbeddingBackward(repr) => {
3783                Box::new([&repr.weights, &repr.out_grad, &repr.indices].into_iter())
3784            }
3785            ModuleOperationIr::Linear(repr) => {
3786                if let Some(bias) = &repr.bias {
3787                    Box::new([&repr.x, &repr.weight, bias].into_iter())
3788                } else {
3789                    Box::new([&repr.x, &repr.weight].into_iter())
3790                }
3791            }
3792            ModuleOperationIr::LinearXBackward(repr) => {
3793                Box::new([&repr.weight, &repr.output_grad].into_iter())
3794            }
3795            ModuleOperationIr::LinearWeightBackward(repr) => {
3796                Box::new([&repr.x, &repr.output_grad].into_iter())
3797            }
3798            ModuleOperationIr::LinearBiasBackward(repr) => {
3799                Box::new([&repr.output_grad].into_iter())
3800            }
3801            ModuleOperationIr::Conv1d(repr) => {
3802                if let Some(bias) = &repr.bias {
3803                    Box::new([&repr.x, &repr.weight, bias].into_iter())
3804                } else {
3805                    Box::new([&repr.x, &repr.weight].into_iter())
3806                }
3807            }
3808            ModuleOperationIr::Conv1dXBackward(repr) => {
3809                Box::new([&repr.x, &repr.weight, &repr.output_grad].into_iter())
3810            }
3811            ModuleOperationIr::Conv1dWeightBackward(repr) => {
3812                Box::new([&repr.x, &repr.weight, &repr.output_grad].into_iter())
3813            }
3814            ModuleOperationIr::Conv1dBiasBackward(repr) => {
3815                Box::new([&repr.x, &repr.bias, &repr.output_grad].into_iter())
3816            }
3817            ModuleOperationIr::Conv2d(repr) => {
3818                if let Some(bias) = &repr.bias {
3819                    Box::new([&repr.x, &repr.weight, bias].into_iter())
3820                } else {
3821                    Box::new([&repr.x, &repr.weight].into_iter())
3822                }
3823            }
3824            ModuleOperationIr::Conv2dXBackward(repr) => {
3825                Box::new([&repr.x, &repr.weight, &repr.output_grad].into_iter())
3826            }
3827            ModuleOperationIr::Conv2dWeightBackward(repr) => {
3828                Box::new([&repr.x, &repr.weight, &repr.output_grad].into_iter())
3829            }
3830            ModuleOperationIr::Conv2dBiasBackward(repr) => {
3831                Box::new([&repr.x, &repr.bias, &repr.output_grad].into_iter())
3832            }
3833            ModuleOperationIr::Conv3d(repr) => {
3834                if let Some(bias) = &repr.bias {
3835                    Box::new([&repr.x, &repr.weight, bias].into_iter())
3836                } else {
3837                    Box::new([&repr.x, &repr.weight].into_iter())
3838                }
3839            }
3840            ModuleOperationIr::Conv3dXBackward(repr) => {
3841                Box::new([&repr.x, &repr.weight, &repr.output_grad].into_iter())
3842            }
3843            ModuleOperationIr::Conv3dWeightBackward(repr) => {
3844                Box::new([&repr.x, &repr.weight, &repr.output_grad].into_iter())
3845            }
3846            ModuleOperationIr::Conv3dBiasBackward(repr) => {
3847                Box::new([&repr.x, &repr.bias, &repr.output_grad].into_iter())
3848            }
3849            ModuleOperationIr::DeformableConv2d(repr) => match (&repr.mask, &repr.bias) {
3850                (Some(mask), Some(bias)) => {
3851                    Box::new([&repr.x, &repr.offset, &repr.weight, mask, bias].into_iter())
3852                }
3853                (Some(mask), None) => {
3854                    Box::new([&repr.x, &repr.offset, &repr.weight, mask].into_iter())
3855                }
3856                (None, Some(bias)) => {
3857                    Box::new([&repr.x, &repr.offset, &repr.weight, bias].into_iter())
3858                }
3859                (None, None) => Box::new([&repr.x, &repr.offset, &repr.weight].into_iter()),
3860            },
3861            ModuleOperationIr::DeformableConv2dBackward(repr) => match (&repr.mask, &repr.bias) {
3862                (Some(mask), Some(bias)) => Box::new(
3863                    [
3864                        &repr.x,
3865                        &repr.offset,
3866                        &repr.weight,
3867                        &repr.out_grad,
3868                        mask,
3869                        bias,
3870                    ]
3871                    .into_iter(),
3872                ),
3873                (Some(mask), None) => Box::new(
3874                    [&repr.x, &repr.offset, &repr.weight, &repr.out_grad, mask].into_iter(),
3875                ),
3876                (None, Some(bias)) => Box::new(
3877                    [&repr.x, &repr.offset, &repr.weight, &repr.out_grad, bias].into_iter(),
3878                ),
3879                (None, None) => {
3880                    Box::new([&repr.x, &repr.offset, &repr.weight, &repr.out_grad].into_iter())
3881                }
3882            },
3883            ModuleOperationIr::ConvTranspose1d(repr) => {
3884                if let Some(bias) = &repr.bias {
3885                    Box::new([&repr.x, &repr.weight, bias].into_iter())
3886                } else {
3887                    Box::new([&repr.x, &repr.weight].into_iter())
3888                }
3889            }
3890            ModuleOperationIr::ConvTranspose2d(repr) => {
3891                if let Some(bias) = &repr.bias {
3892                    Box::new([&repr.x, &repr.weight, bias].into_iter())
3893                } else {
3894                    Box::new([&repr.x, &repr.weight].into_iter())
3895                }
3896            }
3897            ModuleOperationIr::ConvTranspose3d(repr) => {
3898                if let Some(bias) = &repr.bias {
3899                    Box::new([&repr.x, &repr.weight, bias].into_iter())
3900                } else {
3901                    Box::new([&repr.x, &repr.weight].into_iter())
3902                }
3903            }
3904            ModuleOperationIr::AvgPool1d(repr) => Box::new([&repr.x].into_iter()),
3905            ModuleOperationIr::AvgPool2d(repr) => Box::new([&repr.x].into_iter()),
3906            ModuleOperationIr::AvgPool1dBackward(repr) => {
3907                Box::new([&repr.x, &repr.grad].into_iter())
3908            }
3909            ModuleOperationIr::AvgPool2dBackward(repr) => {
3910                Box::new([&repr.x, &repr.grad].into_iter())
3911            }
3912            ModuleOperationIr::AdaptiveAvgPool1d(repr) => Box::new([&repr.x].into_iter()),
3913            ModuleOperationIr::AdaptiveAvgPool2d(repr) => Box::new([&repr.x].into_iter()),
3914            ModuleOperationIr::AdaptiveAvgPool1dBackward(repr) => {
3915                Box::new([&repr.x, &repr.grad].into_iter())
3916            }
3917            ModuleOperationIr::AdaptiveAvgPool2dBackward(repr) => {
3918                Box::new([&repr.x, &repr.grad].into_iter())
3919            }
3920            ModuleOperationIr::AdaptiveAvgPool3d(repr) => Box::new([&repr.x].into_iter()),
3921            ModuleOperationIr::AdaptiveAvgPool3dBackward(repr) => {
3922                Box::new([&repr.x, &repr.grad].into_iter())
3923            }
3924            ModuleOperationIr::MaxPool1d(repr) => Box::new([&repr.x].into_iter()),
3925            ModuleOperationIr::MaxPool1dWithIndices(repr) => Box::new([&repr.x].into_iter()),
3926            ModuleOperationIr::MaxPool1dWithIndicesBackward(repr) => {
3927                Box::new([&repr.x, &repr.indices, &repr.grad].into_iter())
3928            }
3929            ModuleOperationIr::MaxPool2d(repr) => Box::new([&repr.x].into_iter()),
3930            ModuleOperationIr::MaxPool2dWithIndices(repr) => Box::new([&repr.x].into_iter()),
3931            ModuleOperationIr::MaxPool2dWithIndicesBackward(repr) => {
3932                Box::new([&repr.x, &repr.indices, &repr.grad].into_iter())
3933            }
3934            ModuleOperationIr::Interpolate(repr) => Box::new([&repr.x].into_iter()),
3935            ModuleOperationIr::InterpolateBackward(repr) => {
3936                Box::new([&repr.x, &repr.grad].into_iter())
3937            }
3938            ModuleOperationIr::Attention(repr) => {
3939                if let Some(mask) = &repr.mask {
3940                    if let Some(attn_bias) = &repr.attn_bias {
3941                        Box::new([&repr.query, &repr.key, &repr.value, mask, attn_bias].into_iter())
3942                    } else {
3943                        Box::new([&repr.query, &repr.key, &repr.value, mask].into_iter())
3944                    }
3945                } else if let Some(attn_bias) = &repr.attn_bias {
3946                    Box::new([&repr.query, &repr.key, &repr.value, attn_bias].into_iter())
3947                } else {
3948                    Box::new([&repr.query, &repr.key, &repr.value].into_iter())
3949                }
3950            }
3951            ModuleOperationIr::CtcLoss(repr) => Box::new(
3952                [
3953                    &repr.log_probs,
3954                    &repr.targets,
3955                    &repr.input_lengths,
3956                    &repr.target_lengths,
3957                ]
3958                .into_iter(),
3959            ),
3960            ModuleOperationIr::CtcLossBackward(repr) => Box::new(
3961                [
3962                    &repr.log_probs,
3963                    &repr.targets,
3964                    &repr.input_lengths,
3965                    &repr.target_lengths,
3966                    &repr.grad_loss,
3967                ]
3968                .into_iter(),
3969            ),
3970            ModuleOperationIr::LayerNorm(repr) => match &repr.beta {
3971                Some(beta) => Box::new([&repr.input, &repr.gamma, beta].into_iter()),
3972                None => Box::new([&repr.input, &repr.gamma].into_iter()),
3973            },
3974            ModuleOperationIr::Unfold4d(repr) => Box::new([&repr.x].into_iter()),
3975            ModuleOperationIr::ConvTranspose1dWeightBackward(repr) => {
3976                Box::new([&repr.x, &repr.weight, &repr.output_grad].into_iter())
3977            }
3978            ModuleOperationIr::ConvTranspose1dBiasBackward(repr) => {
3979                Box::new([&repr.x, &repr.bias, &repr.output_grad].into_iter())
3980            }
3981            ModuleOperationIr::ConvTranspose2dWeightBackward(repr) => {
3982                Box::new([&repr.x, &repr.weight, &repr.output_grad].into_iter())
3983            }
3984            ModuleOperationIr::ConvTranspose2dBiasBackward(repr) => {
3985                Box::new([&repr.x, &repr.bias, &repr.output_grad].into_iter())
3986            }
3987            ModuleOperationIr::ConvTranspose3dWeightBackward(repr) => {
3988                Box::new([&repr.x, &repr.weight, &repr.output_grad].into_iter())
3989            }
3990            ModuleOperationIr::ConvTranspose3dBiasBackward(repr) => {
3991                Box::new([&repr.x, &repr.bias, &repr.output_grad].into_iter())
3992            }
3993        }
3994    }
3995    fn outputs(&self) -> Box<dyn Iterator<Item = &TensorIr> + '_> {
3996        match self {
3997            ModuleOperationIr::BatchNorm(repr) => Box::new([&repr.out].into_iter()),
3998            ModuleOperationIr::Embedding(repr) => Box::new([&repr.out].into_iter()),
3999            ModuleOperationIr::EmbeddingBackward(repr) => Box::new([&repr.out].into_iter()),
4000            ModuleOperationIr::Linear(repr) => Box::new([&repr.out].into_iter()),
4001            ModuleOperationIr::LinearXBackward(repr) => Box::new([&repr.out].into_iter()),
4002            ModuleOperationIr::LinearWeightBackward(repr) => Box::new([&repr.out].into_iter()),
4003            ModuleOperationIr::LinearBiasBackward(repr) => Box::new([&repr.out].into_iter()),
4004            ModuleOperationIr::Conv1d(repr) => Box::new([&repr.out].into_iter()),
4005            ModuleOperationIr::Conv1dXBackward(repr) => Box::new([&repr.out].into_iter()),
4006            ModuleOperationIr::Conv1dWeightBackward(repr) => Box::new([&repr.out].into_iter()),
4007            ModuleOperationIr::Conv1dBiasBackward(repr) => Box::new([&repr.out].into_iter()),
4008            ModuleOperationIr::Conv2d(repr) => Box::new([&repr.out].into_iter()),
4009            ModuleOperationIr::Conv2dXBackward(repr) => Box::new([&repr.out].into_iter()),
4010            ModuleOperationIr::Conv2dWeightBackward(repr) => Box::new([&repr.out].into_iter()),
4011            ModuleOperationIr::Conv2dBiasBackward(repr) => Box::new([&repr.out].into_iter()),
4012            ModuleOperationIr::Conv3d(repr) => Box::new([&repr.out].into_iter()),
4013            ModuleOperationIr::Conv3dXBackward(repr) => Box::new([&repr.out].into_iter()),
4014            ModuleOperationIr::Conv3dWeightBackward(repr) => Box::new([&repr.out].into_iter()),
4015            ModuleOperationIr::Conv3dBiasBackward(repr) => Box::new([&repr.out].into_iter()),
4016            ModuleOperationIr::DeformableConv2d(repr) => Box::new([&repr.out].into_iter()),
4017            ModuleOperationIr::DeformableConv2dBackward(repr) => {
4018                match (&repr.mask_grad, &repr.bias_grad) {
4019                    (Some(mask_grad), Some(bias_grad)) => Box::new(
4020                        [
4021                            &repr.input_grad,
4022                            &repr.offset_grad,
4023                            &repr.weight_grad,
4024                            mask_grad,
4025                            bias_grad,
4026                        ]
4027                        .into_iter(),
4028                    ),
4029                    (Some(mask_grad), None) => Box::new(
4030                        [
4031                            &repr.input_grad,
4032                            &repr.offset_grad,
4033                            &repr.weight_grad,
4034                            mask_grad,
4035                        ]
4036                        .into_iter(),
4037                    ),
4038                    (None, Some(bias_grad)) => Box::new(
4039                        [
4040                            &repr.input_grad,
4041                            &repr.offset_grad,
4042                            &repr.weight_grad,
4043                            bias_grad,
4044                        ]
4045                        .into_iter(),
4046                    ),
4047                    (None, None) => Box::new(
4048                        [&repr.input_grad, &repr.offset_grad, &repr.weight_grad].into_iter(),
4049                    ),
4050                }
4051            }
4052            ModuleOperationIr::ConvTranspose1d(repr) => Box::new([&repr.out].into_iter()),
4053            ModuleOperationIr::ConvTranspose2d(repr) => Box::new([&repr.out].into_iter()),
4054            ModuleOperationIr::ConvTranspose3d(repr) => Box::new([&repr.out].into_iter()),
4055            ModuleOperationIr::AvgPool1d(repr) => Box::new([&repr.out].into_iter()),
4056            ModuleOperationIr::AvgPool2d(repr) => Box::new([&repr.out].into_iter()),
4057            ModuleOperationIr::AvgPool1dBackward(repr) => Box::new([&repr.out].into_iter()),
4058            ModuleOperationIr::AvgPool2dBackward(repr) => Box::new([&repr.out].into_iter()),
4059            ModuleOperationIr::AdaptiveAvgPool1d(repr) => Box::new([&repr.out].into_iter()),
4060            ModuleOperationIr::AdaptiveAvgPool2d(repr) => Box::new([&repr.out].into_iter()),
4061            ModuleOperationIr::AdaptiveAvgPool1dBackward(repr) => Box::new([&repr.out].into_iter()),
4062            ModuleOperationIr::AdaptiveAvgPool2dBackward(repr) => Box::new([&repr.out].into_iter()),
4063            ModuleOperationIr::AdaptiveAvgPool3d(repr) => Box::new([&repr.out].into_iter()),
4064            ModuleOperationIr::AdaptiveAvgPool3dBackward(repr) => Box::new([&repr.out].into_iter()),
4065            ModuleOperationIr::MaxPool1d(repr) => Box::new([&repr.out].into_iter()),
4066            ModuleOperationIr::MaxPool1dWithIndices(repr) => {
4067                Box::new([&repr.out, &repr.out_indices].into_iter())
4068            }
4069            ModuleOperationIr::MaxPool1dWithIndicesBackward(repr) => {
4070                Box::new([&repr.out].into_iter())
4071            }
4072            ModuleOperationIr::MaxPool2d(repr) => Box::new([&repr.out].into_iter()),
4073            ModuleOperationIr::MaxPool2dWithIndices(repr) => {
4074                Box::new([&repr.out, &repr.out_indices].into_iter())
4075            }
4076            ModuleOperationIr::MaxPool2dWithIndicesBackward(repr) => {
4077                Box::new([&repr.out].into_iter())
4078            }
4079            ModuleOperationIr::Interpolate(repr) => Box::new([&repr.out].into_iter()),
4080            ModuleOperationIr::InterpolateBackward(repr) => Box::new([&repr.out].into_iter()),
4081            ModuleOperationIr::Attention(repr) => Box::new([&repr.out].into_iter()),
4082            ModuleOperationIr::CtcLoss(repr) => Box::new([&repr.out].into_iter()),
4083            ModuleOperationIr::CtcLossBackward(repr) => Box::new([&repr.out].into_iter()),
4084            ModuleOperationIr::LayerNorm(repr) => Box::new([&repr.out].into_iter()),
4085            ModuleOperationIr::Unfold4d(repr) => Box::new([&repr.out].into_iter()),
4086            ModuleOperationIr::ConvTranspose1dWeightBackward(repr) => {
4087                Box::new([&repr.out].into_iter())
4088            }
4089            ModuleOperationIr::ConvTranspose1dBiasBackward(repr) => {
4090                Box::new([&repr.out].into_iter())
4091            }
4092            ModuleOperationIr::ConvTranspose2dWeightBackward(repr) => {
4093                Box::new([&repr.out].into_iter())
4094            }
4095            ModuleOperationIr::ConvTranspose2dBiasBackward(repr) => {
4096                Box::new([&repr.out].into_iter())
4097            }
4098            ModuleOperationIr::ConvTranspose3dWeightBackward(repr) => {
4099                Box::new([&repr.out].into_iter())
4100            }
4101            ModuleOperationIr::ConvTranspose3dBiasBackward(repr) => {
4102                Box::new([&repr.out].into_iter())
4103            }
4104        }
4105    }
4106
4107    fn mark_read_only(&mut self, nodes: &[TensorId]) -> Vec<TensorIr> {
4108        let mut output = Vec::new();
4109
4110        match self {
4111            ModuleOperationIr::BatchNorm(repr) => {
4112                repr.x.mark_read_only(nodes, &mut output);
4113                repr.gamma.mark_read_only(nodes, &mut output);
4114                repr.beta.mark_read_only(nodes, &mut output);
4115                repr.mean.mark_read_only(nodes, &mut output);
4116                repr.variance.mark_read_only(nodes, &mut output);
4117            }
4118            ModuleOperationIr::Embedding(repr) => {
4119                repr.weights.mark_read_only(nodes, &mut output);
4120                repr.indices.mark_read_only(nodes, &mut output);
4121            }
4122            ModuleOperationIr::EmbeddingBackward(repr) => {
4123                repr.weights.mark_read_only(nodes, &mut output);
4124                repr.out_grad.mark_read_only(nodes, &mut output);
4125                repr.indices.mark_read_only(nodes, &mut output);
4126            }
4127            ModuleOperationIr::Linear(repr) => {
4128                repr.x.mark_read_only(nodes, &mut output);
4129                repr.weight.mark_read_only(nodes, &mut output);
4130
4131                if let Some(bias) = &mut repr.bias {
4132                    bias.mark_read_only(nodes, &mut output);
4133                }
4134            }
4135            ModuleOperationIr::LinearXBackward(repr) => {
4136                repr.weight.mark_read_only(nodes, &mut output);
4137                repr.output_grad.mark_read_only(nodes, &mut output);
4138            }
4139            ModuleOperationIr::LinearWeightBackward(repr) => {
4140                repr.x.mark_read_only(nodes, &mut output);
4141                repr.output_grad.mark_read_only(nodes, &mut output);
4142            }
4143            ModuleOperationIr::LinearBiasBackward(repr) => {
4144                repr.output_grad.mark_read_only(nodes, &mut output);
4145            }
4146            ModuleOperationIr::Conv1d(repr) => {
4147                repr.x.mark_read_only(nodes, &mut output);
4148                repr.weight.mark_read_only(nodes, &mut output);
4149
4150                if let Some(bias) = &mut repr.bias {
4151                    bias.mark_read_only(nodes, &mut output);
4152                }
4153            }
4154            ModuleOperationIr::Conv1dXBackward(repr) => {
4155                repr.x.mark_read_only(nodes, &mut output);
4156                repr.weight.mark_read_only(nodes, &mut output);
4157                repr.output_grad.mark_read_only(nodes, &mut output);
4158            }
4159            ModuleOperationIr::Conv1dWeightBackward(repr) => {
4160                repr.x.mark_read_only(nodes, &mut output);
4161                repr.weight.mark_read_only(nodes, &mut output);
4162                repr.output_grad.mark_read_only(nodes, &mut output);
4163            }
4164            ModuleOperationIr::Conv1dBiasBackward(repr) => {
4165                repr.x.mark_read_only(nodes, &mut output);
4166                repr.bias.mark_read_only(nodes, &mut output);
4167                repr.output_grad.mark_read_only(nodes, &mut output);
4168            }
4169            ModuleOperationIr::Conv2d(repr) => {
4170                repr.x.mark_read_only(nodes, &mut output);
4171                repr.weight.mark_read_only(nodes, &mut output);
4172
4173                if let Some(bias) = &mut repr.bias {
4174                    bias.mark_read_only(nodes, &mut output);
4175                }
4176            }
4177            ModuleOperationIr::Conv2dXBackward(repr) => {
4178                repr.x.mark_read_only(nodes, &mut output);
4179                repr.weight.mark_read_only(nodes, &mut output);
4180                repr.output_grad.mark_read_only(nodes, &mut output);
4181            }
4182            ModuleOperationIr::Conv2dWeightBackward(repr) => {
4183                repr.x.mark_read_only(nodes, &mut output);
4184                repr.weight.mark_read_only(nodes, &mut output);
4185                repr.output_grad.mark_read_only(nodes, &mut output);
4186            }
4187            ModuleOperationIr::Conv2dBiasBackward(repr) => {
4188                repr.x.mark_read_only(nodes, &mut output);
4189                repr.bias.mark_read_only(nodes, &mut output);
4190                repr.output_grad.mark_read_only(nodes, &mut output);
4191            }
4192            ModuleOperationIr::Conv3d(repr) => {
4193                repr.x.mark_read_only(nodes, &mut output);
4194                repr.weight.mark_read_only(nodes, &mut output);
4195
4196                if let Some(bias) = &mut repr.bias {
4197                    bias.mark_read_only(nodes, &mut output);
4198                }
4199            }
4200            ModuleOperationIr::Conv3dXBackward(repr) => {
4201                repr.x.mark_read_only(nodes, &mut output);
4202                repr.weight.mark_read_only(nodes, &mut output);
4203                repr.output_grad.mark_read_only(nodes, &mut output);
4204            }
4205            ModuleOperationIr::Conv3dWeightBackward(repr) => {
4206                repr.x.mark_read_only(nodes, &mut output);
4207                repr.weight.mark_read_only(nodes, &mut output);
4208                repr.output_grad.mark_read_only(nodes, &mut output);
4209            }
4210            ModuleOperationIr::Conv3dBiasBackward(repr) => {
4211                repr.x.mark_read_only(nodes, &mut output);
4212                repr.bias.mark_read_only(nodes, &mut output);
4213                repr.output_grad.mark_read_only(nodes, &mut output);
4214            }
4215            ModuleOperationIr::DeformableConv2d(repr) => {
4216                repr.x.mark_read_only(nodes, &mut output);
4217                repr.weight.mark_read_only(nodes, &mut output);
4218                repr.offset.mark_read_only(nodes, &mut output);
4219
4220                match (&mut repr.mask, &mut repr.bias) {
4221                    (Some(mask), Some(bias)) => {
4222                        mask.mark_read_only(nodes, &mut output);
4223                        bias.mark_read_only(nodes, &mut output);
4224                    }
4225                    (Some(mask), None) => {
4226                        mask.mark_read_only(nodes, &mut output);
4227                    }
4228                    (None, Some(bias)) => {
4229                        bias.mark_read_only(nodes, &mut output);
4230                    }
4231                    (None, None) => {}
4232                };
4233            }
4234            ModuleOperationIr::DeformableConv2dBackward(repr) => {
4235                repr.x.mark_read_only(nodes, &mut output);
4236                repr.weight.mark_read_only(nodes, &mut output);
4237                repr.offset.mark_read_only(nodes, &mut output);
4238                repr.out_grad.mark_read_only(nodes, &mut output);
4239
4240                if let Some(mask) = repr.mask.as_mut() {
4241                    mask.mark_read_only(nodes, &mut output);
4242                }
4243                if let Some(bias) = repr.bias.as_mut() {
4244                    bias.mark_read_only(nodes, &mut output);
4245                }
4246            }
4247            ModuleOperationIr::ConvTranspose1d(repr) => {
4248                repr.x.mark_read_only(nodes, &mut output);
4249                repr.weight.mark_read_only(nodes, &mut output);
4250
4251                if let Some(bias) = &mut repr.bias {
4252                    bias.mark_read_only(nodes, &mut output);
4253                }
4254            }
4255            ModuleOperationIr::ConvTranspose2d(repr) => {
4256                repr.x.mark_read_only(nodes, &mut output);
4257                repr.weight.mark_read_only(nodes, &mut output);
4258
4259                if let Some(bias) = &mut repr.bias {
4260                    bias.mark_read_only(nodes, &mut output);
4261                }
4262            }
4263            ModuleOperationIr::ConvTranspose3d(repr) => {
4264                repr.x.mark_read_only(nodes, &mut output);
4265                repr.weight.mark_read_only(nodes, &mut output);
4266
4267                if let Some(bias) = &mut repr.bias {
4268                    bias.mark_read_only(nodes, &mut output);
4269                }
4270            }
4271            ModuleOperationIr::AvgPool1d(repr) => {
4272                repr.x.mark_read_only(nodes, &mut output);
4273            }
4274            ModuleOperationIr::AvgPool2d(repr) => {
4275                repr.x.mark_read_only(nodes, &mut output);
4276            }
4277            ModuleOperationIr::AvgPool1dBackward(repr) => {
4278                repr.x.mark_read_only(nodes, &mut output);
4279                repr.grad.mark_read_only(nodes, &mut output);
4280            }
4281            ModuleOperationIr::AvgPool2dBackward(repr) => {
4282                repr.x.mark_read_only(nodes, &mut output);
4283                repr.grad.mark_read_only(nodes, &mut output);
4284            }
4285            ModuleOperationIr::AdaptiveAvgPool1d(repr) => {
4286                repr.x.mark_read_only(nodes, &mut output);
4287            }
4288            ModuleOperationIr::AdaptiveAvgPool2d(repr) => {
4289                repr.x.mark_read_only(nodes, &mut output);
4290            }
4291            ModuleOperationIr::AdaptiveAvgPool1dBackward(repr) => {
4292                repr.x.mark_read_only(nodes, &mut output);
4293                repr.grad.mark_read_only(nodes, &mut output);
4294            }
4295            ModuleOperationIr::AdaptiveAvgPool2dBackward(repr) => {
4296                repr.x.mark_read_only(nodes, &mut output);
4297                repr.grad.mark_read_only(nodes, &mut output);
4298            }
4299            ModuleOperationIr::AdaptiveAvgPool3d(repr) => {
4300                repr.x.mark_read_only(nodes, &mut output);
4301            }
4302            ModuleOperationIr::AdaptiveAvgPool3dBackward(repr) => {
4303                repr.x.mark_read_only(nodes, &mut output);
4304                repr.grad.mark_read_only(nodes, &mut output);
4305            }
4306            ModuleOperationIr::MaxPool1d(repr) => {
4307                repr.x.mark_read_only(nodes, &mut output);
4308            }
4309            ModuleOperationIr::MaxPool1dWithIndices(repr) => {
4310                repr.x.mark_read_only(nodes, &mut output);
4311            }
4312            ModuleOperationIr::MaxPool1dWithIndicesBackward(repr) => {
4313                repr.x.mark_read_only(nodes, &mut output);
4314                repr.grad.mark_read_only(nodes, &mut output);
4315            }
4316            ModuleOperationIr::MaxPool2d(repr) => {
4317                repr.x.mark_read_only(nodes, &mut output);
4318            }
4319            ModuleOperationIr::MaxPool2dWithIndices(repr) => {
4320                repr.x.mark_read_only(nodes, &mut output);
4321            }
4322            ModuleOperationIr::MaxPool2dWithIndicesBackward(repr) => {
4323                repr.x.mark_read_only(nodes, &mut output);
4324                repr.grad.mark_read_only(nodes, &mut output);
4325            }
4326            ModuleOperationIr::Interpolate(repr) => {
4327                repr.x.mark_read_only(nodes, &mut output);
4328            }
4329            ModuleOperationIr::InterpolateBackward(repr) => {
4330                repr.x.mark_read_only(nodes, &mut output);
4331                repr.grad.mark_read_only(nodes, &mut output);
4332            }
4333            ModuleOperationIr::Attention(repr) => {
4334                repr.query.mark_read_only(nodes, &mut output);
4335                repr.key.mark_read_only(nodes, &mut output);
4336                repr.value.mark_read_only(nodes, &mut output);
4337                if let Some(mask) = &mut repr.mask {
4338                    mask.mark_read_only(nodes, &mut output);
4339                }
4340                if let Some(attn_bias) = &mut repr.attn_bias {
4341                    attn_bias.mark_read_only(nodes, &mut output);
4342                }
4343            }
4344            ModuleOperationIr::CtcLoss(repr) => {
4345                repr.log_probs.mark_read_only(nodes, &mut output);
4346                repr.targets.mark_read_only(nodes, &mut output);
4347                repr.input_lengths.mark_read_only(nodes, &mut output);
4348                repr.target_lengths.mark_read_only(nodes, &mut output);
4349            }
4350            ModuleOperationIr::CtcLossBackward(repr) => {
4351                repr.log_probs.mark_read_only(nodes, &mut output);
4352                repr.targets.mark_read_only(nodes, &mut output);
4353                repr.input_lengths.mark_read_only(nodes, &mut output);
4354                repr.target_lengths.mark_read_only(nodes, &mut output);
4355                repr.grad_loss.mark_read_only(nodes, &mut output);
4356            }
4357            ModuleOperationIr::LayerNorm(repr) => {
4358                repr.input.mark_read_only(nodes, &mut output);
4359                repr.gamma.mark_read_only(nodes, &mut output);
4360                if let Some(beta) = &mut repr.beta {
4361                    beta.mark_read_only(nodes, &mut output);
4362                }
4363            }
4364            ModuleOperationIr::Unfold4d(repr) => {
4365                repr.x.mark_read_only(nodes, &mut output);
4366            }
4367            ModuleOperationIr::ConvTranspose1dWeightBackward(repr) => {
4368                repr.x.mark_read_only(nodes, &mut output);
4369                repr.weight.mark_read_only(nodes, &mut output);
4370                repr.output_grad.mark_read_only(nodes, &mut output);
4371            }
4372            ModuleOperationIr::ConvTranspose1dBiasBackward(repr) => {
4373                repr.x.mark_read_only(nodes, &mut output);
4374                repr.bias.mark_read_only(nodes, &mut output);
4375                repr.output_grad.mark_read_only(nodes, &mut output);
4376            }
4377            ModuleOperationIr::ConvTranspose2dWeightBackward(repr) => {
4378                repr.x.mark_read_only(nodes, &mut output);
4379                repr.weight.mark_read_only(nodes, &mut output);
4380                repr.output_grad.mark_read_only(nodes, &mut output);
4381            }
4382            ModuleOperationIr::ConvTranspose2dBiasBackward(repr) => {
4383                repr.x.mark_read_only(nodes, &mut output);
4384                repr.bias.mark_read_only(nodes, &mut output);
4385                repr.output_grad.mark_read_only(nodes, &mut output);
4386            }
4387            ModuleOperationIr::ConvTranspose3dWeightBackward(repr) => {
4388                repr.x.mark_read_only(nodes, &mut output);
4389                repr.weight.mark_read_only(nodes, &mut output);
4390                repr.output_grad.mark_read_only(nodes, &mut output);
4391            }
4392            ModuleOperationIr::ConvTranspose3dBiasBackward(repr) => {
4393                repr.x.mark_read_only(nodes, &mut output);
4394                repr.bias.mark_read_only(nodes, &mut output);
4395                repr.output_grad.mark_read_only(nodes, &mut output);
4396            }
4397        };
4398
4399        output
4400    }
4401
4402    fn visit_mut(&mut self, v: &mut impl IrVisitorMut) {
4403        match self {
4404            ModuleOperationIr::BatchNorm(repr) => {
4405                v.visit_tensor_mut(&mut repr.x);
4406                v.visit_tensor_mut(&mut repr.gamma);
4407                v.visit_tensor_mut(&mut repr.beta);
4408                v.visit_tensor_mut(&mut repr.mean);
4409                v.visit_tensor_mut(&mut repr.variance);
4410                v.visit_scalar_mut(&mut repr.epsilon);
4411                v.visit_tensor_mut(&mut repr.out);
4412            }
4413            ModuleOperationIr::Embedding(repr) => {
4414                v.visit_tensor_mut(&mut repr.weights);
4415                v.visit_tensor_mut(&mut repr.indices);
4416                v.visit_tensor_mut(&mut repr.out);
4417            }
4418            ModuleOperationIr::EmbeddingBackward(repr) => {
4419                v.visit_tensor_mut(&mut repr.weights);
4420                v.visit_tensor_mut(&mut repr.out_grad);
4421                v.visit_tensor_mut(&mut repr.indices);
4422                v.visit_tensor_mut(&mut repr.out);
4423            }
4424            ModuleOperationIr::Linear(repr) => {
4425                v.visit_tensor_mut(&mut repr.x);
4426                v.visit_tensor_mut(&mut repr.weight);
4427                if let Some(bias) = &mut repr.bias {
4428                    v.visit_tensor_mut(bias);
4429                }
4430                v.visit_tensor_mut(&mut repr.out);
4431            }
4432            ModuleOperationIr::LinearXBackward(repr) => {
4433                v.visit_tensor_mut(&mut repr.weight);
4434                v.visit_tensor_mut(&mut repr.output_grad);
4435                v.visit_tensor_mut(&mut repr.out);
4436            }
4437            ModuleOperationIr::LinearWeightBackward(repr) => {
4438                v.visit_tensor_mut(&mut repr.x);
4439                v.visit_tensor_mut(&mut repr.output_grad);
4440                v.visit_tensor_mut(&mut repr.out);
4441            }
4442            ModuleOperationIr::LinearBiasBackward(repr) => {
4443                v.visit_tensor_mut(&mut repr.output_grad);
4444                v.visit_tensor_mut(&mut repr.out);
4445            }
4446            ModuleOperationIr::Conv1d(repr) => {
4447                v.visit_tensor_mut(&mut repr.x);
4448                v.visit_tensor_mut(&mut repr.weight);
4449                if let Some(bias) = &mut repr.bias {
4450                    v.visit_tensor_mut(bias);
4451                }
4452                v.visit_tensor_mut(&mut repr.out);
4453            }
4454            ModuleOperationIr::Conv1dXBackward(repr) => {
4455                v.visit_tensor_mut(&mut repr.x);
4456                v.visit_tensor_mut(&mut repr.weight);
4457                v.visit_tensor_mut(&mut repr.output_grad);
4458                v.visit_tensor_mut(&mut repr.out);
4459            }
4460            ModuleOperationIr::Conv1dWeightBackward(repr) => {
4461                v.visit_tensor_mut(&mut repr.x);
4462                v.visit_tensor_mut(&mut repr.weight);
4463                v.visit_tensor_mut(&mut repr.output_grad);
4464                v.visit_tensor_mut(&mut repr.out);
4465            }
4466            ModuleOperationIr::Conv1dBiasBackward(repr) => {
4467                v.visit_tensor_mut(&mut repr.x);
4468                v.visit_tensor_mut(&mut repr.bias);
4469                v.visit_tensor_mut(&mut repr.output_grad);
4470                v.visit_tensor_mut(&mut repr.out);
4471            }
4472            ModuleOperationIr::Conv2d(repr) => {
4473                v.visit_tensor_mut(&mut repr.x);
4474                v.visit_tensor_mut(&mut repr.weight);
4475                if let Some(bias) = &mut repr.bias {
4476                    v.visit_tensor_mut(bias);
4477                }
4478                v.visit_tensor_mut(&mut repr.out);
4479            }
4480            ModuleOperationIr::Conv2dXBackward(repr) => {
4481                v.visit_tensor_mut(&mut repr.x);
4482                v.visit_tensor_mut(&mut repr.weight);
4483                v.visit_tensor_mut(&mut repr.output_grad);
4484                v.visit_tensor_mut(&mut repr.out);
4485            }
4486            ModuleOperationIr::Conv2dWeightBackward(repr) => {
4487                v.visit_tensor_mut(&mut repr.x);
4488                v.visit_tensor_mut(&mut repr.weight);
4489                v.visit_tensor_mut(&mut repr.output_grad);
4490                v.visit_tensor_mut(&mut repr.out);
4491            }
4492            ModuleOperationIr::Conv2dBiasBackward(repr) => {
4493                v.visit_tensor_mut(&mut repr.x);
4494                v.visit_tensor_mut(&mut repr.bias);
4495                v.visit_tensor_mut(&mut repr.output_grad);
4496                v.visit_tensor_mut(&mut repr.out);
4497            }
4498            ModuleOperationIr::Conv3d(repr) => {
4499                v.visit_tensor_mut(&mut repr.x);
4500                v.visit_tensor_mut(&mut repr.weight);
4501                if let Some(bias) = &mut repr.bias {
4502                    v.visit_tensor_mut(bias);
4503                }
4504                v.visit_tensor_mut(&mut repr.out);
4505            }
4506            ModuleOperationIr::Conv3dXBackward(repr) => {
4507                v.visit_tensor_mut(&mut repr.x);
4508                v.visit_tensor_mut(&mut repr.weight);
4509                v.visit_tensor_mut(&mut repr.output_grad);
4510                v.visit_tensor_mut(&mut repr.out);
4511            }
4512            ModuleOperationIr::Conv3dWeightBackward(repr) => {
4513                v.visit_tensor_mut(&mut repr.x);
4514                v.visit_tensor_mut(&mut repr.weight);
4515                v.visit_tensor_mut(&mut repr.output_grad);
4516                v.visit_tensor_mut(&mut repr.out);
4517            }
4518            ModuleOperationIr::Conv3dBiasBackward(repr) => {
4519                v.visit_tensor_mut(&mut repr.x);
4520                v.visit_tensor_mut(&mut repr.bias);
4521                v.visit_tensor_mut(&mut repr.output_grad);
4522                v.visit_tensor_mut(&mut repr.out);
4523            }
4524            ModuleOperationIr::DeformableConv2d(repr) => {
4525                v.visit_tensor_mut(&mut repr.x);
4526                v.visit_tensor_mut(&mut repr.offset);
4527                v.visit_tensor_mut(&mut repr.weight);
4528                if let Some(mask) = &mut repr.mask {
4529                    v.visit_tensor_mut(mask);
4530                }
4531                if let Some(bias) = &mut repr.bias {
4532                    v.visit_tensor_mut(bias);
4533                }
4534                v.visit_tensor_mut(&mut repr.out);
4535            }
4536            ModuleOperationIr::DeformableConv2dBackward(repr) => {
4537                v.visit_tensor_mut(&mut repr.x);
4538                v.visit_tensor_mut(&mut repr.offset);
4539                v.visit_tensor_mut(&mut repr.weight);
4540                v.visit_tensor_mut(&mut repr.out_grad);
4541                if let Some(mask) = &mut repr.mask {
4542                    v.visit_tensor_mut(mask);
4543                }
4544                if let Some(bias) = &mut repr.bias {
4545                    v.visit_tensor_mut(bias);
4546                }
4547                v.visit_tensor_mut(&mut repr.input_grad);
4548                v.visit_tensor_mut(&mut repr.offset_grad);
4549                v.visit_tensor_mut(&mut repr.weight_grad);
4550                if let Some(mask_grad) = &mut repr.mask_grad {
4551                    v.visit_tensor_mut(mask_grad);
4552                }
4553                if let Some(bias_grad) = &mut repr.bias_grad {
4554                    v.visit_tensor_mut(bias_grad);
4555                }
4556            }
4557            ModuleOperationIr::ConvTranspose1d(repr) => {
4558                v.visit_tensor_mut(&mut repr.x);
4559                v.visit_tensor_mut(&mut repr.weight);
4560                if let Some(bias) = &mut repr.bias {
4561                    v.visit_tensor_mut(bias);
4562                }
4563                v.visit_tensor_mut(&mut repr.out);
4564            }
4565            ModuleOperationIr::ConvTranspose2d(repr) => {
4566                v.visit_tensor_mut(&mut repr.x);
4567                v.visit_tensor_mut(&mut repr.weight);
4568                if let Some(bias) = &mut repr.bias {
4569                    v.visit_tensor_mut(bias);
4570                }
4571                v.visit_tensor_mut(&mut repr.out);
4572            }
4573            ModuleOperationIr::ConvTranspose3d(repr) => {
4574                v.visit_tensor_mut(&mut repr.x);
4575                v.visit_tensor_mut(&mut repr.weight);
4576                if let Some(bias) = &mut repr.bias {
4577                    v.visit_tensor_mut(bias);
4578                }
4579                v.visit_tensor_mut(&mut repr.out);
4580            }
4581            ModuleOperationIr::AvgPool1d(repr) => {
4582                v.visit_tensor_mut(&mut repr.x);
4583                v.visit_tensor_mut(&mut repr.out);
4584            }
4585            ModuleOperationIr::AvgPool2d(repr) => {
4586                v.visit_tensor_mut(&mut repr.x);
4587                v.visit_tensor_mut(&mut repr.out);
4588            }
4589            ModuleOperationIr::AvgPool1dBackward(repr) => {
4590                v.visit_tensor_mut(&mut repr.x);
4591                v.visit_tensor_mut(&mut repr.grad);
4592                v.visit_tensor_mut(&mut repr.out);
4593            }
4594            ModuleOperationIr::AvgPool2dBackward(repr) => {
4595                v.visit_tensor_mut(&mut repr.x);
4596                v.visit_tensor_mut(&mut repr.grad);
4597                v.visit_tensor_mut(&mut repr.out);
4598            }
4599            ModuleOperationIr::AdaptiveAvgPool1d(repr) => {
4600                v.visit_tensor_mut(&mut repr.x);
4601                v.visit_tensor_mut(&mut repr.out);
4602            }
4603            ModuleOperationIr::AdaptiveAvgPool2d(repr) => {
4604                v.visit_tensor_mut(&mut repr.x);
4605                v.visit_tensor_mut(&mut repr.out);
4606            }
4607            ModuleOperationIr::AdaptiveAvgPool1dBackward(repr) => {
4608                v.visit_tensor_mut(&mut repr.x);
4609                v.visit_tensor_mut(&mut repr.grad);
4610                v.visit_tensor_mut(&mut repr.out);
4611            }
4612            ModuleOperationIr::AdaptiveAvgPool2dBackward(repr) => {
4613                v.visit_tensor_mut(&mut repr.x);
4614                v.visit_tensor_mut(&mut repr.grad);
4615                v.visit_tensor_mut(&mut repr.out);
4616            }
4617            ModuleOperationIr::AdaptiveAvgPool3d(repr) => {
4618                v.visit_tensor_mut(&mut repr.x);
4619                v.visit_tensor_mut(&mut repr.out);
4620            }
4621            ModuleOperationIr::AdaptiveAvgPool3dBackward(repr) => {
4622                v.visit_tensor_mut(&mut repr.x);
4623                v.visit_tensor_mut(&mut repr.grad);
4624                v.visit_tensor_mut(&mut repr.out);
4625            }
4626            ModuleOperationIr::MaxPool1d(repr) => {
4627                v.visit_tensor_mut(&mut repr.x);
4628                v.visit_tensor_mut(&mut repr.out);
4629            }
4630            ModuleOperationIr::MaxPool1dWithIndices(repr) => {
4631                v.visit_tensor_mut(&mut repr.x);
4632                v.visit_tensor_mut(&mut repr.out);
4633                v.visit_tensor_mut(&mut repr.out_indices);
4634            }
4635            ModuleOperationIr::MaxPool1dWithIndicesBackward(repr) => {
4636                v.visit_tensor_mut(&mut repr.x);
4637                v.visit_tensor_mut(&mut repr.indices);
4638                v.visit_tensor_mut(&mut repr.grad);
4639                v.visit_tensor_mut(&mut repr.out);
4640            }
4641            ModuleOperationIr::MaxPool2d(repr) => {
4642                v.visit_tensor_mut(&mut repr.x);
4643                v.visit_tensor_mut(&mut repr.out);
4644            }
4645            ModuleOperationIr::MaxPool2dWithIndices(repr) => {
4646                v.visit_tensor_mut(&mut repr.x);
4647                v.visit_tensor_mut(&mut repr.out);
4648                v.visit_tensor_mut(&mut repr.out_indices);
4649            }
4650            ModuleOperationIr::MaxPool2dWithIndicesBackward(repr) => {
4651                v.visit_tensor_mut(&mut repr.x);
4652                v.visit_tensor_mut(&mut repr.indices);
4653                v.visit_tensor_mut(&mut repr.grad);
4654                v.visit_tensor_mut(&mut repr.out);
4655            }
4656            ModuleOperationIr::Interpolate(repr) => {
4657                v.visit_tensor_mut(&mut repr.x);
4658                v.visit_tensor_mut(&mut repr.out);
4659            }
4660            ModuleOperationIr::InterpolateBackward(repr) => {
4661                v.visit_tensor_mut(&mut repr.x);
4662                v.visit_tensor_mut(&mut repr.grad);
4663                v.visit_tensor_mut(&mut repr.out);
4664            }
4665            ModuleOperationIr::Attention(repr) => {
4666                v.visit_tensor_mut(&mut repr.query);
4667                v.visit_tensor_mut(&mut repr.key);
4668                v.visit_tensor_mut(&mut repr.value);
4669                if let Some(mask) = &mut repr.mask {
4670                    v.visit_tensor_mut(mask);
4671                }
4672                if let Some(attn_bias) = &mut repr.attn_bias {
4673                    v.visit_tensor_mut(attn_bias);
4674                }
4675                v.visit_tensor_mut(&mut repr.out);
4676                if let Some(scale) = &mut repr.options.scale {
4677                    v.visit_scalar_mut(scale);
4678                }
4679                if let Some(softcap) = &mut repr.options.softcap {
4680                    v.visit_scalar_mut(softcap);
4681                }
4682            }
4683            ModuleOperationIr::CtcLoss(repr) => {
4684                v.visit_tensor_mut(&mut repr.log_probs);
4685                v.visit_tensor_mut(&mut repr.targets);
4686                v.visit_tensor_mut(&mut repr.input_lengths);
4687                v.visit_tensor_mut(&mut repr.target_lengths);
4688                v.visit_tensor_mut(&mut repr.out);
4689            }
4690            ModuleOperationIr::CtcLossBackward(repr) => {
4691                v.visit_tensor_mut(&mut repr.log_probs);
4692                v.visit_tensor_mut(&mut repr.targets);
4693                v.visit_tensor_mut(&mut repr.input_lengths);
4694                v.visit_tensor_mut(&mut repr.target_lengths);
4695                v.visit_tensor_mut(&mut repr.grad_loss);
4696                v.visit_tensor_mut(&mut repr.out);
4697            }
4698            ModuleOperationIr::LayerNorm(repr) => {
4699                v.visit_tensor_mut(&mut repr.input);
4700                v.visit_tensor_mut(&mut repr.gamma);
4701                if let Some(beta) = &mut repr.beta {
4702                    v.visit_tensor_mut(beta);
4703                }
4704                v.visit_tensor_mut(&mut repr.out);
4705                v.visit_scalar_mut(&mut repr.epsilon);
4706            }
4707            ModuleOperationIr::Unfold4d(repr) => {
4708                v.visit_tensor_mut(&mut repr.x);
4709                v.visit_tensor_mut(&mut repr.out);
4710            }
4711            ModuleOperationIr::ConvTranspose1dWeightBackward(repr) => {
4712                v.visit_tensor_mut(&mut repr.x);
4713                v.visit_tensor_mut(&mut repr.weight);
4714                v.visit_tensor_mut(&mut repr.output_grad);
4715                v.visit_tensor_mut(&mut repr.out);
4716            }
4717            ModuleOperationIr::ConvTranspose1dBiasBackward(repr) => {
4718                v.visit_tensor_mut(&mut repr.x);
4719                v.visit_tensor_mut(&mut repr.bias);
4720                v.visit_tensor_mut(&mut repr.output_grad);
4721                v.visit_tensor_mut(&mut repr.out);
4722            }
4723            ModuleOperationIr::ConvTranspose2dWeightBackward(repr) => {
4724                v.visit_tensor_mut(&mut repr.x);
4725                v.visit_tensor_mut(&mut repr.weight);
4726                v.visit_tensor_mut(&mut repr.output_grad);
4727                v.visit_tensor_mut(&mut repr.out);
4728            }
4729            ModuleOperationIr::ConvTranspose2dBiasBackward(repr) => {
4730                v.visit_tensor_mut(&mut repr.x);
4731                v.visit_tensor_mut(&mut repr.bias);
4732                v.visit_tensor_mut(&mut repr.output_grad);
4733                v.visit_tensor_mut(&mut repr.out);
4734            }
4735            ModuleOperationIr::ConvTranspose3dWeightBackward(repr) => {
4736                v.visit_tensor_mut(&mut repr.x);
4737                v.visit_tensor_mut(&mut repr.weight);
4738                v.visit_tensor_mut(&mut repr.output_grad);
4739                v.visit_tensor_mut(&mut repr.out);
4740            }
4741            ModuleOperationIr::ConvTranspose3dBiasBackward(repr) => {
4742                v.visit_tensor_mut(&mut repr.x);
4743                v.visit_tensor_mut(&mut repr.bias);
4744                v.visit_tensor_mut(&mut repr.output_grad);
4745                v.visit_tensor_mut(&mut repr.out);
4746            }
4747        }
4748    }
4749}
4750
4751impl DistributedOperationIr {
4752    fn inputs(&self) -> Box<dyn Iterator<Item = &TensorIr> + '_> {
4753        match self {
4754            DistributedOperationIr::AllReduce(repr) => Box::new([&repr.tensor].into_iter()),
4755            DistributedOperationIr::SyncCollective => Box::new([].into_iter()),
4756        }
4757    }
4758
4759    fn outputs(&self) -> Box<dyn Iterator<Item = &TensorIr> + '_> {
4760        match self {
4761            DistributedOperationIr::AllReduce(repr) => Box::new([&repr.out].into_iter()),
4762            DistributedOperationIr::SyncCollective => Box::new([].into_iter()),
4763        }
4764    }
4765
4766    fn mark_read_only(&mut self, nodes: &[TensorId]) -> Vec<TensorIr> {
4767        let mut output = Vec::new();
4768
4769        match self {
4770            DistributedOperationIr::AllReduce(repr) => {
4771                repr.tensor.mark_read_only(nodes, &mut output);
4772            }
4773            DistributedOperationIr::SyncCollective => {}
4774        }
4775
4776        output
4777    }
4778
4779    fn visit_mut(&mut self, v: &mut impl IrVisitorMut) {
4780        match self {
4781            DistributedOperationIr::AllReduce(repr) => {
4782                v.visit_tensor_mut(&mut repr.tensor);
4783                v.visit_tensor_mut(&mut repr.out);
4784            }
4785            DistributedOperationIr::SyncCollective => {}
4786        }
4787    }
4788}
4789
4790impl InitOperationIr {
4791    fn inputs(&self) -> Box<dyn Iterator<Item = &TensorIr> + '_> {
4792        Box::new([].into_iter())
4793    }
4794    fn outputs(&self) -> Box<dyn Iterator<Item = &TensorIr> + '_> {
4795        Box::new([&self.out].into_iter())
4796    }
4797
4798    fn visit_mut(&mut self, v: &mut impl IrVisitorMut) {
4799        v.visit_tensor_mut(&mut self.out);
4800    }
4801}
4802
4803impl TensorIr {
4804    fn mark_read_only(&mut self, nodes: &[TensorId], output: &mut Vec<TensorIr>) {
4805        if self.status == TensorStatus::ReadWrite && nodes.contains(&self.id) {
4806            output.push(self.clone());
4807            self.status = TensorStatus::ReadOnly;
4808        }
4809    }
4810}
4811
4812impl core::hash::Hash for RandomOpIr {
4813    fn hash<H: core::hash::Hasher>(&self, state: &mut H) {
4814        self.out.hash(state);
4815
4816        match self.distribution {
4817            Distribution::Default => 1u8.hash(state),
4818            Distribution::Bernoulli(_) => 2u8.hash(state),
4819            Distribution::Uniform(_, _) => 3u8.hash(state),
4820            Distribution::Normal(_, _) => 4u8.hash(state),
4821        }
4822    }
4823}
4824
4825/// Extension trait to extract outputs when registering an operation.
4826pub trait OperationOutput<O> {
4827    /// Extract a single output.
4828    fn output(self) -> O;
4829
4830    /// Extract a fixed number of outputs.
4831    fn outputs<const N: usize>(self) -> [O; N];
4832}
4833
4834impl<O: core::fmt::Debug> OperationOutput<O> for Vec<O> {
4835    fn output(self) -> O {
4836        let [tensor] = self.outputs();
4837        tensor
4838    }
4839
4840    fn outputs<const N: usize>(self) -> [O; N] {
4841        self.try_into().unwrap()
4842    }
4843}
4844
4845/// Operation IR for sort along a dim. The output preserves the input shape/dtype.
4846#[derive(Clone, Debug, Hash, PartialEq, Serialize, Deserialize)]
4847pub struct SortOpIr {
4848    /// Input tensor.
4849    pub input: TensorIr,
4850    /// Dim along which to sort.
4851    pub dim: usize,
4852    /// Sort descending.
4853    pub descending: bool,
4854    /// Output tensor (same shape/dtype as input).
4855    pub out: TensorIr,
4856}
4857
4858/// Operation IR for sort-with-indices: returns sorted values + source indices.
4859#[derive(Clone, Debug, Hash, PartialEq, Serialize, Deserialize)]
4860pub struct SortWithIndicesOpIr {
4861    /// Input tensor.
4862    pub input: TensorIr,
4863    /// Dim along which to sort.
4864    pub dim: usize,
4865    /// Sort descending.
4866    pub descending: bool,
4867    /// Output tensor with sorted values.
4868    pub out: TensorIr,
4869    /// Output tensor with the indices into the original input.
4870    pub out_indices: TensorIr,
4871}
4872
4873/// Operation IR for layer normalization with optional bias.
4874#[derive(Clone, Debug, Hash, PartialEq, Serialize, Deserialize)]
4875pub struct LayerNormOpIr {
4876    /// Input tensor.
4877    pub input: TensorIr,
4878    /// Scale (gamma) parameter.
4879    pub gamma: TensorIr,
4880    /// Optional shift (beta) parameter.
4881    pub beta: Option<TensorIr>,
4882    /// Numerical-stability epsilon.
4883    pub epsilon: ScalarIr,
4884    /// Output tensor.
4885    pub out: TensorIr,
4886}
4887
4888/// Operation IR for unfold4d (a 4d sliding-window kernel-as-explicit-columns reshape).
4889#[derive(Clone, Debug, Hash, PartialEq, Serialize, Deserialize)]
4890pub struct Unfold4dOpIr {
4891    /// Input tensor of shape `[N, C, H, W]`.
4892    pub x: TensorIr,
4893    /// Kernel size `[kH, kW]`.
4894    pub kernel_size: [usize; 2],
4895    /// Conv-like options (stride, padding, dilation).
4896    pub options: Unfold4dOptionsIr,
4897    /// Output tensor.
4898    pub out: TensorIr,
4899}
4900
4901/// Options for [`Unfold4dOpIr`] — mirrors the backend's `UnfoldOptions`.
4902#[derive(Clone, Debug, Hash, PartialEq, Serialize, Deserialize)]
4903pub struct Unfold4dOptionsIr {
4904    /// Stride `[sH, sW]`.
4905    pub stride: [usize; 2],
4906    /// Padding `[pH, pW]`.
4907    pub padding: [usize; 2],
4908    /// Dilation `[dH, dW]`.
4909    pub dilation: [usize; 2],
4910}
4911
4912/// Operation IR for the weight-gradient of `conv_transpose1d`.
4913#[derive(Clone, Debug, Hash, PartialEq, Serialize, Deserialize)]
4914pub struct ConvTranspose1dWeightBackwardOpIr {
4915    /// Forward input.
4916    pub x: TensorIr,
4917    /// Convolution weights.
4918    pub weight: TensorIr,
4919    /// Upstream gradient.
4920    pub output_grad: TensorIr,
4921    /// Convolution options.
4922    pub options: ConvTranspose1dOptionsIr,
4923    /// Output: gradient w.r.t. `weight`.
4924    pub out: TensorIr,
4925}
4926
4927/// Operation IR for the bias-gradient of `conv_transpose1d`.
4928#[derive(Clone, Debug, Hash, PartialEq, Serialize, Deserialize)]
4929pub struct ConvTranspose1dBiasBackwardOpIr {
4930    /// Forward input.
4931    pub x: TensorIr,
4932    /// Bias tensor (sets the output shape).
4933    pub bias: TensorIr,
4934    /// Upstream gradient.
4935    pub output_grad: TensorIr,
4936    /// Output: gradient w.r.t. `bias`.
4937    pub out: TensorIr,
4938}
4939
4940/// Operation IR for the weight-gradient of `conv_transpose2d`.
4941#[derive(Clone, Debug, Hash, PartialEq, Serialize, Deserialize)]
4942pub struct ConvTranspose2dWeightBackwardOpIr {
4943    /// Forward input.
4944    pub x: TensorIr,
4945    /// Convolution weights.
4946    pub weight: TensorIr,
4947    /// Upstream gradient.
4948    pub output_grad: TensorIr,
4949    /// Convolution options.
4950    pub options: ConvTranspose2dOptionsIr,
4951    /// Output: gradient w.r.t. `weight`.
4952    pub out: TensorIr,
4953}
4954
4955/// Operation IR for the bias-gradient of `conv_transpose2d`.
4956#[derive(Clone, Debug, Hash, PartialEq, Serialize, Deserialize)]
4957pub struct ConvTranspose2dBiasBackwardOpIr {
4958    /// Forward input.
4959    pub x: TensorIr,
4960    /// Bias tensor.
4961    pub bias: TensorIr,
4962    /// Upstream gradient.
4963    pub output_grad: TensorIr,
4964    /// Output: gradient w.r.t. `bias`.
4965    pub out: TensorIr,
4966}
4967
4968/// Operation IR for the weight-gradient of `conv_transpose3d`.
4969#[derive(Clone, Debug, Hash, PartialEq, Serialize, Deserialize)]
4970pub struct ConvTranspose3dWeightBackwardOpIr {
4971    /// Forward input.
4972    pub x: TensorIr,
4973    /// Convolution weights.
4974    pub weight: TensorIr,
4975    /// Upstream gradient.
4976    pub output_grad: TensorIr,
4977    /// Convolution options.
4978    pub options: ConvTranspose3dOptionsIr,
4979    /// Output: gradient w.r.t. `weight`.
4980    pub out: TensorIr,
4981}
4982
4983/// Operation IR for the bias-gradient of `conv_transpose3d`.
4984#[derive(Clone, Debug, Hash, PartialEq, Serialize, Deserialize)]
4985pub struct ConvTranspose3dBiasBackwardOpIr {
4986    /// Forward input.
4987    pub x: TensorIr,
4988    /// Bias tensor.
4989    pub bias: TensorIr,
4990    /// Upstream gradient.
4991    pub output_grad: TensorIr,
4992    /// Output: gradient w.r.t. `bias`.
4993    pub out: TensorIr,
4994}
4995
4996/// Operation IR for the hard-sigmoid activation function, which takes two scalars
4997/// (`alpha` and `beta`) in addition to the input tensor.
4998#[derive(Clone, Debug, Hash, PartialEq, Serialize, Deserialize)]
4999pub struct HardSigmoidOpIr {
5000    /// Input tensor.
5001    pub tensor: TensorIr,
5002    /// Alpha — multiplied with the tensor before adding `beta`.
5003    pub alpha: ScalarIr,
5004    /// Beta — added after multiplying by `alpha`.
5005    pub beta: ScalarIr,
5006    /// Output tensor.
5007    pub out: TensorIr,
5008}
5009
5010/// Operation intermediate representation for activation functions.
5011///
5012/// Activations are kept in their own enum (rather than smeared across `FloatOperationIr`)
5013/// so backends can match a single arm to dispatch the fused implementation, instead of
5014/// receiving the function decomposed into 5–20 primitive ops.
5015#[derive(Clone, Debug, Hash, PartialEq, Serialize, Deserialize)]
5016pub enum ActivationOperationIr {
5017    /// [relu](burn_backend::ops::ActivationOps::relu).
5018    Relu(UnaryOpIr),
5019    /// [relu_backward](burn_backend::ops::ActivationOps::relu_backward).
5020    /// `lhs` = output of the forward pass, `rhs` = upstream gradient.
5021    ReluBackward(BinaryOpIr),
5022    /// [leaky_relu](burn_backend::ops::ActivationOps::leaky_relu).
5023    /// `lhs` = input, `rhs` = `negative_slope` scalar.
5024    LeakyRelu(ScalarOpIr),
5025    /// [prelu](burn_backend::ops::ActivationOps::prelu).
5026    /// `lhs` = input, `rhs` = alpha tensor.
5027    PRelu(BinaryOpIr),
5028    /// [gelu](burn_backend::ops::ActivationOps::gelu).
5029    Gelu(UnaryOpIr),
5030    /// [gelu_backward](burn_backend::ops::ActivationOps::gelu_backward).
5031    /// `lhs` = forward input, `rhs` = upstream gradient.
5032    GeluBackward(BinaryOpIr),
5033    /// [sigmoid](burn_backend::ops::ActivationOps::sigmoid).
5034    Sigmoid(UnaryOpIr),
5035    /// [sigmoid_backward](burn_backend::ops::ActivationOps::sigmoid_backward).
5036    /// `lhs` = output of the forward pass, `rhs` = upstream gradient.
5037    SigmoidBackward(BinaryOpIr),
5038    /// [hard_sigmoid](burn_backend::ops::ActivationOps::hard_sigmoid).
5039    HardSigmoid(HardSigmoidOpIr),
5040    /// [log_sigmoid](burn_backend::ops::ActivationOps::log_sigmoid).
5041    LogSigmoid(UnaryOpIr),
5042    /// [log_sigmoid_backward](burn_backend::ops::ActivationOps::log_sigmoid_backward).
5043    /// `lhs` = forward input, `rhs` = upstream gradient.
5044    LogSigmoidBackward(BinaryOpIr),
5045    /// [softmax](burn_backend::ops::ActivationOps::softmax).
5046    Softmax(DimOpIr),
5047    /// [log_softmax](burn_backend::ops::ActivationOps::log_softmax).
5048    LogSoftmax(DimOpIr),
5049    /// [softmin](burn_backend::ops::ActivationOps::softmin).
5050    Softmin(DimOpIr),
5051}
5052
5053/// Generate [`ActivationOperationIr`]'s `inputs`/`outputs`/`mark_read_only` from a single
5054/// variant → input-field table, so the three methods can't drift out of sync. The `out`
5055/// field is implicit (every variant's op IR has one). Each entry lists the variant and the
5056/// names of its input tensor fields (`input`, `lhs`/`rhs`, `tensor`, …).
5057macro_rules! activation_ir_tensor_access {
5058    ($( $variant:ident => [ $($field:ident),+ ] ),+ $(,)?) => {
5059        impl ActivationOperationIr {
5060            fn inputs(&self) -> Box<dyn Iterator<Item = &TensorIr> + '_> {
5061                match self {
5062                    $( Self::$variant(repr) => Box::new([$(&repr.$field),+].into_iter()), )+
5063                }
5064            }
5065
5066            fn outputs(&self) -> Box<dyn Iterator<Item = &TensorIr> + '_> {
5067                match self {
5068                    $( Self::$variant(repr) => Box::new([&repr.out].into_iter()), )+
5069                }
5070            }
5071
5072            fn mark_read_only(&mut self, nodes: &[TensorId]) -> Vec<TensorIr> {
5073                let mut output = Vec::new();
5074                match self {
5075                    $( Self::$variant(repr) => {
5076                        $( repr.$field.mark_read_only(nodes, &mut output); )+
5077                    } )+
5078                }
5079                output
5080            }
5081        }
5082    };
5083}
5084
5085impl ActivationOperationIr {
5086    fn visit_mut(&mut self, v: &mut impl IrVisitorMut) {
5087        match self {
5088            ActivationOperationIr::Relu(repr) => {
5089                v.visit_tensor_mut(&mut repr.input);
5090                v.visit_tensor_mut(&mut repr.out);
5091            }
5092            ActivationOperationIr::ReluBackward(repr) => {
5093                v.visit_tensor_mut(&mut repr.lhs);
5094                v.visit_tensor_mut(&mut repr.rhs);
5095                v.visit_tensor_mut(&mut repr.out);
5096            }
5097            ActivationOperationIr::LeakyRelu(repr) => {
5098                v.visit_tensor_mut(&mut repr.lhs);
5099                v.visit_tensor_mut(&mut repr.out);
5100                v.visit_scalar_mut(&mut repr.rhs);
5101            }
5102            ActivationOperationIr::PRelu(repr) => {
5103                v.visit_tensor_mut(&mut repr.lhs);
5104                v.visit_tensor_mut(&mut repr.rhs);
5105                v.visit_tensor_mut(&mut repr.out);
5106            }
5107            ActivationOperationIr::Gelu(repr) => {
5108                v.visit_tensor_mut(&mut repr.input);
5109                v.visit_tensor_mut(&mut repr.out);
5110            }
5111            ActivationOperationIr::GeluBackward(repr) => {
5112                v.visit_tensor_mut(&mut repr.lhs);
5113                v.visit_tensor_mut(&mut repr.rhs);
5114                v.visit_tensor_mut(&mut repr.out);
5115            }
5116            ActivationOperationIr::Sigmoid(repr) => {
5117                v.visit_tensor_mut(&mut repr.input);
5118                v.visit_tensor_mut(&mut repr.out);
5119            }
5120            ActivationOperationIr::SigmoidBackward(repr) => {
5121                v.visit_tensor_mut(&mut repr.lhs);
5122                v.visit_tensor_mut(&mut repr.rhs);
5123                v.visit_tensor_mut(&mut repr.out);
5124            }
5125            ActivationOperationIr::HardSigmoid(repr) => {
5126                v.visit_tensor_mut(&mut repr.tensor);
5127                v.visit_tensor_mut(&mut repr.out);
5128                v.visit_scalar_mut(&mut repr.alpha);
5129                v.visit_scalar_mut(&mut repr.beta);
5130            }
5131            ActivationOperationIr::LogSigmoid(repr) => {
5132                v.visit_tensor_mut(&mut repr.input);
5133                v.visit_tensor_mut(&mut repr.out);
5134            }
5135            ActivationOperationIr::LogSigmoidBackward(repr) => {
5136                v.visit_tensor_mut(&mut repr.lhs);
5137                v.visit_tensor_mut(&mut repr.rhs);
5138                v.visit_tensor_mut(&mut repr.out);
5139            }
5140            ActivationOperationIr::Softmax(repr) => {
5141                v.visit_tensor_mut(&mut repr.input);
5142                v.visit_tensor_mut(&mut repr.out);
5143            }
5144            ActivationOperationIr::LogSoftmax(repr) => {
5145                v.visit_tensor_mut(&mut repr.input);
5146                v.visit_tensor_mut(&mut repr.out);
5147            }
5148            ActivationOperationIr::Softmin(repr) => {
5149                v.visit_tensor_mut(&mut repr.input);
5150                v.visit_tensor_mut(&mut repr.out);
5151            }
5152        }
5153    }
5154}
5155
5156activation_ir_tensor_access! {
5157    Relu => [input],
5158    ReluBackward => [lhs, rhs],
5159    LeakyRelu => [lhs],
5160    PRelu => [lhs, rhs],
5161    Gelu => [input],
5162    GeluBackward => [lhs, rhs],
5163    Sigmoid => [input],
5164    SigmoidBackward => [lhs, rhs],
5165    HardSigmoid => [tensor],
5166    LogSigmoid => [input],
5167    LogSigmoidBackward => [lhs, rhs],
5168    Softmax => [input],
5169    LogSoftmax => [input],
5170    Softmin => [input],
5171}
5172
5173#[cfg(test)]
5174mod tests {
5175    use super::*;
5176    use burn_backend::{DType, Shape};
5177
5178    #[test]
5179    #[should_panic(expected = "expected symmetric convolution padding")]
5180    fn conv3d_options_ir_rejects_asymmetric_padding() {
5181        let options =
5182            ConvOptions::new_with_padding([1, 1, 1], [(0, 1), (2, 2), (3, 3)], [1, 1, 1], 1);
5183
5184        let _: Conv3dOptionsIr = options.into();
5185    }
5186
5187    fn tensor(id: u64) -> TensorIr {
5188        TensorIr::uninit(TensorId::new(id), Shape::from([2, 2]), DType::F32)
5189    }
5190
5191    /// Bumps every visited tensor id by 100 and collects (and rewrites) every visited scalar.
5192    #[derive(Default)]
5193    struct CollectVisitor {
5194        scalars: Vec<ScalarIr>,
5195        rewrite_scalar: Option<ScalarIr>,
5196    }
5197
5198    impl IrVisitorMut for CollectVisitor {
5199        fn visit_tensor_mut(&mut self, tensor: &mut TensorIr) {
5200            tensor.id = TensorId::new(tensor.id.value() + 100);
5201        }
5202
5203        fn visit_scalar_mut(&mut self, scalar: &mut ScalarIr) {
5204            self.scalars.push(*scalar);
5205            if let Some(value) = self.rewrite_scalar {
5206                *scalar = value;
5207            }
5208        }
5209    }
5210
5211    #[test]
5212    fn visit_mut_visits_all_tensors_and_scalars() {
5213        // NumericFloat MulScalar (a ScalarOpIr with a scalar `rhs`).
5214        let mut mul = OperationIr::NumericFloat(
5215            DType::F32,
5216            NumericOperationIr::MulScalar(ScalarOpIr {
5217                lhs: tensor(1),
5218                rhs: ScalarIr::Float(2.0),
5219                out: tensor(2),
5220            }),
5221        );
5222
5223        // Bump every tensor id by 100 and rewrite the scalar to 9.0.
5224        let mut visitor = CollectVisitor {
5225            rewrite_scalar: Some(ScalarIr::Float(9.0)),
5226            ..Default::default()
5227        };
5228        mul.visit_mut(&mut visitor);
5229
5230        let ids: Vec<u64> = mul
5231            .inputs()
5232            .chain(mul.outputs())
5233            .map(|t| t.id.value())
5234            .collect();
5235        assert_eq!(ids, vec![101, 102]);
5236        // The scalar must have been visited (and was rewritable).
5237        assert_eq!(visitor.scalars, vec![ScalarIr::Float(2.0)]);
5238
5239        // Visiting again observes the rewritten scalar.
5240        let mut after = CollectVisitor::default();
5241        mul.visit_mut(&mut after);
5242        assert_eq!(after.scalars, vec![ScalarIr::Float(9.0)]);
5243
5244        // BaseFloat Reshape (a ShapeOpIr, input + out, no scalars).
5245        let mut reshape = OperationIr::BaseFloat(BaseOperationIr::Reshape(ShapeOpIr {
5246            input: tensor(10),
5247            out: tensor(11),
5248        }));
5249
5250        let mut visitor = CollectVisitor::default();
5251        reshape.visit_mut(&mut visitor);
5252        let ids: Vec<u64> = reshape
5253            .inputs()
5254            .chain(reshape.outputs())
5255            .map(|t| t.id.value())
5256            .collect();
5257        assert_eq!(ids, vec![110, 111]);
5258        assert_eq!(visitor.scalars.len(), 0);
5259    }
5260
5261    #[test]
5262    fn pad_ir_tracks_shape_tensors_and_constant_value() {
5263        let input = TensorIr::uninit(TensorId::new(1), Shape::from([2, 3]), DType::F32);
5264        let desc = PadOpIr::create(
5265            input,
5266            vec![(1, 2), (3, 4)],
5267            PadModeIr::Constant(ScalarIr::Float(5.0)),
5268            || TensorId::new(2),
5269        );
5270        assert_eq!(desc.out.shape, Shape::from([5, 10]));
5271
5272        let mut op = OperationIr::NumericFloat(DType::F32, NumericOperationIr::Pad(desc));
5273        let mut visitor = CollectVisitor {
5274            rewrite_scalar: Some(ScalarIr::Float(7.0)),
5275            ..Default::default()
5276        };
5277        op.visit_mut(&mut visitor);
5278
5279        let ids = op
5280            .inputs()
5281            .chain(op.outputs())
5282            .map(|tensor| tensor.id.value())
5283            .collect::<Vec<_>>();
5284        assert_eq!(ids, vec![101, 102]);
5285        assert_eq!(visitor.scalars, vec![ScalarIr::Float(5.0)]);
5286
5287        let OperationIr::NumericFloat(_, NumericOperationIr::Pad(desc)) = op else {
5288            panic!("expected pad operation");
5289        };
5290        assert_eq!(desc.mode, PadModeIr::Constant(ScalarIr::Float(7.0)));
5291    }
5292}