#![cfg(feature = "bytecode")]
use echidna::{record_multi, BReverse, BytecodeTape};
#[test]
fn m37_hessian_empty_input_returns_constant_value() {
let mut tape = BytecodeTape::<f64>::with_capacity(4);
let idx = tape.push_const(3.5);
tape.set_output(idx);
tape.set_outputs(&[idx]);
let (value, gradient, hessian) = tape.hessian(&[]);
assert!((value - 3.5).abs() < 1e-15, "value = {}", value);
assert_eq!(gradient.len(), 0);
assert_eq!(hessian.len(), 0);
}
#[test]
fn m37_hessian_vec_empty_input_returns_constant_value() {
let mut tape = BytecodeTape::<f64>::with_capacity(4);
let idx = tape.push_const(2.75);
tape.set_output(idx);
tape.set_outputs(&[idx]);
let (value, gradient, hessian) = tape.hessian_vec::<4>(&[]);
assert!((value - 2.75).abs() < 1e-15, "value = {}", value);
assert_eq!(gradient.len(), 0);
assert_eq!(hessian.len(), 0);
}
#[test]
fn m37_sparse_hessian_empty_input_returns_constant_value() {
let mut tape = BytecodeTape::<f64>::with_capacity(4);
let idx = tape.push_const(1.25);
tape.set_output(idx);
tape.set_outputs(&[idx]);
let (value, gradient, _pattern, hess_vals) = tape.sparse_hessian(&[]);
assert!(
(value - 1.25).abs() < 1e-15,
"sparse_hessian value = {}",
value
);
assert_eq!(gradient.len(), 0);
assert_eq!(hess_vals.len(), 0);
}
#[test]
fn m37_sparse_hessian_vec_empty_input_returns_constant_value() {
let mut tape = BytecodeTape::<f64>::with_capacity(4);
let idx = tape.push_const(4.125);
tape.set_output(idx);
tape.set_outputs(&[idx]);
let (value, gradient, _pattern, hess_vals) = tape.sparse_hessian_vec::<4>(&[]);
assert!(
(value - 4.125).abs() < 1e-15,
"sparse_hessian_vec value = {}",
value
);
assert_eq!(gradient.len(), 0);
assert_eq!(hess_vals.len(), 0);
}
#[test]
#[should_panic(expected = "record_multi: closure returned zero outputs")]
fn m38_record_multi_rejects_empty_outputs() {
let f = |_inputs: &[BReverse<f64>]| -> Vec<BReverse<f64>> { Vec::new() };
let _ = record_multi(f, &[1.0, 2.0]);
}
#[cfg(feature = "diffop")]
#[test]
#[should_panic(expected = "mixed_partial: orders.len() must equal tape.num_inputs()")]
fn m45_mixed_partial_rejects_wrong_orders_length() {
use echidna::record;
let f = |inputs: &[BReverse<f64>]| -> BReverse<f64> { inputs[0] * inputs[0] + inputs[1] };
let (tape, _) = record(f, &[1.0, 2.0]);
let _ = echidna::diffop::mixed_partial(&tape, &[1.0, 2.0], &[1]);
}
#[cfg(feature = "diffop")]
#[test]
fn m46_extraction_prefactor_small_order_exact() {
use echidna::record;
let f = |inputs: &[BReverse<f64>]| -> BReverse<f64> { inputs[0] * inputs[0] * inputs[0] };
let (tape, _) = record(f, &[1.0]);
let (value, deriv) = echidna::diffop::mixed_partial(&tape, &[1.0], &[3]);
assert!((value - 1.0).abs() < 1e-15);
assert!((deriv - 6.0).abs() < 1e-12, "deriv = {}", deriv);
}