problemreductions/models/misc/
register_sufficiency.rs1use crate::registry::{FieldInfo, ProblemSchemaEntry};
8use crate::traits::Problem;
9use serde::{Deserialize, Serialize};
10
11inventory::submit! {
12 ProblemSchemaEntry {
13 name: "RegisterSufficiency",
14 display_name: "Register Sufficiency",
15 aliases: &[],
16 dimensions: &[],
17 module_path: module_path!(),
18 description: "Determine whether a DAG computation can be performed using K or fewer registers",
19 fields: &[
20 FieldInfo { name: "num_vertices", type_name: "usize", description: "Number of vertices n = |V|" },
21 FieldInfo { name: "arcs", type_name: "Vec<(usize, usize)>", description: "Directed arcs (v, u) meaning v depends on u" },
22 FieldInfo { name: "bound", type_name: "usize", description: "Register bound K" },
23 ],
24 }
25}
26
27#[derive(Debug, Clone, Serialize, Deserialize)]
58pub struct RegisterSufficiency {
59 num_vertices: usize,
61 arcs: Vec<(usize, usize)>,
63 bound: usize,
65}
66
67impl RegisterSufficiency {
68 pub fn new(num_vertices: usize, arcs: Vec<(usize, usize)>, bound: usize) -> Self {
75 for &(v, u) in &arcs {
76 assert!(
77 v < num_vertices && u < num_vertices,
78 "Arc ({}, {}) out of bounds for {} vertices",
79 v,
80 u,
81 num_vertices
82 );
83 assert!(v != u, "Self-loop ({}, {}) not allowed in a DAG", v, u);
84 }
85 Self {
86 num_vertices,
87 arcs,
88 bound,
89 }
90 }
91
92 pub fn num_vertices(&self) -> usize {
94 self.num_vertices
95 }
96
97 pub fn num_arcs(&self) -> usize {
99 self.arcs.len()
100 }
101
102 pub fn num_sinks(&self) -> usize {
104 let mut has_dependent = vec![false; self.num_vertices];
105 for &(_, dependency) in &self.arcs {
106 has_dependent[dependency] = true;
107 }
108 has_dependent.into_iter().filter(|&flag| !flag).count()
109 }
110
111 pub fn bound(&self) -> usize {
113 self.bound
114 }
115
116 pub fn arcs(&self) -> &[(usize, usize)] {
118 &self.arcs
119 }
120
121 pub fn simulate_registers(&self, config: &[usize]) -> Option<usize> {
125 let n = self.num_vertices;
126 if config.len() != n {
127 return None;
128 }
129
130 let mut order = vec![0usize; n]; let mut used = vec![false; n];
133 for (vertex, &position) in config.iter().enumerate() {
134 if position >= n {
135 return None;
136 }
137 if used[position] {
138 return None;
139 }
140 used[position] = true;
141 order[position] = vertex;
142 }
143
144 let mut dependencies: Vec<Vec<usize>> = vec![vec![]; n];
148 let mut dependents: Vec<Vec<usize>> = vec![vec![]; n];
149 for &(v, u) in &self.arcs {
150 dependencies[v].push(u);
151 dependents[u].push(v);
152 }
153
154 let mut last_use = vec![0usize; n];
157 for u in 0..n {
158 if dependents[u].is_empty() {
159 last_use[u] = n; } else {
163 let mut latest = 0;
164 for &v in &dependents[u] {
165 latest = latest.max(config[v]);
166 }
167 last_use[u] = latest;
168 }
169 }
170
171 let mut max_registers = 0;
172
173 for step in 0..n {
175 let vertex = order[step];
176
177 for &dep in &dependencies[vertex] {
180 if config[dep] >= step {
181 return None;
183 }
184 }
185
186 let reg_count = order[..=step]
194 .iter()
195 .filter(|&&v| last_use[v] > step)
196 .count();
197
198 max_registers = max_registers.max(reg_count);
199 }
200
201 Some(max_registers)
202 }
203
204 pub fn solve_exact(&self) -> Option<Vec<usize>> {
216 let n = self.num_vertices;
217 if n == 0 {
218 return Some(vec![]);
219 }
220
221 let mut dependents: Vec<Vec<usize>> = vec![vec![]; n];
222 let mut dependencies: Vec<Vec<usize>> = vec![vec![]; n];
223 let mut in_degree = vec![0u32; n];
224 for &(v, u) in &self.arcs {
225 in_degree[v] += 1;
226 dependents[u].push(v);
227 dependencies[v].push(u);
228 }
229
230 let mut state = BnBState {
231 n,
232 bound: self.bound,
233 config: vec![0usize; n],
234 live: vec![false; n],
235 live_count: 0,
236 remaining_in_degree: in_degree.clone(),
237 remaining_deps: dependents.iter().map(|d| d.len()).collect(),
238 ready: (0..n).filter(|&v| in_degree[v] == 0).collect(),
239 dependents,
240 dependencies,
241 };
242 state.ready.sort_unstable();
243
244 if state.backtrack(0) {
245 Some(state.config)
246 } else {
247 None
248 }
249 }
250}
251
252struct BnBState {
253 n: usize,
254 bound: usize,
255 config: Vec<usize>,
256 live: Vec<bool>,
257 live_count: usize,
258 remaining_in_degree: Vec<u32>,
259 remaining_deps: Vec<usize>,
260 ready: Vec<usize>,
261 dependents: Vec<Vec<usize>>,
262 dependencies: Vec<Vec<usize>>,
263}
264
265impl BnBState {
266 fn backtrack(&mut self, step: usize) -> bool {
267 if step == self.n {
268 return true;
269 }
270
271 let mut candidates = self.ready.clone();
273 candidates.sort_by_key(|&v| {
274 let frees = self.dependencies[v]
275 .iter()
276 .filter(|&&dep| self.remaining_deps[dep] == 1 && self.live[dep])
277 .count();
278 std::cmp::Reverse(frees)
279 });
280
281 for &vertex in &candidates {
282 self.config[vertex] = step;
283
284 let was_live = self.live[vertex];
285 if !was_live {
286 self.live[vertex] = true;
287 self.live_count += 1;
288 }
289
290 let mut freed = Vec::new();
291 for &dep in &self.dependencies[vertex] {
292 self.remaining_deps[dep] -= 1;
293 if self.remaining_deps[dep] == 0 && self.live[dep] {
294 self.live[dep] = false;
295 self.live_count -= 1;
296 freed.push(dep);
297 }
298 }
299
300 if self.live_count <= self.bound {
301 self.ready.retain(|&v| v != vertex);
302 let mut newly_ready = Vec::new();
303 for &dep in &self.dependents[vertex] {
304 self.remaining_in_degree[dep] -= 1;
305 if self.remaining_in_degree[dep] == 0 {
306 self.ready.push(dep);
307 newly_ready.push(dep);
308 }
309 }
310
311 if self.backtrack(step + 1) {
312 return true;
313 }
314
315 for &dep in &newly_ready {
316 self.ready.retain(|&v| v != dep);
317 }
318 for &dep in &self.dependents[vertex] {
319 self.remaining_in_degree[dep] += 1;
320 }
321 self.ready.push(vertex);
322 self.ready.sort_unstable();
323 }
324
325 for &dep in &freed {
326 self.live[dep] = true;
327 self.live_count += 1;
328 }
329 for &dep in &self.dependencies[vertex] {
330 self.remaining_deps[dep] += 1;
331 }
332
333 if !was_live {
334 self.live[vertex] = false;
335 self.live_count -= 1;
336 }
337 }
338
339 false
340 }
341}
342
343impl Problem for RegisterSufficiency {
344 const NAME: &'static str = "RegisterSufficiency";
345 type Value = crate::types::Or;
346
347 fn variant() -> Vec<(&'static str, &'static str)> {
348 crate::variant_params![]
349 }
350
351 fn dims(&self) -> Vec<usize> {
352 vec![self.num_vertices; self.num_vertices]
353 }
354
355 fn evaluate(&self, config: &[usize]) -> crate::types::Or {
356 crate::types::Or(
357 self.simulate_registers(config)
358 .is_some_and(|max_reg| max_reg <= self.bound),
359 )
360 }
361}
362
363crate::declare_variants! {
364 default RegisterSufficiency => "num_vertices ^ 2 * 2 ^ num_vertices",
365}
366
367#[cfg(feature = "example-db")]
368pub(crate) fn canonical_model_example_specs() -> Vec<crate::example_db::specs::ModelExampleSpec> {
369 vec![crate::example_db::specs::ModelExampleSpec {
370 id: "register_sufficiency",
371 instance: Box::new(RegisterSufficiency::new(
375 7,
376 vec![
377 (2, 0),
378 (2, 1),
379 (3, 1),
380 (4, 2),
381 (4, 3),
382 (5, 0),
383 (6, 4),
384 (6, 5),
385 ],
386 3,
387 )),
388 optimal_config: vec![0, 1, 2, 3, 5, 4, 6],
391 optimal_value: serde_json::json!(true),
392 }]
393}
394
395#[cfg(test)]
396#[path = "../../unit_tests/models/misc/register_sufficiency.rs"]
397mod tests;