problemreductions/models/misc/
dynamic_storage_allocation.rs1use crate::registry::{FieldInfo, ProblemSchemaEntry};
9use crate::traits::Problem;
10use crate::types::Or;
11use serde::de::Error as _;
12use serde::{Deserialize, Deserializer, Serialize};
13
14inventory::submit! {
15 ProblemSchemaEntry {
16 name: "DynamicStorageAllocation",
17 display_name: "Dynamic Storage Allocation",
18 aliases: &[],
19 dimensions: &[],
20 category: crate::registry::ProblemCategory::Misc,
21 module_path: module_path!(),
22 description: "Assign starting addresses for items with time intervals and sizes within bounded memory",
23 fields: &[
24 FieldInfo { name: "items", type_name: "Vec<(usize, usize, usize)>", description: "Items as (arrival, departure, size) tuples" },
25 FieldInfo { name: "memory_size", type_name: "usize", description: "Total memory size D" },
26 ],
27 }
28}
29
30#[derive(Debug, Clone, Serialize)]
36pub struct DynamicStorageAllocation {
37 items: Vec<(usize, usize, usize)>,
38 memory_size: usize,
39}
40
41impl DynamicStorageAllocation {
42 fn validate_inputs(
43 items: &[(usize, usize, usize)],
44 memory_size: usize,
45 ) -> Result<(), crate::registry::ConstructionError> {
46 if items.is_empty() {
47 return Err("DynamicStorageAllocation requires at least one item"
48 .to_string()
49 .into());
50 }
51 if memory_size == 0 {
52 return Err("DynamicStorageAllocation requires a positive memory_size"
53 .to_string()
54 .into());
55 }
56 for (i, &(arrival, departure, size)) in items.iter().enumerate() {
57 if size == 0 {
58 return Err(format!("Item {i} has zero size; all sizes must be >= 1").into());
59 }
60 if departure <= arrival {
61 return Err(format!(
62 "Item {i} has departure ({departure}) <= arrival ({arrival}); departure must be strictly greater"
63 ).into());
64 }
65 if size > memory_size {
66 return Err(format!(
67 "Item {i} has size ({size}) > memory_size ({memory_size}); every item must fit in memory"
68 ).into());
69 }
70 }
71 Ok(())
72 }
73
74 pub fn try_new(
76 items: Vec<(usize, usize, usize)>,
77 memory_size: usize,
78 ) -> Result<Self, crate::registry::ConstructionError> {
79 Self::validate_inputs(&items, memory_size)?;
80 Ok(Self { items, memory_size })
81 }
82
83 pub fn new(items: Vec<(usize, usize, usize)>, memory_size: usize) -> Self {
89 Self::try_new(items, memory_size).unwrap_or_else(|message| panic!("{message}"))
90 }
91
92 pub fn items(&self) -> &[(usize, usize, usize)] {
94 &self.items
95 }
96
97 pub fn memory_size(&self) -> usize {
99 self.memory_size
100 }
101
102 pub fn num_items(&self) -> usize {
104 self.items.len()
105 }
106}
107
108#[derive(Deserialize)]
109struct DynamicStorageAllocationData {
110 items: Vec<(usize, usize, usize)>,
111 memory_size: usize,
112}
113
114impl<'de> Deserialize<'de> for DynamicStorageAllocation {
115 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
116 where
117 D: Deserializer<'de>,
118 {
119 let data = DynamicStorageAllocationData::deserialize(deserializer)?;
120 Self::try_new(data.items, data.memory_size).map_err(D::Error::custom)
121 }
122}
123
124impl Problem for DynamicStorageAllocation {
125 const NAME: &'static str = "DynamicStorageAllocation";
126 type Solution = Vec<usize>;
127 type Value = Or;
128
129 crate::problem_parameters![("memory_size", memory_size), ("num_items", num_items),];
130
131 fn variant() -> Vec<(&'static str, &'static str)> {
132 crate::variant_params![]
133 }
134
135 fn evaluate(&self, config: &Self::Solution) -> Result<Or, crate::traits::EvaluationError> {
136 Ok({
137 Or({
138 if config.len() != self.num_items() {
139 return Err(crate::traits::EvaluationError::InvalidConfiguration(
140 "allocation length does not match the number of items".into(),
141 ));
142 }
143
144 for (i, &(_, _, size)) in self.items.iter().enumerate() {
146 let start = config[i];
147 if start + size > self.memory_size {
148 return Ok(Or(false));
149 }
150 }
151
152 for (i, &(r_i, d_i, s_i)) in self.items.iter().enumerate() {
154 let sigma_i = config[i];
155 for (j, &(r_j, d_j, s_j)) in self.items.iter().enumerate().skip(i + 1) {
156 if r_i < d_j && r_j < d_i {
158 let sigma_j = config[j];
159 let no_memory_overlap =
161 sigma_i + s_i <= sigma_j || sigma_j + s_j <= sigma_i;
162 if !no_memory_overlap {
163 return Ok(Or(false));
164 }
165 }
166 }
167 }
168 true
169 })
170 })
171 }
172}
173
174impl crate::solvers::BruteForceProblem for DynamicStorageAllocation {
175 fn dimensions(&self) -> Vec<usize> {
176 self.items
177 .iter()
178 .map(|&(_, _, s)| self.memory_size - s + 1)
179 .collect()
180 }
181}
182
183crate::declare_variants! {
184 default DynamicStorageAllocation => "(memory_size + 1)^num_items",
185}
186
187crate::register_brute_force! {
188 DynamicStorageAllocation,
189}
190
191#[cfg(feature = "example-db")]
192pub(crate) fn canonical_model_example_specs() -> Vec<crate::example_db::specs::ModelExampleSpec> {
193 vec![crate::example_db::specs::ModelExampleSpec {
194 id: "dynamic_storage_allocation",
195 instance: Box::new(DynamicStorageAllocation::new(
196 vec![(0, 3, 2), (0, 2, 3), (1, 4, 1), (2, 5, 3), (3, 5, 2)],
197 6,
198 )),
199 optimal_config: serde_json::json!(vec![0, 2, 5, 2, 0]),
200 optimal_value: serde_json::json!(true),
201 }]
202}
203
204#[cfg(test)]
205#[path = "../../unit_tests/models/misc/dynamic_storage_allocation.rs"]
206mod tests;