|
| 1 | +// # Knapsack to QUBO Reduction |
| 2 | +// |
| 3 | +// ## Reduction Overview |
| 4 | +// The 0-1 Knapsack capacity constraint sum(w_i * x_i) <= C is converted to equality |
| 5 | +// using B = floor(log2(C)) + 1 binary slack variables. The QUBO objective combines |
| 6 | +// -sum(v_i * x_i) with penalty P * (sum(w_i * x_i) + sum(2^j * s_j) - C)^2 where P > sum(v_i). |
| 7 | +// |
| 8 | +// ## This Example |
| 9 | +// - 4 items: weights=[2,3,4,5], values=[3,4,5,7], capacity=7 |
| 10 | +// - QUBO: 7 variables (4 items + 3 slack bits) |
| 11 | +// - Optimal: items {0,3} (weight=7, value=10) |
| 12 | +// |
| 13 | +// ## Output |
| 14 | +// Exports `docs/paper/examples/knapsack_to_qubo.json` and `knapsack_to_qubo.result.json`. |
| 15 | + |
| 16 | +use problemreductions::export::*; |
| 17 | +use problemreductions::prelude::*; |
| 18 | + |
| 19 | +pub fn run() { |
| 20 | + // Source: Knapsack with 4 items, capacity 7 |
| 21 | + let knapsack = Knapsack::new(vec![2, 3, 4, 5], vec![3, 4, 5, 7], 7); |
| 22 | + |
| 23 | + let reduction = ReduceTo::<QUBO<f64>>::reduce_to(&knapsack); |
| 24 | + let qubo = reduction.target_problem(); |
| 25 | + |
| 26 | + println!("\n=== Problem Transformation ==="); |
| 27 | + println!( |
| 28 | + "Source: Knapsack with {} items, capacity {}", |
| 29 | + knapsack.num_items(), |
| 30 | + knapsack.capacity() |
| 31 | + ); |
| 32 | + println!("Target: QUBO with {} variables", qubo.num_vars()); |
| 33 | + |
| 34 | + let solver = BruteForce::new(); |
| 35 | + let qubo_solutions = solver.find_all_best(qubo); |
| 36 | + println!("\n=== Solution ==="); |
| 37 | + println!("Target solutions found: {}", qubo_solutions.len()); |
| 38 | + |
| 39 | + let mut solutions = Vec::new(); |
| 40 | + for target_sol in &qubo_solutions { |
| 41 | + let source_sol = reduction.extract_solution(target_sol); |
| 42 | + let eval = knapsack.evaluate(&source_sol); |
| 43 | + assert!(eval.is_valid()); |
| 44 | + solutions.push(SolutionPair { |
| 45 | + source_config: source_sol.clone(), |
| 46 | + target_config: target_sol.clone(), |
| 47 | + }); |
| 48 | + } |
| 49 | + |
| 50 | + let source_sol = reduction.extract_solution(&qubo_solutions[0]); |
| 51 | + println!("Source solution: {:?}", source_sol); |
| 52 | + println!("Source value: {:?}", knapsack.evaluate(&source_sol)); |
| 53 | + println!("\nReduction verified successfully"); |
| 54 | + |
| 55 | + // Export JSON |
| 56 | + let source_variant = variant_to_map(Knapsack::variant()); |
| 57 | + let target_variant = variant_to_map(QUBO::<f64>::variant()); |
| 58 | + let overhead = lookup_overhead("Knapsack", &source_variant, "QUBO", &target_variant) |
| 59 | + .expect("Knapsack -> QUBO overhead not found"); |
| 60 | + |
| 61 | + let data = ReductionData { |
| 62 | + source: ProblemSide { |
| 63 | + problem: Knapsack::NAME.to_string(), |
| 64 | + variant: source_variant, |
| 65 | + instance: serde_json::json!({ |
| 66 | + "num_items": knapsack.num_items(), |
| 67 | + "weights": knapsack.weights(), |
| 68 | + "values": knapsack.values(), |
| 69 | + "capacity": knapsack.capacity(), |
| 70 | + }), |
| 71 | + }, |
| 72 | + target: ProblemSide { |
| 73 | + problem: QUBO::<f64>::NAME.to_string(), |
| 74 | + variant: target_variant, |
| 75 | + instance: serde_json::json!({ |
| 76 | + "num_vars": qubo.num_vars(), |
| 77 | + }), |
| 78 | + }, |
| 79 | + overhead: overhead_to_json(&overhead), |
| 80 | + }; |
| 81 | + |
| 82 | + let results = ResultData { solutions }; |
| 83 | + write_example("knapsack_to_qubo", &data, &results); |
| 84 | +} |
| 85 | + |
| 86 | +fn main() { |
| 87 | + run() |
| 88 | +} |
0 commit comments