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 category: crate::registry::ProblemCategory::Misc,
19 module_path: module_path!(),
20 description: "Find an ordering of parallel assignments minimizing backward dependencies",
21 fields: &[
22 FieldInfo { name: "num_variables", type_name: "usize", description: "Number of variables" },
23 FieldInfo { name: "assignments", type_name: "Vec<(usize, Vec<usize>)>", description: "Each assignment (target_var, read_vars)" },
24 ],
25 }
26}
27
28#[derive(Debug, Clone, Serialize, Deserialize)]
59pub struct MinimumCodeGenerationParallelAssignments {
60 num_variables: usize,
61 assignments: Vec<(usize, Vec<usize>)>,
62}
63
64impl MinimumCodeGenerationParallelAssignments {
65 pub fn new(num_variables: usize, assignments: Vec<(usize, Vec<usize>)>) -> Self {
70 for (i, (target, reads)) in assignments.iter().enumerate() {
71 assert!(
72 *target < num_variables,
73 "assignment {i}: target variable {target} >= num_variables {num_variables}"
74 );
75 for &r in reads {
76 assert!(
77 r < num_variables,
78 "assignment {i}: read variable {r} >= num_variables {num_variables}"
79 );
80 }
81 }
82 Self {
83 num_variables,
84 assignments,
85 }
86 }
87
88 pub fn num_variables(&self) -> usize {
90 self.num_variables
91 }
92
93 pub fn num_assignments(&self) -> usize {
95 self.assignments.len()
96 }
97
98 pub fn assignments(&self) -> &[(usize, Vec<usize>)] {
100 &self.assignments
101 }
102}
103
104impl Problem for MinimumCodeGenerationParallelAssignments {
105 const NAME: &'static str = "MinimumCodeGenerationParallelAssignments";
106 type Solution = Vec<usize>;
107 type Value = Min<i64>;
108
109 crate::problem_parameters![
110 ("num_variables", num_variables),
111 ("num_assignments", num_assignments),
112 ];
113
114 fn variant() -> Vec<(&'static str, &'static str)> {
115 crate::variant_params![]
116 }
117
118 fn evaluate(
119 &self,
120 config: &Self::Solution,
121 ) -> Result<Min<i64>, crate::traits::EvaluationError> {
122 Ok({
123 let m = self.num_assignments();
124
125 if config.len() != m {
127 return Err(crate::traits::EvaluationError::InvalidConfiguration(
128 "assignment length does not match the internal nodes".into(),
129 ));
130 }
131
132 if config.iter().any(|&position| position >= m) {
133 return Err(crate::traits::EvaluationError::InvalidConfiguration(
134 "assignment contains an out-of-range execution position".into(),
135 ));
136 }
137
138 let mut seen = vec![false; m];
140 for &pos in config {
141 if seen[pos] {
142 return Ok(Min(None));
143 }
144 seen[pos] = true;
145 }
146
147 let mut order = vec![0usize; m];
150 for (assignment_idx, &pos) in config.iter().enumerate() {
151 order[pos] = assignment_idx;
152 }
153
154 let mut count = 0usize;
158 for (i, &earlier) in order.iter().enumerate() {
159 let (target_var, _) = &self.assignments[earlier];
160 for &later in &order[(i + 1)..] {
161 let (_, read_vars) = &self.assignments[later];
162 if read_vars.contains(target_var) {
163 count += 1;
164 }
165 }
166 }
167
168 Min(Some(i64::try_from(count).map_err(|_| {
169 crate::traits::EvaluationError::IntegerOverflow(
170 "converting parallel instruction count to i64".into(),
171 )
172 })?))
173 })
174 }
175}
176
177impl crate::solvers::BruteForceProblem for MinimumCodeGenerationParallelAssignments {
178 fn dimensions(&self) -> Vec<usize> {
179 let m = self.num_assignments();
180 vec![m; m]
181 }
182}
183
184crate::declare_variants! {
185 default MinimumCodeGenerationParallelAssignments => "2^num_assignments",
186}
187
188crate::register_brute_force! {
189 MinimumCodeGenerationParallelAssignments,
190}
191
192#[cfg(feature = "example-db")]
193pub(crate) fn canonical_model_example_specs() -> Vec<crate::example_db::specs::ModelExampleSpec> {
194 let assignments = vec![(0, vec![1, 2]), (1, vec![0]), (2, vec![3]), (3, vec![1, 2])];
207 vec![crate::example_db::specs::ModelExampleSpec {
208 id: "minimum_code_generation_parallel_assignments",
209 instance: Box::new(MinimumCodeGenerationParallelAssignments::new(
210 4,
211 assignments,
212 )),
213 optimal_config: serde_json::json!(vec![0, 3, 1, 2]),
214 optimal_value: serde_json::json!(2),
215 }]
216}
217
218#[cfg(test)]
219#[path = "../../unit_tests/models/misc/minimum_code_generation_parallel_assignments.rs"]
220mod tests;