problemreductions/models/misc/
minimum_code_generation_parallel_assignments.rs1use crate::registry::{FieldInfo, ProblemSchemaEntry};
8use crate::traits::Problem;
9use crate::types::Min;
10use serde::{Deserialize, Serialize};
11
12inventory::submit! {
13 ProblemSchemaEntry {
14 name: "MinimumCodeGenerationParallelAssignments",
15 display_name: "Minimum Code Generation (Parallel Assignments)",
16 aliases: &[],
17 dimensions: &[],
18 module_path: module_path!(),
19 description: "Find an ordering of parallel assignments minimizing backward dependencies",
20 fields: &[
21 FieldInfo { name: "num_variables", type_name: "usize", description: "Number of variables" },
22 FieldInfo { name: "assignments", type_name: "Vec<(usize, Vec<usize>)>", description: "Each assignment (target_var, read_vars)" },
23 ],
24 }
25}
26
27#[derive(Debug, Clone, Serialize, Deserialize)]
58pub struct MinimumCodeGenerationParallelAssignments {
59 num_variables: usize,
60 assignments: Vec<(usize, Vec<usize>)>,
61}
62
63impl MinimumCodeGenerationParallelAssignments {
64 pub fn new(num_variables: usize, assignments: Vec<(usize, Vec<usize>)>) -> Self {
69 for (i, (target, reads)) in assignments.iter().enumerate() {
70 assert!(
71 *target < num_variables,
72 "assignment {i}: target variable {target} >= num_variables {num_variables}"
73 );
74 for &r in reads {
75 assert!(
76 r < num_variables,
77 "assignment {i}: read variable {r} >= num_variables {num_variables}"
78 );
79 }
80 }
81 Self {
82 num_variables,
83 assignments,
84 }
85 }
86
87 pub fn num_variables(&self) -> usize {
89 self.num_variables
90 }
91
92 pub fn num_assignments(&self) -> usize {
94 self.assignments.len()
95 }
96
97 pub fn assignments(&self) -> &[(usize, Vec<usize>)] {
99 &self.assignments
100 }
101}
102
103impl Problem for MinimumCodeGenerationParallelAssignments {
104 const NAME: &'static str = "MinimumCodeGenerationParallelAssignments";
105 type Value = Min<usize>;
106
107 fn variant() -> Vec<(&'static str, &'static str)> {
108 crate::variant_params![]
109 }
110
111 fn dims(&self) -> Vec<usize> {
112 let m = self.num_assignments();
113 vec![m; m]
114 }
115
116 fn evaluate(&self, config: &[usize]) -> Min<usize> {
117 let m = self.num_assignments();
118
119 if config.len() != m {
121 return Min(None);
122 }
123
124 let mut seen = vec![false; m];
126 for &pos in config {
127 if pos >= m || seen[pos] {
128 return Min(None);
129 }
130 seen[pos] = true;
131 }
132
133 let mut order = vec![0usize; m];
136 for (assignment_idx, &pos) in config.iter().enumerate() {
137 order[pos] = assignment_idx;
138 }
139
140 let mut count = 0usize;
144 for (i, &earlier) in order.iter().enumerate() {
145 let (target_var, _) = &self.assignments[earlier];
146 for &later in &order[(i + 1)..] {
147 let (_, read_vars) = &self.assignments[later];
148 if read_vars.contains(target_var) {
149 count += 1;
150 }
151 }
152 }
153
154 Min(Some(count))
155 }
156}
157
158crate::declare_variants! {
159 default MinimumCodeGenerationParallelAssignments => "2^num_assignments",
160}
161
162#[cfg(feature = "example-db")]
163pub(crate) fn canonical_model_example_specs() -> Vec<crate::example_db::specs::ModelExampleSpec> {
164 let assignments = vec![(0, vec![1, 2]), (1, vec![0]), (2, vec![3]), (3, vec![1, 2])];
177 vec![crate::example_db::specs::ModelExampleSpec {
178 id: "minimum_code_generation_parallel_assignments",
179 instance: Box::new(MinimumCodeGenerationParallelAssignments::new(
180 4,
181 assignments,
182 )),
183 optimal_config: vec![0, 3, 1, 2],
184 optimal_value: serde_json::json!(2),
185 }]
186}
187
188#[cfg(test)]
189#[path = "../../unit_tests/models/misc/minimum_code_generation_parallel_assignments.rs"]
190mod tests;