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)]
64pub struct AdditionalKey {
65 num_attributes: usize,
66 dependencies: Vec<(Vec<usize>, Vec<usize>)>,
67 relation_attrs: Vec<usize>,
68 known_keys: Vec<Vec<usize>>,
69}
70
71impl AdditionalKey {
72 pub fn new(
79 num_attributes: usize,
80 dependencies: Vec<(Vec<usize>, Vec<usize>)>,
81 relation_attrs: Vec<usize>,
82 known_keys: Vec<Vec<usize>>,
83 ) -> Self {
84 for &a in &relation_attrs {
86 assert!(
87 a < num_attributes,
88 "relation_attrs element {a} >= num_attributes {num_attributes}"
89 );
90 }
91 let mut sorted_ra = relation_attrs.clone();
93 sorted_ra.sort_unstable();
94 sorted_ra.dedup();
95 assert_eq!(
96 sorted_ra.len(),
97 relation_attrs.len(),
98 "relation_attrs contains duplicates"
99 );
100 for (lhs, rhs) in &dependencies {
101 for &a in lhs {
102 assert!(
103 a < num_attributes,
104 "dependency lhs attribute {a} >= num_attributes {num_attributes}"
105 );
106 }
107 for &a in rhs {
108 assert!(
109 a < num_attributes,
110 "dependency rhs attribute {a} >= num_attributes {num_attributes}"
111 );
112 }
113 }
114 for key in &known_keys {
115 for &a in key {
116 assert!(
117 a < num_attributes,
118 "known_keys attribute {a} >= num_attributes {num_attributes}"
119 );
120 }
121 }
122 let known_keys: Vec<Vec<usize>> = known_keys
124 .into_iter()
125 .map(|mut k| {
126 k.sort_unstable();
127 k
128 })
129 .collect();
130 Self {
131 num_attributes,
132 dependencies,
133 relation_attrs,
134 known_keys,
135 }
136 }
137
138 pub fn num_attributes(&self) -> usize {
140 self.num_attributes
141 }
142
143 pub fn num_dependencies(&self) -> usize {
145 self.dependencies.len()
146 }
147
148 pub fn num_relation_attrs(&self) -> usize {
150 self.relation_attrs.len()
151 }
152
153 pub fn num_known_keys(&self) -> usize {
155 self.known_keys.len()
156 }
157
158 pub fn dependencies(&self) -> &[(Vec<usize>, Vec<usize>)] {
160 &self.dependencies
161 }
162
163 pub fn relation_attrs(&self) -> &[usize] {
165 &self.relation_attrs
166 }
167
168 pub fn known_keys(&self) -> &[Vec<usize>] {
170 &self.known_keys
171 }
172
173 fn compute_closure(&self, attrs: &[bool]) -> Vec<bool> {
175 let mut closure = attrs.to_vec();
176 let mut changed = true;
177 while changed {
178 changed = false;
179 for (lhs, rhs) in &self.dependencies {
180 if lhs.iter().all(|&a| closure[a]) {
181 for &a in rhs {
182 if !closure[a] {
183 closure[a] = true;
184 changed = true;
185 }
186 }
187 }
188 }
189 }
190 closure
191 }
192}
193
194impl Problem for AdditionalKey {
195 const NAME: &'static str = "AdditionalKey";
196 type Solution = Vec<bool>;
197 type Value = crate::types::Or;
198
199 crate::problem_parameters![
200 ("num_attributes", num_attributes),
201 ("num_dependencies", num_dependencies),
202 ("num_relation_attrs", num_relation_attrs),
203 ("num_known_keys", num_known_keys),
204 ];
205
206 fn variant() -> Vec<(&'static str, &'static str)> {
207 crate::variant_params![]
208 }
209
210 fn evaluate(
211 &self,
212 config: &Self::Solution,
213 ) -> Result<crate::types::Or, crate::traits::EvaluationError> {
214 Ok({
215 crate::types::Or({
216 if config.len() != self.relation_attrs.len() {
218 return Err(crate::traits::EvaluationError::InvalidConfiguration(
219 "attribute-selection length does not match the relation".into(),
220 ));
221 }
222 let selected: Vec<usize> = config
225 .iter()
226 .enumerate()
227 .filter(|(_, &v)| v)
228 .map(|(i, _)| self.relation_attrs[i])
229 .collect();
230
231 if selected.is_empty() {
233 return Ok(crate::types::Or(false));
234 }
235
236 let mut attr_set = vec![false; self.num_attributes];
238 for &a in &selected {
239 attr_set[a] = true;
240 }
241 let closure = self.compute_closure(&attr_set);
242
243 if !self.relation_attrs.iter().all(|&a| closure[a]) {
245 return Ok(crate::types::Or(false));
246 }
247
248 for &a in &selected {
250 let mut reduced = attr_set.clone();
251 reduced[a] = false;
252 let reduced_closure = self.compute_closure(&reduced);
253 if self.relation_attrs.iter().all(|&ra| reduced_closure[ra]) {
254 return Ok(crate::types::Or(false)); }
256 }
257
258 let mut sorted_selected = selected;
260 sorted_selected.sort_unstable();
261 !self.known_keys.contains(&sorted_selected)
262 })
263 })
264 }
265}
266
267impl crate::solvers::BruteForceProblem for AdditionalKey {
268 fn dimensions(&self) -> Vec<usize> {
269 vec![2; self.relation_attrs.len()]
270 }
271}
272
273crate::declare_variants! {
274 default AdditionalKey => "2^num_relation_attrs * num_dependencies * num_attributes",
275}
276
277crate::register_brute_force! {
278 AdditionalKey decode |_, indices: Vec<usize>| crate::config::config_to_bits(&indices),
279}
280
281#[cfg(feature = "example-db")]
282pub(crate) fn canonical_model_example_specs() -> Vec<crate::example_db::specs::ModelExampleSpec> {
283 vec![crate::example_db::specs::ModelExampleSpec {
284 id: "additional_key",
285 instance: Box::new(AdditionalKey::new(
286 6,
287 vec![
288 (vec![0, 1], vec![2, 3]),
289 (vec![2, 3], vec![4, 5]),
290 (vec![4, 5], vec![0, 1]),
291 (vec![0, 2], vec![3]),
292 (vec![3, 5], vec![1]),
293 ],
294 vec![0, 1, 2, 3, 4, 5],
295 vec![vec![0, 1], vec![2, 3], vec![4, 5]],
296 )),
297 optimal_config: serde_json::json!(vec![true, false, true, false, false, false]),
298 optimal_value: serde_json::json!(true),
299 }]
300}
301
302#[cfg(test)]
303#[path = "../../unit_tests/models/misc/additional_key.rs"]
304mod tests;