fn quadratic_programming_interior_point() {
println!("=== Example 4: Quadratic Programming with Interior Point ===\n");
let n = 5;
let mut q_data = vec![0.0; n * n];
for i in 0..n {
for j in 0..n {
if i == j {
q_data[i * n + j] = 2.0 + (i as f32) * 0.5;
} else {
let val = ((i + j) as f32 * 0.3).sin() * 0.2;
q_data[i * n + j] = val;
}
}
}
let Q = Matrix::from_vec(n, n, q_data).expect("Valid Q matrix");
let c = Vector::from_slice(&[1.0, -0.5, 0.8, -0.3, 0.6]);
println!("Quadratic Programming Problem:");
println!("minimize ½xᵀQx + cᵀx");
println!("subject to:");
println!(" Σx_i ≤ 5 (budget constraint)");
println!(" x_i ≥ 0 (non-negativity)\n");
let objective = |x: &Vector<f32>| -> f32 {
let qx = Q.matvec(x).expect("Matrix-vector multiplication");
0.5 * x.dot(&qx) + c.dot(x)
};
let gradient = |x: &Vector<f32>| -> Vector<f32> {
let qx = Q.matvec(x).expect("Matrix-vector multiplication");
&qx + &c
};
let inequality = |x: &Vector<f32>| -> Vector<f32> {
let mut g = Vector::zeros(n + 1);
let mut sum = 0.0;
for i in 0..n {
sum += x[i];
}
g[0] = sum - 5.0;
for i in 0..n {
g[i + 1] = -x[i];
}
g
};
let inequality_jac = |_x: &Vector<f32>| -> Vec<Vector<f32>> {
let mut jac = Vec::with_capacity(n + 1);
jac.push(Vector::ones(n));
for i in 0..n {
let mut row = Vector::zeros(n);
row[i] = -1.0;
jac.push(row);
}
jac
};
let x0 = Vector::from_slice(&[0.5, 0.6, 0.7, 0.8, 0.9]);
let mut interior_point = InteriorPoint::new(100, 1e-5, 1.0);
println!("Running Interior Point Method for QP...\n");
let result = interior_point.minimize(objective, gradient, inequality, inequality_jac, x0);
println!("Convergence status: {:?}", result.status);
println!("Iterations: {}", result.iterations);
println!("Final objective: {:.6}", result.objective_value);
println!("Elapsed time: {:?}", result.elapsed_time);
println!("\nOptimal solution:");
for i in 0..n {
println!(" x[{}] = {:.6}", i, result.solution[i]);
}
let g_final = inequality(&result.solution);
let mut sum_x = 0.0;
for i in 0..n {
sum_x += result.solution[i];
}
println!("\nConstraint satisfaction:");
println!(" Σx_i = {sum_x:.6} (≤ 5.0)");
println!(" Budget slack: {:.6}", 5.0 - sum_x);
let mut min_x = f32::INFINITY;
for i in 0..n {
if result.solution[i] < min_x {
min_x = result.solution[i];
}
}
println!(" min(x_i) = {min_x:.6} (≥ 0)");
let active_budget = g_final[0].abs() < 0.1;
let mut active_bounds = 0;
for i in 1..=n {
if g_final[i].abs() < 0.1 {
active_bounds += 1;
}
}
println!("\nActive constraints:");
if active_budget {
println!(" Budget constraint is active (solution on boundary)");
} else {
println!(" Budget constraint is inactive (interior solution)");
}
println!(" {active_bounds} variables at lower bound (x_i = 0)");
println!();
}
#[allow(clippy::too_many_lines)]
fn method_comparison() {
println!("=== Example 5: Method Comparison - Box-Constrained Quadratic ===\n");
let n = 6;
let target = Vector::from_slice(&[1.5, -0.5, 0.3, 0.8, 1.2, -0.2]);
println!("Problem: minimize ½‖x - target‖²");
println!("subject to: 0 ≤ x ≤ 1 (box constraints)");
println!("Problem size: {n} variables\n");
println!(
"Target vector: [{:.2}, {:.2}, {:.2}, {:.2}, {:.2}, {:.2}]",
target[0], target[1], target[2], target[3], target[4], target[5]
);
println!("(Note: Some target values outside [0,1] box)\n");
let objective = |x: &Vector<f32>| -> f32 {
let diff = x - ⌖
0.5 * diff.dot(&diff)
};
let gradient = |x: &Vector<f32>| -> Vector<f32> { x - &target };
println!("--- Method 1: Projected Gradient Descent ---");
let project_box = |x: &Vector<f32>| -> Vector<f32> {
let mut x_proj = Vector::zeros(n);
for i in 0..n {
x_proj[i] = x[i].clamp(0.0, 1.0);
}
x_proj
};
let x0_pgd = Vector::from_slice(&[0.5; 6]);
let mut pgd = ProjectedGradientDescent::new(200, 0.1, 1e-6);
let result_pgd = pgd.minimize(|x| objective(x), |x| gradient(x), project_box, x0_pgd);
println!("Status: {:?}", result_pgd.status);
println!("Iterations: {}", result_pgd.iterations);
println!("Objective: {:.6}", result_pgd.objective_value);
println!("Time: {:?}", result_pgd.elapsed_time);
println!(
"Solution: [{:.3}, {:.3}, {:.3}, {:.3}, {:.3}, {:.3}]",
result_pgd.solution[0],
result_pgd.solution[1],
result_pgd.solution[2],
result_pgd.solution[3],
result_pgd.solution[4],
result_pgd.solution[5]
);
println!("\n--- Method 2: Augmented Lagrangian ---");
println!("(Equality reformulation: minimize f(x) s.t. x² - x + s = 0, 0 ≤ s ≤ 0.25)");
let equality_box = |x: &Vector<f32>| -> Vector<f32> {
let mut h = Vector::zeros(n);
for i in 0..n {
if x[i] < 0.0 {
h[i] = x[i]; } else if x[i] > 1.0 {
h[i] = x[i] - 1.0; }
}
h
};
let equality_jac_box = |_x: &Vector<f32>| -> Vec<Vector<f32>> {
let mut jac = Vec::with_capacity(n);
for i in 0..n {
let mut row = Vector::zeros(n);
row[i] = 1.0;
jac.push(row);
}
jac
};
let x0_al = Vector::from_slice(&[0.5; 6]);
let mut auglag = AugmentedLagrangian::new(50, 1e-5, 10.0);
let result_al = auglag.minimize_equality(
|x| objective(x),
|x| gradient(x),
equality_box,
equality_jac_box,
x0_al,
);
println!("Status: {:?}", result_al.status);
println!("Iterations: {}", result_al.iterations);
println!("Objective: {:.6}", result_al.objective_value);
println!("Time: {:?}", result_al.elapsed_time);
println!(
"Solution: [{:.3}, {:.3}, {:.3}, {:.3}, {:.3}, {:.3}]",
result_al.solution[0],
result_al.solution[1],
result_al.solution[2],
result_al.solution[3],
result_al.solution[4],
result_al.solution[5]
);
println!("\n--- Method 3: Interior Point Method ---");
let inequality_box = |x: &Vector<f32>| -> Vector<f32> {
let mut g = Vector::zeros(2 * n);
for i in 0..n {
g[i] = -x[i]; g[n + i] = x[i] - 1.0; }
g
};
let inequality_jac_box = |_x: &Vector<f32>| -> Vec<Vector<f32>> {
let mut jac = Vec::with_capacity(2 * n);
for i in 0..n {
let mut row_lower = Vector::zeros(n);
row_lower[i] = -1.0;
jac.push(row_lower);
}
for i in 0..n {
let mut row_upper = Vector::zeros(n);
row_upper[i] = 1.0;
jac.push(row_upper);
}
jac
};
let x0_ip = Vector::from_slice(&[0.5; 6]);
let mut interior_point = InteriorPoint::new(100, 1e-5, 0.1);
let result_ip = interior_point.minimize(
|x| objective(x),
|x| gradient(x),
inequality_box,
inequality_jac_box,
x0_ip,
);
println!("Status: {:?}", result_ip.status);
println!("Iterations: {}", result_ip.iterations);
println!("Objective: {:.6}", result_ip.objective_value);
println!("Time: {:?}", result_ip.elapsed_time);
println!(
"Solution: [{:.3}, {:.3}, {:.3}, {:.3}, {:.3}, {:.3}]",
result_ip.solution[0],
result_ip.solution[1],
result_ip.solution[2],
result_ip.solution[3],
result_ip.solution[4],
result_ip.solution[5]
);
println!("\n--- Comparison Summary ---");
println!(
"\n{:<25} {:>12} {:>12} {:>12}",
"Method", "Iterations", "Objective", "Time (μs)"
);
println!("{}", "─".repeat(65));
println!(
"{:<25} {:>12} {:>12.6} {:>12.0}",
"Projected GD",
result_pgd.iterations,
result_pgd.objective_value,
result_pgd.elapsed_time.as_micros()
);
println!(
"{:<25} {:>12} {:>12.6} {:>12.0}",
"Augmented Lagrangian",
result_al.iterations,
result_al.objective_value,
result_al.elapsed_time.as_micros()
);
println!(
"{:<25} {:>12} {:>12.6} {:>12.0}",
"Interior Point",
result_ip.iterations,
result_ip.objective_value,
result_ip.elapsed_time.as_micros()
);
println!("\nKey Insights:");
println!("• Projected GD: Simple projection, fast iterations, O(1/k) convergence");
println!(
"• Augmented Lagrangian: Handles general equality constraints, penalty parameter tuning"
);
println!("• Interior Point: Natural for inequalities, log-barrier guarantees feasibility");
println!("\nWhen to use each method:");
println!("• Projected GD: Simple convex constraints (box, simplex, ball), fast projection");
println!("• Augmented Lagrangian: Equality constraints, nonlinear constraints");
println!("• Interior Point: Inequality constraints, LP/QP, strict interior feasibility");
println!();
}
fn main() {
println!("\n╔═══════════════════════════════════════════════════════════════╗");
println!("║ Constrained Optimization Examples (Phase 3) ║");
println!("║ Projected GD + Augmented Lagrangian + Interior Point ║");
println!("╚═══════════════════════════════════════════════════════════════╝\n");
nonnegative_quadratic_pgd();
println!("{}", "═".repeat(70));
println!();
equality_constrained_least_squares();
println!("{}", "═".repeat(70));
println!();
linear_programming_interior_point();
println!("{}", "═".repeat(70));
println!();
quadratic_programming_interior_point();
println!("{}", "═".repeat(70));
println!();
method_comparison();
println!("╔═══════════════════════════════════════════════════════════════╗");
println!("║ All constrained optimization examples completed! ║");
println!("╚═══════════════════════════════════════════════════════════════╝\n");
}