problemreductions/models/misc/
additional_key.rs1use crate::registry::{FieldInfo, ProblemSchemaEntry};
11use crate::traits::Problem;
12use serde::{Deserialize, Serialize};
13
14inventory::submit! {
15 ProblemSchemaEntry {
16 name: "AdditionalKey",
17 display_name: "Additional Key",
18 aliases: &[],
19 dimensions: &[],
20 category: crate::registry::ProblemCategory::Misc,
21 module_path: module_path!(),
22 description: "Determine whether a relational schema has a candidate key not in a given set",
23 fields: &[
24 FieldInfo { name: "num_attributes", type_name: "usize", description: "Number of attributes in A" },
25 FieldInfo { name: "dependencies", type_name: "Vec<(Vec<usize>, Vec<usize>)>", description: "Functional dependencies F; each (lhs, rhs)" },
26 FieldInfo { name: "relation_attrs", type_name: "Vec<usize>", description: "Relation scheme attributes R ⊆ A" },
27 FieldInfo { name: "known_keys", type_name: "Vec<Vec<usize>>", description: "Known candidate keys K" },
28 ],
29 }
30}
31
32#[derive(Debug, Clone, Serialize, Deserialize)]
64#[serde(try_from = "AdditionalKeyData")]
65pub struct AdditionalKey {
66 num_attributes: usize,
67 dependencies: Vec<(Vec<usize>, Vec<usize>)>,
68 relation_attrs: Vec<usize>,
69 known_keys: Vec<Vec<usize>>,
70}
71
72#[derive(Deserialize)]
73struct AdditionalKeyData {
74 num_attributes: usize,
75 dependencies: Vec<(Vec<usize>, Vec<usize>)>,
76 relation_attrs: Vec<usize>,
77 known_keys: Vec<Vec<usize>>,
78}
79
80impl TryFrom<AdditionalKeyData> for AdditionalKey {
81 type Error = crate::registry::ConstructionError;
82 fn try_from(data: AdditionalKeyData) -> Result<Self, Self::Error> {
83 Self::try_new(
84 data.num_attributes,
85 data.dependencies,
86 data.relation_attrs,
87 data.known_keys,
88 )
89 }
90}
91
92impl AdditionalKey {
93 pub fn new(
100 num_attributes: usize,
101 dependencies: Vec<(Vec<usize>, Vec<usize>)>,
102 relation_attrs: Vec<usize>,
103 known_keys: Vec<Vec<usize>>,
104 ) -> Self {
105 Self::try_new(num_attributes, dependencies, relation_attrs, known_keys)
106 .unwrap_or_else(|error| panic!("{error}"))
107 }
108
109 fn try_new(
110 num_attributes: usize,
111 dependencies: Vec<(Vec<usize>, Vec<usize>)>,
112 relation_attrs: Vec<usize>,
113 known_keys: Vec<Vec<usize>>,
114 ) -> Result<Self, crate::registry::ConstructionError> {
115 for &a in &relation_attrs {
117 if a >= num_attributes {
118 return Err(format!(
119 "relation_attrs element {a} >= num_attributes {num_attributes}"
120 )
121 .into());
122 }
123 }
124 let mut sorted_ra = relation_attrs.clone();
126 sorted_ra.sort_unstable();
127 sorted_ra.dedup();
128 if sorted_ra.len() != relation_attrs.len() {
129 return Err("relation_attrs contains duplicates".into());
130 }
131 for (lhs, rhs) in &dependencies {
132 for &a in lhs {
133 if a >= num_attributes {
134 return Err(format!(
135 "dependency lhs attribute {a} >= num_attributes {num_attributes}"
136 )
137 .into());
138 }
139 }
140 for &a in rhs {
141 if a >= num_attributes {
142 return Err(format!(
143 "dependency rhs attribute {a} >= num_attributes {num_attributes}"
144 )
145 .into());
146 }
147 }
148 }
149 for key in &known_keys {
150 for &a in key {
151 if a >= num_attributes {
152 return Err(format!(
153 "known_keys attribute {a} >= num_attributes {num_attributes}"
154 )
155 .into());
156 }
157 }
158 }
159 let known_keys: Vec<Vec<usize>> = known_keys
161 .into_iter()
162 .map(|mut k| {
163 k.sort_unstable();
164 k
165 })
166 .collect();
167 Ok(Self {
168 num_attributes,
169 dependencies,
170 relation_attrs,
171 known_keys,
172 })
173 }
174
175 pub fn num_attributes(&self) -> usize {
177 self.num_attributes
178 }
179
180 pub fn num_dependencies(&self) -> usize {
182 self.dependencies.len()
183 }
184
185 pub fn num_relation_attrs(&self) -> usize {
187 self.relation_attrs.len()
188 }
189
190 pub fn num_known_keys(&self) -> usize {
192 self.known_keys.len()
193 }
194
195 pub fn dependencies(&self) -> &[(Vec<usize>, Vec<usize>)] {
197 &self.dependencies
198 }
199
200 pub fn relation_attrs(&self) -> &[usize] {
202 &self.relation_attrs
203 }
204
205 pub fn known_keys(&self) -> &[Vec<usize>] {
207 &self.known_keys
208 }
209
210 fn compute_closure(&self, attrs: &[bool]) -> Vec<bool> {
212 let mut closure = attrs.to_vec();
213 let mut changed = true;
214 while changed {
215 changed = false;
216 for (lhs, rhs) in &self.dependencies {
217 if lhs.iter().all(|&a| closure[a]) {
218 for &a in rhs {
219 if !closure[a] {
220 closure[a] = true;
221 changed = true;
222 }
223 }
224 }
225 }
226 }
227 closure
228 }
229}
230
231impl Problem for AdditionalKey {
232 const NAME: &'static str = "AdditionalKey";
233 type Solution = Vec<bool>;
234 type Value = crate::types::Or;
235
236 crate::problem_parameters![
237 ("num_attributes", num_attributes),
238 ("num_dependencies", num_dependencies),
239 ("num_relation_attrs", num_relation_attrs),
240 ("num_known_keys", num_known_keys),
241 ];
242
243 fn variant() -> Vec<(&'static str, &'static str)> {
244 crate::variant_params![]
245 }
246
247 fn evaluate(
248 &self,
249 config: &Self::Solution,
250 ) -> Result<crate::types::Or, crate::traits::EvaluationError> {
251 Ok({
252 crate::types::Or({
253 if config.len() != self.relation_attrs.len() {
255 return Err(crate::traits::EvaluationError::InvalidConfiguration(
256 "attribute-selection length does not match the relation".into(),
257 ));
258 }
259 let selected: Vec<usize> = config
262 .iter()
263 .enumerate()
264 .filter(|(_, &v)| v)
265 .map(|(i, _)| self.relation_attrs[i])
266 .collect();
267
268 if selected.is_empty() {
270 return Ok(crate::types::Or(false));
271 }
272
273 let mut attr_set = vec![false; self.num_attributes];
275 for &a in &selected {
276 attr_set[a] = true;
277 }
278 let closure = self.compute_closure(&attr_set);
279
280 if !self.relation_attrs.iter().all(|&a| closure[a]) {
282 return Ok(crate::types::Or(false));
283 }
284
285 for &a in &selected {
287 let mut reduced = attr_set.clone();
288 reduced[a] = false;
289 let reduced_closure = self.compute_closure(&reduced);
290 if self.relation_attrs.iter().all(|&ra| reduced_closure[ra]) {
291 return Ok(crate::types::Or(false)); }
293 }
294
295 let mut sorted_selected = selected;
297 sorted_selected.sort_unstable();
298 !self.known_keys.contains(&sorted_selected)
299 })
300 })
301 }
302}
303
304impl crate::solvers::BruteForceProblem for AdditionalKey {
305 fn dimensions(&self) -> Vec<usize> {
306 vec![2; self.relation_attrs.len()]
307 }
308}
309
310crate::declare_variants! {
311 default AdditionalKey => "2^num_relation_attrs * num_dependencies * num_attributes",
312}
313
314crate::register_brute_force! {
315 AdditionalKey decode |_, indices: Vec<usize>| crate::config::config_to_bits(&indices),
316}
317
318#[cfg(feature = "example-db")]
319pub(crate) fn canonical_model_example_specs() -> Vec<crate::example_db::specs::ModelExampleSpec> {
320 vec![crate::example_db::specs::ModelExampleSpec {
321 id: "additional_key",
322 instance: Box::new(AdditionalKey::new(
323 6,
324 vec![
325 (vec![0, 1], vec![2, 3]),
326 (vec![2, 3], vec![4, 5]),
327 (vec![4, 5], vec![0, 1]),
328 (vec![0, 2], vec![3]),
329 (vec![3, 5], vec![1]),
330 ],
331 vec![0, 1, 2, 3, 4, 5],
332 vec![vec![0, 1], vec![2, 3], vec![4, 5]],
333 )),
334 optimal_config: serde_json::json!(vec![true, false, true, false, false, false]),
335 optimal_value: serde_json::json!(true),
336 }]
337}
338
339#[cfg(test)]
340#[path = "../../unit_tests/models/misc/additional_key.rs"]
341mod tests;