A comprehensive Python pipeline for solving the binary knapsack problem using four different optimization approaches:
- Classical exact solution (Pyomo + Gurobi)
- QUBO formulation (Pyomo + Gurobi)
- Quantum simulation (Qiskit QAOA)
- Quantum-inspired annealing (Dimod)
knapsack-optimization/
βββ src/ # All source code
β βββ pipeline.py # Main orchestration script
β βββ config.py # Centralized configuration
β βββ utils.py # Shared utilities (logging, validation, timeouts)
β βββ knapsack_solver.py # Task 1: Classical exact
β βββ knapsack_solver_qubo.py # Task 2: QUBO formulation
β βββ knapsack_qiskit_eigen.py# Task 3: Qiskit quantum
β βββ knapsack_dimod.py # Task 4: Dimod annealing
β βββ analyze_results.py # Result parsing and reporting
βββ input/ # JSON knapsack instances
β βββ knapsack_data_6.json
β βββ knapsack_data_10.json
β βββ knapsack_data_20.json
β βββ knapsack_data_50.json
β βββ knapsack_data_100.json
β βββ knapsack_data_1000.json
β βββ knapsack_data_10000.json
β βββ ...
βββ outputs/ # Auto-generated output directories
β βββ run_20260314_220406/
β β βββ risultati_task1.txt
β β βββ risultati_task2_qubo.txt
β β βββ risultati_task3_qiskit.txt
β β βββ risultati_task4_dimod.txt
β β βββ benchmark_tempi.csv
β β βββ final_comparison_report.csv
β β βββ report.html
β β βββ pipeline.log
β βββ run_20260314_222727/
β βββ ...
βββ uv.lock # Dependency lock file
βββ README.md # This file
- Python 3.8+
uvpackage manager
# Navigate to the project directory
cd /{path}/knapsack-optimization
# Install dependencies using uv
uv pip install \
pyomo \
gurobi \
qiskit \
qiskit-aer \
qiskit-optimization \
dimod \
neal \
pandas \
psutilOptional: Install Qiskit algorithms for enhanced quantum features
uv pip install qiskit-algorithmsAll hardcoded values are centralized in src/config.py:
| Parameter | Default | Purpose |
|---|---|---|
QUBO_PENALTY_MULTIPLIER |
2.0 | Penalty strength for constraint violations |
QISKIT_TIMEOUT_SECONDS |
120 | Max time per instance for Qiskit |
QISKIT_MAX_INSTANCE_SIZE |
10 | Skip instances larger than this |
GUROBI_MAX_INSTANCE_SIZE |
100 | Skip instances larger than this (free license limit) |
DIMOD_NUM_READS |
100 | Annealing runs per instance |
DIMOD_TIMEOUT_SECONDS |
120 | Max time per instance for Dimod |
DIMOD_LARGE_INSTANCE_THRESHOLD |
10000 | Skip instances with >= this items |
CONTINUE_ON_ERROR |
True | Continue pipeline on task failure |
LOG_LEVEL |
INFO | Logging verbosity |
Modify src/config.py to adjust behavior without changing task implementations.
cd /{path}/knapsack-optimization
uv run src/pipeline.pyThis executes all 4 tasks sequentially and generates:
- Individual result files for each task
- Benchmark timing CSV
- Comparative analysis report (CSV + HTML)
- Unified log file
Output location: outputs/run_YYYYMMDD_HHMMSS/
| File | Purpose | Priority |
|---|---|---|
final_comparison_report.csv |
Compare all solutions | β Primary |
report.html |
Interactive visual report | β Primary |
benchmark_tempi.csv |
Execution times per task | π Secondary |
pipeline.log |
Detailed execution logs | π§ Debug |
risultati_task1.txt |
Classical optimal solutions | π Reference |
risultati_task2_qubo.txt |
QUBO solutions | π Reference |
risultati_task3_qiskit.txt |
Quantum (Qiskit) solutions | π Reference |
risultati_task4_dimod.txt |
Quantum-inspired (Dimod) solutions | π Reference |
- Algorithm: Branch & Bound (via Gurobi)
- Guarantee: Optimal solution
- Time Complexity: Variable (NP-hard)
- Use Case: Baseline and ground truth
- Limitations: Slow for instances > 100 items
- Algorithm: Penalty method + Gurobi
- Guarantee: Not guaranteed optimal (due to penalty approximation)
- Time Complexity: Variable (converted to QP)
- Use Case: Understand penalty-based methods
- Limitations: Quality depends on penalty multiplier
- Algorithm: QAOA (Quantum Approximate Optimization Algorithm)
- Fallback Chain: QAOA β CPLEX β Greedy heuristic
- Guarantee: Heuristic solution
- Timeout: 120 seconds per instance
- Use Case: Explore quantum-inspired algorithms
- Limitations: Expensive for larger instances
- Algorithm: Simulated annealing (Neal sampler)
- Runs: 10 independent runs per instance
- Guarantee: Heuristic solution
- Timeout: 120 seconds per instance
- Use Case: Fast heuristic solutions
- Limitations: Quality depends on annealing parameters
# Task 1: Classical exact
uv run knapsack_solver.py
# Task 2: QUBO
uv run knapsack_solver_qubo.py
# Task 3: Qiskit quantum
uv run knapsack_qiskit_eigen.py
# Task 4: Dimod annealing
uv run knapsack_dimod.py
# Generate comparison report
uv run analyze_results.pyEach knapsack instance must follow this structure:
{
"sets": {
"P": ["1", "2", "3", "4"]
},
"parameters": {
"b": 10,
"C": {
"1": 8,
"2": 6,
"3": 5,
"4": 4
},
"a": {
"1": 6,
"2": 4,
"3": 3,
"4": 2
}
}
}sets.P: List of item identifiersparameters.b: Knapsack capacityparameters.C: Item values/profitsparameters.a: Item weights
risultati_task1.txt - Exact classical solution
- Optimal value
- Selected items
- Feasibility guaranteed
risultati_task2_qubo.txt - QUBO solution
- QUBO-formulated solution
- May be suboptimal (depends on penalty coefficient)
- Feasibility not guaranteed
risultati_task3_qiskit.txt - Quantum simulation results
- QAOA solution (or fallback Slsqp)
- Heuristic (variable across runs)
- May timeout on large instances
risultati_task4_dimod.txt - Annealing results
- Simulated annealing solution
- Shows solution diversity (unique solutions found)
- Heuristic (variable across runs)
benchmark_tempi.csv - Execution metrics
Task,Duration (s),Memory (MB),Status
Task 1 - Classico Esatto,2.15,45.32,Success
Task 2 - QUBO (Gurobi/HiGHS),1.89,42.15,Success
...
final_comparison_report.csv - Quality comparison
JSON_Instance,T1_Value,T2_Value,T3_Value,T4_Value,Gap_T1_T4 (%)
knapsack_data_10.json,42.0,42.0,40.0,38.0,9.52
...
The pipeline implements differentiated error handling:
try:
func(input_dir, output_file)
except TimeoutError:
# Operation exceeded time limit
except MemoryError:
# Insufficient memory
except ImportError:
# Missing dependency
except Exception:
# Other runtime errorsQiskit and Dimod tasks use context managers to enforce timeouts:
with timeout(QISKIT_TIMEOUT_SECONDS):
# Automatic timeout after N secondsDual logging to console and file:
2025-03-14 15:39:34,123 - KnapsackPipeline - INFO - Task 1 completed in 2.15s
| Size | Task 1 | Task 2 | Task 3 | Task 4 |
|---|---|---|---|---|
| β€10 items | β Fast | β Fast | β Fast | β Fast |
| 10-50 items | β Fast | β Fast | β Slow | β Medium |
| 50-100 items | β Medium | β Medium | β Medium | |
| 100-1000 items | β Medium | β Medium | β Skip | |
| >1000 items | β Skip | β Skip |
Qiskit has lower instance size limits due to quantum circuit complexity. Dimod can handle larger instances but may timeout with very large ones.
Track memory via benchmark CSV or log file:
grep "Memory (MB)" run_*/benchmark_tempi.csvuv pip install qiskit-algorithmsuv pip install gurobi
# Or use fallback solver: appsi_highsAdjust in config.py:
QISKIT_TIMEOUT_SECONDS = 60 # Increase timeout
QISKIT_MAX_INSTANCE_SIZE = 20 # Increase max sizeEnsure all task files are in the same directory:
ls -la *.py | grep knapsackTask 1 (Exact): Always optimal β
Task 2 (QUBO): Depends on penalty coefficient
The quality gap shows how far Tasks 3-4 are from the optimal Task 1 solution.
Gap (%) = (T1_Value - T4_Value) / T1_Value * 100
- 0% = Task 4 found optimal
- <5% = Excellent heuristic
- 5-15% = Good heuristic
-
15% = Poor heuristic or wrong parameters
- Kochol, P. (2007). A Polynomial Algorithm for the Knapsack Problem Based on a New Decomposition Theorem
- Qiskit Documentation: https://qiskit.org
- Dimod Documentation: https://docs.ocean.dwavesys.com/en/stable/docs_dimod/
Educational project - Master-level Python course
Last Updated: March 2026 Version: 2.0 (Refactored with config centralization)