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)]
65#[serde(try_from = "MinimumCodeGenerationUnlimitedRegistersData")]
66pub struct MinimumCodeGenerationUnlimitedRegisters {
67 num_vertices: usize,
69 left_arcs: Vec<(usize, usize)>,
71 right_arcs: Vec<(usize, usize)>,
73}
74
75#[derive(Deserialize)]
76struct MinimumCodeGenerationUnlimitedRegistersData {
77 num_vertices: usize,
78 left_arcs: Vec<(usize, usize)>,
79 right_arcs: Vec<(usize, usize)>,
80}
81
82impl TryFrom<MinimumCodeGenerationUnlimitedRegistersData>
83 for MinimumCodeGenerationUnlimitedRegisters
84{
85 type Error = crate::registry::ConstructionError;
86 fn try_from(data: MinimumCodeGenerationUnlimitedRegistersData) -> Result<Self, Self::Error> {
87 Self::try_new(data.num_vertices, data.left_arcs, data.right_arcs)
88 }
89}
90
91impl MinimumCodeGenerationUnlimitedRegisters {
92 pub fn new(
106 num_vertices: usize,
107 left_arcs: Vec<(usize, usize)>,
108 right_arcs: Vec<(usize, usize)>,
109 ) -> Self {
110 Self::try_new(num_vertices, left_arcs, right_arcs).unwrap_or_else(|error| panic!("{error}"))
111 }
112
113 fn try_new(
114 num_vertices: usize,
115 left_arcs: Vec<(usize, usize)>,
116 right_arcs: Vec<(usize, usize)>,
117 ) -> Result<Self, crate::registry::ConstructionError> {
118 let mut left_count = vec![0usize; num_vertices];
119 let mut right_count = vec![0usize; num_vertices];
120
121 for &(parent, child) in &left_arcs {
122 if parent >= num_vertices || child >= num_vertices {
123 return Err(format!(
124 "Left arc ({parent}, {child}) out of bounds for {num_vertices} vertices"
125 )
126 .into());
127 }
128 if parent == child {
129 return Err(format!("Self-loop ({parent}, {parent}) not allowed").into());
130 }
131 left_count[parent] += 1;
132 }
133 for &(parent, child) in &right_arcs {
134 if parent >= num_vertices || child >= num_vertices {
135 return Err(format!(
136 "Right arc ({parent}, {child}) out of bounds for {num_vertices} vertices"
137 )
138 .into());
139 }
140 if parent == child {
141 return Err(format!("Self-loop ({parent}, {parent}) not allowed").into());
142 }
143 right_count[parent] += 1;
144 }
145
146 for v in 0..num_vertices {
147 let out = left_count[v] + right_count[v];
148 if out > 2 {
149 return Err(format!("Vertex {v} has out-degree {out} > 2").into());
150 }
151 if out == 2 && !(left_count[v] == 1 && right_count[v] == 1) {
153 return Err(
154 format!("Binary vertex {v} must have exactly 1 left and 1 right arc").into(),
155 );
156 }
157 if out == 1 && !(left_count[v] == 1 && right_count[v] == 0) {
159 return Err(format!(
160 "Unary vertex {v} must have exactly 1 left arc and 0 right arcs"
161 )
162 .into());
163 }
164 }
165
166 Ok(Self {
167 num_vertices,
168 left_arcs,
169 right_arcs,
170 })
171 }
172
173 pub fn num_vertices(&self) -> usize {
175 self.num_vertices
176 }
177
178 pub fn left_arcs(&self) -> &[(usize, usize)] {
180 &self.left_arcs
181 }
182
183 pub fn right_arcs(&self) -> &[(usize, usize)] {
185 &self.right_arcs
186 }
187
188 pub fn num_leaves(&self) -> usize {
190 self.num_vertices - self.num_internal()
191 }
192
193 pub fn num_internal(&self) -> usize {
195 let mut has_children = vec![false; self.num_vertices];
196 for &(parent, _) in &self.left_arcs {
197 has_children[parent] = true;
198 }
199 for &(parent, _) in &self.right_arcs {
200 has_children[parent] = true;
201 }
202 has_children.iter().filter(|&&b| b).count()
203 }
204
205 fn internal_vertices(&self) -> Vec<usize> {
207 let mut has_children = vec![false; self.num_vertices];
208 for &(parent, _) in &self.left_arcs {
209 has_children[parent] = true;
210 }
211 for &(parent, _) in &self.right_arcs {
212 has_children[parent] = true;
213 }
214 (0..self.num_vertices)
215 .filter(|&v| has_children[v])
216 .collect()
217 }
218
219 fn left_child(&self, v: usize) -> Option<usize> {
221 self.left_arcs
222 .iter()
223 .find(|&&(parent, _)| parent == v)
224 .map(|&(_, child)| child)
225 }
226
227 fn right_child(&self, v: usize) -> Option<usize> {
229 self.right_arcs
230 .iter()
231 .find(|&&(parent, _)| parent == v)
232 .map(|&(_, child)| child)
233 }
234
235 pub fn simulate(
246 &self,
247 config: &[usize],
248 ) -> Result<Option<i64>, crate::traits::EvaluationError> {
249 let internal = self.internal_vertices();
250 let n_internal = internal.len();
251 if config.len() != n_internal {
252 return Ok(None);
253 }
254
255 let mut order = vec![0usize; n_internal];
258 let mut used = vec![false; n_internal];
259 for (i, &pos) in config.iter().enumerate() {
260 if pos >= n_internal {
261 return Ok(None);
262 }
263 if used[pos] {
264 return Ok(None);
265 }
266 used[pos] = true;
267 order[pos] = i;
268 }
269
270 let mut computed = vec![false; self.num_vertices];
272 let has_children: Vec<bool> = {
274 let mut hc = vec![false; self.num_vertices];
275 for &(parent, _) in &self.left_arcs {
276 hc[parent] = true;
277 }
278 for &(parent, _) in &self.right_arcs {
279 hc[parent] = true;
280 }
281 hc
282 };
283 for v in 0..self.num_vertices {
284 if !has_children[v] {
285 computed[v] = true;
286 }
287 }
288
289 let mut future_left_uses = vec![0usize; self.num_vertices];
294 let mut future_right_uses = vec![0usize; self.num_vertices];
295 for &idx in &order {
296 let v = internal[idx];
297 if let Some(lc) = self.left_child(v) {
298 future_left_uses[lc] += 1;
299 }
300 if let Some(rc) = self.right_child(v) {
301 future_right_uses[rc] += 1;
302 }
303 }
304
305 let mut instructions = 0_i64;
306
307 for step in 0..n_internal {
313 let v = internal[order[step]];
314 let lc = self.left_child(v);
315 let rc = self.right_child(v);
316
317 if let Some(l) = lc {
319 if !computed[l] {
320 return Ok(None);
321 }
322 }
323 if let Some(r) = rc {
324 if !computed[r] {
325 return Ok(None);
326 }
327 }
328
329 if let Some(l) = lc {
331 future_left_uses[l] -= 1;
332 }
333 if let Some(r) = rc {
334 future_right_uses[r] -= 1;
335 }
336
337 if let Some(l) = lc {
339 let still_needed = future_left_uses[l] + future_right_uses[l] > 0;
340 if still_needed {
341 instructions = instructions.checked_add(1).ok_or_else(|| {
342 crate::traits::EvaluationError::IntegerOverflow(
343 "counting unlimited-register instructions".to_string(),
344 )
345 })?; }
347 }
348
349 instructions = instructions.checked_add(1).ok_or_else(|| {
351 crate::traits::EvaluationError::IntegerOverflow(
352 "counting unlimited-register instructions".to_string(),
353 )
354 })?;
355
356 computed[v] = true;
358 }
359
360 Ok(Some(instructions))
361 }
362}
363
364impl Problem for MinimumCodeGenerationUnlimitedRegisters {
365 const NAME: &'static str = "MinimumCodeGenerationUnlimitedRegisters";
366 type Solution = Vec<usize>;
367 type Value = Min<i64>;
368
369 crate::problem_parameters![("num_vertices", num_vertices),];
370
371 fn variant() -> Vec<(&'static str, &'static str)> {
372 crate::variant_params![]
373 }
374
375 fn evaluate(
376 &self,
377 config: &Self::Solution,
378 ) -> Result<Min<i64>, crate::traits::EvaluationError> {
379 let n = self.internal_vertices().len();
380 if config.len() != n {
381 return Err(crate::traits::EvaluationError::InvalidConfiguration(
382 "evaluation ordering length does not match the internal vertices".into(),
383 ));
384 }
385 if config.iter().any(|&position| position >= n) {
386 return Err(crate::traits::EvaluationError::InvalidConfiguration(
387 "evaluation ordering contains an out-of-range position".into(),
388 ));
389 }
390 Ok(Min(self.simulate(config)?))
391 }
392}
393
394impl crate::solvers::BruteForceProblem for MinimumCodeGenerationUnlimitedRegisters {
395 fn dimensions(&self) -> Vec<usize> {
396 super::lehmer_dims(self.num_internal())
397 }
398}
399
400crate::declare_variants! {
401 default MinimumCodeGenerationUnlimitedRegisters => "2 ^ num_vertices",
402}
403
404crate::register_brute_force! {
405 MinimumCodeGenerationUnlimitedRegisters decode |problem: &MinimumCodeGenerationUnlimitedRegisters, indices: Vec<usize>| super::decode_lehmer(&indices, problem.num_internal()).expect("enumerated Lehmer digits are valid"),
406}
407
408#[cfg(feature = "example-db")]
409pub(crate) fn canonical_model_example_specs() -> Vec<crate::example_db::specs::ModelExampleSpec> {
410 vec![crate::example_db::specs::ModelExampleSpec {
411 id: "minimum_code_generation_unlimited_registers",
412 instance: Box::new(MinimumCodeGenerationUnlimitedRegisters::new(
420 5,
421 vec![(1, 3), (2, 3), (0, 1)],
422 vec![(1, 4), (2, 4), (0, 2)],
423 )),
424 optimal_config: serde_json::json!(vec![2, 0, 1]),
425 optimal_value: serde_json::json!(4),
426 }]
427}
428
429#[cfg(test)]
430#[path = "../../unit_tests/models/misc/minimum_code_generation_unlimited_registers.rs"]
431mod tests;