problemreductions/models/misc/
feasible_register_assignment.rs1use crate::registry::{FieldInfo, ProblemSchemaEntry};
9use crate::traits::Problem;
10use serde::{Deserialize, Deserializer, Serialize};
11
12inventory::submit! {
13 ProblemSchemaEntry {
14 name: "FeasibleRegisterAssignment",
15 display_name: "Feasible Register Assignment",
16 aliases: &[],
17 dimensions: &[],
18 category: crate::registry::ProblemCategory::Misc,
19 module_path: module_path!(),
20 description: "Determine whether a DAG computation can be scheduled without register conflicts under a fixed assignment",
21 fields: &[
22 FieldInfo { name: "num_vertices", type_name: "usize", description: "Number of vertices n = |V|" },
23 FieldInfo { name: "arcs", type_name: "Vec<(usize, usize)>", description: "Directed arcs (v, u) meaning v depends on u" },
24 FieldInfo { name: "num_registers", type_name: "usize", description: "Number of registers K" },
25 FieldInfo { name: "assignment", type_name: "Vec<usize>", description: "Register assignment f(v) for each vertex" },
26 ],
27 }
28}
29
30#[derive(Debug, Clone, Serialize)]
62pub struct FeasibleRegisterAssignment {
63 num_vertices: usize,
65 arcs: Vec<(usize, usize)>,
67 num_registers: usize,
69 assignment: Vec<usize>,
71 #[serde(skip)]
73 dependencies: Vec<Vec<usize>>,
74 #[serde(skip)]
76 dependents: Vec<Vec<usize>>,
77}
78
79#[derive(Deserialize)]
80struct FeasibleRegisterAssignmentData {
81 num_vertices: usize,
82 arcs: Vec<(usize, usize)>,
83 num_registers: usize,
84 assignment: Vec<usize>,
85}
86
87impl<'de> Deserialize<'de> for FeasibleRegisterAssignment {
88 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
89 where
90 D: Deserializer<'de>,
91 {
92 let data = FeasibleRegisterAssignmentData::deserialize(deserializer)?;
93 Self::try_new(
94 data.num_vertices,
95 data.arcs,
96 data.num_registers,
97 data.assignment,
98 )
99 .map_err(serde::de::Error::custom)
100 }
101}
102
103impl FeasibleRegisterAssignment {
104 pub fn new(
112 num_vertices: usize,
113 arcs: Vec<(usize, usize)>,
114 num_registers: usize,
115 assignment: Vec<usize>,
116 ) -> Self {
117 Self::try_new(num_vertices, arcs, num_registers, assignment)
118 .unwrap_or_else(|error| panic!("{error}"))
119 }
120
121 fn try_new(
122 num_vertices: usize,
123 arcs: Vec<(usize, usize)>,
124 num_registers: usize,
125 assignment: Vec<usize>,
126 ) -> Result<Self, crate::registry::ConstructionError> {
127 for &(v, u) in &arcs {
128 if v >= num_vertices || u >= num_vertices {
129 return Err(format!(
130 "Arc ({}, {}) out of bounds for {} vertices",
131 v, u, num_vertices
132 )
133 .into());
134 }
135 if v == u {
136 return Err(format!("Self-loop ({}, {}) not allowed in a DAG", v, u).into());
137 }
138 }
139 if assignment.len() != num_vertices {
140 return Err(format!(
141 "Assignment length {} does not match num_vertices {}",
142 assignment.len(),
143 num_vertices
144 )
145 .into());
146 }
147 if num_vertices > 0 && num_registers == 0 {
148 return Err("num_registers must be positive when there are vertices".into());
149 }
150 for (v, &r) in assignment.iter().enumerate() {
151 if r >= num_registers {
152 return Err(format!(
153 "Assignment[{}] = {} is out of bounds for {} registers",
154 v, r, num_registers
155 )
156 .into());
157 }
158 }
159 let (dependencies, dependents) = Self::build_adjacency(num_vertices, &arcs);
160 Ok(Self {
161 num_vertices,
162 arcs,
163 num_registers,
164 assignment,
165 dependencies,
166 dependents,
167 })
168 }
169
170 fn build_adjacency(
172 num_vertices: usize,
173 arcs: &[(usize, usize)],
174 ) -> (Vec<Vec<usize>>, Vec<Vec<usize>>) {
175 let mut dependencies = vec![vec![]; num_vertices];
176 let mut dependents = vec![vec![]; num_vertices];
177 for &(v, u) in arcs {
178 dependencies[v].push(u);
179 dependents[u].push(v);
180 }
181 (dependencies, dependents)
182 }
183
184 pub fn num_vertices(&self) -> usize {
186 self.num_vertices
187 }
188
189 pub fn num_arcs(&self) -> usize {
191 self.arcs.len()
192 }
193
194 pub fn num_registers(&self) -> usize {
196 self.num_registers
197 }
198
199 pub fn num_same_register_pairs(&self) -> usize {
201 let mut counts = vec![0usize; self.num_registers];
202 for ®ister in &self.assignment {
203 counts[register] += 1;
204 }
205 counts
206 .into_iter()
207 .map(|count| count.saturating_sub(1) * count / 2)
208 .sum()
209 }
210
211 pub fn arcs(&self) -> &[(usize, usize)] {
213 &self.arcs
214 }
215
216 pub fn assignment(&self) -> &[usize] {
218 &self.assignment
219 }
220
221 pub fn is_feasible(&self, config: &[usize]) -> bool {
226 let n = self.num_vertices;
227 if config.len() != n {
228 return false;
229 }
230
231 let mut order = vec![0usize; n]; let mut used = vec![false; n];
234 for (vertex, &position) in config.iter().enumerate() {
235 if position >= n {
236 return false;
237 }
238 if used[position] {
239 return false;
240 }
241 used[position] = true;
242 order[position] = vertex;
243 }
244
245 let mut computed = vec![false; n];
247
248 for step in 0..n {
249 let vertex = order[step];
250
251 for &dep in &self.dependencies[vertex] {
253 if !computed[dep] {
254 return false;
255 }
256 }
257
258 let reg = self.assignment[vertex];
261 for &w in &order[..step] {
262 if self.assignment[w] == reg {
263 let still_live = self.dependents[w]
264 .iter()
265 .any(|&d| d != vertex && !computed[d]);
266 if still_live {
267 return false;
268 }
269 }
270 }
271
272 computed[vertex] = true;
273 }
274
275 true
276 }
277}
278
279impl Problem for FeasibleRegisterAssignment {
280 const NAME: &'static str = "FeasibleRegisterAssignment";
281 type Solution = Vec<usize>;
282 type Value = crate::types::Or;
283
284 crate::problem_parameters![
285 ("num_arcs", num_arcs),
286 ("num_registers", num_registers),
287 ("num_same_register_pairs", num_same_register_pairs),
288 ("num_vertices", num_vertices),
289 ];
290
291 fn variant() -> Vec<(&'static str, &'static str)> {
292 crate::variant_params![]
293 }
294
295 fn evaluate(
296 &self,
297 config: &Self::Solution,
298 ) -> Result<crate::types::Or, crate::traits::EvaluationError> {
299 if config.len() != self.num_vertices {
300 return Err(crate::traits::EvaluationError::InvalidConfiguration(
301 "ordering length does not match the graph vertices".into(),
302 ));
303 }
304 if config.iter().any(|&position| position >= self.num_vertices) {
305 return Err(crate::traits::EvaluationError::InvalidConfiguration(
306 "ordering contains an out-of-range position".into(),
307 ));
308 }
309 Ok(crate::types::Or(self.is_feasible(config)))
310 }
311}
312
313impl crate::solvers::BruteForceProblem for FeasibleRegisterAssignment {
314 fn dimensions(&self) -> Vec<usize> {
315 vec![self.num_vertices; self.num_vertices]
316 }
317}
318
319crate::declare_variants! {
320 default FeasibleRegisterAssignment => "factorial(num_vertices)",
321}
322
323crate::register_brute_force! {
324 FeasibleRegisterAssignment,
325}
326
327#[cfg(feature = "example-db")]
328pub(crate) fn canonical_model_example_specs() -> Vec<crate::example_db::specs::ModelExampleSpec> {
329 vec![crate::example_db::specs::ModelExampleSpec {
330 id: "feasible_register_assignment",
331 instance: Box::new(FeasibleRegisterAssignment::new(
334 4,
335 vec![(0, 1), (0, 2), (1, 3)],
336 2,
337 vec![0, 1, 0, 0],
338 )),
339 optimal_config: serde_json::json!(vec![3, 1, 2, 0]),
342 optimal_value: serde_json::json!(true),
343 }]
344}
345
346#[cfg(test)]
347#[path = "../../unit_tests/models/misc/feasible_register_assignment.rs"]
348mod tests;