extern crate autograd as ag; extern crate ndarray; use ag::prelude::*; use ag::tensor_ops as T; use ag::VariableEnvironment; use ndarray::array; #[test] fn scalar_add() { let ctx = ag::VariableEnvironment::new(); ctx.run(|g| { let x = g.placeholder("x", &[]); let y = x + 2.; let grad = T::grad(&[y], &[x])[0]; assert_eq!(1., grad.eval(g).unwrap()[ndarray::IxDyn(&[])]); }); } #[test] fn scalar_sub() { let ctx = ag::VariableEnvironment::new(); ctx.run(|g| { let x = g.placeholder("x", &[]); let y = x - 2.; let grad = T::grad(&[y], &[x])[0]; assert_eq!(1., grad.eval(g).unwrap()[ndarray::IxDyn(&[])]); }); } #[test] fn scalar_mul() { let ctx = ag::VariableEnvironment::::new(); ctx.run(|g| { let x = g.placeholder("x", &[]); let y = 3. * x; let grad = T::grad(&[y], &[x])[0]; assert_eq!(3., grad.eval(g).unwrap()[ndarray::IxDyn(&[])]); }); } #[test] fn scalar_div() { let ctx = ag::VariableEnvironment::new(); ctx.run(|g| { let x = g.placeholder("x", &[]); let y = x / 3.; let grad = T::grad(&[y], &[x])[0]; assert_eq!(1. / 3., grad.eval(g).unwrap()[ndarray::IxDyn(&[])]); }); } #[test] fn scalar_div2() { let ctx = ag::VariableEnvironment::new(); ctx.run(|g| { let x = g.placeholder("x", &[]); let y = x / 3. / 4.; let grad = T::grad(&[y], &[x])[0]; assert_eq!(1. / 3. / 4., grad.eval(g).unwrap()[ndarray::IxDyn(&[])]); }); } #[test] fn expr0() { let ctx = ag::VariableEnvironment::::new(); ctx.run(|g| { let x = g.placeholder("x", &[]); let y = 3. * x; let grad = T::grad(&[y], &[x])[0]; assert_eq!(3., grad.eval(g).unwrap()[ndarray::IxDyn(&[])]); }); } #[test] fn expr1() { let ctx = ag::VariableEnvironment::new(); ctx.run(|g| { let x = g.placeholder("x", &[]); let y = 3. * x + 2.; let grad = T::grad(&[y], &[x])[0]; assert_eq!(3., grad.eval(g).unwrap()[ndarray::IxDyn(&[])]); }); } #[test] fn expr2() { let ctx = ag::VariableEnvironment::new(); ctx.run(|g| { let x = g.placeholder("x", &[]); let y = 3. * x * x; let grad = T::grad(&[y], &[x])[0]; let eval = g .evaluator() .push(grad) .feed(x, ndarray::arr0(3.).view()) .run(); assert_eq!(18., eval[0].as_ref().unwrap()[ndarray::IxDyn(&[])]); }); } #[test] fn expr3() { let ctx = ag::VariableEnvironment::new(); ctx.run(|g| { let x = g.placeholder("x", &[]); let y = 3. * x * x + 2.; let grad = T::grad(&[y], &[x])[0]; let eval = g .evaluator() .push(grad) .feed(x, ndarray::arr0(3.).view()) .run(); assert_eq!(18., eval[0].as_ref().unwrap()[ndarray::IxDyn(&[])]); }); } #[test] fn expr4() { let ctx = ag::VariableEnvironment::new(); ctx.run(|g| { let x = g.placeholder("x", &[]); let y = 3. * x * x + 2. * x + 1.; let grad = T::grad(&[y], &[x])[0]; let eval = g .evaluator() .feed(x, ndarray::arr0(3.).view()) .push(grad) .run(); assert_eq!(20., eval[0].as_ref().unwrap()[ndarray::IxDyn(&[])]); }); } #[test] fn expr5() { let ctx = ag::VariableEnvironment::new(); ctx.run(|g| { let x1 = g.placeholder("x1", &[]); let x2 = g.placeholder("x2", &[]); let y = 3. * x1 * x1 + 2. * x1 + x2 + 1.; let grad = T::grad(&[y], &[x1])[0]; let eval = g .evaluator() .push(grad) .feed(x1, ndarray::arr0(3.).view()) .run(); assert_eq!(20., eval[0].as_ref().unwrap()[ndarray::IxDyn(&[])]); }); } #[test] // Test with intention that grad of `x2` should be computed // even if the value of `x1` is not given fn expr6() { let mut env = VariableEnvironment::new(); let x2 = env.slot().set(ndarray::arr0(0.)); env.run(|g| { let x1 = g.placeholder("x1", &[]); let x2 = g.variable(x2); let y = 3. * x1 * x1 + 5. * x2; let grad = T::grad(&[y], &[x2])[0]; assert_eq!(5., grad.eval(g).unwrap()[ndarray::IxDyn(&[])]); }); } #[test] fn differentiate_twice() { let ctx = ag::VariableEnvironment::::new(); ctx.run(|g| { let x = g.placeholder("x", &[]); let y = x * x; let g1 = T::grad(&[y], &[x])[0]; let g2 = T::grad(&[g1], &[x])[0]; assert_eq!(2., g2.eval(g).unwrap()[ndarray::IxDyn(&[])]); }); } #[test] fn expr7() { let ctx = ag::VariableEnvironment::new(); ctx.run(|g| { let x1 = g.placeholder("x1", &[]); let x2 = g.placeholder("x2", &[]); let y = 2. * x1 * x1 + 3. * x2; let g1 = T::grad(&[y], &[x1])[0]; let g2 = T::grad(&[y], &[x2])[0]; let gg1 = T::grad(&[g1], &[x1])[0]; assert_eq!(3., g2.eval(g).unwrap()[ndarray::IxDyn(&[])]); assert_eq!(4., gg1.eval(g).unwrap()[ndarray::IxDyn(&[])]); let eval = g .evaluator() .push(g1) .feed(x1, ndarray::arr0(2.).view()) .run(); assert_eq!(8., eval[0].as_ref().unwrap()[ndarray::IxDyn(&[])]); }); } #[test] fn expr8() { let env = ag::VariableEnvironment::new(); env.run(|graph| { let x1 = graph.placeholder("x1", &[]); let y = x1 * x1 * x1 * x1; let g = T::grad(&[y], &[x1])[0]; let gg = T::grad(&[g], &[x1])[0]; let ggg = T::grad(&[gg], &[x1])[0]; let eval = graph .evaluator() .push(ggg) .feed(x1, ndarray::arr0(2.).view()) .run(); assert_eq!(48., eval[0].as_ref().unwrap()[ndarray::IxDyn(&[])]); }); } #[test] fn scalar_tensor_add() { let mut env = ag::VariableEnvironment::new(); let v = env.slot().set(ndarray::arr0(1.)); let v2 = env.slot().set(ndarray::arr1(&[1., 2., 3.])); env.run(|graph| { let v = graph.variable(v); let v2 = graph.variable(v2); let a: ag::Tensor = v2 + v; let g = T::grad(&[a], &[v]); assert_eq!( (&g[0]).eval(graph).unwrap().shape(), v.eval(graph).unwrap().shape() ); ag::test_helper::check_theoretical_grads( a, g.as_slice(), &[v], ag::Feeder::new(), 1e-3, 1e-3, graph, ); }); } #[test] fn scalar_tensor_add2() { let mut env = ag::VariableEnvironment::new(); let v = env.slot().set(ndarray::arr0(1.)); let v2 = env.slot().set(ndarray::arr1(&[1., 2., 3.])); env.run(|graph| { let v = graph.variable(v); let v2 = graph.variable(v2); let a: ag::Tensor = v + v2; let g = T::grad(&[a], &[v]); assert_eq!( (&g[0]).eval(graph).unwrap().shape(), v.eval(graph).unwrap().shape() ); ag::test_helper::check_theoretical_grads( a, g.as_slice(), &[v], ag::Feeder::new(), 1e-3, 1e-3, graph, ); }); } #[test] fn scalar_tensor_sub() { let mut env = ag::VariableEnvironment::new(); let v = env.slot().set(ndarray::arr0(1.)); let v2 = env.slot().set(ndarray::arr1(&[1., 2., 3.])); env.run(|graph| { let v = graph.variable(v); let v2 = graph.variable(v2); let a: ag::Tensor = v2 - v; let g = T::grad(&[a], &[v]); assert_eq!( (&g[0]).eval(graph).unwrap().shape(), v.eval(graph).unwrap().shape() ); ag::test_helper::check_theoretical_grads( a, g.as_slice(), &[v], ag::Feeder::new(), 1e-3, 1e-3, graph, ); }); } #[test] fn scalar_tensor_sub2() { let mut env = ag::VariableEnvironment::new(); let v = env.slot().set(ndarray::arr0(1.)); let v2 = env.slot().set(ndarray::arr1(&[1., 2., 3.])); env.run(|graph| { let v = graph.variable(v); let v2 = graph.variable(v2); let a: ag::Tensor = v - v2; let g = T::grad(&[a], &[v]); assert_eq!( (&g[0]).eval(graph).unwrap().shape(), v.eval(graph).unwrap().shape() ); ag::test_helper::check_theoretical_grads( a, g.as_slice(), &[v], ag::Feeder::new(), 1e-3, 1e-3, graph, ); }); } #[test] fn scalar_tensor_mul() { let mut env = ag::VariableEnvironment::new(); let v = env.slot().set(ndarray::arr0(1.)); let v2 = env.slot().set(ndarray::arr1(&[1., 2., 3.])); env.run(|graph| { let v = graph.variable(v); let v2 = graph.variable(v2); let a: ag::Tensor = v2 * v; let g = T::grad(&[a], &[v]); assert_eq!( (&g[0]).eval(graph).unwrap().shape(), v.eval(graph).unwrap().shape() ); ag::test_helper::check_theoretical_grads( a, g.as_slice(), &[v], ag::Feeder::new(), 1e-3, 1e-3, graph, ); }); } #[test] fn scalar_tensor_mul2() { let mut env = ag::VariableEnvironment::new(); let v = env.slot().set(ndarray::arr0(1.)); let v2 = env.slot().set(ndarray::arr1(&[1., 2., 3.])); env.run(|graph| { let v = graph.variable(v); let v2 = graph.variable(v2); let a: ag::Tensor = v * v2; let g = T::grad(&[a], &[v]); assert_eq!( (&g[0]).eval(graph).unwrap().shape(), v.eval(graph).unwrap().shape() ); ag::test_helper::check_theoretical_grads( a, g.as_slice(), &[v], ag::Feeder::new(), 1e-3, 1e-3, graph, ); }); } #[test] fn scalar_tensor_div() { let mut env = ag::VariableEnvironment::new(); let v = env.slot().set(ndarray::arr0(1.)); let v2 = env.slot().set(ndarray::arr1(&[1., 2., 3.])); env.run(|graph| { let v = graph.variable(v); let v2 = graph.variable(v2); let a: ag::Tensor = v / v2; let g = T::grad(&[a], &[v]); assert_eq!( (&g[0]).eval(graph).unwrap().shape(), v.eval(graph).unwrap().shape() ); ag::test_helper::check_theoretical_grads( a, g.as_slice(), &[v], ag::Feeder::new(), 1e-3, 1e-3, graph, ); }); } #[test] fn scalar_tensor_div2() { let mut env = ag::VariableEnvironment::new(); let v = env.slot().set(ndarray::arr0(1.)); let v2 = env.slot().set(ndarray::arr1(&[1., 2., 3.])); env.run(|graph| { let v = graph.variable(v); let v2 = graph.variable(v2); let a: ag::Tensor = v2 / v; let g = T::grad(&[a], &[v]); assert_eq!( (&g[0]).eval(graph).unwrap().shape(), v.eval(graph).unwrap().shape() ); ag::test_helper::check_theoretical_grads( a, g.as_slice(), &[v], ag::Feeder::new(), 1e-3, 1e-3, graph, ); }); } #[test] fn scalar_tensor_mul_g3() { let mut env = ag::VariableEnvironment::new(); let three = env.slot().set(array![3., 3., 3.]); let v = env.slot().set(ag::ndarray_ext::from_scalar(2.)); env.run(|graph| { let v = graph.variable(v); let three = graph.variable(three); let y = three * v * v * v; let g = T::grad(&[y], &[v])[0]; let gg = T::grad(&[g], &[v])[0]; let ggg = T::grad(&[gg], &[v]); assert_eq!( (&ggg[0]).eval(graph).unwrap().shape(), v.eval(graph).unwrap().shape() ); ag::test_helper::check_theoretical_grads( gg, ggg.as_slice(), &[v], ag::Feeder::new(), 1e-3, 1e-3, graph, ); }); } #[test] fn scalar_tensor_div_g3() { let mut env = ag::VariableEnvironment::new(); let three = env.slot().set(array![3., 3., 3.]); let v = env.slot().set(ag::ndarray_ext::from_scalar(2.)); env.run(|graph| { let v = graph.variable(v); let three = graph.variable(three); let y = three / v / v / v; let g = T::grad(&[y], &[v])[0]; let gg = T::grad(&[g], &[v])[0]; let ggg = T::grad(&[gg], &[v]); assert_eq!( (&ggg[0]).eval(graph).unwrap().shape(), v.eval(graph).unwrap().shape() ); ag::test_helper::check_theoretical_grads( gg, ggg.as_slice(), &[v], ag::Feeder::new(), 1e-3, 1e-3, graph, ); }); }