problemreductions/models/misc/
knapsack.rs1use crate::registry::{FieldInfo, ProblemSchemaEntry};
7use crate::traits::{OptimizationProblem, Problem};
8use crate::types::{Direction, SolutionSize};
9use serde::{Deserialize, Serialize};
10
11inventory::submit! {
12 ProblemSchemaEntry {
13 name: "Knapsack",
14 module_path: module_path!(),
15 description: "Select items to maximize total value subject to weight capacity constraint",
16 fields: &[
17 FieldInfo { name: "weights", type_name: "Vec<i64>", description: "Item weights w_i" },
18 FieldInfo { name: "values", type_name: "Vec<i64>", description: "Item values v_i" },
19 FieldInfo { name: "capacity", type_name: "i64", description: "Knapsack capacity C" },
20 ],
21 }
22}
23
24#[derive(Debug, Clone, Serialize, Deserialize)]
46pub struct Knapsack {
47 weights: Vec<i64>,
48 values: Vec<i64>,
49 capacity: i64,
50}
51
52impl Knapsack {
53 pub fn new(weights: Vec<i64>, values: Vec<i64>, capacity: i64) -> Self {
58 assert_eq!(
59 weights.len(),
60 values.len(),
61 "weights and values must have the same length"
62 );
63 Self {
64 weights,
65 values,
66 capacity,
67 }
68 }
69
70 pub fn weights(&self) -> &[i64] {
72 &self.weights
73 }
74
75 pub fn values(&self) -> &[i64] {
77 &self.values
78 }
79
80 pub fn capacity(&self) -> i64 {
82 self.capacity
83 }
84
85 pub fn num_items(&self) -> usize {
87 self.weights.len()
88 }
89}
90
91impl Problem for Knapsack {
92 const NAME: &'static str = "Knapsack";
93 type Metric = SolutionSize<i64>;
94
95 fn variant() -> Vec<(&'static str, &'static str)> {
96 crate::variant_params![]
97 }
98
99 fn dims(&self) -> Vec<usize> {
100 vec![2; self.num_items()]
101 }
102
103 fn evaluate(&self, config: &[usize]) -> SolutionSize<i64> {
104 if config.len() != self.num_items() {
105 return SolutionSize::Invalid;
106 }
107 if config.iter().any(|&v| v >= 2) {
108 return SolutionSize::Invalid;
109 }
110 let total_weight: i64 = config
111 .iter()
112 .enumerate()
113 .filter(|(_, &x)| x == 1)
114 .map(|(i, _)| self.weights[i])
115 .sum();
116 if total_weight > self.capacity {
117 return SolutionSize::Invalid;
118 }
119 let total_value: i64 = config
120 .iter()
121 .enumerate()
122 .filter(|(_, &x)| x == 1)
123 .map(|(i, _)| self.values[i])
124 .sum();
125 SolutionSize::Valid(total_value)
126 }
127}
128
129impl OptimizationProblem for Knapsack {
130 type Value = i64;
131
132 fn direction(&self) -> Direction {
133 Direction::Maximize
134 }
135}
136
137crate::declare_variants! {
138 Knapsack => "2^(num_items / 2)",
139}
140
141#[cfg(test)]
142#[path = "../../unit_tests/models/misc/knapsack.rs"]
143mod tests;