#[cfg(test)]
mod circuit_tests {
use crate::Circuit;
use std::sync::Arc;
const DEBUG: bool = true;
#[test]
fn test_evaluate_function() {
let mut circuit = Circuit::new();
let x = circuit.init();
let x_squared = circuit.mul(x, x);
let five = circuit.constant(5);
let x_squared_plus_5 = circuit.add(x_squared, five);
circuit.add(x_squared_plus_5, x);
assert!(circuit.evaluate(&[3], DEBUG).is_ok());
assert!(circuit.check_constraints().is_ok());
}
#[test]
fn test_division_hint() {
let mut circuit = Circuit::new();
let a = circuit.init();
let one = circuit.constant(1);
let b = circuit.add(a, one);
let c = circuit.hint(
b,
Arc::new(|x: u32| x / 8) as Arc<dyn Fn(u32) -> u32 + Send + Sync>,
);
let eight = circuit.constant(8);
let c_times_8 = circuit.mul(c, eight);
circuit.assert_equal(b, c_times_8);
assert!(circuit.evaluate(&[7], DEBUG).is_ok());
assert!(circuit.check_constraints().is_ok());
}
#[test]
fn test_sqrt_hint() {
let mut circuit = Circuit::new();
let x = circuit.init();
let seven = circuit.constant(7);
let x_plus_seven = circuit.add(x, seven);
let sqrt_x_plus_seven = circuit.hint(
x_plus_seven,
Arc::new(|x: u32| (x as f32).sqrt().round() as u32)
as Arc<dyn Fn(u32) -> u32 + Send + Sync>,
);
let computed_sq = circuit.mul(sqrt_x_plus_seven, sqrt_x_plus_seven);
circuit.assert_equal(computed_sq, x_plus_seven);
assert!(circuit.evaluate(&[2], DEBUG).is_ok());
assert!(circuit.check_constraints().is_ok());
}
#[test]
fn test_layerize() {
let mut circuit = Circuit::new();
let x = circuit.init(); let y = circuit.init(); let z = circuit.init(); let w = circuit.init();
let sum_xy = circuit.add(x, y); let product_xyz = circuit.mul(sum_xy, z); let total = circuit.add(product_xyz, w);
let input_vals = vec![1, 2, 3, 4];
assert!(circuit.evaluate(&input_vals, DEBUG).is_ok());
println!("The result of the circuit is: {}", circuit.results[total]);
if let Some(layers) = &circuit.layers {
println!("Layers of the circuit:");
for (i, layer) in layers.iter().enumerate() {
println!("Layer {}: {:?}", i, layer);
}
}
}
#[test]
fn test_random_circuits() {
let mut circuit = Circuit::new();
let num_gates = 10000000;
circuit.generate_random(num_gates);
let inputs = vec![42; 10];
assert!(circuit.evaluate(&inputs, DEBUG).is_ok());
assert!(circuit.check_constraints().is_ok());
println!(
"Sample of evaluation results: {:?}",
&circuit.results[..std::cmp::min(10, circuit.results.len())]
);
}
#[test]
fn test_circuit_initialization() {
let circuit = Circuit::new();
assert!(circuit.nodes.is_empty());
assert!(circuit.equalities.is_empty());
assert!(circuit.layers.is_none());
assert!(circuit.results.is_empty());
}
#[test]
fn test_adding_gates() {
let mut circuit = Circuit::new();
let idx1 = circuit.init(); let idx2 = circuit.constant(10); let add_idx = circuit.add(idx1, idx2); assert_eq!(add_idx, 2);
assert_eq!(circuit.nodes.len(), 3);
}
#[test]
fn test_evaluate_simple_circuit() {
let mut circuit = Circuit::new();
let idx1 = circuit.init();
let idx2 = circuit.constant(20);
let add_idx = circuit.add(idx1, idx2);
assert!(circuit.evaluate(&[10], DEBUG).is_ok());
assert_eq!(circuit.results[add_idx], 30);
}
#[test]
fn test_check_constraints() {
let mut circuit = Circuit::new();
let idx1 = circuit.constant(10);
let idx2 = circuit.constant(10);
circuit.assert_equal(idx1, idx2);
assert!(circuit.evaluate(&[], DEBUG).is_ok());
assert!(circuit.check_constraints().is_ok());
}
#[test]
fn test_empty_circuit_eval_is_error() {
assert!(Circuit::new().evaluate(&[], DEBUG).is_err());
}
#[test]
#[allow(clippy::out_of_bounds_indexing)]
fn test_hint_panic() {
let mut circuit = Circuit::new();
let one = circuit.init();
let small_array = [3_u32, 7, 9]; let _c = circuit.hint(
one,
Arc::new(move |_| small_array[10]) as Arc<dyn Fn(u32) -> u32 + Send + Sync>,
);
assert!(circuit.evaluate(&[0], DEBUG).is_err());
}
#[test]
fn test_saturating_addition() {
let mut circuit = Circuit::new();
let max_value = circuit.constant(u32::MAX);
let one = circuit.constant(1);
let result_idx = circuit.add(max_value, one);
circuit
.evaluate(&[], DEBUG)
.expect("Evaluation should not fail, it should saturate");
assert_eq!(
circuit.results[result_idx],
u32::MAX,
"Addition should saturate at u32::MAX"
);
}
#[test]
fn test_saturating_multiplication() {
let mut circuit = Circuit::new();
let large_value = circuit.constant(u32::MAX / 2 + 1);
let two = circuit.constant(2);
let result_idx = circuit.mul(large_value, two);
circuit
.evaluate(&[], DEBUG)
.expect("Evaluation should not fail, it should saturate");
assert_eq!(
circuit.results[result_idx],
u32::MAX,
"Multiplication should saturate at u32::MAX"
);
}
#[test]
fn test_division_with_large_denominator() {
let mut circuit = Circuit::new();
let numerator = circuit.constant(1);
let result_idx = circuit.hint(
numerator,
Arc::new(|num: u32| num / 1000) as Arc<dyn Fn(u32) -> u32 + Send + Sync>,
);
circuit
.evaluate(&[], DEBUG)
.expect("Evaluation should handle division properly");
assert_eq!(
circuit.results[result_idx], 0,
"Division of a smaller number by a larger should result in 0"
);
}
}