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 let (dependencies, dependents) = Self::build_adjacency(data.num_vertices, &data.arcs);
94 Ok(Self {
95 num_vertices: data.num_vertices,
96 arcs: data.arcs,
97 num_registers: data.num_registers,
98 assignment: data.assignment,
99 dependencies,
100 dependents,
101 })
102 }
103}
104
105impl FeasibleRegisterAssignment {
106 pub fn new(
114 num_vertices: usize,
115 arcs: Vec<(usize, usize)>,
116 num_registers: usize,
117 assignment: Vec<usize>,
118 ) -> Self {
119 for &(v, u) in &arcs {
120 assert!(
121 v < num_vertices && u < num_vertices,
122 "Arc ({}, {}) out of bounds for {} vertices",
123 v,
124 u,
125 num_vertices
126 );
127 assert!(v != u, "Self-loop ({}, {}) not allowed in a DAG", v, u);
128 }
129 assert_eq!(
130 assignment.len(),
131 num_vertices,
132 "Assignment length {} does not match num_vertices {}",
133 assignment.len(),
134 num_vertices
135 );
136 if num_vertices > 0 {
137 assert!(
138 num_registers > 0,
139 "num_registers must be positive when there are vertices"
140 );
141 }
142 for (v, &r) in assignment.iter().enumerate() {
143 assert!(
144 r < num_registers,
145 "Assignment[{}] = {} is out of bounds for {} registers",
146 v,
147 r,
148 num_registers
149 );
150 }
151 let (dependencies, dependents) = Self::build_adjacency(num_vertices, &arcs);
152 Self {
153 num_vertices,
154 arcs,
155 num_registers,
156 assignment,
157 dependencies,
158 dependents,
159 }
160 }
161
162 fn build_adjacency(
164 num_vertices: usize,
165 arcs: &[(usize, usize)],
166 ) -> (Vec<Vec<usize>>, Vec<Vec<usize>>) {
167 let mut dependencies = vec![vec![]; num_vertices];
168 let mut dependents = vec![vec![]; num_vertices];
169 for &(v, u) in arcs {
170 dependencies[v].push(u);
171 dependents[u].push(v);
172 }
173 (dependencies, dependents)
174 }
175
176 pub fn num_vertices(&self) -> usize {
178 self.num_vertices
179 }
180
181 pub fn num_arcs(&self) -> usize {
183 self.arcs.len()
184 }
185
186 pub fn num_registers(&self) -> usize {
188 self.num_registers
189 }
190
191 pub fn num_same_register_pairs(&self) -> usize {
193 let mut counts = vec![0usize; self.num_registers];
194 for ®ister in &self.assignment {
195 counts[register] += 1;
196 }
197 counts
198 .into_iter()
199 .map(|count| count.saturating_sub(1) * count / 2)
200 .sum()
201 }
202
203 pub fn arcs(&self) -> &[(usize, usize)] {
205 &self.arcs
206 }
207
208 pub fn assignment(&self) -> &[usize] {
210 &self.assignment
211 }
212
213 pub fn is_feasible(&self, config: &[usize]) -> bool {
218 let n = self.num_vertices;
219 if config.len() != n {
220 return false;
221 }
222
223 let mut order = vec![0usize; n]; let mut used = vec![false; n];
226 for (vertex, &position) in config.iter().enumerate() {
227 if position >= n {
228 return false;
229 }
230 if used[position] {
231 return false;
232 }
233 used[position] = true;
234 order[position] = vertex;
235 }
236
237 let mut computed = vec![false; n];
239
240 for step in 0..n {
241 let vertex = order[step];
242
243 for &dep in &self.dependencies[vertex] {
245 if !computed[dep] {
246 return false;
247 }
248 }
249
250 let reg = self.assignment[vertex];
253 for &w in &order[..step] {
254 if self.assignment[w] == reg {
255 let still_live = self.dependents[w]
256 .iter()
257 .any(|&d| d != vertex && !computed[d]);
258 if still_live {
259 return false;
260 }
261 }
262 }
263
264 computed[vertex] = true;
265 }
266
267 true
268 }
269}
270
271impl Problem for FeasibleRegisterAssignment {
272 const NAME: &'static str = "FeasibleRegisterAssignment";
273 type Solution = Vec<usize>;
274 type Value = crate::types::Or;
275
276 crate::problem_parameters![
277 ("num_arcs", num_arcs),
278 ("num_registers", num_registers),
279 ("num_same_register_pairs", num_same_register_pairs),
280 ("num_vertices", num_vertices),
281 ];
282
283 fn variant() -> Vec<(&'static str, &'static str)> {
284 crate::variant_params![]
285 }
286
287 fn evaluate(
288 &self,
289 config: &Self::Solution,
290 ) -> Result<crate::types::Or, crate::traits::EvaluationError> {
291 if config.len() != self.num_vertices {
292 return Err(crate::traits::EvaluationError::InvalidConfiguration(
293 "ordering length does not match the graph vertices".into(),
294 ));
295 }
296 if config.iter().any(|&position| position >= self.num_vertices) {
297 return Err(crate::traits::EvaluationError::InvalidConfiguration(
298 "ordering contains an out-of-range position".into(),
299 ));
300 }
301 Ok(crate::types::Or(self.is_feasible(config)))
302 }
303}
304
305impl crate::solvers::BruteForceProblem for FeasibleRegisterAssignment {
306 fn dimensions(&self) -> Vec<usize> {
307 vec![self.num_vertices; self.num_vertices]
308 }
309}
310
311crate::declare_variants! {
312 default FeasibleRegisterAssignment => "factorial(num_vertices)",
313}
314
315crate::register_brute_force! {
316 FeasibleRegisterAssignment,
317}
318
319#[cfg(feature = "example-db")]
320pub(crate) fn canonical_model_example_specs() -> Vec<crate::example_db::specs::ModelExampleSpec> {
321 vec![crate::example_db::specs::ModelExampleSpec {
322 id: "feasible_register_assignment",
323 instance: Box::new(FeasibleRegisterAssignment::new(
326 4,
327 vec![(0, 1), (0, 2), (1, 3)],
328 2,
329 vec![0, 1, 0, 0],
330 )),
331 optimal_config: serde_json::json!(vec![3, 1, 2, 0]),
334 optimal_value: serde_json::json!(true),
335 }]
336}
337
338#[cfg(test)]
339#[path = "../../unit_tests/models/misc/feasible_register_assignment.rs"]
340mod tests;