problemreductions/models/misc/
minimum_code_generation_unlimited_registers.rs1use crate::registry::{FieldInfo, ProblemSchemaEntry};
12use crate::traits::Problem;
13use crate::types::Min;
14use serde::{Deserialize, Serialize};
15
16inventory::submit! {
17 ProblemSchemaEntry {
18 name: "MinimumCodeGenerationUnlimitedRegisters",
19 display_name: "Minimum Code Generation (Unlimited Registers)",
20 aliases: &[],
21 dimensions: &[],
22 category: crate::registry::ProblemCategory::Misc,
23 module_path: module_path!(),
24 description: "Find minimum-length instruction sequence for an unlimited-register machine with 2-address instructions to evaluate an expression DAG",
25 fields: &[
26 FieldInfo { name: "num_vertices", type_name: "usize", description: "Number of vertices n = |V|" },
27 FieldInfo { name: "left_arcs", type_name: "Vec<(usize, usize)>", description: "Left operand arcs L: (parent, child) — child's register is destroyed" },
28 FieldInfo { name: "right_arcs", type_name: "Vec<(usize, usize)>", description: "Right operand arcs R: (parent, child) — child's register is preserved" },
29 ],
30 }
31}
32
33#[derive(Debug, Clone, Serialize, Deserialize)]
65pub struct MinimumCodeGenerationUnlimitedRegisters {
66 num_vertices: usize,
68 left_arcs: Vec<(usize, usize)>,
70 right_arcs: Vec<(usize, usize)>,
72}
73
74impl MinimumCodeGenerationUnlimitedRegisters {
75 pub fn new(
89 num_vertices: usize,
90 left_arcs: Vec<(usize, usize)>,
91 right_arcs: Vec<(usize, usize)>,
92 ) -> Self {
93 let mut left_count = vec![0usize; num_vertices];
94 let mut right_count = vec![0usize; num_vertices];
95
96 for &(parent, child) in &left_arcs {
97 assert!(
98 parent < num_vertices && child < num_vertices,
99 "Left arc ({parent}, {child}) out of bounds for {num_vertices} vertices"
100 );
101 assert!(
102 parent != child,
103 "Self-loop ({parent}, {parent}) not allowed"
104 );
105 left_count[parent] += 1;
106 }
107 for &(parent, child) in &right_arcs {
108 assert!(
109 parent < num_vertices && child < num_vertices,
110 "Right arc ({parent}, {child}) out of bounds for {num_vertices} vertices"
111 );
112 assert!(
113 parent != child,
114 "Self-loop ({parent}, {parent}) not allowed"
115 );
116 right_count[parent] += 1;
117 }
118
119 for v in 0..num_vertices {
120 let out = left_count[v] + right_count[v];
121 assert!(out <= 2, "Vertex {v} has out-degree {out} > 2");
122 if out == 2 {
124 assert!(
125 left_count[v] == 1 && right_count[v] == 1,
126 "Binary vertex {v} must have exactly 1 left and 1 right arc"
127 );
128 }
129 if out == 1 {
131 assert!(
132 left_count[v] == 1 && right_count[v] == 0,
133 "Unary vertex {v} must have exactly 1 left arc and 0 right arcs"
134 );
135 }
136 }
137
138 Self {
139 num_vertices,
140 left_arcs,
141 right_arcs,
142 }
143 }
144
145 pub fn num_vertices(&self) -> usize {
147 self.num_vertices
148 }
149
150 pub fn left_arcs(&self) -> &[(usize, usize)] {
152 &self.left_arcs
153 }
154
155 pub fn right_arcs(&self) -> &[(usize, usize)] {
157 &self.right_arcs
158 }
159
160 pub fn num_leaves(&self) -> usize {
162 self.num_vertices - self.num_internal()
163 }
164
165 pub fn num_internal(&self) -> usize {
167 let mut has_children = vec![false; self.num_vertices];
168 for &(parent, _) in &self.left_arcs {
169 has_children[parent] = true;
170 }
171 for &(parent, _) in &self.right_arcs {
172 has_children[parent] = true;
173 }
174 has_children.iter().filter(|&&b| b).count()
175 }
176
177 fn internal_vertices(&self) -> Vec<usize> {
179 let mut has_children = vec![false; self.num_vertices];
180 for &(parent, _) in &self.left_arcs {
181 has_children[parent] = true;
182 }
183 for &(parent, _) in &self.right_arcs {
184 has_children[parent] = true;
185 }
186 (0..self.num_vertices)
187 .filter(|&v| has_children[v])
188 .collect()
189 }
190
191 fn left_child(&self, v: usize) -> Option<usize> {
193 self.left_arcs
194 .iter()
195 .find(|&&(parent, _)| parent == v)
196 .map(|&(_, child)| child)
197 }
198
199 fn right_child(&self, v: usize) -> Option<usize> {
201 self.right_arcs
202 .iter()
203 .find(|&&(parent, _)| parent == v)
204 .map(|&(_, child)| child)
205 }
206
207 pub fn simulate(
218 &self,
219 config: &[usize],
220 ) -> Result<Option<i64>, crate::traits::EvaluationError> {
221 let internal = self.internal_vertices();
222 let n_internal = internal.len();
223 if config.len() != n_internal {
224 return Ok(None);
225 }
226
227 let mut order = vec![0usize; n_internal];
230 let mut used = vec![false; n_internal];
231 for (i, &pos) in config.iter().enumerate() {
232 if pos >= n_internal {
233 return Ok(None);
234 }
235 if used[pos] {
236 return Ok(None);
237 }
238 used[pos] = true;
239 order[pos] = i;
240 }
241
242 let mut computed = vec![false; self.num_vertices];
244 let has_children: Vec<bool> = {
246 let mut hc = vec![false; self.num_vertices];
247 for &(parent, _) in &self.left_arcs {
248 hc[parent] = true;
249 }
250 for &(parent, _) in &self.right_arcs {
251 hc[parent] = true;
252 }
253 hc
254 };
255 for v in 0..self.num_vertices {
256 if !has_children[v] {
257 computed[v] = true;
258 }
259 }
260
261 let mut future_left_uses = vec![0usize; self.num_vertices];
266 let mut future_right_uses = vec![0usize; self.num_vertices];
267 for &idx in &order {
268 let v = internal[idx];
269 if let Some(lc) = self.left_child(v) {
270 future_left_uses[lc] += 1;
271 }
272 if let Some(rc) = self.right_child(v) {
273 future_right_uses[rc] += 1;
274 }
275 }
276
277 let mut instructions = 0_i64;
278
279 for step in 0..n_internal {
285 let v = internal[order[step]];
286 let lc = self.left_child(v);
287 let rc = self.right_child(v);
288
289 if let Some(l) = lc {
291 if !computed[l] {
292 return Ok(None);
293 }
294 }
295 if let Some(r) = rc {
296 if !computed[r] {
297 return Ok(None);
298 }
299 }
300
301 if let Some(l) = lc {
303 future_left_uses[l] -= 1;
304 }
305 if let Some(r) = rc {
306 future_right_uses[r] -= 1;
307 }
308
309 if let Some(l) = lc {
311 let still_needed = future_left_uses[l] + future_right_uses[l] > 0;
312 if still_needed {
313 instructions = instructions.checked_add(1).ok_or_else(|| {
314 crate::traits::EvaluationError::IntegerOverflow(
315 "counting unlimited-register instructions".to_string(),
316 )
317 })?; }
319 }
320
321 instructions = instructions.checked_add(1).ok_or_else(|| {
323 crate::traits::EvaluationError::IntegerOverflow(
324 "counting unlimited-register instructions".to_string(),
325 )
326 })?;
327
328 computed[v] = true;
330 }
331
332 Ok(Some(instructions))
333 }
334}
335
336impl Problem for MinimumCodeGenerationUnlimitedRegisters {
337 const NAME: &'static str = "MinimumCodeGenerationUnlimitedRegisters";
338 type Solution = Vec<usize>;
339 type Value = Min<i64>;
340
341 crate::problem_parameters![("num_vertices", num_vertices),];
342
343 fn variant() -> Vec<(&'static str, &'static str)> {
344 crate::variant_params![]
345 }
346
347 fn evaluate(
348 &self,
349 config: &Self::Solution,
350 ) -> Result<Min<i64>, crate::traits::EvaluationError> {
351 let n = self.internal_vertices().len();
352 if config.len() != n {
353 return Err(crate::traits::EvaluationError::InvalidConfiguration(
354 "evaluation ordering length does not match the internal vertices".into(),
355 ));
356 }
357 if config.iter().any(|&position| position >= n) {
358 return Err(crate::traits::EvaluationError::InvalidConfiguration(
359 "evaluation ordering contains an out-of-range position".into(),
360 ));
361 }
362 Ok(Min(self.simulate(config)?))
363 }
364}
365
366impl crate::solvers::BruteForceProblem for MinimumCodeGenerationUnlimitedRegisters {
367 fn dimensions(&self) -> Vec<usize> {
368 let n_internal = self.num_internal();
369 vec![n_internal; n_internal]
370 }
371}
372
373crate::declare_variants! {
374 default MinimumCodeGenerationUnlimitedRegisters => "2 ^ num_vertices",
375}
376
377crate::register_brute_force! {
378 MinimumCodeGenerationUnlimitedRegisters,
379}
380
381#[cfg(feature = "example-db")]
382pub(crate) fn canonical_model_example_specs() -> Vec<crate::example_db::specs::ModelExampleSpec> {
383 vec![crate::example_db::specs::ModelExampleSpec {
384 id: "minimum_code_generation_unlimited_registers",
385 instance: Box::new(MinimumCodeGenerationUnlimitedRegisters::new(
393 5,
394 vec![(1, 3), (2, 3), (0, 1)],
395 vec![(1, 4), (2, 4), (0, 2)],
396 )),
397 optimal_config: serde_json::json!(vec![2, 0, 1]),
398 optimal_value: serde_json::json!(4),
399 }]
400}
401
402#[cfg(test)]
403#[path = "../../unit_tests/models/misc/minimum_code_generation_unlimited_registers.rs"]
404mod tests;