#[cfg(test)]
mod examples {
use crate::symbolic::codegen::CodegenIR::{CodegenLanguage, CodegenModule};
use crate::symbolic::symbolic_engine::Expr;
use std::fs;
use tempfile::tempdir;
#[test]
fn example_simple_quadratic() {
let x = Expr::Var("x".to_string());
let expr =
x.clone().pow(Expr::Const(2.0)) + Expr::Const(2.0) * x.clone() + Expr::Const(1.0);
let module = CodegenModule::new("quadratic")
.with_language(CodegenLanguage::C)
.add_function("evaluate_quadratic", &expr, &["x"]);
let c_source = module.emit_source();
let c_header = module.emit_c_header();
println!("=== C Header ===");
println!("{}", c_header);
println!("\n=== C Source ===");
println!("{}", c_source);
assert!(c_source.contains("double evaluate_quadratic(const double* inputs)"));
assert!(c_source.contains("pow("));
assert!(c_header.contains("double evaluate_quadratic(const double* inputs);"));
}
#[test]
fn example_residual_system() {
let x = Expr::Var("x".to_string());
let y = Expr::Var("y".to_string());
let residuals = vec![
x.clone().pow(Expr::Const(2.0)) + y.clone().pow(Expr::Const(2.0)) - Expr::Const(10.0),
x.clone() - y.clone() - Expr::Const(4.0),
];
let module = CodegenModule::new("nonlinear_system")
.with_language(CodegenLanguage::C)
.add_block("compute_residuals", &residuals, &["x", "y"]);
let c_source = module.emit_source();
let c_header = module.emit_c_header();
println!("=== Nonlinear System C Code ===");
println!("{}", c_source);
assert!(c_source.contains("void compute_residuals(const double* inputs, double* outputs)"));
assert!(c_source.contains("outputs[0] = "));
assert!(c_source.contains("outputs[1] = "));
}
#[test]
fn example_trigonometric_functions() {
let theta = Expr::Var("theta".to_string());
let trig_exprs = vec![
Expr::sin(Box::new(theta.clone())),
Expr::cos(Box::new(theta.clone())),
Expr::tg(Box::new(theta.clone())),
Expr::sin(Box::new(theta.clone())).pow(Expr::Const(2.0))
+ Expr::cos(Box::new(theta.clone())).pow(Expr::Const(2.0)), ];
let module = CodegenModule::new("trigonometry")
.with_language(CodegenLanguage::C)
.add_block("trig_functions", &trig_exprs, &["theta"]);
let c_source = module.emit_source();
println!("=== Trigonometric Functions C Code ===");
println!("{}", c_source);
assert!(c_source.contains("sin("));
assert!(c_source.contains("cos("));
assert!(c_source.contains("tan("));
}
#[test]
fn example_exp_log_functions() {
let x = Expr::Var("x".to_string());
let exprs = vec![
Expr::Exp(Box::new(x.clone())),
Expr::Ln(Box::new(x.clone())),
Expr::Exp(Box::new(Expr::Ln(Box::new(x.clone())))), x.clone().pow(Expr::Const(2.0)),
];
let module = CodegenModule::new("exp_log")
.with_language(CodegenLanguage::C)
.add_block("exp_log_functions", &exprs, &["x"]);
let c_source = module.emit_source();
println!("=== Exponential and Logarithmic Functions C Code ===");
println!("{}", c_source);
assert!(c_source.contains("exp("));
assert!(c_source.contains("log("));
assert!(!c_source.contains("ln("));
}
#[test]
fn example_rust_vs_c_comparison() {
let x = Expr::Var("x".to_string());
let y = Expr::Var("y".to_string());
let expr = (x.clone().pow(Expr::Const(2.0)) + y.clone().pow(Expr::Const(2.0)))
.pow(Expr::Const(0.5));
let rust_module = CodegenModule::new("distance")
.with_language(CodegenLanguage::Rust)
.add_function("euclidean_distance", &expr, &["x", "y"]);
let c_module = CodegenModule::new("distance")
.with_language(CodegenLanguage::C)
.add_function("euclidean_distance", &expr, &["x", "y"]);
let rust_source = rust_module.emit_source();
let c_source = c_module.emit_source();
println!("=== Rust Version ===");
println!("{}", rust_source);
println!("\n=== C Version ===");
println!("{}", c_source);
assert!(rust_source.contains("euclidean_distance"));
assert!(c_source.contains("euclidean_distance"));
}
#[test]
fn example_write_to_files() {
let x = Expr::Var("x".to_string());
let y = Expr::Var("y".to_string());
let exprs = vec![
x.clone() + y.clone(),
x.clone() * y.clone(),
x.clone() - y.clone(),
x.clone() / y.clone(),
];
let module = CodegenModule::new("arithmetic")
.with_language(CodegenLanguage::C)
.add_block("basic_operations", &exprs, &["x", "y"]);
let dir = tempdir().expect("Failed to create temp directory");
let header_path = dir.path().join("arithmetic.h");
let source_path = dir.path().join("arithmetic.c");
fs::write(&header_path, module.emit_c_header()).expect("Failed to write header file");
fs::write(&source_path, module.emit_source()).expect("Failed to write source file");
assert!(header_path.exists());
assert!(source_path.exists());
let header_content = fs::read_to_string(&header_path).unwrap();
let source_content = fs::read_to_string(&source_path).unwrap();
println!("=== Generated arithmetic.h ===");
println!("{}", header_content);
println!("\n=== Generated arithmetic.c ===");
println!("{}", source_content);
assert!(header_content.contains("#ifndef GENERATED_FUNCTIONS_H"));
assert!(source_content.contains("#include <math.h>"));
}
#[test]
fn example_optimized_expression() {
let x = Expr::Var("x".to_string());
let expr = (x.clone() + Expr::Const(0.0)) * Expr::Const(1.0)
+ x.clone().pow(Expr::Const(1.0))
+ Expr::Const(0.0);
let ir = expr.lower_to_linear(&["x"]);
let optimized_ir = ir.peephole_optimize();
println!("Original IR instructions: {}", ir.instructions.len());
println!(
"Optimized IR instructions: {}",
optimized_ir.instructions.len()
);
let module = CodegenModule::new("optimized")
.with_language(CodegenLanguage::C)
.add_function("optimized_func", &expr, &["x"]);
let c_source = module.emit_source();
println!("=== Optimized C Code ===");
println!("{}", c_source);
assert!(optimized_ir.instructions.len() < ir.instructions.len());
}
#[test]
fn example_jacobian_structure() {
let x = Expr::Var("x".to_string());
let y = Expr::Var("y".to_string());
let f = x.clone().pow(Expr::Const(2.0)) + y.clone().pow(Expr::Const(2.0));
let df_dx = f.diff("x");
let df_dy = f.diff("y");
let jacobian_entries = vec![df_dx, df_dy];
let module = CodegenModule::new("jacobian")
.with_language(CodegenLanguage::C)
.add_block("compute_gradient", &jacobian_entries, &["x", "y"]);
let c_source = module.emit_source();
println!("=== Jacobian/Gradient C Code ===");
println!("{}", c_source);
assert!(c_source.contains("void compute_gradient"));
}
#[test]
fn example_multiple_functions_module() {
let x = Expr::Var("x".to_string());
let square = x.clone().pow(Expr::Const(2.0));
let cube = x.clone().pow(Expr::Const(3.0));
let sqrt = x.clone().pow(Expr::Const(0.5));
let module = CodegenModule::new("powers")
.with_language(CodegenLanguage::C)
.add_function("square", &square, &["x"])
.add_function("cube", &cube, &["x"])
.add_function("sqrt_func", &sqrt, &["x"]);
let c_source = module.emit_source();
let c_header = module.emit_c_header();
println!("=== Multiple Functions Module ===");
println!("{}", c_source);
assert!(c_source.contains("double square"));
assert!(c_source.contains("double cube"));
assert!(c_source.contains("double sqrt_func"));
assert!(c_header.contains("double square(const double* inputs);"));
assert!(c_header.contains("double cube(const double* inputs);"));
assert!(c_header.contains("double sqrt_func(const double* inputs);"));
}
#[test]
fn example_verify_numerical_correctness() {
let x = Expr::Var("x".to_string());
let y = Expr::Var("y".to_string());
let expr = (x.clone() + y.clone()).pow(Expr::Const(2.0))
+ Expr::sin(Box::new(x.clone() * y.clone()));
let symbolic_func = expr.lambdify1(&["x", "y"]);
let args = [1.5, 2.5];
let symbolic_result = symbolic_func(&args);
let ir = expr.lower_to_linear(&["x", "y"]);
let ir_result = ir.eval(&args);
println!("Symbolic result: {}", symbolic_result);
println!("IR result: {}", ir_result);
println!("Difference: {}", (symbolic_result - ir_result).abs());
assert!((symbolic_result - ir_result).abs() < 1e-12);
let module = CodegenModule::new("verified")
.with_language(CodegenLanguage::C)
.add_function("verified_func", &expr, &["x", "y"]);
let c_source = module.emit_source();
println!("\n=== Generated C Code (numerically verified) ===");
println!("{}", c_source);
}
}