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 module_path: module_path!(),
21 description: "Determine whether a relational schema has a candidate key not in a given set",
22 fields: &[
23 FieldInfo { name: "num_attributes", type_name: "usize", description: "Number of attributes in A" },
24 FieldInfo { name: "dependencies", type_name: "Vec<(Vec<usize>, Vec<usize>)>", description: "Functional dependencies F; each (lhs, rhs)" },
25 FieldInfo { name: "relation_attrs", type_name: "Vec<usize>", description: "Relation scheme attributes R ⊆ A" },
26 FieldInfo { name: "known_keys", type_name: "Vec<Vec<usize>>", description: "Known candidate keys K" },
27 ],
28 }
29}
30
31#[derive(Debug, Clone, Serialize, Deserialize)]
63pub struct AdditionalKey {
64 num_attributes: usize,
65 dependencies: Vec<(Vec<usize>, Vec<usize>)>,
66 relation_attrs: Vec<usize>,
67 known_keys: Vec<Vec<usize>>,
68}
69
70impl AdditionalKey {
71 pub fn new(
78 num_attributes: usize,
79 dependencies: Vec<(Vec<usize>, Vec<usize>)>,
80 relation_attrs: Vec<usize>,
81 known_keys: Vec<Vec<usize>>,
82 ) -> Self {
83 for &a in &relation_attrs {
85 assert!(
86 a < num_attributes,
87 "relation_attrs element {a} >= num_attributes {num_attributes}"
88 );
89 }
90 let mut sorted_ra = relation_attrs.clone();
92 sorted_ra.sort_unstable();
93 sorted_ra.dedup();
94 assert_eq!(
95 sorted_ra.len(),
96 relation_attrs.len(),
97 "relation_attrs contains duplicates"
98 );
99 for (lhs, rhs) in &dependencies {
100 for &a in lhs {
101 assert!(
102 a < num_attributes,
103 "dependency lhs attribute {a} >= num_attributes {num_attributes}"
104 );
105 }
106 for &a in rhs {
107 assert!(
108 a < num_attributes,
109 "dependency rhs attribute {a} >= num_attributes {num_attributes}"
110 );
111 }
112 }
113 for key in &known_keys {
114 for &a in key {
115 assert!(
116 a < num_attributes,
117 "known_keys attribute {a} >= num_attributes {num_attributes}"
118 );
119 }
120 }
121 let known_keys: Vec<Vec<usize>> = known_keys
123 .into_iter()
124 .map(|mut k| {
125 k.sort_unstable();
126 k
127 })
128 .collect();
129 Self {
130 num_attributes,
131 dependencies,
132 relation_attrs,
133 known_keys,
134 }
135 }
136
137 pub fn num_attributes(&self) -> usize {
139 self.num_attributes
140 }
141
142 pub fn num_dependencies(&self) -> usize {
144 self.dependencies.len()
145 }
146
147 pub fn num_relation_attrs(&self) -> usize {
149 self.relation_attrs.len()
150 }
151
152 pub fn num_known_keys(&self) -> usize {
154 self.known_keys.len()
155 }
156
157 pub fn dependencies(&self) -> &[(Vec<usize>, Vec<usize>)] {
159 &self.dependencies
160 }
161
162 pub fn relation_attrs(&self) -> &[usize] {
164 &self.relation_attrs
165 }
166
167 pub fn known_keys(&self) -> &[Vec<usize>] {
169 &self.known_keys
170 }
171
172 fn compute_closure(&self, attrs: &[bool]) -> Vec<bool> {
174 let mut closure = attrs.to_vec();
175 let mut changed = true;
176 while changed {
177 changed = false;
178 for (lhs, rhs) in &self.dependencies {
179 if lhs.iter().all(|&a| closure[a]) {
180 for &a in rhs {
181 if !closure[a] {
182 closure[a] = true;
183 changed = true;
184 }
185 }
186 }
187 }
188 }
189 closure
190 }
191}
192
193impl Problem for AdditionalKey {
194 const NAME: &'static str = "AdditionalKey";
195 type Value = crate::types::Or;
196
197 fn variant() -> Vec<(&'static str, &'static str)> {
198 crate::variant_params![]
199 }
200
201 fn dims(&self) -> Vec<usize> {
202 vec![2; self.relation_attrs.len()]
203 }
204
205 fn evaluate(&self, config: &[usize]) -> crate::types::Or {
206 crate::types::Or({
207 if config.len() != self.relation_attrs.len() {
209 return crate::types::Or(false);
210 }
211 if config.iter().any(|&v| v >= 2) {
213 return crate::types::Or(false);
214 }
215
216 let selected: Vec<usize> = config
218 .iter()
219 .enumerate()
220 .filter(|(_, &v)| v == 1)
221 .map(|(i, _)| self.relation_attrs[i])
222 .collect();
223
224 if selected.is_empty() {
226 return crate::types::Or(false);
227 }
228
229 let mut attr_set = vec![false; self.num_attributes];
231 for &a in &selected {
232 attr_set[a] = true;
233 }
234 let closure = self.compute_closure(&attr_set);
235
236 if !self.relation_attrs.iter().all(|&a| closure[a]) {
238 return crate::types::Or(false);
239 }
240
241 for &a in &selected {
243 let mut reduced = attr_set.clone();
244 reduced[a] = false;
245 let reduced_closure = self.compute_closure(&reduced);
246 if self.relation_attrs.iter().all(|&ra| reduced_closure[ra]) {
247 return crate::types::Or(false); }
249 }
250
251 let mut sorted_selected = selected;
253 sorted_selected.sort_unstable();
254 !self.known_keys.contains(&sorted_selected)
255 })
256 }
257}
258
259crate::declare_variants! {
260 default AdditionalKey => "2^num_relation_attrs * num_dependencies * num_attributes",
261}
262
263#[cfg(feature = "example-db")]
264pub(crate) fn canonical_model_example_specs() -> Vec<crate::example_db::specs::ModelExampleSpec> {
265 vec![crate::example_db::specs::ModelExampleSpec {
266 id: "additional_key",
267 instance: Box::new(AdditionalKey::new(
268 6,
269 vec![
270 (vec![0, 1], vec![2, 3]),
271 (vec![2, 3], vec![4, 5]),
272 (vec![4, 5], vec![0, 1]),
273 (vec![0, 2], vec![3]),
274 (vec![3, 5], vec![1]),
275 ],
276 vec![0, 1, 2, 3, 4, 5],
277 vec![vec![0, 1], vec![2, 3], vec![4, 5]],
278 )),
279 optimal_config: vec![1, 0, 1, 0, 0, 0],
280 optimal_value: serde_json::json!(true),
281 }]
282}
283
284#[cfg(test)]
285#[path = "../../unit_tests/models/misc/additional_key.rs"]
286mod tests;