use crate::models::CustomSet;
use crate::operations::basic_ops::SetOperations;
use std::hash::Hash;
pub struct AdvancedSetOperations;
impl AdvancedSetOperations {
pub fn cartesian_product<T: Eq + Hash + Clone, U: Eq + Hash + Clone>(
a: &CustomSet<T>,
b: &CustomSet<U>,
) -> CustomSet<(T, U)> {
if a.is_empty() || b.is_empty() {
return CustomSet::empty();
}
let mut pairs = Vec::new();
for element_a in a.iter() {
for element_b in b.iter() {
pairs.push((element_a.clone(), element_b.clone()));
}
}
CustomSet::new(pairs)
}
pub fn cartesian_product_n<T: Eq + Hash + Clone>(sets: Vec<CustomSet<T>>) -> CustomSet<Vec<T>> {
if sets.is_empty() || sets.iter().any(|s| s.is_empty()) {
return CustomSet::empty();
}
let mut result: Vec<Vec<T>> = vec![vec![]];
for set in sets {
let mut new_result = Vec::new();
for prefix in &result {
for element in set.iter() {
let mut new_tuple = prefix.clone();
new_tuple.push(element.clone());
new_result.push(new_tuple);
}
}
result = new_result;
}
CustomSet::new(result)
}
pub fn is_partition<T: Eq + Hash + Clone + std::fmt::Debug>(
partitions: &CustomSet<CustomSet<T>>,
original: &CustomSet<T>,
) -> bool {
for partition in partitions.iter() {
if partition.is_empty() {
return false;
}
}
let mut union_set = CustomSet::<T>::empty();
for partition in partitions.iter() {
union_set = SetOperations::union(&union_set, partition);
}
if !union_set.equals(original) {
return false;
}
let partition_list: Vec<_> = partitions.iter().collect();
for i in 0..partition_list.len() {
for j in (i + 1)..partition_list.len() {
if !partition_list[i].is_disjoint_from(partition_list[j]) {
return false;
}
}
}
true
}
pub fn inclusion_exclusion_2<T: Eq + Hash + Clone>(
a: &CustomSet<T>,
b: &CustomSet<T>,
) -> usize {
a.cardinality() + b.cardinality() - SetOperations::intersection(a, b).cardinality()
}
pub fn inclusion_exclusion_3<T: Eq + Hash + Clone>(
a: &CustomSet<T>,
b: &CustomSet<T>,
c: &CustomSet<T>,
) -> usize {
a.cardinality() + b.cardinality() + c.cardinality()
- SetOperations::intersection(a, b).cardinality()
- SetOperations::intersection(a, c).cardinality()
- SetOperations::intersection(b, c).cardinality()
+ SetOperations::intersection(&SetOperations::intersection(a, b), c).cardinality()
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_cartesian_product() {
let c = CustomSet::from(vec![1, 2, 3]);
let d = CustomSet::from(vec!['a', 'b']);
let result = AdvancedSetOperations::cartesian_product(&c, &d);
assert_eq!(result.cardinality(), 6);
assert!(result.contains(&(1, 'a')));
assert!(result.contains(&(3, 'b')));
}
#[test]
fn test_cartesian_product_empty() {
let a = CustomSet::from(vec![1, 2, 3]);
let empty = CustomSet::<char>::empty();
let result = AdvancedSetOperations::cartesian_product(&a, &empty);
assert!(result.is_empty());
}
#[test]
fn test_cartesian_product_n() {
let sets: Vec<CustomSet<i32>> =
vec![CustomSet::from(vec![1, 2]), CustomSet::from(vec![3, 4])];
let result = AdvancedSetOperations::cartesian_product_n(sets);
assert_eq!(result.cardinality(), 4, "Should have 2 × 2 = 4 tuples");
}
#[test]
fn test_is_partition_valid() {
let original = CustomSet::from(vec![1, 2, 3, 4, 5, 6, 7, 8]);
let partitions = CustomSet::from(vec![
CustomSet::from(vec![1]),
CustomSet::from(vec![2, 3, 4]),
CustomSet::from(vec![5, 6]),
CustomSet::from(vec![7, 8]),
]);
assert!(AdvancedSetOperations::is_partition(&partitions, &original));
}
#[test]
fn test_is_partition_invalid_overlap() {
let original = CustomSet::from(vec![1, 2, 3, 4]);
let partitions = CustomSet::from(vec![
CustomSet::from(vec![1, 2]),
CustomSet::from(vec![2, 3]), CustomSet::from(vec![4]),
]);
assert!(!AdvancedSetOperations::is_partition(&partitions, &original));
}
#[test]
fn test_inclusion_exclusion_2() {
let a = CustomSet::from(vec![1, 2, 3, 4, 5]);
let b = CustomSet::from(vec![4, 5, 6, 7, 8]);
let calculated = AdvancedSetOperations::inclusion_exclusion_2(&a, &b);
let actual = SetOperations::union(&a, &b).cardinality();
assert_eq!(calculated, actual);
assert_eq!(calculated, 8);
}
#[test]
fn test_inclusion_exclusion_3() {
let a = CustomSet::from(vec![1, 2, 3, 4]);
let b = CustomSet::from(vec![3, 4, 5, 6]);
let c = CustomSet::from(vec![5, 6, 7, 8]);
let calculated = AdvancedSetOperations::inclusion_exclusion_3(&a, &b, &c);
let actual = SetOperations::union(&SetOperations::union(&a, &b), &c).cardinality();
assert_eq!(calculated, actual);
}
#[test]
fn test_real_world_inclusion_exclusion() {
let universal = CustomSet::from((1..=100).collect::<Vec<_>>());
let div3 = CustomSet::from_predicate(universal.iter().cloned(), |x| x % 3 == 0);
let div5 = CustomSet::from_predicate(universal.iter().cloned(), |x| x % 5 == 0);
let count = AdvancedSetOperations::inclusion_exclusion_2(&div3, &div5);
assert_eq!(count, 47);
}
}