#![cfg(feature = "bytecode")]
use echidna::BytecodeTape;
#[test]
#[should_panic(expected = "set_outputs: indices[")]
fn l26_set_outputs_panics_on_out_of_bounds() {
let mut tape = BytecodeTape::<f64>::with_capacity(4);
let _ = tape.new_input(1.0); tape.set_outputs(&[5]); }
#[test]
fn l26_set_outputs_accepts_duplicate_indices() {
let mut tape = BytecodeTape::<f64>::with_capacity(4);
let idx = tape.new_input(1.0);
tape.set_outputs(&[idx, idx]);
assert_eq!(tape.num_outputs(), 2);
}
#[cfg(feature = "stde")]
#[test]
fn l36_hessian_diagonal_empty_input_returns_constant() {
use echidna::stde::hessian_diagonal;
let mut tape = BytecodeTape::<f64>::with_capacity(4);
let idx = tape.push_const(7.25);
tape.set_output(idx);
tape.set_outputs(&[idx]);
let (value, diag) = hessian_diagonal(&tape, &[]);
assert!((value - 7.25).abs() < 1e-15, "value = {}", value);
assert_eq!(diag.len(), 0);
}
#[cfg(feature = "ndarray")]
#[test]
fn l37_ndarray_wrappers_accept_owned_arrays() {
use echidna::ndarray_support::grad_ndarray;
use echidna::BReverse;
use ndarray::Array1;
let x: Array1<f64> = Array1::from_vec(vec![1.0, 5.0, 3.0]);
let f = |v: &[BReverse<f64>]| -> BReverse<f64> { v[0] * v[0] + v[1] + v[2] * v[2] * v[2] };
let g = grad_ndarray(f, &x);
assert!((g[0] - 2.0).abs() < 1e-12, "∂f/∂a at a=1 → 2, got {}", g[0]);
assert!((g[1] - 1.0).abs() < 1e-12, "∂f/∂b → 1, got {}", g[1]);
assert!(
(g[2] - 27.0).abs() < 1e-12,
"∂f/∂c at c=3 → 27, got {}",
g[2]
);
}
#[cfg(feature = "diffop")]
#[test]
fn l38_mixed_partial_still_returns_correct_value() {
use echidna::diffop::mixed_partial;
use echidna::{record, BReverse};
let f = |v: &[BReverse<f64>]| -> BReverse<f64> { v[0] * v[0] + v[0] };
let (tape, _) = record(f, &[2.0]);
let (value, _d) = mixed_partial(&tape, &[2.0], &[1]);
assert!(
(value - 6.0).abs() < 1e-12,
"value (= f(2) = 6) should not be affected by the placeholder change, got {}",
value
);
}
#[cfg(feature = "ndarray")]
#[test]
fn l39_sparse_jacobian_ndarray_returns_outputs() {
use echidna::ndarray_support::sparse_jacobian_ndarray;
use echidna::BReverse;
use ndarray::Array1;
let f = |v: &[BReverse<f64>]| -> Vec<BReverse<f64>> { vec![v[0], v[1], v[0] + v[1]] };
let x = Array1::from_vec(vec![3.0, 5.0]);
let (outputs, _pattern, _values) = sparse_jacobian_ndarray(f, &x);
assert_eq!(outputs.len(), 3);
assert!((outputs[0] - 3.0).abs() < 1e-12);
assert!((outputs[1] - 5.0).abs() < 1e-12);
assert!((outputs[2] - 8.0).abs() < 1e-12);
}
#[cfg(feature = "diffop")]
#[test]
fn l40_mixed_partial_all_zero_orders_returns_value() {
use echidna::diffop::mixed_partial;
use echidna::{record, BReverse};
let f = |v: &[BReverse<f64>]| -> BReverse<f64> { v[0] * v[0] * v[0] };
let (tape, _) = record(f, &[2.0]);
let (value, deriv) = mixed_partial(&tape, &[2.0], &[0]);
assert!(
(value - 8.0).abs() < 1e-12,
"value = f(2) = 8, got {}",
value
);
assert!(
(deriv - 8.0).abs() < 1e-12,
"all-zero orders → deriv = f(x) = 8, got {}",
deriv
);
}