use super::*;
#[test]
fn test_map_each() {
let graph = FlowBuilder::from(Identity)
.map(Doubler)
.each()
.build()
.unwrap();
let x = Variable::new(from_f32(&[1.0, 2.0, 3.0, 4.0, 5.0, 6.0], &[3, 2]), false);
let y = graph.forward(&x).unwrap();
let data = y.data().to_f32_vec().unwrap();
assert_eq!(y.shape(), vec![3, 2]);
assert!((data[0] - 2.0).abs() < 1e-5);
assert!((data[5] - 12.0).abs() < 1e-5);
}
#[test]
fn test_map_batched() {
let graph = FlowBuilder::from(Identity)
.map(Doubler)
.batched()
.each()
.build()
.unwrap();
let x = Variable::new(from_f32(&[1.0, 2.0, 3.0, 4.0], &[2, 2]), false);
let y = graph.forward(&x).unwrap();
let data = y.data().to_f32_vec().unwrap();
assert_eq!(data, vec![2.0, 4.0, 6.0, 8.0]);
}
#[test]
fn test_map_backward() {
let graph = FlowBuilder::from(Linear::on_device(2, 2, crate::tensor::test_device()).unwrap())
.map(Linear::on_device(2, 2, crate::tensor::test_device()).unwrap())
.each()
.build()
.unwrap();
let x = Variable::new(from_f32(&[1.0, 2.0, 3.0, 4.0], &[2, 2]), true);
let y = graph.forward(&x).unwrap();
let loss = y.sum().unwrap();
loss.backward().unwrap();
assert!(x.grad().is_some());
for p in graph.parameters() {
assert!(p.variable.grad().is_some(), "{} should have gradient", p.name);
}
}
#[test]
fn test_input_auxiliary() {
let graph = FlowBuilder::from(Identity)
.input(&["ctx"])
.through(SumRefs)
.using(&["ctx"])
.build()
.unwrap();
let main = Variable::new(from_f32(&[1.0, 2.0], &[1, 2]), false);
let ctx = Variable::new(from_f32(&[10.0, 20.0], &[1, 2]), false);
let y = graph.forward_multi(&[main, ctx]).unwrap();
let data = y.data().to_f32_vec().unwrap();
assert!((data[0] - 11.0).abs() < 1e-5, "got {}", data[0]);
assert!((data[1] - 22.0).abs() < 1e-5, "got {}", data[1]);
}
#[test]
fn test_input_multiple() {
let graph = FlowBuilder::from(Identity)
.input(&["a", "b"])
.through(SumRefs)
.using(&["a", "b"])
.build()
.unwrap();
let main = Variable::new(from_f32(&[1.0], &[1, 1]), false);
let a = Variable::new(from_f32(&[10.0], &[1, 1]), false);
let b = Variable::new(from_f32(&[100.0], &[1, 1]), false);
let y = graph.forward_multi(&[main, a, b]).unwrap();
let data = y.data().to_f32_vec().unwrap();
assert!((data[0] - 111.0).abs() < 1e-5, "got {}", data[0]);
}
#[test]
fn test_input_error_count_mismatch() {
let graph = FlowBuilder::from(Identity)
.input(&["ctx"])
.build()
.unwrap();
let x = Variable::new(from_f32(&[1.0], &[1, 1]), false);
assert!(graph.forward(&x).is_err());
}
#[test]
fn test_map_over_tag() {
let graph = FlowBuilder::from(Identity)
.tag("features")
.through(Doubler) .map(Doubler)
.over("features") .build()
.unwrap();
let x = Variable::new(from_f32(&[1.0, 2.0, 3.0, 4.0], &[2, 2]), false);
let y = graph.forward(&x).unwrap();
let data = y.data().to_f32_vec().unwrap();
assert_eq!(y.shape(), vec![2, 2]);
assert!((data[0] - 2.0).abs() < 1e-5); assert!((data[1] - 4.0).abs() < 1e-5); assert!((data[2] - 6.0).abs() < 1e-5); assert!((data[3] - 8.0).abs() < 1e-5); }
#[test]
fn test_map_over_unknown_tag_error() {
let result = FlowBuilder::from(Identity)
.map(Doubler)
.over("nonexistent")
.build();
assert!(result.is_err());
}
#[test]
fn test_map_slices() {
let graph = FlowBuilder::from(Identity)
.map(Doubler)
.slices(2)
.build()
.unwrap();
let x = Variable::new(
from_f32(&[1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0], &[2, 4]),
false,
);
let y = graph.forward(&x).unwrap();
let data = y.data().to_f32_vec().unwrap();
assert_eq!(y.shape(), vec![2, 4]);
assert!((data[0] - 2.0).abs() < 1e-5);
assert!((data[7] - 16.0).abs() < 1e-5);
}
#[test]
fn test_map_slices_batched() {
let graph = FlowBuilder::from(Identity)
.map(Doubler)
.batched()
.slices(2)
.build()
.unwrap();
let x = Variable::new(
from_f32(&[1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0], &[2, 4]),
false,
);
let y = graph.forward(&x).unwrap();
let data = y.data().to_f32_vec().unwrap();
assert_eq!(y.shape(), vec![2, 4]);
assert!((data[0] - 2.0).abs() < 1e-5);
assert!((data[7] - 16.0).abs() < 1e-5);
}
#[test]
fn test_map_slices_gradient() {
let graph = FlowBuilder::from(Identity)
.map(Linear::on_device(2, 3, crate::tensor::test_device()).unwrap())
.slices(2)
.build()
.unwrap();
let x = Variable::new(from_f32(&[1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0], &[2, 4]), true);
let y = graph.forward(&x).unwrap();
assert_eq!(y.shape(), vec![2, 6]); let loss = y.sum().unwrap();
loss.backward().unwrap();
assert!(x.grad().is_some());
for p in graph.parameters() {
assert!(p.variable.grad().is_some(), "{} should have gradient", p.name);
}
}
#[test]
fn test_map_slices_not_divisible_error() {
let graph = FlowBuilder::from(Identity)
.map(Doubler)
.slices(3)
.build()
.unwrap();
let x = Variable::new(from_f32(&[1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0], &[2, 4]), false);
assert!(graph.forward(&x).is_err());
}