use crate::backend::{Backend, BinaryOp, ReduceOp, UnaryOp};
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct TensorId(pub(crate) u64);
impl Default for TensorId {
fn default() -> Self {
Self::new()
}
}
impl TensorId {
pub fn new() -> Self {
use std::sync::atomic::{AtomicU64, Ordering};
static COUNTER: AtomicU64 = AtomicU64::new(0);
TensorId(COUNTER.fetch_add(1, Ordering::Relaxed))
}
}
pub enum Op<B: Backend> {
None,
Binary {
lhs: crate::Tensor<B>,
rhs: crate::Tensor<B>,
op: BinaryOp,
},
Unary {
input: crate::Tensor<B>,
op: UnaryOp,
},
Reduce {
input: crate::Tensor<B>,
op: ReduceOp,
dims: Vec<usize>,
keep_dim: bool,
},
Matmul {
lhs: crate::Tensor<B>,
rhs: crate::Tensor<B>,
},
Reshape {
input: crate::Tensor<B>,
src_shape: crate::Shape,
},
Transpose {
input: crate::Tensor<B>,
dim0: usize,
dim1: usize,
},
Narrow {
input: crate::Tensor<B>,
dim: usize,
start: usize,
len: usize,
},
Affine {
input: crate::Tensor<B>,
mul: f64,
add: f64,
},
Contiguous { input: crate::Tensor<B> },
Conv2d {
input: crate::Tensor<B>,
weight: crate::Tensor<B>,
bias: Option<crate::Tensor<B>>,
stride: [usize; 2],
padding: [usize; 2],
},
MaxPool2d {
input: crate::Tensor<B>,
kernel_size: [usize; 2],
stride: [usize; 2],
padding: [usize; 2],
indices: Vec<usize>,
},
Cat {
inputs: Vec<crate::Tensor<B>>,
dim: usize,
sizes: Vec<usize>,
},
Powf {
input: crate::Tensor<B>,
exponent: f64,
},
Clamp {
input: crate::Tensor<B>,
min: f64,
max: f64,
},
WhereCond {
mask: crate::Tensor<B>,
on_true: crate::Tensor<B>,
on_false: crate::Tensor<B>,
},
Gather {
input: crate::Tensor<B>,
index: crate::Tensor<B>,
dim: usize,
},
Pad {
input: crate::Tensor<B>,
padding: Vec<[usize; 2]>,
},
AvgPool2d {
input: crate::Tensor<B>,
kernel_size: [usize; 2],
stride: [usize; 2],
padding: [usize; 2],
},
Conv1d {
input: crate::Tensor<B>,
weight: crate::Tensor<B>,
bias: Option<crate::Tensor<B>>,
stride: usize,
padding: usize,
},
IndexSelect {
input: crate::Tensor<B>,
indices: crate::Tensor<B>,
dim: usize,
},
ToDtype {
input: crate::Tensor<B>,
src_dtype: crate::dtype::DType,
},
}
impl<B: Backend> Clone for Op<B> {
fn clone(&self) -> Self {
match self {
Op::None => Op::None,
Op::Binary { lhs, rhs, op } => Op::Binary {
lhs: lhs.clone(),
rhs: rhs.clone(),
op: *op,
},
Op::Unary { input, op } => Op::Unary {
input: input.clone(),
op: *op,
},
Op::Reduce {
input,
op,
dims,
keep_dim,
} => Op::Reduce {
input: input.clone(),
op: *op,
dims: dims.clone(),
keep_dim: *keep_dim,
},
Op::Matmul { lhs, rhs } => Op::Matmul {
lhs: lhs.clone(),
rhs: rhs.clone(),
},
Op::Reshape { input, src_shape } => Op::Reshape {
input: input.clone(),
src_shape: src_shape.clone(),
},
Op::Transpose { input, dim0, dim1 } => Op::Transpose {
input: input.clone(),
dim0: *dim0,
dim1: *dim1,
},
Op::Narrow {
input,
dim,
start,
len,
} => Op::Narrow {
input: input.clone(),
dim: *dim,
start: *start,
len: *len,
},
Op::Affine { input, mul, add } => Op::Affine {
input: input.clone(),
mul: *mul,
add: *add,
},
Op::Contiguous { input } => Op::Contiguous {
input: input.clone(),
},
Op::Conv2d {
input,
weight,
bias,
stride,
padding,
} => Op::Conv2d {
input: input.clone(),
weight: weight.clone(),
bias: bias.clone(),
stride: *stride,
padding: *padding,
},
Op::MaxPool2d {
input,
kernel_size,
stride,
padding,
indices,
} => Op::MaxPool2d {
input: input.clone(),
kernel_size: *kernel_size,
stride: *stride,
padding: *padding,
indices: indices.clone(),
},
Op::Cat { inputs, dim, sizes } => Op::Cat {
inputs: inputs.clone(),
dim: *dim,
sizes: sizes.clone(),
},
Op::Powf { input, exponent } => Op::Powf {
input: input.clone(),
exponent: *exponent,
},
Op::Clamp { input, min, max } => Op::Clamp {
input: input.clone(),
min: *min,
max: *max,
},
Op::WhereCond {
mask,
on_true,
on_false,
} => Op::WhereCond {
mask: mask.clone(),
on_true: on_true.clone(),
on_false: on_false.clone(),
},
Op::Gather { input, index, dim } => Op::Gather {
input: input.clone(),
index: index.clone(),
dim: *dim,
},
Op::Pad { input, padding } => Op::Pad {
input: input.clone(),
padding: padding.clone(),
},
Op::AvgPool2d {
input,
kernel_size,
stride,
padding,
} => Op::AvgPool2d {
input: input.clone(),
kernel_size: *kernel_size,
stride: *stride,
padding: *padding,
},
Op::Conv1d {
input,
weight,
bias,
stride,
padding,
} => Op::Conv1d {
input: input.clone(),
weight: weight.clone(),
bias: bias.clone(),
stride: *stride,
padding: *padding,
},
Op::IndexSelect {
input,
indices,
dim,
} => Op::IndexSelect {
input: input.clone(),
indices: indices.clone(),
dim: *dim,
},
Op::ToDtype { input, src_dtype } => Op::ToDtype {
input: input.clone(),
src_dtype: *src_dtype,
},
}
}
}
impl<B: Backend> std::fmt::Debug for Op<B> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Op::None => write!(f, "None"),
Op::Binary { lhs, rhs, op } => {
write!(f, "Binary({:?}, id={:?}, id={:?})", op, lhs.id(), rhs.id())
}
Op::Unary { input, op } => {
write!(f, "Unary({:?}, id={:?})", op, input.id())
}
Op::Reduce {
input, op, dims, ..
} => {
write!(f, "Reduce({:?}, dims={:?}, id={:?})", op, dims, input.id())
}
Op::Matmul { lhs, rhs } => {
write!(f, "Matmul(id={:?}, id={:?})", lhs.id(), rhs.id())
}
Op::Reshape { input, src_shape } => {
write!(f, "Reshape({} → ?, id={:?})", src_shape, input.id())
}
Op::Transpose { input, dim0, dim1 } => {
write!(f, "Transpose({}, {}, id={:?})", dim0, dim1, input.id())
}
Op::Narrow {
input,
dim,
start,
len,
} => {
write!(
f,
"Narrow(dim={}, {}..{}, id={:?})",
dim,
start,
start + len,
input.id()
)
}
Op::Affine { input, mul, add } => {
write!(f, "Affine(*{} +{}, id={:?})", mul, add, input.id())
}
Op::Contiguous { input } => {
write!(f, "Contiguous(id={:?})", input.id())
}
Op::Conv2d {
input,
weight,
bias,
stride,
padding,
} => {
write!(
f,
"Conv2d(in={:?}, w={:?}, bias={}, s={:?}, p={:?})",
input.id(),
weight.id(),
bias.is_some(),
stride,
padding
)
}
Op::MaxPool2d {
input,
kernel_size,
stride,
padding,
..
} => {
write!(
f,
"MaxPool2d(in={:?}, k={:?}, s={:?}, p={:?})",
input.id(),
kernel_size,
stride,
padding
)
}
Op::Cat { inputs, dim, .. } => {
let ids: Vec<_> = inputs.iter().map(|t| t.id()).collect();
write!(f, "Cat(dim={}, ids={:?})", dim, ids)
}
Op::Powf { input, exponent } => {
write!(f, "Powf(exp={}, id={:?})", exponent, input.id())
}
Op::Clamp { input, min, max } => {
write!(f, "Clamp(min={}, max={}, id={:?})", min, max, input.id())
}
Op::WhereCond {
mask,
on_true,
on_false,
} => {
write!(
f,
"WhereCond(mask={:?}, true={:?}, false={:?})",
mask.id(),
on_true.id(),
on_false.id()
)
}
Op::Gather { input, index, dim } => {
write!(
f,
"Gather(dim={}, input={:?}, index={:?})",
dim,
input.id(),
index.id()
)
}
Op::Pad { input, padding } => {
write!(f, "Pad(pad={:?}, id={:?})", padding, input.id())
}
Op::AvgPool2d {
input,
kernel_size,
stride,
padding,
..
} => {
write!(
f,
"AvgPool2d(in={:?}, k={:?}, s={:?}, p={:?})",
input.id(),
kernel_size,
stride,
padding
)
}
Op::Conv1d {
input,
weight,
bias,
stride,
padding,
} => {
write!(
f,
"Conv1d(in={:?}, w={:?}, bias={}, s={}, p={})",
input.id(),
weight.id(),
bias.is_some(),
stride,
padding
)
}
Op::IndexSelect {
input,
indices,
dim,
} => {
write!(
f,
"IndexSelect(dim={}, input={:?}, indices={:?})",
dim,
input.id(),
indices.id()
)
}
Op::ToDtype { input, src_dtype } => {
write!(f, "ToDtype(from={:?}, id={:?})", src_dtype, input.id())
}
}
}
}
impl<B: Backend> Op<B> {
pub fn inputs(&self) -> Vec<&crate::Tensor<B>> {
match self {
Op::None => vec![],
Op::Binary { lhs, rhs, .. } | Op::Matmul { lhs, rhs } => vec![lhs, rhs],
Op::Unary { input, .. }
| Op::Reduce { input, .. }
| Op::Reshape { input, .. }
| Op::Transpose { input, .. }
| Op::Narrow { input, .. }
| Op::Affine { input, .. }
| Op::Contiguous { input }
| Op::MaxPool2d { input, .. }
| Op::AvgPool2d { input, .. }
| Op::Powf { input, .. }
| Op::Clamp { input, .. } => vec![input],
Op::Conv2d {
input,
weight,
bias,
..
} => {
let mut v = vec![input, weight];
if let Some(b) = bias {
v.push(b);
}
v
}
Op::Conv1d {
input,
weight,
bias,
..
} => {
let mut v = vec![input, weight];
if let Some(b) = bias {
v.push(b);
}
v
}
Op::Cat { inputs, .. } => inputs.iter().collect(),
Op::WhereCond {
mask,
on_true,
on_false,
} => {
vec![mask, on_true, on_false]
}
Op::Gather { input, index, .. } => vec![input, index],
Op::IndexSelect { input, indices, .. } => vec![input, indices],
Op::ToDtype { input, .. } => vec![input],
Op::Pad { input, .. } => vec![input],
}
}
}