use std::fmt;
use fixedbitset::FixedBitSet;
use itertools::Itertools;
use crate::optimizer::property::Order;
#[derive(Debug, PartialEq, Eq, Clone, Default, Hash)]
pub struct FunctionalDependency {
from: FixedBitSet,
to: FixedBitSet,
}
impl fmt::Display for FunctionalDependency {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let from = self.from.ones().collect_vec();
let to = self.to.ones().collect_vec();
f.write_fmt(format_args!("{:?} --> {:?}", from, to))
}
}
impl FunctionalDependency {
pub fn new(from: FixedBitSet, to: FixedBitSet) -> Self {
assert_eq!(
from.len(),
to.len(),
"from and to should have the same length"
);
assert!(!to.is_clear(), "`to` should contains at least one element");
FunctionalDependency { from, to }
}
pub fn from(&self) -> &FixedBitSet {
&self.from
}
pub fn to(&self) -> &FixedBitSet {
&self.to
}
pub fn grow(&mut self, columns: usize) {
self.from.grow(columns);
self.to.grow(columns);
}
pub fn set_from(&mut self, column_index: usize, enabled: bool) {
self.from.set(column_index, enabled);
}
pub fn set_to(&mut self, column_index: usize, enabled: bool) {
self.to.set(column_index, enabled);
}
pub fn with_indices(column_cnt: usize, from: &[usize], to: &[usize]) -> Self {
let from = {
let mut tmp = FixedBitSet::with_capacity(column_cnt);
for &i in from {
tmp.set(i, true);
}
tmp
};
let to = {
let mut tmp = FixedBitSet::with_capacity(column_cnt);
for &i in to {
tmp.set(i, true);
}
tmp
};
FunctionalDependency { from, to }
}
fn with_key(column_cnt: usize, key_indices: &[usize]) -> Self {
let mut from = FixedBitSet::with_capacity(column_cnt);
for &idx in key_indices {
from.set(idx, true);
}
let mut to = from.clone();
to.toggle_range(0..to.len());
FunctionalDependency { from, to }
}
pub fn with_constant(column_cnt: usize, constant_indices: &[usize]) -> Self {
let mut to = FixedBitSet::with_capacity(column_cnt);
for &i in constant_indices {
to.set(i, true);
}
FunctionalDependency {
from: FixedBitSet::with_capacity(column_cnt),
to,
}
}
pub fn into_parts(self) -> (FixedBitSet, FixedBitSet) {
(self.from, self.to)
}
}
#[derive(Debug, PartialEq, Eq, Hash, Clone, Default)]
pub struct FunctionalDependencySet {
column_count: usize,
strict: Vec<FunctionalDependency>,
}
impl fmt::Display for FunctionalDependencySet {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.write_str("{")?;
self.strict.iter().format(", ").fmt(f)?;
f.write_str("}")
}
}
impl FunctionalDependencySet {
pub fn new(column_count: usize) -> Self {
Self {
strict: Vec::new(),
column_count,
}
}
pub fn with_key(column_cnt: usize, key_indices: &[usize]) -> Self {
let mut tmp = Self::new(column_cnt);
tmp.add_key(key_indices);
tmp
}
pub fn with_dependencies(
column_count: usize,
strict_dependencies: Vec<FunctionalDependency>,
) -> Self {
for i in &strict_dependencies {
assert_eq!(column_count, i.from().len())
}
Self {
strict: strict_dependencies,
column_count,
}
}
pub fn as_dependencies_mut(&mut self) -> &mut Vec<FunctionalDependency> {
&mut self.strict
}
pub fn as_dependencies(&self) -> &Vec<FunctionalDependency> {
&self.strict
}
pub fn into_dependencies(self) -> Vec<FunctionalDependency> {
self.strict
}
pub fn add_functional_dependency(&mut self, fd: FunctionalDependency) {
let FunctionalDependency { from, to } = fd;
assert_eq!(self.column_count, from.len());
if !to.is_clear() {
match self.strict.iter().position(|elem| elem.from == from) {
Some(idx) => self.strict[idx].to.union_with(&to),
None => self.strict.push(FunctionalDependency::new(from, to)),
}
}
}
pub fn add_key(&mut self, key_indices: &[usize]) {
self.add_functional_dependency(FunctionalDependency::with_key(
self.column_count,
key_indices,
));
}
pub fn add_constant_columns(&mut self, constant_columns: &[usize]) {
self.add_functional_dependency(FunctionalDependency::with_constant(
self.column_count,
constant_columns,
));
}
pub fn add_functional_dependency_by_column_indices(&mut self, from: &[usize], to: &[usize]) {
self.add_functional_dependency(FunctionalDependency::with_indices(
self.column_count,
from,
to,
))
}
fn get_closure(&self, columns: &FixedBitSet) -> FixedBitSet {
let mut closure = columns.clone();
let mut no_updates;
loop {
no_updates = true;
for FunctionalDependency { from, to } in &self.strict {
if from.is_subset(&closure) && !to.is_subset(&closure) {
closure.union_with(to);
no_updates = false;
}
}
if no_updates {
break;
}
}
closure
}
pub fn is_determined_by(&self, determinant: &FixedBitSet, dependant: &FixedBitSet) -> bool {
self.get_closure(determinant).is_superset(dependant)
}
fn is_key_inner(&self, columns: &FixedBitSet) -> bool {
let all_columns = {
let mut tmp = columns.clone();
tmp.set_range(.., true);
tmp
};
self.is_determined_by(columns, &all_columns)
}
pub fn is_key(&self, columns: &[usize]) -> bool {
let mut key_bitset = FixedBitSet::from_iter(columns.iter().copied());
key_bitset.grow(self.column_count);
self.is_key_inner(&key_bitset)
}
pub fn minimize_key(&self, key_indices: &[usize]) -> Vec<usize> {
let mut key_bitset = FixedBitSet::from_iter(key_indices.iter().copied());
key_bitset.grow(self.column_count);
let res = self.minimize_key_bitset(key_bitset);
res.ones().collect_vec()
}
fn minimize_key_bitset(&self, key: FixedBitSet) -> FixedBitSet {
assert!(
self.is_key_inner(&key),
"{:?} is not a key!",
key.ones().collect_vec()
);
let mut new_key = key.clone();
for i in key.ones() {
new_key.set(i, false);
if !self.is_key_inner(&new_key) {
new_key.set(i, true);
}
}
new_key
}
pub fn minimize_order_key(&self, order_key: Order, dist_key_indices: &[usize]) -> Order {
let dist_key_bitset = FixedBitSet::from_iter(dist_key_indices.iter().copied());
let order_key_indices = order_key
.column_orders
.iter()
.map(|o| o.column_index)
.collect();
let min_bitset = self.minimize_order_key_bitset(order_key_indices);
let order = order_key
.column_orders
.iter()
.filter(|o| {
min_bitset.contains(o.column_index) || dist_key_bitset.contains(o.column_index)
})
.cloned()
.collect_vec();
Order::new(order)
}
fn minimize_order_key_bitset(&self, order_key: Vec<usize>) -> FixedBitSet {
if order_key.is_empty() {
return FixedBitSet::new();
}
let mut prefix = FixedBitSet::with_capacity(self.column_count);
for i in order_key {
let mut next = FixedBitSet::with_capacity(self.column_count);
next.set(i, true);
if !self.is_determined_by(&prefix, &next) {
prefix.set(i, true);
}
}
prefix
}
}
#[cfg(test)]
mod tests {
use fixedbitset::FixedBitSet;
use itertools::Itertools;
use super::FunctionalDependencySet;
#[test]
fn test_minimize_key() {
let mut fd_set = FunctionalDependencySet::new(5);
fd_set.add_key(&[0, 2, 3, 4]);
fd_set.add_constant_columns(&[0]);
fd_set.add_functional_dependency_by_column_indices(&[1, 2], &[3]);
fd_set.add_functional_dependency_by_column_indices(&[0, 2], &[3]);
fd_set.add_functional_dependency_by_column_indices(&[3, 4], &[2]);
let key = fd_set.minimize_key(&[0, 2, 3, 4]);
assert_eq!(key, &[3, 4]);
}
#[test]
fn test_with_key() {
let fd = FunctionalDependencySet::with_key(4, &[1]);
let fd_inner = fd.into_dependencies();
assert_eq!(fd_inner.len(), 1);
let (from, to) = fd_inner[0].clone().into_parts();
assert_eq!(from.ones().collect_vec(), &[1]);
assert_eq!(to.ones().collect_vec(), &[0, 2, 3]);
}
#[test]
fn test_add_key() {
let mut fd = FunctionalDependencySet::new(4);
fd.add_key(&[1]);
let fd_inner = fd.into_dependencies();
assert_eq!(fd_inner.len(), 1);
let (from, to) = fd_inner[0].clone().into_parts();
assert_eq!(from.ones().collect_vec(), &[1]);
assert_eq!(to.ones().collect_vec(), &[0, 2, 3]);
}
#[test]
fn test_add_constant_columns() {
let mut fd = FunctionalDependencySet::new(4);
fd.add_constant_columns(&[1]);
let fd_inner = fd.into_dependencies();
assert_eq!(fd_inner.len(), 1);
let (from, to) = fd_inner[0].clone().into_parts();
assert!(from.ones().collect_vec().is_empty());
assert_eq!(to.ones().collect_vec(), &[1]);
}
#[test]
fn test_add_fd_by_indices() {
let mut fd = FunctionalDependencySet::new(4);
fd.add_functional_dependency_by_column_indices(&[1, 2], &[0]); let fd_inner = fd.into_dependencies();
assert_eq!(fd_inner.len(), 1);
let (from, to) = fd_inner[0].clone().into_parts();
assert_eq!(from.ones().collect_vec(), &[1, 2]);
assert_eq!(to.ones().collect_vec(), &[0]);
}
#[test]
fn test_determined_by() {
let mut fd = FunctionalDependencySet::new(5);
fd.add_functional_dependency_by_column_indices(&[1, 2], &[0]); fd.add_functional_dependency_by_column_indices(&[0, 1], &[3]); fd.add_functional_dependency_by_column_indices(&[3], &[4]); let from = FixedBitSet::from_iter([1usize, 2usize]);
let to = FixedBitSet::from_iter([4usize]);
assert!(fd.is_determined_by(&from, &to)); }
#[test]
fn test_minimize_order_by_prefix() {
let mut fd = FunctionalDependencySet::new(5);
fd.add_functional_dependency_by_column_indices(&[1, 2], &[0]); let order_key = vec![1usize, 2usize, 0usize];
let actual_key = fd.minimize_order_key_bitset(order_key);
let mut expected_key = FixedBitSet::with_capacity(5);
expected_key.set(1, true);
expected_key.set(2, true);
println!("{:b}", actual_key);
println!("{:b}", expected_key);
assert_eq!(actual_key, expected_key);
}
#[test]
fn test_minimize_order_by_tail_subset_prefix() {
let mut fd = FunctionalDependencySet::new(5);
fd.add_functional_dependency_by_column_indices(&[1, 2], &[0]); let order_key = vec![3usize, 1usize, 2usize, 0usize];
let actual_key = fd.minimize_order_key_bitset(order_key);
let mut expected_key = FixedBitSet::with_capacity(5);
expected_key.set(1, true);
expected_key.set(2, true);
expected_key.set(3, true);
println!("{:b}", actual_key);
println!("{:b}", expected_key);
assert_eq!(actual_key, expected_key);
}
#[test]
fn test_minimize_order_by_middle_subset_prefix() {
let mut fd = FunctionalDependencySet::new(5);
fd.add_functional_dependency_by_column_indices(&[1, 2], &[0]); let order_key = vec![3usize, 1usize, 2usize, 4usize, 0usize];
let actual_key = fd.minimize_order_key_bitset(order_key);
let mut expected_key = FixedBitSet::with_capacity(5);
expected_key.set(1, true);
expected_key.set(2, true);
expected_key.set(3, true);
expected_key.set(4, true);
println!("{:b}", actual_key);
println!("{:b}", expected_key);
assert_eq!(actual_key, expected_key);
}
#[test]
fn test_minimize_order_by_suffix_cant_prune_prefix() {
let mut fd = FunctionalDependencySet::new(5);
fd.add_functional_dependency_by_column_indices(&[1, 2], &[0]); let order_key = vec![0usize, 1usize, 2usize];
let actual_key = fd.minimize_order_key_bitset(order_key);
let mut expected_key = FixedBitSet::with_capacity(5);
expected_key.set(0, true);
expected_key.set(1, true);
expected_key.set(2, true);
println!("{:b}", actual_key);
println!("{:b}", expected_key);
assert_eq!(actual_key, expected_key);
}
#[test]
fn test_minimize_order_by_with_empty_key() {
let mut fd = FunctionalDependencySet::new(5);
fd.add_functional_dependency_by_column_indices(&[], &[0]); let order_key = vec![0];
let actual_key = fd.minimize_order_key_bitset(order_key);
let expected_key = FixedBitSet::with_capacity(5);
println!("{:b}", actual_key);
println!("{:b}", expected_key);
assert_eq!(actual_key, expected_key);
}
}