use rustorch::autograd::{
detect_anomaly, grad, gradcheck, gradcheck_simple, hessian, hvp, jacobian, no_grad,
GradCheckConfig, Variable,
};
use rustorch::error::RusTorchError;
use rustorch::tensor::Tensor;
#[test]
fn test_grad_integration() {
let x = Variable::new(Tensor::from_vec(vec![2.0f32], vec![1]), true);
let y = Variable::new(Tensor::from_vec(vec![3.0f32], vec![1]), true);
let z1 = &x * &x;
let z2 = &y * &y;
let output = &z1 + &z2;
let gradients = grad(&[output], &[x.clone(), y.clone()], None, false, false).unwrap();
assert!(gradients[0].is_some());
assert!(gradients[1].is_some());
let grad_x = gradients[0].as_ref().unwrap().as_array()[0];
let grad_y = gradients[1].as_ref().unwrap().as_array()[0];
assert!((grad_x - 4.0).abs() < 1e-6); assert!((grad_y - 6.0).abs() < 1e-6); }
#[test]
fn test_jacobian_integration() {
let input = Variable::new(Tensor::from_vec(vec![2.0f32], vec![1]), true);
let jacobian_result = jacobian(|x| x * x, &input, false).unwrap();
let jac_data = jacobian_result.as_array().as_slice().unwrap();
assert!((jac_data[0] - 4.0).abs() < 1e-6);
}
#[test]
fn test_hessian_integration() {
let input = Variable::new(Tensor::from_vec(vec![3.0f32], vec![1]), true);
let hessian_result = hessian(|x| x * x, &input).unwrap();
let hessian_val = hessian_result.as_array().as_slice().unwrap()[0];
assert!((hessian_val - 2.0).abs() < 1e-1); }
#[test]
fn test_hvp_integration() {
let input = Variable::new(Tensor::from_vec(vec![2.0f32], vec![1]), true);
let v = Variable::new(Tensor::from_vec(vec![1.0f32], vec![1]), false);
let hvp_result = hvp(|x| x * x, &input, &v).unwrap();
let hvp_data_guard = hvp_result.data();
let hvp_data = hvp_data_guard.read().unwrap();
let hvp_val = hvp_data.as_array().as_slice().unwrap()[0];
assert!((hvp_val - 2.0).abs() < 1e-1); }
#[test]
fn test_gradcheck_integration() {
let input = Variable::new(Tensor::from_vec(vec![1.5f32], vec![1]), true);
let config = GradCheckConfig {
eps: 1e-4f32,
atol: 1e-2f32,
rtol: 1e-1f32,
nondet_tol: 0.0f32,
check_sparse_nnz: true,
};
let result = gradcheck(
|inputs| {
let x = &inputs[0];
x * x
},
&[input],
Some(config),
)
.unwrap();
assert!(
result.passed,
"Gradient check failed: {:?}",
result.error_details
);
assert!(result.max_error < 0.1); }
#[test]
fn test_gradcheck_simple_integration() {
let input = Variable::new(Tensor::from_vec(vec![2.5f32], vec![1]), true);
let passed = gradcheck_simple(
|inputs| {
let x = &inputs[0];
x * x
},
&[input],
);
assert!(passed);
}
#[test]
fn test_context_managers_integration() {
assert!(rustorch::autograd::is_grad_enabled());
let result = no_grad(|| {
assert!(!rustorch::autograd::is_grad_enabled());
let x = Variable::new(Tensor::from_vec(vec![1.0f32], vec![1]), true);
let y = &x * &x;
y.backward();
let grad_guard = x.grad();
let grad = grad_guard.read().unwrap();
grad.is_none()
});
assert!(result);
assert!(rustorch::autograd::is_grad_enabled());
let anomaly_result = detect_anomaly(|| {
assert!(rustorch::autograd::is_anomaly_detection_enabled());
"anomaly detection active"
});
assert_eq!(anomaly_result, "anomaly detection active");
assert!(!rustorch::autograd::is_anomaly_detection_enabled()); }
#[test]
fn test_performance_benchmark() {
use std::time::Instant;
let input = Variable::new(Tensor::from_vec(vec![1.0f32; 100], vec![100]), true);
let start = Instant::now();
for _ in 0..10 {
let sum_var = input.sum();
sum_var.backward();
input.zero_grad();
}
let duration = start.elapsed();
assert!(
duration.as_millis() < 1000,
"Performance too slow: {:?}",
duration
);
}
#[test]
fn test_error_handling_integration() {
let x = Variable::new(Tensor::from_vec(vec![1.0f32, 2.0f32], vec![2]), true);
let result = gradcheck(
|inputs| {
let input = &inputs[0];
input.clone() },
&[x],
None,
);
assert!(result.is_err());
match result.unwrap_err() {
RusTorchError::InvalidParameters { operation, message } => {
assert_eq!(operation, "gradcheck");
assert!(message.contains("scalar"));
}
_ => panic!("Expected InvalidParameters error"),
}
}
#[test]
fn test_complex_computation_graph() {
let x = Variable::new(Tensor::from_vec(vec![2.0f32], vec![1]), true);
let y = Variable::new(Tensor::from_vec(vec![3.0f32], vec![1]), true);
let x_squared = &x * &x;
let y_squared = &y * &y;
let result = &x_squared + &y_squared;
let gradients = grad(&[result], &[x.clone(), y.clone()], None, false, false).unwrap();
assert!(gradients[0].is_some());
assert!(gradients[1].is_some());
let grad_x = gradients[0].as_ref().unwrap().as_array()[0];
let grad_y = gradients[1].as_ref().unwrap().as_array()[0];
assert!((grad_x - 4.0).abs() < 1e-6); assert!((grad_y - 6.0).abs() < 1e-6); }