// ops.mbt

///|
/// Broadcast two shapes and return the output shape. Returns None if incompatible.
pub fn broadcast_shapes(
  shape1 : Array[Int],
  shape2 : Array[Int],
) -> Array[Int]? {
  let len1 = shape1.length()
  let len2 = shape2.length()
  let max_len = if len1 > len2 { len1 } else { len2 }
  let out_shape = Array::make(max_len, 1)

  for i in 0.. Int {
  let out_len = out_shape.length()
  let target_len = target_shape.length()
  if target_len == 0 {
    return 0
  }
  let mut target_idx = 0
  let mut remaining = flat_idx

  for i in 0..= 0 {
      let dim_size = target_shape[target_dim_idx]
      let coord_mapped = if dim_size == 1 { 0 } else { coord }
      target_idx = target_idx + coord_mapped * target_strides[target_dim_idx]
    }
  }
  target_idx
}

///|
/// Element-wise addition of two Tensors with broadcasting support.
pub impl Add for Tensor with fn add(self : Tensor, other : Tensor) -> Tensor {
  let out_shape = match broadcast_shapes(self.shape, other.shape) {
    Some(s) => s
    None => panic() // Broadcast failed
  }
  let out_strides = shape_to_strides(out_shape)
  let mut size = 1
  for dim in out_shape {
    size = size * dim
  }
  if out_shape.length() == 0 {
    size = 1
  }
  let data = Array::make(size, 0.0)
  for i in 0.. Tensor {
  let out_shape = match broadcast_shapes(self.shape, other.shape) {
    Some(s) => s
    None => panic()
  }
  let out_strides = shape_to_strides(out_shape)
  let mut size = 1
  for dim in out_shape {
    size = size * dim
  }
  if out_shape.length() == 0 {
    size = 1
  }
  let data = Array::make(size, 0.0)
  for i in 0.. Tensor {
  let out_shape = match broadcast_shapes(self.shape, other.shape) {
    Some(s) => s
    None => panic()
  }
  let out_strides = shape_to_strides(out_shape)
  let mut size = 1
  for dim in out_shape {
    size = size * dim
  }
  if out_shape.length() == 0 {
    size = 1
  }
  let data = Array::make(size, 0.0)
  for i in 0.. Tensor {
  let out_shape = match broadcast_shapes(self.shape, other.shape) {
    Some(s) => s
    None => panic()
  }
  let out_strides = shape_to_strides(out_shape)
  let mut size = 1
  for dim in out_shape {
    size = size * dim
  }
  if out_shape.length() == 0 {
    size = 1
  }
  let data = Array::make(size, 0.0)
  for i in 0..