mod common;
use oxionnx::{Attributes, OpKind, Tensor};
use common::{assert_tensor_approx, run_single_op};
#[test]
fn test_matmul_2d() {
let a = Tensor::new(vec![1.0, 2.0, 3.0, 4.0, 5.0, 6.0], vec![2, 3]);
let b = Tensor::new(
vec![1.0, 0.0, 1.0, 0.0, 0.0, 1.0, 0.0, 1.0, 1.0, 1.0, 1.0, 1.0],
vec![3, 4],
);
let outputs = run_single_op(
OpKind::MatMul,
vec![("a", a), ("b", b)],
vec![],
vec!["a", "b"],
vec!["a", "b"],
"out",
Attributes::default(),
);
let out = outputs.get("out").unwrap();
assert_eq!(out.shape, vec![2, 4]);
assert_tensor_approx(out, &[4.0, 5.0, 4.0, 5.0, 10.0, 11.0, 10.0, 11.0], 1e-5);
}
#[test]
fn test_matmul_batched() {
let mut a_data = vec![1.0f32; 12]; a_data.extend(vec![2.0f32; 12]); let a = Tensor::new(a_data, vec![2, 3, 4]);
let b_data = vec![1.0f32; 40]; let b = Tensor::new(b_data, vec![2, 4, 5]);
let outputs = run_single_op(
OpKind::MatMul,
vec![("a", a), ("b", b)],
vec![],
vec!["a", "b"],
vec!["a", "b"],
"out",
Attributes::default(),
);
let out = outputs.get("out").unwrap();
assert_eq!(out.shape, vec![2, 3, 5]);
for i in 0..15 {
assert!(
(out.data[i] - 4.0).abs() < 1e-5,
"batch0 idx {}: {} vs 4.0",
i,
out.data[i]
);
}
for i in 15..30 {
assert!(
(out.data[i] - 8.0).abs() < 1e-5,
"batch1 idx {}: {} vs 8.0",
i,
out.data[i]
);
}
}
#[test]
fn test_matmul_batch1() {
let a = Tensor::new(vec![1.0, 2.0, 3.0, 4.0, 5.0, 6.0], vec![1, 2, 3]);
let b = Tensor::new(vec![1.0, 0.0, 0.0, 1.0, 1.0, 1.0], vec![1, 3, 2]);
let outputs = run_single_op(
OpKind::MatMul,
vec![("a", a), ("b", b)],
vec![],
vec!["a", "b"],
vec!["a", "b"],
"out",
Attributes::default(),
);
let out = outputs.get("out").unwrap();
assert_eq!(out.shape, vec![1, 2, 2]);
assert_tensor_approx(out, &[4.0, 5.0, 10.0, 11.0], 1e-5);
}
#[test]
fn test_matmul_batch4() {
let eye = [1.0, 0.0, 0.0, 1.0]; let a_data: Vec<f32> = (0..4)
.flat_map(|batch| {
let b = batch as f32;
vec![b + 1.0, b + 2.0, b + 3.0, b + 4.0]
})
.collect();
let b_data: Vec<f32> = eye.iter().copied().cycle().take(16).collect();
let a = Tensor::new(a_data.clone(), vec![4, 2, 2]);
let b = Tensor::new(b_data, vec![4, 2, 2]);
let outputs = run_single_op(
OpKind::MatMul,
vec![("a", a), ("b", b)],
vec![],
vec!["a", "b"],
vec!["a", "b"],
"out",
Attributes::default(),
);
let out = outputs.get("out").unwrap();
assert_eq!(out.shape, vec![4, 2, 2]);
assert_tensor_approx(out, &a_data, 1e-5);
}
#[test]
fn test_matmul_small() {
let a = Tensor::new(vec![1.0, 2.0, 3.0], vec![1, 3]);
let b = Tensor::new(
vec![1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0],
vec![3, 4],
);
let outputs = run_single_op(
OpKind::MatMul,
vec![("a", a), ("b", b)],
vec![],
vec!["a", "b"],
vec!["a", "b"],
"out",
Attributes::default(),
);
let out = outputs.get("out").unwrap();
assert_eq!(out.shape, vec![1, 4]);
assert_tensor_approx(out, &[1.0, 2.0, 3.0, 0.0], 1e-5);
}
#[test]
fn test_gemm_trans_b() {
let mut attrs = Attributes::default();
attrs.ints.insert("transB".to_string(), 1);
attrs.floats.insert("alpha".to_string(), 0.5);
attrs.floats.insert("beta".to_string(), 2.0);
let a = Tensor::new(vec![1.0, 2.0, 3.0, 4.0], vec![2, 2]);
let b = Tensor::new(vec![1.0, 3.0, 2.0, 4.0], vec![2, 2]);
let c = Tensor::new(vec![10.0, 20.0], vec![2]);
let outputs = run_single_op(
OpKind::Gemm,
vec![("a", a), ("b", b)],
vec![("c", c)],
vec!["a", "b"],
vec!["a", "b", "c"],
"out",
attrs,
);
let out = outputs.get("out").unwrap();
assert_eq!(out.shape, vec![2, 2]);
assert_tensor_approx(out, &[23.5, 45.0, 27.5, 51.0], 1e-4);
}
#[test]
fn test_reduce_mean_axis() {
let mut attrs = Attributes::default();
attrs.int_lists.insert("axes".to_string(), vec![1]);
attrs.ints.insert("keepdims".to_string(), 0);
let x = Tensor::new(vec![1.0, 2.0, 3.0, 4.0, 5.0, 6.0], vec![2, 3]);
let outputs = run_single_op(
OpKind::ReduceMean,
vec![("x", x)],
vec![],
vec!["x"],
vec!["x"],
"out",
attrs,
);
let out = outputs.get("out").unwrap();
assert_tensor_approx(out, &[2.0, 5.0], 1e-5);
}
#[test]
fn test_reduce_sum_keepdims() {
let mut attrs = Attributes::default();
attrs.int_lists.insert("axes".to_string(), vec![1]);
attrs.ints.insert("keepdims".to_string(), 1);
let x = Tensor::new(vec![1.0, 2.0, 3.0, 4.0, 5.0, 6.0], vec![2, 3]);
let outputs = run_single_op(
OpKind::ReduceSum,
vec![("x", x)],
vec![],
vec!["x"],
vec!["x"],
"out",
attrs,
);
let out = outputs.get("out").unwrap();
assert_eq!(out.shape, vec![2, 1]);
assert_tensor_approx(out, &[6.0, 15.0], 1e-5);
}
#[test]
fn test_reduce_max() {
let mut attrs = Attributes::default();
attrs.int_lists.insert("axes".to_string(), vec![1]);
attrs.ints.insert("keepdims".to_string(), 0);
let x = Tensor::new(vec![1.0, 5.0, 3.0, 4.0, 2.0, 6.0], vec![2, 3]);
let outputs = run_single_op(
OpKind::ReduceMax,
vec![("x", x)],
vec![],
vec!["x"],
vec!["x"],
"out",
attrs,
);
let out = outputs.get("out").unwrap();
assert_tensor_approx(out, &[5.0, 6.0], 1e-5);
}
#[test]
fn test_reduce_min() {
let mut attrs = Attributes::default();
attrs.int_lists.insert("axes".to_string(), vec![1]);
attrs.ints.insert("keepdims".to_string(), 0);
let x = Tensor::new(vec![1.0, 5.0, 3.0, 4.0, 2.0, 6.0], vec![2, 3]);
let outputs = run_single_op(
OpKind::ReduceMin,
vec![("x", x)],
vec![],
vec!["x"],
vec!["x"],
"out",
attrs,
);
let out = outputs.get("out").unwrap();
assert_tensor_approx(out, &[1.0, 2.0], 1e-5);
}
#[test]
fn test_reduce_l1() {
let mut attrs = Attributes::default();
attrs.int_lists.insert("axes".to_string(), vec![1]);
attrs.ints.insert("keepdims".to_string(), 0);
let x = Tensor::new(vec![1.0, 2.0, 3.0, 4.0], vec![2, 2]);
let outputs = run_single_op(
OpKind::ReduceL1,
vec![("x", x)],
vec![],
vec!["x"],
vec!["x"],
"out",
attrs,
);
let out = outputs.get("out").unwrap();
assert_tensor_approx(out, &[3.0, 7.0], 1e-5);
}
#[test]
fn test_reduce_l2() {
let attrs = Attributes::default(); let x = Tensor::new(vec![3.0, 4.0], vec![2]);
let outputs = run_single_op(
OpKind::ReduceL2,
vec![("x", x)],
vec![],
vec!["x"],
vec!["x"],
"out",
attrs,
);
let out = outputs.get("out").unwrap();
assert_tensor_approx(out, &[5.0], 1e-5);
}
#[test]
fn test_reduce_log_sum() {
let attrs = Attributes::default();
let x = Tensor::new(vec![1.0, 1.0, 1.0], vec![3]);
let outputs = run_single_op(
OpKind::ReduceLogSum,
vec![("x", x)],
vec![],
vec!["x"],
vec!["x"],
"out",
attrs,
);
let out = outputs.get("out").unwrap();
let expected = 3.0f32.ln();
assert!(
(out.data[0] - expected).abs() < 1e-5,
"reduce_log_sum: got {}, expected {}",
out.data[0],
expected
);
}
#[test]
fn test_reduce_log_sum_exp() {
let attrs = Attributes::default();
let x = Tensor::new(vec![0.0, 1.0, 2.0], vec![3]);
let outputs = run_single_op(
OpKind::ReduceLogSumExp,
vec![("x", x)],
vec![],
vec!["x"],
vec!["x"],
"out",
attrs,
);
let out = outputs.get("out").unwrap();
let expected = (0.0f32.exp() + 1.0f32.exp() + 2.0f32.exp()).ln();
assert!(
(out.data[0] - expected).abs() < 1e-4,
"reduce_log_sum_exp: got {}, expected {}",
out.data[0],
expected
);
}
#[test]
fn test_reduce_sum_square() {
let attrs = Attributes::default();
let x = Tensor::new(vec![2.0, 3.0, 4.0], vec![3]);
let outputs = run_single_op(
OpKind::ReduceSumSquare,
vec![("x", x)],
vec![],
vec!["x"],
vec!["x"],
"out",
attrs,
);
let out = outputs.get("out").unwrap();
assert_tensor_approx(out, &[29.0], 1e-5);
}