problemreductions/models/misc/
minimum_code_generation_one_register.rs1use crate::registry::{FieldInfo, ProblemSchemaEntry};
9use crate::traits::Problem;
10use crate::types::Min;
11use serde::{Deserialize, Serialize};
12
13inventory::submit! {
14 ProblemSchemaEntry {
15 name: "MinimumCodeGenerationOneRegister",
16 display_name: "Minimum Code Generation (One Register)",
17 aliases: &[],
18 dimensions: &[],
19 category: crate::registry::ProblemCategory::Misc,
20 module_path: module_path!(),
21 description: "Find minimum-length instruction sequence for a one-register machine to evaluate an expression DAG",
22 fields: &[
23 FieldInfo { name: "num_vertices", type_name: "usize", description: "Number of vertices n = |V|" },
24 FieldInfo { name: "edges", type_name: "Vec<(usize, usize)>", description: "Directed arcs (parent, child) in the expression DAG" },
25 FieldInfo { name: "num_leaves", type_name: "usize", description: "Number of leaf vertices (out-degree 0)" },
26 ],
27 }
28}
29
30#[derive(Debug, Clone, Serialize, Deserialize)]
60#[serde(try_from = "MinimumCodeGenerationOneRegisterData")]
61pub struct MinimumCodeGenerationOneRegister {
62 num_vertices: usize,
64 edges: Vec<(usize, usize)>,
66 num_leaves: usize,
68}
69
70#[derive(Deserialize)]
71struct MinimumCodeGenerationOneRegisterData {
72 num_vertices: usize,
73 edges: Vec<(usize, usize)>,
74 num_leaves: usize,
75}
76
77impl TryFrom<MinimumCodeGenerationOneRegisterData> for MinimumCodeGenerationOneRegister {
78 type Error = crate::registry::ConstructionError;
79 fn try_from(data: MinimumCodeGenerationOneRegisterData) -> Result<Self, Self::Error> {
80 Self::try_new(data.num_vertices, data.edges, data.num_leaves)
81 }
82}
83
84impl MinimumCodeGenerationOneRegister {
85 pub fn new(num_vertices: usize, edges: Vec<(usize, usize)>, num_leaves: usize) -> Self {
98 Self::try_new(num_vertices, edges, num_leaves).unwrap_or_else(|error| panic!("{error}"))
99 }
100
101 fn try_new(
102 num_vertices: usize,
103 edges: Vec<(usize, usize)>,
104 num_leaves: usize,
105 ) -> Result<Self, crate::registry::ConstructionError> {
106 if num_leaves > num_vertices {
107 return Err(
108 format!("num_leaves ({num_leaves}) exceeds num_vertices ({num_vertices})").into(),
109 );
110 }
111 let mut out_degree = vec![0usize; num_vertices];
112 for &(parent, child) in &edges {
113 if parent >= num_vertices || child >= num_vertices {
114 return Err(format!(
115 "Edge ({parent}, {child}) out of bounds for {num_vertices} vertices"
116 )
117 .into());
118 }
119 if parent == child {
120 return Err(format!("Self-loop ({parent}, {parent}) not allowed").into());
121 }
122 out_degree[parent] += 1;
123 }
124 for (v, °) in out_degree.iter().enumerate() {
125 if deg > 2 {
126 return Err(format!("Vertex {v} has out-degree {deg} > 2").into());
127 }
128 }
129 let actual_leaves = out_degree.iter().filter(|&&d| d == 0).count();
131 if actual_leaves != num_leaves {
132 return Err(format!(
133 "Declared num_leaves ({num_leaves}) != actual leaf count ({actual_leaves})"
134 )
135 .into());
136 }
137 Ok(Self {
138 num_vertices,
139 edges,
140 num_leaves,
141 })
142 }
143
144 pub fn num_vertices(&self) -> usize {
146 self.num_vertices
147 }
148
149 pub fn num_edges(&self) -> usize {
151 self.edges.len()
152 }
153
154 pub fn num_leaves(&self) -> usize {
156 self.num_leaves
157 }
158
159 pub fn num_internal(&self) -> usize {
161 self.num_vertices - self.num_leaves
162 }
163
164 pub fn edges(&self) -> &[(usize, usize)] {
166 &self.edges
167 }
168
169 fn children(&self) -> Vec<Vec<usize>> {
171 let mut ch = vec![vec![]; self.num_vertices];
172 for &(parent, child) in &self.edges {
173 ch[parent].push(child);
174 }
175 ch
176 }
177
178 fn internal_vertices(&self) -> Vec<usize> {
180 let children = self.children();
181 (0..self.num_vertices)
182 .filter(|&v| !children[v].is_empty())
183 .collect()
184 }
185
186 fn leaf_set(&self) -> Vec<bool> {
188 let children = self.children();
189 (0..self.num_vertices)
190 .map(|v| children[v].is_empty())
191 .collect()
192 }
193
194 pub fn simulate(
198 &self,
199 config: &[usize],
200 ) -> Result<Option<i64>, crate::traits::EvaluationError> {
201 let internal = self.internal_vertices();
202 let n_internal = internal.len();
203 if config.len() != n_internal {
204 return Ok(None);
205 }
206
207 let mut order = vec![0usize; n_internal];
211 let mut used = vec![false; n_internal];
212 for (i, &pos) in config.iter().enumerate() {
213 if pos >= n_internal {
214 return Ok(None);
215 }
216 if used[pos] {
217 return Ok(None);
218 }
219 used[pos] = true;
220 order[pos] = i;
221 }
222
223 let children = self.children();
224 let is_leaf = self.leaf_set();
225
226 let mut computed = vec![false; self.num_vertices];
228 for v in 0..self.num_vertices {
230 if is_leaf[v] {
231 computed[v] = true;
232 }
233 }
234
235 let mut future_uses = vec![0usize; self.num_vertices];
238 for &idx in &order {
239 let v = internal[idx];
240 for &c in &children[v] {
241 future_uses[c] += 1;
242 }
243 }
244
245 let mut register: Option<usize> = None; let mut in_memory = vec![false; self.num_vertices];
247 for v in 0..self.num_vertices {
249 if is_leaf[v] {
250 in_memory[v] = true;
251 }
252 }
253
254 let mut instructions = 0_i64;
255
256 for step in 0..n_internal {
257 let v = internal[order[step]];
258
259 for &c in &children[v] {
261 let available = in_memory[c] || register == Some(c);
262 if !available {
263 return Ok(None); }
265 }
266
267 for &c in &children[v] {
269 future_uses[c] -= 1;
270 }
271
272 let operands = &children[v];
273
274 if let Some(r) = register {
280 if !in_memory[r] && future_uses[r] > 0 {
281 instructions = instructions.checked_add(1).ok_or_else(|| {
282 crate::traits::EvaluationError::IntegerOverflow(
283 "counting one-register instructions".to_string(),
284 )
285 })?; in_memory[r] = true;
287 }
288 }
289
290 if operands.len() == 2 {
292 let c0 = operands[0];
293 let c1 = operands[1];
294 let one_in_register = (register == Some(c0) && in_memory[c1])
295 || (register == Some(c1) && in_memory[c0]);
296 if one_in_register {
297 instructions = instructions.checked_add(1).ok_or_else(|| {
298 crate::traits::EvaluationError::IntegerOverflow(
299 "counting one-register instructions".to_string(),
300 )
301 })?; } else {
303 instructions = instructions.checked_add(2).ok_or_else(|| {
305 crate::traits::EvaluationError::IntegerOverflow(
306 "counting one-register instructions".to_string(),
307 )
308 })?; }
310 } else if operands.len() == 1 {
311 let c0 = operands[0];
312 if register == Some(c0) {
313 instructions = instructions.checked_add(1).ok_or_else(|| {
314 crate::traits::EvaluationError::IntegerOverflow(
315 "counting one-register instructions".to_string(),
316 )
317 })?; } else {
319 instructions = instructions.checked_add(2).ok_or_else(|| {
320 crate::traits::EvaluationError::IntegerOverflow(
321 "counting one-register instructions".to_string(),
322 )
323 })?; }
325 }
326
327 register = Some(v);
328 }
329
330 Ok(Some(instructions))
331 }
332}
333
334impl Problem for MinimumCodeGenerationOneRegister {
335 const NAME: &'static str = "MinimumCodeGenerationOneRegister";
336 type Solution = Vec<usize>;
337 type Value = Min<i64>;
338
339 crate::problem_parameters![
340 ("num_vertices", num_vertices),
341 ("num_edges", num_edges),
342 ("num_leaves", num_leaves),
343 ("num_internal", num_internal),
344 ];
345
346 fn variant() -> Vec<(&'static str, &'static str)> {
347 crate::variant_params![]
348 }
349
350 fn evaluate(
351 &self,
352 config: &Self::Solution,
353 ) -> Result<Min<i64>, crate::traits::EvaluationError> {
354 let n = self.internal_vertices().len();
355 if config.len() != n {
356 return Err(crate::traits::EvaluationError::InvalidConfiguration(
357 "evaluation ordering length does not match the internal vertices".into(),
358 ));
359 }
360 if config.iter().any(|&position| position >= n) {
361 return Err(crate::traits::EvaluationError::InvalidConfiguration(
362 "evaluation ordering contains an out-of-range position".into(),
363 ));
364 }
365 Ok(Min(self.simulate(config)?))
366 }
367}
368
369impl crate::solvers::BruteForceProblem for MinimumCodeGenerationOneRegister {
370 fn dimensions(&self) -> Vec<usize> {
371 let n_internal = self.num_internal();
372 vec![n_internal; n_internal]
373 }
374}
375
376crate::declare_variants! {
377 default MinimumCodeGenerationOneRegister => "2 ^ num_vertices",
378}
379
380crate::register_brute_force! {
381 MinimumCodeGenerationOneRegister,
382}
383
384#[cfg(feature = "example-db")]
385pub(crate) fn canonical_model_example_specs() -> Vec<crate::example_db::specs::ModelExampleSpec> {
386 vec![crate::example_db::specs::ModelExampleSpec {
387 id: "minimum_code_generation_one_register",
388 instance: Box::new(MinimumCodeGenerationOneRegister::new(
397 7,
398 vec![
399 (0, 1),
400 (0, 2),
401 (1, 3),
402 (1, 4),
403 (2, 3),
404 (2, 5),
405 (3, 5),
406 (3, 6),
407 ],
408 3,
409 )),
410 optimal_config: serde_json::json!(vec![3, 2, 1, 0]),
411 optimal_value: serde_json::json!(8),
412 }]
413}
414
415#[cfg(test)]
416#[path = "../../unit_tests/models/misc/minimum_code_generation_one_register.rs"]
417mod tests;