use xla::{ArrayElement, Result};
#[test]
fn add_op() -> Result<()> {
let client = xla::PjRtClient::cpu()?;
let builder = xla::XlaBuilder::new("test");
let cst42 = builder.constant_r0(42f32)?;
let cst43 = builder.constant_r1c(43f32, 2)?;
let sum = (cst42 + &cst43)?;
let computation = sum.build()?;
let result = client.compile(&computation)?;
let result = result.execute::<xla::Literal>(&[])?;
let result = result[0][0].to_literal_sync()?;
assert_eq!(result.element_count(), 2);
assert_eq!(result.array_shape()?, xla::ArrayShape::new::<f32>(vec![2]));
assert_eq!(result.get_first_element::<f32>()?, 85.);
assert_eq!(result.to_vec::<f32>()?, [85., 85.]);
Ok(())
}
#[test]
fn matmul_op() -> Result<()> {
let client = xla::PjRtClient::cpu()?;
let builder = xla::XlaBuilder::new("test");
let x = builder.parameter(0, f32::TY, &[2, 2, 3], "x")?;
let w = builder.parameter(1, f32::TY, &[3, 2], "w")?;
let exe = x.matmul(&w)?.build()?.compile(&client)?;
let x =
xla::Literal::vec1(&(1..=12).map(|v| v as f32).collect::<Vec<_>>()).reshape(&[2, 2, 3])?;
let w = xla::Literal::vec1(&[1f32, 0., 0., 1., 1., 1.]).reshape(&[3, 2])?;
let result = exe.execute::<xla::Literal>(&[x, w])?[0][0].to_literal_sync()?;
assert_eq!(result.array_shape()?, xla::ArrayShape::new::<f32>(vec![2, 2, 2]));
assert_eq!(result.to_vec::<f32>()?, [4., 5., 10., 11., 16., 17., 22., 23.]);
let builder = xla::XlaBuilder::new("test");
let x = builder.parameter(0, f32::TY, &[2, 3], "x")?;
let v = builder.parameter(1, f32::TY, &[3], "v")?;
let exe = x.matmul(&v)?.build()?.compile(&client)?;
let x = xla::Literal::vec1(&[1f32, 2., 3., 4., 5., 6.]).reshape(&[2, 3])?;
let v = xla::Literal::vec1(&[1f32, 1., 1.]);
let result = exe.execute::<xla::Literal>(&[x, v])?[0][0].to_literal_sync()?;
assert_eq!(result.to_vec::<f32>()?, [6., 15.]);
let builder = xla::XlaBuilder::new("test");
let v = builder.parameter(0, f32::TY, &[3], "v")?;
let x = builder.parameter(1, f32::TY, &[2, 3, 2], "x")?;
let exe = v.matmul(&x)?.build()?.compile(&client)?;
let v = xla::Literal::vec1(&[1f32, 1., 1.]);
let x =
xla::Literal::vec1(&(1..=12).map(|v| v as f32).collect::<Vec<_>>()).reshape(&[2, 3, 2])?;
let result = exe.execute::<xla::Literal>(&[v, x])?[0][0].to_literal_sync()?;
assert_eq!(result.array_shape()?, xla::ArrayShape::new::<f32>(vec![2, 2]));
assert_eq!(result.to_vec::<f32>()?, [9., 12., 27., 30.]);
let builder = xla::XlaBuilder::new("test");
let x = builder.parameter(0, f32::TY, &[2, 3], "x")?;
let w = builder.parameter(1, f32::TY, &[2, 4], "w")?;
assert!(x.matmul(&w).and_then(|op| op.build()).is_err());
Ok(())
}
#[test]
fn pad_op() -> Result<()> {
let client = xla::PjRtClient::cpu()?;
let builder = xla::XlaBuilder::new("test");
let x = builder.parameter(0, f32::TY, &[2, 2], "x")?;
let zero = builder.zero(xla::ElementType::F32)?;
let exe = x.pad(&zero, &[(1, 0, 0), (0, 1, 0)])?.build()?.compile(&client)?;
let x = xla::Literal::vec1(&[1f32, 2., 3., 4.]).reshape(&[2, 2])?;
let result = exe.execute::<xla::Literal>(&[x])?[0][0].to_literal_sync()?;
assert_eq!(result.array_shape()?, xla::ArrayShape::new::<f32>(vec![3, 3]));
assert_eq!(result.to_vec::<f32>()?, [0., 0., 0., 1., 2., 0., 3., 4., 0.]);
let builder = xla::XlaBuilder::new("test");
let x = builder.parameter(0, f32::TY, &[3], "x")?;
let zero = builder.zero(xla::ElementType::F32)?;
let exe = x.pad(&zero, &[(0, 0, 1)])?.build()?.compile(&client)?;
let x = xla::Literal::vec1(&[1f32, 2., 3.]);
let result = exe.execute::<xla::Literal>(&[x])?[0][0].to_literal_sync()?;
assert_eq!(result.to_vec::<f32>()?, [1., 0., 2., 0., 3.]);
let builder = xla::XlaBuilder::new("test");
let x = builder.parameter(0, f32::TY, &[2, 2], "x")?;
let zero = builder.zero(xla::ElementType::F32)?;
let exe = x.pad_in_dim(&zero, -1, 1, 1)?.build()?.compile(&client)?;
let x = xla::Literal::vec1(&[1f32, 2., 3., 4.]).reshape(&[2, 2])?;
let result = exe.execute::<xla::Literal>(&[x])?[0][0].to_literal_sync()?;
assert_eq!(result.array_shape()?, xla::ArrayShape::new::<f32>(vec![2, 4]));
assert_eq!(result.to_vec::<f32>()?, [0., 1., 2., 0., 0., 3., 4., 0.]);
Ok(())
}
#[test]
fn scatter_op() -> Result<()> {
let client = xla::PjRtClient::cpu()?;
let add = {
let builder = xla::XlaBuilder::new("add");
let x = builder.parameter(0, f32::TY, &[], "x")?;
let y = builder.parameter(1, f32::TY, &[], "y")?;
(x + y)?.build()?
};
let builder = xla::XlaBuilder::new("test");
let operand = builder.parameter(0, f32::TY, &[4], "operand")?;
let indices = builder.parameter(1, i64::TY, &[2], "indices")?;
let updates = builder.parameter(2, f32::TY, &[2], "updates")?;
let exe =
operand.scatter(&indices, &updates, &add, &[], &[0], &[0], 1)?.build()?.compile(&client)?;
let operand = xla::Literal::vec1(&[10f32, 20., 30., 40.]);
let indices = xla::Literal::vec1(&[0i64, 2]);
let updates = xla::Literal::vec1(&[1f32, 2.]);
let result =
exe.execute::<xla::Literal>(&[operand, indices, updates])?[0][0].to_literal_sync()?;
assert_eq!(result.to_vec::<f32>()?, [11., 20., 32., 40.]);
let replace = {
let builder = xla::XlaBuilder::new("replace");
let _x = builder.parameter(0, f32::TY, &[], "x")?;
let y = builder.parameter(1, f32::TY, &[], "y")?;
y.build()?
};
let builder = xla::XlaBuilder::new("test");
let operand = builder.parameter(0, f32::TY, &[3, 2], "operand")?;
let indices = builder.parameter(1, i64::TY, &[2], "indices")?;
let updates = builder.parameter(2, f32::TY, &[2, 2], "updates")?;
let exe = operand
.scatter(&indices, &updates, &replace, &[1], &[0], &[0], 1)?
.build()?
.compile(&client)?;
let operand = xla::Literal::vec1(&[0f32; 6]).reshape(&[3, 2])?;
let indices = xla::Literal::vec1(&[2i64, 0]);
let updates = xla::Literal::vec1(&[1f32, 2., 3., 4.]).reshape(&[2, 2])?;
let result =
exe.execute::<xla::Literal>(&[operand, indices, updates])?[0][0].to_literal_sync()?;
assert_eq!(result.to_vec::<f32>()?, [3., 4., 0., 0., 1., 2.]);
Ok(())
}
#[test]
fn sort_ops() -> Result<()> {
let client = xla::PjRtClient::cpu()?;
let builder = xla::XlaBuilder::new("test");
let x = builder.parameter(0, f32::TY, &[4], "x")?;
let exe = x.sort_asc(-1, false)?.build()?.compile(&client)?;
let x = xla::Literal::vec1(&[3f32, 1., 4., 2.]);
let result = exe.execute::<xla::Literal>(&[x])?[0][0].to_literal_sync()?;
assert_eq!(result.to_vec::<f32>()?, [1., 2., 3., 4.]);
let builder = xla::XlaBuilder::new("test");
let x = builder.parameter(0, f32::TY, &[2, 2], "x")?;
let exe = x.sort_desc(0, false)?.build()?.compile(&client)?;
let x = xla::Literal::vec1(&[1f32, 4., 3., 2.]).reshape(&[2, 2])?;
let result = exe.execute::<xla::Literal>(&[x])?[0][0].to_literal_sync()?;
assert_eq!(result.to_vec::<f32>()?, [3., 4., 1., 2.]);
let builder = xla::XlaBuilder::new("test");
let x = builder.parameter(0, f32::TY, &[5], "x")?;
let exe = x.top_k(3, true)?.build()?.compile(&client)?;
let x = xla::Literal::vec1(&[3f32, 1., 4., 1., 5.]);
let result = exe.execute::<xla::Literal>(&[x])?;
assert_eq!(result[0].len(), 2);
assert_eq!(result[0][0].to_literal_sync()?.to_vec::<f32>()?, [5., 4., 3.]);
assert_eq!(result[0][1].to_literal_sync()?.to_vec::<i32>()?, [4, 2, 0]);
let builder = xla::XlaBuilder::new("test");
let x = builder.parameter(0, f32::TY, &[2, 3], "x")?;
let argmax = x.argmax(xla::ElementType::S32, -1)?;
let argmin = x.argmin(xla::ElementType::S32, -1)?;
let exe = builder.tuple(&[argmax, argmin])?.build()?.compile(&client)?;
let x = xla::Literal::vec1(&[1f32, 5., 2., 7., 3., 4.]).reshape(&[2, 3])?;
let result = exe.execute::<xla::Literal>(&[x])?;
assert_eq!(result[0][0].to_literal_sync()?.to_vec::<i32>()?, [1, 0]);
assert_eq!(result[0][1].to_literal_sync()?.to_vec::<i32>()?, [0, 1]);
Ok(())
}
#[test]
fn dynamic_slice_op() -> Result<()> {
let client = xla::PjRtClient::cpu()?;
let builder = xla::XlaBuilder::new("test");
let x = builder.parameter(0, f32::TY, &[5], "x")?;
let start = builder.parameter(1, i64::TY, &[], "start")?;
let exe = x.dynamic_slice(&[start], &[2])?.build()?.compile(&client)?;
let x = xla::Literal::vec1(&[10f32, 11., 12., 13., 14.]);
let start = xla::Literal::scalar(2i64);
let result = exe.execute::<xla::Literal>(&[x, start])?[0][0].to_literal_sync()?;
assert_eq!(result.to_vec::<f32>()?, [12., 13.]);
let x = xla::Literal::vec1(&[10f32, 11., 12., 13., 14.]);
let start = xla::Literal::scalar(4i64);
let result = exe.execute::<xla::Literal>(&[x, start])?[0][0].to_literal_sync()?;
assert_eq!(result.to_vec::<f32>()?, [13., 14.]);
let builder = xla::XlaBuilder::new("test");
let x = builder.parameter(0, f32::TY, &[3, 3], "x")?;
let one = builder.c0(1i64)?;
let exe = x.dynamic_slice(&[&one, &one], &[2, 2])?.build()?.compile(&client)?;
let x = xla::Literal::vec1(&(0..9).map(|v| v as f32).collect::<Vec<_>>()).reshape(&[3, 3])?;
let result = exe.execute::<xla::Literal>(&[x])?[0][0].to_literal_sync()?;
assert_eq!(result.to_vec::<f32>()?, [4., 5., 7., 8.]);
Ok(())
}
#[test]
fn dynamic_update_slice_op() -> Result<()> {
let client = xla::PjRtClient::cpu()?;
let builder = xla::XlaBuilder::new("test");
let x = builder.parameter(0, f32::TY, &[5], "x")?;
let update = builder.parameter(1, f32::TY, &[2], "update")?;
let start = builder.parameter(2, i64::TY, &[], "start")?;
let exe = x.dynamic_update_slice(&update, &[start])?.build()?.compile(&client)?;
let x = xla::Literal::vec1(&[0f32, 1., 2., 3., 4.]);
let update = xla::Literal::vec1(&[20f32, 21.]);
let start = xla::Literal::scalar(2i64);
let result = exe.execute::<xla::Literal>(&[x, update, start])?[0][0].to_literal_sync()?;
assert_eq!(result.to_vec::<f32>()?, [0., 1., 20., 21., 4.]);
Ok(())
}
#[test]
fn sum_op() -> Result<()> {
let client = xla::PjRtClient::cpu()?;
let builder = xla::XlaBuilder::new("test");
let x = builder.parameter(0, f32::TY, &[2], "x")?;
let sum = x.reduce_sum(&[], false)?.build()?.compile(&client)?;
let input = xla::Literal::vec1(&[4.2f32, 1.337f32]);
let result = sum.execute::<xla::Literal>(&[input])?;
let result = result[0][0].to_literal_sync()?;
assert_eq!(result.to_vec::<f32>()?, [4.2, 1.337]);
let builder = xla::XlaBuilder::new("test");
let x = builder.parameter(0, f32::TY, &[-2], "x")?;
let sum = x.reduce_sum(&[0], false)?.build()?.compile(&client)?;
let input = xla::Literal::vec1(&[4.2f32, 1.337f32]);
let result = sum.execute::<xla::Literal>(&[input])?;
let result = result[0][0].to_literal_sync()?;
assert_eq!(result.to_vec::<f32>()?, [5.5369997]);
assert_eq!(result.array_shape()?.dims(), []);
let builder = xla::XlaBuilder::new("test");
let x = builder.parameter(0, f32::TY, &[-2], "x")?;
let sum = x.reduce_sum(&[0], true)?.build()?.compile(&client)?;
let input = xla::Literal::vec1(&[4.2f32, 1.337f32]);
let result = sum.execute::<xla::Literal>(&[input])?;
let result = result[0][0].to_literal_sync()?;
assert_eq!(result.to_vec::<f32>()?, [5.5369997]);
assert_eq!(result.array_shape()?.dims(), [1]);
Ok(())
}
#[test]
fn mean_op() -> Result<()> {
let client = xla::PjRtClient::cpu()?;
let builder = xla::XlaBuilder::new("test");
let x = builder.parameter(0, f32::TY, &[-2], "x")?;
let sum = x.reduce_mean(&[0], false)?.build()?.compile(&client)?;
let input = xla::Literal::vec1(&[4.2f32, 1.337f32]);
let result = sum.execute::<xla::Literal>(&[input])?;
let result = result[0][0].to_literal_sync()?;
assert_eq!(result.to_vec::<f32>()?, [2.7684999]);
assert_eq!(result.array_shape()?.dims(), []);
Ok(())
}
#[test]
fn tuple_op() -> Result<()> {
let client = xla::PjRtClient::cpu()?;
let builder = xla::XlaBuilder::new("test");
let x = builder.parameter(0, f32::TY, &[-1], "x")?;
let y = builder.parameter(1, f32::TY, &[2], "x")?;
let tuple = builder.tuple(&[x, y])?.build()?.compile(&client)?;
let x = xla::Literal::scalar(3.1f32);
let y = xla::Literal::vec1(&[4.2f32, 1.337f32]);
let result = tuple.execute::<xla::Literal>(&[x, y])?;
assert_eq!(result[0].len(), 2);
assert_eq!(result[0][1].to_literal_sync()?.to_vec::<f32>()?, [4.2, 1.337]);
assert_eq!(result[0][0].to_literal_sync()?.to_vec::<f32>()?, [3.1]);
Ok(())
}
#[test]
fn tuple_literal() -> Result<()> {
let x = xla::Literal::scalar(3.1f32);
let y = xla::Literal::vec1(&[4.2f32, 1.337f32]);
let result = xla::Literal::tuple(vec![x, y]);
assert_eq!(result.shape()?.tuple_size(), Some(2));
let mut result = result;
let result = result.decompose_tuple()?;
assert_eq!(result[1].to_vec::<f32>()?, [4.2, 1.337]);
assert_eq!(result[0].to_vec::<f32>()?, [3.1]);
Ok(())
}