#![allow(clippy::uninlined_format_args)]
#![allow(clippy::suboptimal_flops)]
#![allow(clippy::useless_vec)]
use std::collections::HashMap;
use quantrs2_symengine_pure::{
optimization::{gradient_at, hessian_at, ParameterShiftRule, VqeOptimizer},
Expression,
};
fn main() {
println!("=== VQE Gradient Computation Example ===\n");
example_symbolic_gradient();
example_parameter_shift();
example_vqe_optimization();
example_hessian_computation();
}
fn example_symbolic_gradient() {
println!("--- Example 1: Symbolic Gradient Computation ---\n");
let theta = Expression::symbol("theta");
let phi = Expression::symbol("phi");
let sin_theta = quantrs2_symengine_pure::ops::trig::sin(&theta);
let cos_phi = quantrs2_symengine_pure::ops::trig::cos(&phi);
let energy = sin_theta.clone() * sin_theta + cos_phi.clone() * cos_phi;
println!("Energy expression: E(θ, φ) = sin²(θ) + cos²(φ)");
let grad_theta = energy.diff(&theta);
let grad_phi = energy.diff(&phi);
println!("∂E/∂θ (symbolic): computed");
println!("∂E/∂φ (symbolic): computed");
let mut values = HashMap::new();
values.insert("theta".to_string(), std::f64::consts::FRAC_PI_4); values.insert("phi".to_string(), std::f64::consts::FRAC_PI_3);
let grad_theta_val = grad_theta.eval(&values);
let grad_phi_val = grad_phi.eval(&values);
println!("\nAt θ = π/4, φ = π/3:");
match grad_theta_val {
Ok(v) => println!(" ∂E/∂θ = {:.6}", v),
Err(e) => println!(" ∂E/∂θ error: {}", e),
}
match grad_phi_val {
Ok(v) => println!(" ∂E/∂φ = {:.6}", v),
Err(e) => println!(" ∂E/∂φ error: {}", e),
}
println!();
}
fn example_parameter_shift() {
println!("--- Example 2: Parameter-Shift Rule ---\n");
let psr = ParameterShiftRule::new();
let energy_fn = |params: &[f64]| -> f64 {
params[0].sin() * params[1].cos() + 0.5
};
let params = vec![0.5, 1.0];
println!("Energy function: E(θ₁, θ₂) = sin(θ₁)·cos(θ₂) + 0.5");
println!(
"Initial parameters: θ₁ = {:.4}, θ₂ = {:.4}",
params[0], params[1]
);
println!("Initial energy: E = {:.6}", energy_fn(¶ms));
let gradient = psr.compute_gradient(energy_fn, ¶ms);
println!("\nGradient (via parameter-shift):");
println!(" ∂E/∂θ₁ = {:.6}", gradient[0]);
println!(" ∂E/∂θ₂ = {:.6}", gradient[1]);
let analytical_grad = vec![
params[0].cos() * params[1].cos(),
-params[0].sin() * params[1].sin(),
];
println!("\nAnalytical gradient:");
println!(" ∂E/∂θ₁ = {:.6}", analytical_grad[0]);
println!(" ∂E/∂θ₂ = {:.6}", analytical_grad[1]);
println!("\nDifference (should be ~0):");
println!(
" Δ(∂E/∂θ₁) = {:.2e}",
(gradient[0] - analytical_grad[0]).abs()
);
println!(
" Δ(∂E/∂θ₂) = {:.2e}",
(gradient[1] - analytical_grad[1]).abs()
);
println!();
}
fn example_vqe_optimization() {
println!("--- Example 3: VQE Optimization Step ---\n");
let theta = Expression::symbol("theta");
let one = Expression::one();
let diff = theta.clone() - one;
let energy = diff.clone() * diff;
let params = vec![theta];
let learning_rate = 0.1;
let optimizer = VqeOptimizer::new(energy, params, learning_rate);
let mut values = HashMap::new();
values.insert("theta".to_string(), 0.0);
println!("Energy: E(θ) = (θ - 1)²");
println!("Learning rate: {}", learning_rate);
println!("Initial θ = 0.0");
let mut theta_val = 0.0;
println!("\nOptimization steps:");
for step in 0..10 {
values.insert("theta".to_string(), theta_val);
let grad = optimizer.compute_gradient(&values);
match grad {
Ok(g) => {
let energy_val = (theta_val - 1.0).powi(2);
println!(
" Step {}: θ = {:.6}, E = {:.6}, ∂E/∂θ = {:.6}",
step, theta_val, energy_val, g[0]
);
theta_val -= learning_rate * g[0];
}
Err(e) => {
println!(" Step {}: gradient error: {}", step, e);
break;
}
}
}
println!("\nFinal θ = {:.6} (optimal = 1.0)", theta_val);
println!();
}
fn example_hessian_computation() {
println!("--- Example 4: Hessian Computation ---\n");
let x = Expression::symbol("x");
let y = Expression::symbol("y");
let two = Expression::int(2);
let three = Expression::int(3);
let f = x.clone() * x.clone() + two * x.clone() * y.clone() + three * y.clone() * y.clone();
println!("Function: f(x, y) = x² + 2xy + 3y²");
let params = [x, y];
let mut values = HashMap::new();
values.insert("x".to_string(), 1.0);
values.insert("y".to_string(), 2.0);
let grad = gradient_at(&f, ¶ms, &values);
match &grad {
Ok(g) => {
println!("\nAt (x, y) = (1, 2):");
println!(" ∇f = [{:.4}, {:.4}]", g[0], g[1]);
}
Err(e) => println!("Gradient error: {}", e),
}
let hess = hessian_at(&f, ¶ms, &values);
match hess {
Ok(h) => {
println!("\n Hessian H = ");
println!(" [{:.4}, {:.4}]", h[0][0], h[0][1]);
println!(" [{:.4}, {:.4}]", h[1][0], h[1][1]);
}
Err(e) => println!("Hessian error: {}", e),
}
println!("\nAnalytical Hessian (for comparison):");
println!(" [2.0000, 2.0000]");
println!(" [2.0000, 6.0000]");
println!();
}