diff --git a/btypes_primitives/src/main/rust_embedded/btypes/src/brelation.rs b/btypes_primitives/src/main/rust_embedded/btypes/src/brelation.rs index aea2a14208699d88dedcd816e2de115039b98e6a..82f5b199b0fb84008330a25b81c7d9a7b696d63f 100644 --- a/btypes_primitives/src/main/rust_embedded/btypes/src/brelation.rs +++ b/btypes_primitives/src/main/rust_embedded/btypes/src/brelation.rs @@ -1,6 +1,7 @@ #![ allow( non_snake_case) ] use core::marker::PhantomData; +use crate::bboolean::BBoolean; use crate::binteger::BInteger; use crate::bset::{BSet, PowSetItem, Set, SetItem}; @@ -24,9 +25,9 @@ pub trait RelLeftItem<const LEFT_SIZE: usize, RightItem: SetItem<RIGHT_SIZE>, co fn rel_to_idx(rel_arr: [[bool; RIGHT_SIZE]; LEFT_SIZE]) -> usize { let mut flat_arr = [false; REL_SIZE]; - for left_idx in 0..6 { - for right_idx in 0..6 { - flat_arr[left_idx * 6 + right_idx] = rel_arr[left_idx][right_idx]; + for left_idx in 0..LEFT_SIZE { + for right_idx in 0..RIGHT_SIZE { + flat_arr[left_idx * RIGHT_SIZE + right_idx] = rel_arr[left_idx][right_idx]; } } return Self::RelEnum::arr_to_idx(flat_arr); @@ -37,7 +38,7 @@ pub trait RelLeftItem<const LEFT_SIZE: usize, RightItem: SetItem<RIGHT_SIZE>, co let mut result = [[false; RIGHT_SIZE]; LEFT_SIZE]; for left_idx in 0..LEFT_SIZE { for right_idx in 0..RIGHT_SIZE { - result[left_idx][right_idx] = flat_arr[left_idx * 6 + right_idx]; + result[left_idx][right_idx] = flat_arr[left_idx * RIGHT_SIZE + right_idx]; } } return result; @@ -56,6 +57,10 @@ where L: SetItem<LS> + RelLeftItem<LS, R, RS, SIZE, REL_SIZE>, } } +//impl<I> PowAble<> for I +//where I: SetItem<> +//TODO: pow/fin/pow1/fin1, maybe + impl<L, const LS: usize, R, const RS: usize, const REL_SIZE: usize> BRelation<L, LS, R, RS, REL_SIZE> where L: SetItem<LS>, R: SetItem<RS>{ @@ -95,16 +100,6 @@ impl<L, const LS: usize, R, const RS: usize, const REL_SIZE: usize> BRelation<L, BSet::const_from_arr(self.rel[key.as_idx()]) } - pub fn _union(&self, other: &Self) -> Self { - let mut result = self.copy(); - for left_idx in 0..LS { - for right_idx in 0..RS { - if other.rel[left_idx][right_idx] { result.rel[left_idx][right_idx] = true; } - } - } - return result; - } - pub fn card(&self) -> BInteger { let mut result: BInteger = 0; for left_idx in 0..LS { @@ -182,6 +177,17 @@ impl<L, const LS: usize, R, const RS: usize, const REL_SIZE: usize> BRelation<L, return BSet::const_from_arr(result); } + pub fn range(&self) -> BSet<R, RS> { + let mut result = [false; RS]; + for left_idx in 0..LS { + let current_arr = self.rel[left_idx]; + for right_idx in 0..RS { + result[right_idx] |= current_arr[right_idx]; + } + } + return BSet::const_from_arr(result); + } + pub fn cartesian_product<TL, TR>(left_set: &TL, right_set: &TR) -> Self where TL: Set<LS, ItemType = L>, TR: Set<RS, ItemType = R> { @@ -193,6 +199,153 @@ impl<L, const LS: usize, R, const RS: usize, const REL_SIZE: usize> BRelation<L, } return result; } + + pub fn inverse(&self) -> BRelation<R, RS, L, LS, REL_SIZE> { + let mut result = BRelation::<R, RS, L, LS, REL_SIZE>::empty(); + for left_idx in 0..LS { + for right_idx in 0..RS { + result.rel[right_idx][left_idx] = self.rel[left_idx][right_idx]; + } + } + return result; + } + + pub fn domainRestriction(&self, domain_set: &BSet<L, LS>) -> Self { + let mut result = self.copy(); + for left_idx in 0..LS { + if !domain_set.contains_idx(left_idx) { result.rel[left_idx] = [false; RS]; } + } + return result; + } + + pub fn domainSubstraction(&self, domain_set: &BSet<L, LS>) -> Self { + let mut result = self.copy(); + for left_idx in 0..LS { + if domain_set.contains_idx(left_idx) { result.rel[left_idx] = [false; RS]; } + } + return result; + } + + pub fn rangeRestriction(&self, range_set: &BSet<R, RS>) -> Self { + let mut result = self.copy(); + let range_arr = range_set.as_arr(); + for left_idx in 0..LS { + for right_idx in 0..RS { + //retain only elements that are in self *and* in range_set + result.rel[left_idx][right_idx] &= range_arr[right_idx]; + } + } + return result; + } + + pub fn rangeSubstraction(&self, range_set: &BSet<R, RS>) -> Self { + let mut result = self.copy(); + let range_arr = range_set.as_arr(); + for left_idx in 0..LS { + for right_idx in 0..RS { + //retain only elements that are in self *but not* in range_set + result.rel[left_idx][right_idx] &= !range_arr[right_idx]; + } + } + return result; + } + + pub fn relationImage(&self, result_domain: &BSet<L, LS>) -> BSet<R, RS> { + let mut result_arr = [false; RS]; + for left_idx in 0..LS { + if result_domain.contains_idx(left_idx) { + for right_idx in 0..RS { + result_arr[right_idx] |= self.rel[left_idx][right_idx]; + } + } + } + return BSet::<R, RS>::const_from_arr(result_arr); + } + + pub fn intersect(&self, other: &Self) -> Self { + return self.relation_combine(other, |s, o| s && o); + } + + pub fn difference(&self, other: &Self) -> Self { + return self.relation_combine(other, |s, o| s && !o); + } + + pub fn _union(&self, other: &Self) -> Self { + return self.relation_combine(other, |s, o| s | o); + } + + fn relation_combine(&self, other: &Self, combine_fn: fn(bool, bool) -> bool) -> Self { + let mut result = self.copy(); + for left_idx in 0..LS { + for right_idx in 0..RS { + result.rel[left_idx][right_idx] = combine_fn(result.rel[left_idx][right_idx], other.rel[left_idx][right_idx]); + } + } + return result; + } + + pub fn equal(&self, other: &Self) -> BBoolean { + return self.rel.eq(&other.rel); + } + + pub fn unequal(&self, other: &Self) -> BBoolean { + return !self.rel.eq(&other.rel); + } + + pub fn elementOf(&self, (k, v): (L, R)) -> BBoolean { + return self.rel[k.as_idx()][v.as_idx()]; + } + + pub fn noElementOf(&self, (k, v): (L, R)) -> BBoolean { + return !self.rel[k.as_idx()][v.as_idx()]; + } + + pub fn subset(&self, other: &Self) -> BBoolean { + for left_idx in 0..LS { + for right_idx in 0..RS { + if other.rel[left_idx][right_idx] && !self.rel[left_idx][right_idx] { return false; } + } + } + return true; + } + + pub fn notSubset(&self, other: &Self) -> BBoolean { + return !self.subset(other); + } + + pub fn _override(&self, other: &Self) -> Self { + let mut result = self.copy(); + for left_idx in 0..LS { + if other.rel[left_idx].contains(&true) { result.rel[left_idx] = other.rel[left_idx]; } + } + return result; + } + + //TODO: directProduct/ParallelProduct maybe? + + //TODO: support const-params in template? maybe compiler can figure them out itself? + pub fn composition<NewR, const NewRS: usize, const ParamTotal: usize, const NewTotal: usize>(&self, arg: &BRelation<R, RS, NewR, NewRS, ParamTotal>) -> BRelation<L, LS, NewR, NewRS, NewTotal> + where NewR: SetItem<NewRS>{ + let mut result = BRelation::<L, LS, NewR, NewRS, NewTotal>::empty(); + for left_idx in 0..LS { + result.rel[left_idx] = arg.relationImage(&BSet::const_from_arr(self.rel[left_idx])).as_arr() + } + return result; + } + + //TODO: projection1/2 maybe? would need to impl SetItem for (L,R) and (R,L), might need adjustment in codegenerator? + // or we use the relation-item enums for the tuples as well... + + //TODO: support const-params in template? maybe compiler can figure them out itself? + pub fn fnc<NewR, const NewRS: usize, const newRelTotal: usize>(&self) -> BRelation<L, LS, NewR, NewRS, newRelTotal> + where NewR: Set<RS> + SetItem<NewRS>{ //BRelation<L, LS, BSet<R, RS>, NewRS, newRelTotal + //NewR::ItemType = R; not yet supported in rust, NewR: Set<RS, I = R> might be, but I'd need to rewrite the trait for that and the related code. For now, we assume the code-generator creates correct code (if it wouldn't the code probably wouldn't run anyway...) + let mut result = BRelation::<L, LS, NewR, NewRS, newRelTotal>::empty(); + for left_idx in 0..LS { + result.rel[left_idx][NewR::from_arr(self.rel[left_idx]).as_idx()] = true; + } + return result; + } } #[macro_export]