problemreductions/models/misc/
feasible_register_assignment.rs1use crate::registry::{FieldInfo, ProblemSchemaEntry};
9use crate::traits::Problem;
10use serde::{Deserialize, Deserializer, Serialize};
11
12inventory::submit! {
13 ProblemSchemaEntry {
14 name: "FeasibleRegisterAssignment",
15 display_name: "Feasible Register Assignment",
16 aliases: &[],
17 dimensions: &[],
18 module_path: module_path!(),
19 description: "Determine whether a DAG computation can be scheduled without register conflicts under a fixed assignment",
20 fields: &[
21 FieldInfo { name: "num_vertices", type_name: "usize", description: "Number of vertices n = |V|" },
22 FieldInfo { name: "arcs", type_name: "Vec<(usize, usize)>", description: "Directed arcs (v, u) meaning v depends on u" },
23 FieldInfo { name: "num_registers", type_name: "usize", description: "Number of registers K" },
24 FieldInfo { name: "assignment", type_name: "Vec<usize>", description: "Register assignment f(v) for each vertex" },
25 ],
26 }
27}
28
29#[derive(Debug, Clone, Serialize)]
61pub struct FeasibleRegisterAssignment {
62 num_vertices: usize,
64 arcs: Vec<(usize, usize)>,
66 num_registers: usize,
68 assignment: Vec<usize>,
70 #[serde(skip)]
72 dependencies: Vec<Vec<usize>>,
73 #[serde(skip)]
75 dependents: Vec<Vec<usize>>,
76}
77
78#[derive(Deserialize)]
79struct FeasibleRegisterAssignmentData {
80 num_vertices: usize,
81 arcs: Vec<(usize, usize)>,
82 num_registers: usize,
83 assignment: Vec<usize>,
84}
85
86impl<'de> Deserialize<'de> for FeasibleRegisterAssignment {
87 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
88 where
89 D: Deserializer<'de>,
90 {
91 let data = FeasibleRegisterAssignmentData::deserialize(deserializer)?;
92 let (dependencies, dependents) = Self::build_adjacency(data.num_vertices, &data.arcs);
93 Ok(Self {
94 num_vertices: data.num_vertices,
95 arcs: data.arcs,
96 num_registers: data.num_registers,
97 assignment: data.assignment,
98 dependencies,
99 dependents,
100 })
101 }
102}
103
104impl FeasibleRegisterAssignment {
105 pub fn new(
113 num_vertices: usize,
114 arcs: Vec<(usize, usize)>,
115 num_registers: usize,
116 assignment: Vec<usize>,
117 ) -> Self {
118 for &(v, u) in &arcs {
119 assert!(
120 v < num_vertices && u < num_vertices,
121 "Arc ({}, {}) out of bounds for {} vertices",
122 v,
123 u,
124 num_vertices
125 );
126 assert!(v != u, "Self-loop ({}, {}) not allowed in a DAG", v, u);
127 }
128 assert_eq!(
129 assignment.len(),
130 num_vertices,
131 "Assignment length {} does not match num_vertices {}",
132 assignment.len(),
133 num_vertices
134 );
135 if num_vertices > 0 {
136 assert!(
137 num_registers > 0,
138 "num_registers must be positive when there are vertices"
139 );
140 }
141 for (v, &r) in assignment.iter().enumerate() {
142 assert!(
143 r < num_registers,
144 "Assignment[{}] = {} is out of bounds for {} registers",
145 v,
146 r,
147 num_registers
148 );
149 }
150 let (dependencies, dependents) = Self::build_adjacency(num_vertices, &arcs);
151 Self {
152 num_vertices,
153 arcs,
154 num_registers,
155 assignment,
156 dependencies,
157 dependents,
158 }
159 }
160
161 fn build_adjacency(
163 num_vertices: usize,
164 arcs: &[(usize, usize)],
165 ) -> (Vec<Vec<usize>>, Vec<Vec<usize>>) {
166 let mut dependencies = vec![vec![]; num_vertices];
167 let mut dependents = vec![vec![]; num_vertices];
168 for &(v, u) in arcs {
169 dependencies[v].push(u);
170 dependents[u].push(v);
171 }
172 (dependencies, dependents)
173 }
174
175 pub fn num_vertices(&self) -> usize {
177 self.num_vertices
178 }
179
180 pub fn num_arcs(&self) -> usize {
182 self.arcs.len()
183 }
184
185 pub fn num_registers(&self) -> usize {
187 self.num_registers
188 }
189
190 pub fn num_same_register_pairs(&self) -> usize {
192 let mut counts = vec![0usize; self.num_registers];
193 for ®ister in &self.assignment {
194 counts[register] += 1;
195 }
196 counts
197 .into_iter()
198 .map(|count| count.saturating_sub(1) * count / 2)
199 .sum()
200 }
201
202 pub fn arcs(&self) -> &[(usize, usize)] {
204 &self.arcs
205 }
206
207 pub fn assignment(&self) -> &[usize] {
209 &self.assignment
210 }
211
212 pub fn is_feasible(&self, config: &[usize]) -> bool {
217 let n = self.num_vertices;
218 if config.len() != n {
219 return false;
220 }
221
222 let mut order = vec![0usize; n]; let mut used = vec![false; n];
225 for (vertex, &position) in config.iter().enumerate() {
226 if position >= n {
227 return false;
228 }
229 if used[position] {
230 return false;
231 }
232 used[position] = true;
233 order[position] = vertex;
234 }
235
236 let mut computed = vec![false; n];
238
239 for step in 0..n {
240 let vertex = order[step];
241
242 for &dep in &self.dependencies[vertex] {
244 if !computed[dep] {
245 return false;
246 }
247 }
248
249 let reg = self.assignment[vertex];
252 for &w in &order[..step] {
253 if self.assignment[w] == reg {
254 let still_live = self.dependents[w]
255 .iter()
256 .any(|&d| d != vertex && !computed[d]);
257 if still_live {
258 return false;
259 }
260 }
261 }
262
263 computed[vertex] = true;
264 }
265
266 true
267 }
268}
269
270impl Problem for FeasibleRegisterAssignment {
271 const NAME: &'static str = "FeasibleRegisterAssignment";
272 type Value = crate::types::Or;
273
274 fn variant() -> Vec<(&'static str, &'static str)> {
275 crate::variant_params![]
276 }
277
278 fn dims(&self) -> Vec<usize> {
279 vec![self.num_vertices; self.num_vertices]
280 }
281
282 fn evaluate(&self, config: &[usize]) -> crate::types::Or {
283 crate::types::Or(self.is_feasible(config))
284 }
285}
286
287crate::declare_variants! {
288 default FeasibleRegisterAssignment => "factorial(num_vertices)",
289}
290
291#[cfg(feature = "example-db")]
292pub(crate) fn canonical_model_example_specs() -> Vec<crate::example_db::specs::ModelExampleSpec> {
293 vec![crate::example_db::specs::ModelExampleSpec {
294 id: "feasible_register_assignment",
295 instance: Box::new(FeasibleRegisterAssignment::new(
298 4,
299 vec![(0, 1), (0, 2), (1, 3)],
300 2,
301 vec![0, 1, 0, 0],
302 )),
303 optimal_config: vec![3, 1, 2, 0],
306 optimal_value: serde_json::json!(true),
307 }]
308}
309
310#[cfg(test)]
311#[path = "../../unit_tests/models/misc/feasible_register_assignment.rs"]
312mod tests;