diff --git a/btypes_lazy/src/main/rust/btypes/Cargo.toml b/btypes_lazy/src/main/rust/btypes/Cargo.toml new file mode 100644 index 0000000000000000000000000000000000000000..f1c1a2a93fe25128e266521f7468465569ade379 --- /dev/null +++ b/btypes_lazy/src/main/rust/btypes/Cargo.toml @@ -0,0 +1,11 @@ +[package] +name = "btypes" +version = "0.1.0" +edition = "2018" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +rand = "0.8.3" +im = "15.0.0" +lazy_static = "1.4.0" \ No newline at end of file diff --git a/btypes_lazy/src/main/rust/btypes/src/bboolean.rs b/btypes_lazy/src/main/rust/btypes/src/bboolean.rs new file mode 100644 index 0000000000000000000000000000000000000000..b1188ebb86908343e28a29db304c0f18e0e8b531 --- /dev/null +++ b/btypes_lazy/src/main/rust/btypes/src/bboolean.rs @@ -0,0 +1,40 @@ +use crate::bobject::BObject; + +pub type BBoolean = bool; + +pub trait IntoBool { + #![allow(non_snake_case)] + fn booleanValue(&self) -> bool; +} + +pub trait BBooleanT: BObject + IntoBool + Copy { + fn new(val: bool) -> Self; + fn or(&self, other: &Self) -> Self; + fn xor(&self, other: &Self) -> Self; + fn and(&self, other: &Self) -> Self; + fn not(&self) -> Self; + fn implies(&self, other: &Self) -> Self; + fn equivalent(&self, other: &Self) -> Self; + fn equal(&self, other: &Self) -> Self; + fn unequal(&self, other: &Self) -> Self; +} + +impl IntoBool for bool { + fn booleanValue(&self) -> bool { + return *self; + } +} + +impl BObject for bool {} + +impl BBooleanT for bool { + fn new(val: bool) -> Self { val } + fn or(&self, other: &Self) -> Self { *self || *other } + fn xor(&self, other: &Self) -> Self { *self ^ *other } + fn and(&self, other: &Self) -> Self { *self && *other } + fn not(&self) -> Self { !*self } + fn implies(&self, other: &Self) -> Self { !*self || *other } + fn equivalent(&self, other: &Self) -> Self { *self == *other } + fn equal(&self, other: &Self) -> Self { *self == *other } + fn unequal(&self, other: &Self) -> Self { *self != *other } +} diff --git a/btypes_lazy/src/main/rust/btypes/src/binteger.rs b/btypes_lazy/src/main/rust/btypes/src/binteger.rs new file mode 100644 index 0000000000000000000000000000000000000000..e3e70874cc1fb28f3648ae9d3f66291047221c42 --- /dev/null +++ b/btypes_lazy/src/main/rust/btypes/src/binteger.rs @@ -0,0 +1,138 @@ +use std::convert::TryInto; +use crate::bboolean::{BBoolean, BBooleanT}; +use crate::bobject::BObject; + +use std::fmt; +use std::hash::Hash; + +pub trait BInt: BObject { fn get_binteger_value(&self) -> BInteger { panic!("get_integer_value not implemented!"); }} +pub trait FromBInt { fn from<T: BInt>(value: &T) -> Self; } + +#[derive(Default, Debug, Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)] +pub struct BInteger { + val: i64, +} + +impl BObject for BInteger {} +impl BInt for BInteger { + fn get_binteger_value(&self) -> BInteger { return *self; } +} + +impl FromBInt for BInteger { + fn from<T: BInt>(value: &T) -> Self { + return value.get_binteger_value(); + } +} + +impl BInteger { + #![allow(non_snake_case, dead_code)] + + pub const fn new(init: i64) -> BInteger { + return BInteger { + val: init, + } + } + + pub fn get_val(&self) -> i64 { return self.val; } + + pub fn compareTo(&self, o: &BInteger) -> i64 { + return self.val - o.val; + } + + pub fn lessEqual(&self, o: &BInteger) -> BBoolean { + return BBoolean::new(self.val <= o.val); + } + + pub fn greaterEqual(&self, o: &BInteger) -> BBoolean { + return BBoolean::new(self.val >= o.val); + } + + pub fn less(&self, o: &BInteger) -> BBoolean { + return BBoolean::new(self.val < o.val); + } + + pub fn greater(&self, o: &BInteger) -> BBoolean { + return BBoolean::new(self.val > o.val); + } + + pub fn equal(&self, o: &BInteger) -> BBoolean { + return BBoolean::new(self.val == o.val); + } + + pub fn unequal(&self, o: &BInteger) -> BBoolean { + return BBoolean::new(self.val != o.val); + } + + pub fn plus(&self, v: &BInteger) -> BInteger { + return BInteger::new(self.val + v.val); + } + + pub fn minus(&self, v: &BInteger) -> BInteger { + return BInteger::new(self.val - v.val); + } + + pub fn multiply(&self, v: &BInteger) -> BInteger { + return BInteger::new(self.val * v.val); + } + + pub fn power(&self, v: &BInteger) -> BInteger { + if v.val < 0 { panic!("Power with negative exponent!") } + let exp: u32 = v.val.unsigned_abs().try_into().unwrap(); + return BInteger::new(self.val.pow(exp)); + } + + pub fn divide(&self, v: &BInteger) -> BInteger { + return BInteger::new(self.val / v.val); + } + + pub fn modulo(&self, v: &BInteger) -> BInteger { + //return BInteger::new(self.val.rem_euclid(v.val)); + return BInteger::new(self.val % v.val); + } + + pub fn succ(&self) -> BInteger { + return BInteger::new(self.val + 1); + } + + pub fn pred(&self) -> BInteger { + return BInteger::new(self.val - 1); + } + + pub fn negative(&self) -> BInteger { + return BInteger::new(-self.val); + } + + pub fn positive(&self) -> BInteger { + return *self; + } + + pub fn isInteger(&self) -> BBoolean { + return BBoolean::new(true); + } + + pub fn isNotInteger(&self) -> BBoolean { + return BBoolean::new(false); + } + + pub fn isNatural(&self) -> BBoolean { + return BBoolean::new(self.val >= 0); + } + + pub fn isNotNatural(&self) -> BBoolean { + return BBoolean::new(self.val < 0); + } + + pub fn isNatural1(&self) -> BBoolean { + return BBoolean::new(self.val > 0); + } + + pub fn isNotNatural1(&self) -> BBoolean { + return BBoolean::new(self.val < 1); + } +} + +impl fmt::Display for BInteger { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "{}", self.val) + } +} \ No newline at end of file diff --git a/btypes_lazy/src/main/rust/btypes/src/bobject.rs b/btypes_lazy/src/main/rust/btypes/src/bobject.rs new file mode 100644 index 0000000000000000000000000000000000000000..a913ee366977ce5b49bbec8353c0e8363623e3cb --- /dev/null +++ b/btypes_lazy/src/main/rust/btypes/src/bobject.rs @@ -0,0 +1,8 @@ +use std::hash::Hash; +use std::clone::Clone; +use std::fmt::{Debug, Display}; +use crate::bboolean::{BBoolean, BBooleanT}; + +pub trait BObject: Eq + Hash + Ord + Clone + Display + Debug { + fn is_struct(&self) -> BBoolean { BBoolean::new(false) } +} \ No newline at end of file diff --git a/btypes_lazy/src/main/rust/btypes/src/brelation.rs b/btypes_lazy/src/main/rust/btypes/src/brelation.rs new file mode 100644 index 0000000000000000000000000000000000000000..d1eab3dffa1067b36e38952b53c5f77198e25e49 --- /dev/null +++ b/btypes_lazy/src/main/rust/btypes/src/brelation.rs @@ -0,0 +1,652 @@ +#![ allow( dead_code, non_snake_case) ] + +use std::collections::hash_map::DefaultHasher; +use std::collections::LinkedList; +use std::cell::RefCell; +use std::cmp::Ordering; +use crate::bobject::BObject; +use crate::binteger::{BInt, BInteger, FromBInt}; +use crate::btuple::BTuple; + +use std::fmt; +use std::hash::{Hash, Hasher}; +use std::convert::TryInto; +use rand::prelude::IteratorRandom; +use crate::orderedhashset::OrderedHashSet as OrdSet; //TODO try OrdMap instead +use im::OrdMap as HashMap; +use crate::bboolean::{BBoolean, BBooleanT}; +use crate::brelation::CombiningType::{DIFFERENCE, INTERSECTION, UNION}; +use crate::bset::{BSet, SetLike, TBSet}; +use crate::bstring::TBString; +use crate::bstruct::BStruct; + +enum CombiningType { + DIFFERENCE, + INTERSECTION, + UNION +} + +#[derive(Default, Debug, Eq, Clone)] +pub struct BRelation<L: BObject, R: BObject> { + map: HashMap<L, OrdSet<R>>, + hash_cache: RefCell<Option<u64>>, +} + +impl<L: BObject, R: BObject> PartialOrd for BRelation<L, R> { + fn partial_cmp(&self, other: &Self) -> Option<Ordering> { self.map.partial_cmp(&other.map) } + fn lt(&self, other: &Self) -> bool { self.map.lt(&other.map) } + fn le(&self, other: &Self) -> bool { self.map.le(&other.map) } + fn gt(&self, other: &Self) -> bool { self.map.gt(&other.map) } + fn ge(&self, other: &Self) -> bool { self.map.ge(&other.map) } +} + +impl<L: BObject, R: BObject> Ord for BRelation<L, R> { + fn cmp(&self, other: &Self) -> Ordering { self.map.cmp(&other.map) } + fn max(self, other: Self) -> Self { + match self.cmp(&other) { + Ordering::Less => other, + Ordering::Greater => self, + Ordering::Equal => other, + } + } + fn min(self, other: Self) -> Self { + match self.cmp(&other) { + Ordering::Less => self, + Ordering::Greater => other, + Ordering::Equal => self, + } + } + fn clamp(self, min: Self, max: Self) -> Self { + if self < min { + min + } else if self > max { + max + } else { + self + } + } +} + +//TODO: check if replacing cache with mutex works and does not impact permormance too much +unsafe impl<L: BObject, R: BObject> Sync for BRelation<L, R> {} + +impl<L: BObject, R: BObject> PartialEq for BRelation<L, R> { + fn eq(&self, other: &BRelation<L, R>) -> bool { + self.map.eq(&other.map) + } +} + +impl<L: BObject, R: BObject> Hash for BRelation<L, R> { + fn hash<H: Hasher>(self: &BRelation<L, R>, state: &mut H) { + let cache = self.hash_cache.clone().take(); + let hash: u64; + + if cache.is_none() { + let mut hasher = DefaultHasher::new(); + self.map.hash(&mut hasher); + /* + let mut kvs = self.map.iter().collect::<Vec<(&L, &OrdSet<R>)>>(); + kvs.sort_by(|(k1, _v1), (k2, _v2)| k1.cmp(k2)); + for (key, value) in kvs { + key.hash(&mut hasher); + value.iter().for_each(|v| v.hash(&mut hasher)); + } + */ + hash = hasher.finish(); + //println!("BRelation: cache miss"); + self.hash_cache.replace(Option::Some(hash)); + } else { + //println!("BRelation: cache hit"); + hash = cache.unwrap(); + } + hash.hash(state); + } +} + +pub trait TBRelation { + type Left: BObject; + type Right: BObject; + + fn get_as_brelation(&self) -> &BRelation<Self::Left, Self::Right>; + + fn isPartialInteger(&self) -> BBoolean { return BBoolean::new(false); } + fn checkDomainInteger(&self) -> BBoolean { return BBoolean::new(false); } + fn isPartialNatural(&self) -> BBoolean { return BBoolean::new(false); } + fn checkDomainNatural(&self) -> BBoolean { return BBoolean::new(false); } + fn isPartialNatural1(&self) -> BBoolean { return BBoolean::new(false); } + fn checkDomainNatural1(&self) -> BBoolean { return BBoolean::new(false); } + fn checkRangeInteger(&self) -> BBoolean { return BBoolean::new(false); } + fn checkRangeNatural(&self) -> BBoolean { return BBoolean::new(false); } + fn checkRangeNatural1(&self) -> BBoolean { return BBoolean::new(false); } + fn checkDomainString(&self) -> BBoolean { return BBoolean::new(false); } + fn isPartialString(&self) -> BBoolean { return BBoolean::new(false); } + fn checkRangeString(&self) -> BBoolean { return BBoolean::new(false); } + fn checkDomainStruct(&self) -> BBoolean { return BBoolean::new(false); } + fn isPartialStruct(&self) -> BBoolean { return BBoolean::new(false); } + fn checkRangeStruct(&self) -> BBoolean { return BBoolean::new(false); } +} + +impl<L: BObject, R: BObject> fmt::Display for BRelation<L, R> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let mut result = "{".to_owned(); + let mut first = true; + for (key, range) in self.map.iter() { + for value in range.iter() { + if !first { result = result + ", " } + else { first = false; } + result = result + &format!("({} |-> {})", key, value).to_string(); + } + } + result = result + "}"; + return write!(f, "{}", result); + } +} +impl<L: BObject, R: BObject> TBRelation for BRelation<L, R> { + type Left = L; + type Right = R; + fn get_as_brelation(&self) -> &BRelation<Self::Left, Self::Right> { self } +} +impl<L: BObject, R: BObject> BObject for BRelation<L, R> {} + +impl<L: 'static + BObject, R: 'static + BObject> BRelation<L, R> { + pub fn new(mut args: Vec<BTuple<L, R>>) -> BRelation<L,R> { + let mut ret: BRelation<L, R> = BRelation {map: HashMap::new(), hash_cache: RefCell::new(Option::None) }; + while !args.is_empty() { + let current_tuple = args.remove(0); + ret.insert(¤t_tuple); + } + return ret; + } + + pub fn fromSet(set: BSet<BTuple<L, R>>) -> BRelation<L, R> { + let mut ret: BRelation<L, R> = BRelation {map: HashMap::new(), hash_cache: RefCell::new(Option::None)}; + set.iter().for_each(|current_tuple| ret.insert(current_tuple)); + return ret; + } + + fn insert(&mut self, tuple: &BTuple<L, R>) { + let set = self.map.get(&tuple.projection1()); + let new_set: OrdSet<R>; + if set.is_some() { + new_set = set.unwrap().update(tuple.projection2()); + } else { + new_set = OrdSet::from(vec![tuple.projection2()]); + } + self.map.insert(tuple.projection1(), new_set); + self.hash_cache.replace(Option::None); + } + + fn update(&self, key: L, value: OrdSet<R>) -> Self { + BRelation{ map: self.map.update(key, value), hash_cache: RefCell::new(Option::None) } + } + + fn update_unit(&self, key: L, value: R) -> Self { + self.update(key, OrdSet::unit(value)) + } + + pub fn card(&self) -> BInteger { + return self.size(); + } + + pub fn size(&self) -> BInteger { + let mut size = 0; + for val in self.map.values() { + size += val.len(); + } + return BInteger::new(size.try_into().unwrap()); + } + + pub fn intersect(&self, relation: &BRelation<L, R>) -> BRelation<L, R> { + return self.relation_combine(relation, INTERSECTION) + } + + pub fn difference(&self, relation: &BRelation<L, R>) -> BRelation<L, R> { + return self.relation_combine(relation, DIFFERENCE); + } + + pub fn _union(&self, relation: &BRelation<L, R>) -> BRelation<L, R> { + return self.relation_combine(relation, UNION); + } + + fn relation_combine(&self, relation: &BRelation<L, R>, comb_type: CombiningType) -> BRelation<L, R> { + let other_map = &relation.map; + let other_domain: OrdSet<L> = OrdSet::from(relation.map.keys().cloned().collect::<Vec<L>>()); + let this_domain: OrdSet<L> = OrdSet::from(self.map.keys().cloned().collect::<Vec<L>>()); + let intersection_domain = this_domain.clone().intersection(other_domain.clone()); + let difference_domain = this_domain.relative_complement(other_domain.clone()); + + let loop1_set; + let loop2_set; + match comb_type { + CombiningType::DIFFERENCE => {loop1_set = difference_domain; loop2_set = intersection_domain;} + CombiningType::INTERSECTION => {loop1_set = intersection_domain; loop2_set = difference_domain;} + CombiningType::UNION => {loop1_set = other_domain; loop2_set = OrdSet::new();} + } + + let empty_map = OrdSet::new(); + let mut result_map = BRelation{map: self.map.clone(), hash_cache: RefCell::new(Option::None)}; + for domain_element in loop1_set { + let this_range_set = self.map.get(&domain_element).unwrap_or(&empty_map).clone(); + let other_range_set = other_map.get(&domain_element).unwrap_or(&empty_map).clone(); + let new_range_set; + match comb_type { + CombiningType::DIFFERENCE => {new_range_set = this_range_set.relative_complement(other_range_set);} + CombiningType::INTERSECTION => {new_range_set = this_range_set.intersection(other_range_set);} + CombiningType::UNION => {new_range_set = this_range_set.union(other_range_set);} + } + if new_range_set.is_empty() { + result_map.map.remove(&domain_element); + } else { + result_map.map.insert(domain_element, new_range_set); + } + } + + for domain_element in loop2_set { + result_map.map.remove(&domain_element); + } + + return result_map; + } + + pub fn equal(&self, o: &BRelation<L, R>) -> BBoolean { + return BBoolean::new(self.eq(o)); + } + + pub fn unequal(&self, o: &BRelation<L, R>) -> BBoolean { + return BBoolean::new(!self.eq(o)); + } + + pub fn elementOf(&self, element: &BTuple<L, R>) -> BBoolean { + let prj1 = element.projection1(); + let prj2 = element.projection2(); + return BBoolean::new(self.map.get(&prj1).unwrap_or(&OrdSet::new()).contains(&prj2)); + } + + pub fn notElementOf(&self, element: &BTuple<L, R>) -> BBoolean { + let prj1 = element.projection1(); + let prj2 = element.projection2(); + return BBoolean::new(!self.map.get(&prj1).unwrap_or(&OrdSet::new()).contains(&prj2)); + } + + pub fn relationImage(&self, domain: &BSet<L>) -> BSet<R> { + let result_set = OrdSet::unions(domain.iter().map(|e| self.map.get(&e).unwrap_or(&OrdSet::new()).clone()).into_iter()); + return BSet::fromOrdSet(result_set); + } + + pub fn functionCall(&self, arg: &L) -> R { + let range = self.map.get(arg); + if range.is_none() { + panic!("Argument is not in the domain of this relation"); + } + + return range.unwrap().iter().next().unwrap_or_else(|| panic!("Argument is not in the domain of this relation")).clone(); + } + + pub fn pow(&self) -> BSet<BRelation<L, R>> { return self._pow(true); } + pub fn fin(&self) -> BSet<BRelation<L, R>> { return self.pow(); } + pub fn pow1(&self) -> BSet<BRelation<L, R>> { return self._pow(false); } + pub fn fin1(&self) -> BSet<BRelation<L, R>> { return self.pow1(); } + + fn _pow(&self, with_empty_set: bool) -> BSet<BRelation<L, R>> { + let this_map = &self.map; + + let mut result: BSet<BRelation<L, R>> = BSet::new(vec![]); + let start: BRelation<L, R> = BRelation::new(vec![]); + let mut queue: LinkedList<BRelation<L, R>> = LinkedList::new(); + queue.push_back(start.clone()); + if with_empty_set { result = result._union(&BSet::<BRelation<L, R>>::new(vec![start])); } + while !queue.is_empty() { + let current_set = queue.pop_front().unwrap(); + + for domain_element in self.map.keys() { + let range_option = this_map.get(&domain_element); + if range_option.is_none() { break; } + let mut range = range_option.unwrap().clone(); + while !range.is_empty() { + let range_element = range.remove_min().unwrap(); + let next_relation = current_set._union(&BRelation::fromSet(BSet::new(vec![BTuple::new(domain_element.clone(), range_element)]))); + let previous_size = result.size(); + result = result._union(&BSet::new(vec![next_relation.clone()])); + if previous_size < result.size() { queue.push_back(next_relation) } + } + } + } + return result; + } + + pub fn domain(&self) -> BSet<L> { + let result_set: Vec<L> = self.map.iter().filter_map(|(k, v)| return if !v.is_empty() { Some(k.clone()) } else { None }).collect(); + return BSet::new(result_set); + } + + pub fn range(&self) -> BSet<R> { + if self.map.is_empty() { + return BSet::<R>::new(vec![]); + } else { + return BSet::fromOrdSet(self.map.values().cloned().reduce(|v1, v2| v1.union(v2)).unwrap()); + } + } + + pub fn inverse(&self) -> BRelation<R, L> { + if self.map.is_empty() { + return BRelation::new(vec![]); + } else { + return self.map.iter().fold(BRelation::<R, L>::new(vec![]), + |mut map, (k, v)| { + v.iter().for_each(|cv| map.insert(&BTuple::new(cv.clone(), k.clone()))); + return map + }); + } + } + + pub fn domainRestriction(&self, arg: &BSet<L>) -> BRelation<L, R> { + return self.domainSubstraction(&self.domain().difference(&arg)); + } + + pub fn domainSubstraction(&self, arg: &BSet<L>) -> BRelation<L, R> { + return BRelation {map: arg.iter().fold(self.map.clone(), |map, e| map.without(e)), hash_cache: RefCell::new(Option::None)} + } + + pub fn rangeRestriction(&self, arg: &BSet<R>) -> BRelation<L, R> { + //return self.rangeSubstraction(self.range().difference(arg)); + return self.map.iter().filter_map(|(key, value)| { + let resut_range = BSet::fromOrdSet(value.clone()).intersect(arg); + if resut_range.isEmpty() { Option::None } else { Option::Some((key, resut_range)) } + }).fold(BRelation::<L, R>::new(vec![]), |rel, (key, val)| rel.update(key.clone(), val.as_ord_set())); + } + + pub fn rangeSubstraction(&self, arg: &BSet<R>) -> BRelation<L, R> { + return self.map.iter().filter_map(|(key, value)| { + let resut_range = BSet::fromOrdSet(value.clone()).difference(arg); + if resut_range.isEmpty() { Option::None } else { Option::Some((key, resut_range)) } + }).fold(BRelation::<L, R>::new(vec![]), |rel, (key, val)| rel.update(key.clone(), val.as_ord_set())); + } + + pub fn subset(&self, arg: &BRelation<L, R>) -> BBoolean { + let emptySet = OrdSet::new(); + for (k, v) in self.map.clone() { + let arg_v = arg.map.get(&k).unwrap_or(&emptySet).clone(); + if !v.is_subset(arg_v) { return BBoolean::new(false) } + } + return BBoolean::new(true); + } + + pub fn notSubset(&self, arg: &BRelation<L, R>) -> BBoolean { + return self.subset(arg).not(); + } + + pub fn _override(&self, arg: &BRelation<L, R>) -> BRelation<L, R> { + return BRelation { map: arg.map.clone().union(self.map.clone()), hash_cache: RefCell::new(Option::None)} + } + + pub fn directProduct<ArgR: 'static + BObject>(&self, arg: &BRelation<L, ArgR>) -> BRelation<L, BTuple<R, ArgR>> { + self.map.iter() + .fold(BRelation::<L, BTuple<R, ArgR>>::new(vec![]), + |mut rel, (k, v)| { + let option = arg.map.get(k); + if option.is_some() { + rel.map.insert(k.clone(), BSet::<R>::cartesian::<R, ArgR>(v, option.unwrap())); + } + return rel; + }) + } + + pub fn parallelProduct<ArgL, ArgR>(&self, arg: &BRelation<ArgL, ArgR>) + -> BRelation<BTuple<L, ArgL>, BTuple<R, ArgR>> + where ArgL: 'static + BObject, + ArgR: 'static + BObject { + let mut result_relation: BRelation<BTuple<L, ArgL>, BTuple<R, ArgR>> = BRelation::new(vec![]); + for (this_key, this_range) in self.map.clone() { + for (that_key, that_range) in arg.map.clone() { + result_relation.map.insert(BTuple::new(this_key.clone(), that_key), + BSet::<R>::cartesian::<R, ArgR>(&this_range, &that_range)); + } + } + return result_relation; //TODO? + } + + pub fn composition<NewR: 'static + BObject>(&self, arg: &BRelation<R, NewR>) -> BRelation<L, NewR> { + let mut result_set: BRelation<L, NewR> = BRelation::new(vec![]); + let empty_set = OrdSet::<NewR>::new(); + for (this_key, this_range) in self.map.iter() { + let new_range = this_range.iter().fold(OrdSet::<NewR>::new(), + |set, element| set.union(arg.map.get(element).unwrap_or(&empty_set).clone())); + if !new_range.is_empty() { result_set.map.insert(this_key.clone(), new_range); } + } + return result_set; + } + + pub fn projection1(arg1: &BSet<L>, arg2: &BSet<R>) -> BRelation<BTuple<L,R>,L> { + return arg1.iter().fold(BRelation::new(vec![]), |rel, element1| + arg2.iter().cloned().fold(rel, |nrel, element2| + nrel.update_unit(BTuple::new(element1.clone(), element2), element1.clone()))); + } + + pub fn projection2(arg1: &BSet<L>, arg2: &BSet<R>) -> BRelation<BTuple<L,R>,R> { + return arg1.iter().fold(BRelation::new(vec![]), |rel, element1| + arg2.iter().cloned().fold(rel, |nrel, element2| + nrel.update_unit(BTuple::new(element1.clone(), element2.clone()), element2))); + } + + pub fn fnc(&self) -> BRelation<L, BSet<R>> { + return self.map.iter().fold(BRelation::new(vec![]), |rel, (key, range)| + rel.update_unit(key.clone(), BSet::fromOrdSet(range.clone()))) + } + + pub fn cartesianProduct(set_a: &BSet<L>, set_b: &BSet<R>) -> BRelation<L, R> { + // slightly inefficient due to double iteration + return BSet::<L>::cartesian::<L, R>(&set_a.as_ord_set(), &set_b.as_ord_set()).iter() + .fold(BRelation::new(vec![]), |mut rel, tuple| { rel.insert(tuple); return rel; }); + } + + pub fn nondeterminism(&self) -> BTuple<L, R> { + let mut rng = rand::thread_rng(); + let tuple = self.map.iter().choose(&mut rng).unwrap(); + return BTuple::new(tuple.0.clone(), tuple.1.iter().choose(&mut rng).unwrap().clone()); + } + + pub fn isTotal(&self, domain: &BSet<L>) -> BBoolean { return self.domain().equal(domain); } + pub fn isTotalInteger(&self) -> BBoolean { return BBoolean::new(false); } + pub fn isTotalNatural(&self) -> BBoolean { return BBoolean::new(false); } + pub fn isTotalNatural1(&self) -> BBoolean { return BBoolean::new(false); } + pub fn isTotalString(&self) -> BBoolean { return BBoolean::new(false); } + pub fn isTotalStruct(&self) -> BBoolean { return BBoolean::new(false); } + pub fn isPartial(&self, domain: &BSet<L>) -> BBoolean { return self.domain().subset(domain); } + pub fn checkDomain(&self, domain: &BSet<L>) -> BBoolean { return self.domain().subset(domain); } + pub fn checkRange(&self, range: &BSet<R>) -> BBoolean { return self.range().subset(range); } + + pub fn isRelation(&self) -> BBoolean { return BBoolean::new(true); } + + pub fn isFunction(&self) -> BBoolean { + return BBoolean::new(self.map.values().find(|set| set.len() > 1).is_none()); + } + + pub fn isSurjection(&self, range: &BSet<R>) -> BBoolean { return self.range().equal(range); } + pub fn isSurjectionInteger(&self) -> BBoolean { return BBoolean::new(false); } + pub fn isSurjectionNatural(&self) -> BBoolean { return BBoolean::new(false); } + pub fn isSurjectionNatural1(&self) -> BBoolean { return BBoolean::new(false); } + pub fn isSurjectionString(&self) -> BBoolean { return BBoolean::new(false); } + pub fn isSurjectionStruct(&self) -> BBoolean { return BBoolean::new(false); } + + pub fn isInjection(&self) -> BBoolean { + if self.map.is_empty() { return BBoolean::new(true); } + let mut ranges = self.map.values().cloned(); + let mut checked = ranges.next().unwrap(); + for to_check in ranges { + //current range "hits" and element that was already "hit" before + if !checked.clone().intersection(to_check.clone()).is_empty() { return BBoolean::new(false); } + checked = checked.union(to_check); + } + return BBoolean::new(true); + } + + pub fn isBijection(&self, range: &BSet<R>) -> BBoolean { return self.isSurjection(range).and(&self.isInjection()); } + pub fn isBijectionInteger(&self) -> BBoolean { return BBoolean::new(false); } + pub fn isBijectionNatural(&self) -> BBoolean { return BBoolean::new(false); } + pub fn isBijectionNatural1(&self) -> BBoolean { return BBoolean::new(false); } + pub fn isBijectionString(&self) -> BBoolean { return BBoolean::new(false); } + pub fn isBijectionStruct(&self) -> BBoolean { return BBoolean::new(false); } +} + + +impl<L: 'static + BObject> BRelation<L, L> { + pub fn identity(set: &BSet<L>) -> BRelation<L, L> { + return set.iter().fold(BRelation::<L, L>::new(vec![]), |rel, v| rel.update_unit(v.clone(), v.clone())); + } + + pub fn iterate(&self, n: &BInteger) -> BRelation<L, L> { + return (0..n.get_val()).fold(BRelation::identity(&self.domain()._union(&self.range())), + |rel, _| rel.composition(self)); + } + + pub fn closure(&self) -> BRelation<L, L> { + return self.closure_closure1(false); + } + + pub fn closure1(&self) -> BRelation<L, L> { + return self.closure_closure1(true); + } + + fn closure_closure1(&self, is_closure1: bool) -> BRelation<L, L> { + let mut result = if is_closure1 { BRelation::new(vec![]) } else { self.iterate(&BInteger::new(0)) }; + let mut current_iteration = self.iterate(&BInteger::new(1)); + let mut next_result = result._union(¤t_iteration); + while !result.eq(&next_result) { + result = next_result; + current_iteration = current_iteration.composition(self); + next_result = result._union(¤t_iteration); + } + return result; + } +} + +//sequence +impl<L, R> BRelation<L, R> +where L: 'static + BInt + FromBInt, + R: 'static + BObject { + //this actually works, ridiculous... + pub fn first(&self) -> R { + return self.functionCall(&L::from(&BInteger::new(1))); + } + + pub fn last(&self) -> R { + return self.functionCall(&L::from(&self.card())); + } + + pub fn reverse(&self) -> BRelation<L, R> { + let size = self.card().succ(); + return BRelation { + map: self.map.iter().fold(HashMap::<L, OrdSet<R>>::new(), + |result, (k, v)| + result.update(L::from(&size.minus(&k.get_binteger_value())), v.clone())), + hash_cache: RefCell::new(Option::None) + } + } + + pub fn front(&self) -> BRelation<L, R> { + return self.domainSubstraction(&BSet::new(vec![L::from(&self.card())])); + } + + pub fn tail(&self) -> BRelation<L, R> { + return self.drop(&BInteger::new(1)) + } + + pub fn take(&self, n: &BInteger) -> BRelation<L, R> { + return self.domainRestriction(&BSet::new((1..n.get_val()+1).map(|i| L::from(&BInteger::new(i))).collect())); + } + + pub fn drop(&self, n: &BInteger) -> BRelation<L, R> { + return BSet::<BInteger>::interval(&n.succ(), &self.card()).iter().map(|i| (L::from(&i.minus(n)), L::from(i))) + .fold(BRelation::<L, R>::new(vec![]), |rel, (i, i2)| rel.update(i, self.map.get(&i2).unwrap().clone())); + } + + pub fn concat(&self, arg: &BRelation<L,R>) -> BRelation<L, R> { + return arg.map.iter().fold(self.clone(), |rel, (k, v)| + rel.update(L::from(&k.get_binteger_value().plus(&self.card())), v.clone())); + } + + pub fn append(&self, arg: &R) -> BRelation<L, R> { + return self.update_unit(L::from(&self.card().succ()), arg.clone()); + } + + pub fn prepend(&self, arg: &R) -> BRelation<L, R> { + return self.map.iter().fold(self.clone(), |rel, (k, v)| + rel.update(L::from(&k.get_binteger_value().succ()), v.clone())) + .update_unit(L::from(&self.card().succ()), arg.clone()); + } + + pub fn isPartialInteger(&self) -> BBoolean { return BBoolean::new(true); } + pub fn checkDomainInteger(&self) -> BBoolean { return self.isPartialInteger(); } + pub fn isPartialNatural(&self) -> BBoolean { return self.domain().subsetOfNatural(); } + pub fn checkDomainNatural(&self) -> BBoolean { return self.isPartialNatural(); } + pub fn isPartialNatural1(&self) -> BBoolean { return self.domain().subsetOfNatural1(); } + pub fn checkDomainNatural1(&self) -> BBoolean { return self.isPartialNatural1(); } +} + +impl<L, R> BRelation<L, R> + where L: 'static + BInt + FromBInt, + R: 'static + BObject + TBRelation, + R::Left: 'static + BInt + FromBInt { + + pub fn conc(&self) -> BRelation<R::Left, R::Right> { + return self.map.values().map(|set| set.iter().next().unwrap().get_as_brelation()) + .fold(BRelation::<R::Left, R::Right>::new(vec![]), + |result, next| result.concat(next)); + } +} + +impl<L, R> BRelation<L, R> + where L: 'static + BObject, + R: 'static + BInt + FromBInt { + + pub fn checkRangeInteger(&self) -> BBoolean { return BBoolean::new(true); } + pub fn checkRangeNatural(&self) -> BBoolean { return self.range().subsetOfNatural(); } + pub fn checkRangeNatural1(&self) -> BBoolean { return self.range().subsetOfNatural1(); } +} + +impl<L, R> BRelation<L, R> +where L: 'static + BObject, + R: 'static + BObject + TBSet { + + pub fn rel(&self) -> BRelation<L, R::Item> { + return self.map.iter().fold(BRelation::<L, R::Item>::new(vec![]), |rel, (key, range)| + rel.update(key.clone(), range.iter().next().unwrap().as_ord_set())); + } + +} + +impl<L, R> BRelation<L, R> + where L: 'static + BObject + TBString, + R: 'static + BObject { + + pub fn checkDomainString(&self) -> BBoolean { return BBoolean::new(true); } + pub fn isPartialString(&self) -> BBoolean { return self.checkDomainString(); } +} + +impl<L, R> BRelation<L, R> + where L: 'static + BObject, + R: 'static + BObject + TBString { + + pub fn checkRangeString(&self) -> BBoolean { return BBoolean::new(true); } +} + +impl<L, R> BRelation<L, R> +where L: 'static + BObject + BStruct, + R: 'static + BObject { + + pub fn checkDomainStruct(&self) -> BBoolean { return BBoolean::new(true); } + pub fn isPartialStruct(&self) -> BBoolean { return self.checkDomainStruct(); } +} + +impl<L, R> BRelation<L, R> + where L: 'static + BObject, + R: 'static + BObject + BStruct { + + pub fn checkRangeStruct(&self) -> BBoolean { return BBoolean::new(true); } +} + +impl<L: 'static + BObject, R: 'static + BObject> SetLike for BRelation<L, R> { + fn get_empty() -> Self { BRelation::<L, R>::new(vec![]) } + fn _union(&self, other: &Self) -> Self { self._union(other) } + fn intersect(&self, other: &Self) -> Self { self.intersect(other) } +} \ No newline at end of file diff --git a/btypes_lazy/src/main/rust/btypes/src/bset.rs b/btypes_lazy/src/main/rust/btypes/src/bset.rs new file mode 100644 index 0000000000000000000000000000000000000000..b374eb142b63ca789ef1245823fde3f575ade86e --- /dev/null +++ b/btypes_lazy/src/main/rust/btypes/src/bset.rs @@ -0,0 +1,399 @@ +#![ allow( dead_code, non_snake_case) ] + +use crate::bboolean::{IntoBool, BBoolean, BBooleanT}; +use crate::binteger::{BInt, BInteger}; +use crate::bstring::BString; +use crate::bobject::BObject; +use crate::btuple::BTuple; +use crate::orderedhashset::OrderedHashSet as OrdSet; + +use std::any::TypeId; +use std::borrow::Borrow; +use std::convert::TryInto; +use im::ordset::Iter; +use std::hash::{Hash, Hasher}; +use std::collections::LinkedList; +use std::fmt; +use std::fmt::Debug; +use rand::Rng; +use crate::lazy_ops::set_ops::setops::{SetOp, SetOpTraits}; + +pub trait TBSet: BObject { + type Item: BObject; + + fn as_ord_set(&self) -> OrdSet<Self::Item>; + fn as_bset(&self) -> &BSet<Self::Item>; +} + +pub trait SetLike: BObject { + fn get_empty() -> Self; + fn _union(&self, other: &Self) -> Self; + fn intersect(&self, other: &Self) -> Self; +} + +#[derive(Default, Debug, PartialEq, Eq, PartialOrd, Ord, Clone)] +pub struct BSet<T: BObject> { + set: OrdSet<T>, + transformation: Option<Box<dyn SetOp<Item = T>>>, +} + +impl<T: BObject> SetOp for BSet<T> { + type Item = T; + + fn compute(&self, _: &BSet<Self::Item>) -> BSet<Self::Item> { + match self.transformation.borrow() { + Some(trans) => trans.compute(&self) , //todo save computation? + None => self.clone(), + } + } + + fn clone_box(&self) -> Box<dyn SetOp<Item=Self::Item>> { + todo!() + } +} + +impl<T: BObject> SetOpTraits for BSet<T> { + +} + +impl<I: BObject> Hash for BSet<I> { + fn hash<H: Hasher>(self: &BSet<I>, state: &mut H) { self.set.hash(state); } +} + +impl<T: BObject> BObject for BSet<T> {} + +impl<T: BObject> TBSet for BSet<T> { + type Item = T; + fn as_ord_set(&self) -> OrdSet<Self::Item> { self.set.clone() } + fn as_bset(&self) -> &BSet<Self::Item> { self } +} + +impl<T: BObject> fmt::Display for BSet<T> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let mut result = "{".to_owned(); + let mut first = true; + for e in self.set.iter() { + if !first { result = result + ", " } + else { first = false; } + result = result + &format!("{}", e).to_string(); + } + result = result + "}"; + return write!(f, "{}", result); + } +} + +impl<'a, T: 'static + BObject> IntoIterator for &'a BSet<T> +where + T: 'a + Ord, +{ + type Item = &'a T; + type IntoIter = im::ordset::Iter<'a, T>; + + fn into_iter(self) -> Self::IntoIter { + self.iter() + } +} + +//TODO: check if replacing cache with mutex works and does not impact permormance too much +unsafe impl<T: BObject> Sync for BSet<T> {} + +impl<T: 'static + BObject> BSet<T> { + + pub fn new(mut args: Vec<T>) -> BSet<T> { + let mut ret: BSet<T> = BSet { + set: OrdSet::new(), + transformation: Option::None + }; + while !args.is_empty() { + ret.set.insert(args.remove(0)); + } + return ret; + } + + pub fn fromOrdSet(set: OrdSet<T>) -> BSet<T> { + return BSet { set: set, transformation: Option::None }; + } + + + pub fn iter(&self) -> Iter<'_, T> { + return self.set.iter(); + } + + pub fn size(&self) -> usize { + return self.set.len(); + } + + pub fn isEmpty(&self) -> bool { + return self.set.is_empty(); + } + + pub fn contains(&self, o: &T) -> bool { + return self.set.contains(o); + } + + pub fn intersect(&self, set: &BSet<T>) -> BSet<T> { + return BSet{ set: self.set.clone().intersection(set.set.clone()), transformation: Option::None }; + } + + pub fn difference(&self, set: &BSet<T>) -> BSet<T> { + return BSet{ set: self.set.clone().relative_complement(set.set.clone()), transformation: Option::None }; + } + + pub fn _union(&self, set: &BSet<T>) -> BSet<T> { + return BSet{ set: self.set.clone().union(set.set.clone()), transformation: Option::None }; + } + + pub fn interval(a: &BInteger, b: &BInteger) -> BSet<BInteger> { + let mut result: BSet<BInteger> = BSet::new(vec![]); + for i in a.get_val()..b.get_val()+1 { + result.set.insert(BInteger::new(i)); + } + return result; + } + + pub fn card(&self) -> BInteger { + return self._size(); + } + + pub fn _size(&self) -> BInteger { + return BInteger::new(self.set.len().try_into().unwrap()); + } + + pub fn elementOf(&self, object: &T) -> BBoolean { + return BBoolean::new(self.contains(object)); + } + + pub fn notElementOf(&self, object: &T) -> BBoolean { + return BBoolean::new(!self.contains(object)); + } + + pub fn subset(&self, set: &BSet<T>) -> BBoolean { + return BBoolean::new(self.set.is_subset(&set.set)); + } + + pub fn notSubset(&self, set: &BSet<T>) -> BBoolean { + return BBoolean::new(!self.set.is_subset(&set.set)); + } + + pub fn strictSubset(&self, set: &BSet<T>) -> BBoolean { + return BBoolean::new(self.set.len() < set.set.len() && self.set.is_subset(&set.set)); + } + + pub fn strictNotSubset(&self, set: &BSet<T>) -> BBoolean { + return BBoolean::new(self.set.len() == set.set.len() || !self.set.is_subset(&set.set)); + } + + pub fn fin(&self) -> BSet<BSet<T>> { + return self.pow(); + } + + pub fn pow(&self) -> BSet<BSet<T>> { + return self._pow(true); + } + + pub fn fin1(&self) -> BSet<BSet<T>> { + return self.pow1(); + } + + pub fn pow1(&self) -> BSet<BSet<T>> { + return self._pow(false); + } + + fn _pow(&self, with_empty_set: bool) -> BSet<BSet<T>> { + let mut result: BSet<BSet<T>> = BSet::new(vec![]); + let start: BSet<T> = BSet::new(vec![]); + let mut queue: LinkedList<BSet<T>> = LinkedList::new(); + queue.push_back(start.clone()); + if with_empty_set { result = result._union(&BSet::new(vec![start])); } + + while !queue.is_empty() { + let current_set: BSet<T> = queue.pop_front().unwrap(); + for element in self.set.iter() { + let next_set: BSet<T> = current_set._union(&BSet::new(vec![element.clone()])); + let previous_size = result.size(); + result = result._union(&BSet::new(vec![next_set.clone()])); + if previous_size < result.size() { + queue.push_back(next_set); + } + } + } + + return result; + } + + pub fn nondeterminism(&self) -> T { + let mut rng = rand::thread_rng(); + return self.set.iter().nth(rng.gen_range(0..self.set.len())).unwrap().clone(); + } + + pub fn equal(&self, other: &BSet<T>) -> BBoolean { + return BBoolean::new(self.set.eq(&other.set)); + } + + pub fn unequal(&self, other: &BSet<T>) -> BBoolean { + return BBoolean::new(!self.set.eq(&other.set)); + } + + pub fn subsetOfInteger(&self) -> BBoolean { + return BBoolean::new(TypeId::of::<BInteger>() == TypeId::of::<T>()); + } + + pub fn strictSubsetOfInteger(&self) -> BBoolean { + return self.subsetOfInteger(); + } + + pub fn notSubsetOfInteger(&self) -> BBoolean { + return self.subsetOfInteger().not(); + } + + pub fn equalInteger(&self) -> BBoolean { + return BBoolean::new(false); + } + + pub fn unequalInteger(&self) -> BBoolean { + return BBoolean::new(true); + } + + pub fn equalNatural(&self) -> BBoolean { + return BBoolean::new(false); + } + + pub fn unequalNatural(&self) -> BBoolean { + return BBoolean::new(true); + } + + pub fn equalNatural1(&self) -> BBoolean { + return BBoolean::new(false); + } + + pub fn unequalNatural1(&self) -> BBoolean { + return BBoolean::new(true); + } + + pub fn equalString(&self) -> BBoolean { + return BBoolean::new(false); + } + + pub fn unequalString(&self) -> BBoolean { + return BBoolean::new(true); + } + + pub fn equalStruct(&self) -> BBoolean { + return BBoolean::new(false); + } + + pub fn unequalStruct(&self) -> BBoolean { + return BBoolean::new(true); + } + + pub fn subsetOfString(&self) -> BBoolean { + return BBoolean::new(TypeId::of::<BString>() == TypeId::of::<T>()); + } + + pub fn strictSubsetOfString(&self) -> BBoolean { + return self.subsetOfString(); + } + + pub fn notSubsetOfString(&self) -> BBoolean { + return self.subsetOfString().not(); + } + + pub fn notStrictSubsetOfString(&self) -> BBoolean { + return self.strictSubsetOfString().not(); + } + + pub fn subsetOfStruct(&self) -> BBoolean { + return self.is_struct(); + } + + pub fn strictsubsetOfStruct(&self) -> BBoolean { + return self.subsetOfStruct(); + } + + pub fn notsubsetOfStruct(&self) -> BBoolean { + return self.subsetOfStruct().not(); + } + + pub fn notStrictsubsetOfStruct(&self) -> BBoolean { + return self.strictsubsetOfStruct().not(); + } + + //rust specific + pub fn cartesian<T1: 'static + BObject, T2: 'static + BObject>(set_a: &OrdSet<T1>, set_b: &OrdSet<T2>) -> OrdSet<BTuple<T1, T2>> { + if set_a.is_empty() || set_b.is_empty() {return OrdSet::<BTuple<T1, T2>>::new();} + return set_a.iter() + .fold(OrdSet::<BTuple<T1, T2>>::new(), + |set, lhs| set_b.iter().cloned() + .fold(set, + |tset, rhs| tset.update(BTuple::new(lhs.clone(), rhs)))) + } +} + +impl<T: 'static + BInt> BSet<T> { + + pub fn notStrictSubsetOfInteger(&self) -> BBoolean { + return self.strictSubsetOfInteger().not(); + } + + pub fn subsetOfNatural(&self) -> BBoolean { + if self.subsetOfInteger().booleanValue() { + return BBoolean::new(self.set.iter().find(|i| i.get_binteger_value().isNotNatural().booleanValue()).is_none()); + } + return BBoolean::new(false); + } + + pub fn strictSubsetOfNatural(&self) -> BBoolean { + return self.subsetOfNatural(); + } + + pub fn notSubsetOfNatural(&self) -> BBoolean { + return self.subsetOfNatural().not(); + } + + pub fn notStrictSubsetOfNatural(&self) -> BBoolean { + return self.strictSubsetOfNatural().not(); + } + + pub fn subsetOfNatural1(&self) -> BBoolean { + if self.subsetOfInteger().booleanValue() { + return BBoolean::new(self.set.iter().find(|i| i.get_binteger_value().isNotNatural1().booleanValue()).is_none()); + } + return BBoolean::new(false); + } + + pub fn strictSubsetOfNatural1(&self) -> BBoolean { + return self.subsetOfNatural(); + } + + pub fn notSubsetOfNatural1(&self) -> BBoolean { + return self.subsetOfNatural1().not(); + } + + pub fn notStrictSubsetOfNatural1(&self) -> BBoolean { + return self.strictSubsetOfNatural1().not(); + } + + pub fn _min(self: &BSet<T>) -> BInteger { + return self.set.get_min().unwrap().get_binteger_value(); + } + + pub fn _max(self: &BSet<T>) -> BInteger { + return self.set.get_max().unwrap().get_binteger_value(); + } +} + +impl<T: 'static + BObject> SetLike for BSet<T> { + fn get_empty() -> Self { BSet::<T>::new(vec![]) } + fn _union(&self, other: &Self) -> Self { self._union(other) } + fn intersect(&self, other: &Self) -> Self { self.intersect(other) } +} + +impl<T: 'static + SetLike> BSet<T> { + pub fn unary__union(&self) -> T { + return self.iter().fold(T::get_empty(), |result, next| result._union(next)); + } + + pub fn unary_intersect(&self) -> T { + return self.iter().fold(T::get_empty(), |result, next| result.intersect(next)); + } +} \ No newline at end of file diff --git a/btypes_lazy/src/main/rust/btypes/src/bstring.rs b/btypes_lazy/src/main/rust/btypes/src/bstring.rs new file mode 100644 index 0000000000000000000000000000000000000000..e49302b41c87b2d8b511fd4bad1b10456db9e2e8 --- /dev/null +++ b/btypes_lazy/src/main/rust/btypes/src/bstring.rs @@ -0,0 +1,19 @@ +use std::fmt::{Display, Formatter}; +use crate::bobject::BObject; + +#[derive(Default, Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)] +pub struct BString { + val: String, +} + +pub trait TBString {} + +impl TBString for BString {} + +impl Display for BString { + fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { + write!(f, "{}", self.val) + } +} + +impl BObject for BString {} \ No newline at end of file diff --git a/btypes_lazy/src/main/rust/btypes/src/bstruct.rs b/btypes_lazy/src/main/rust/btypes/src/bstruct.rs new file mode 100644 index 0000000000000000000000000000000000000000..ca151047b3a4cf9c69f159a08cd1f9a00a7aa1a6 --- /dev/null +++ b/btypes_lazy/src/main/rust/btypes/src/bstruct.rs @@ -0,0 +1,6 @@ +use crate::bboolean::{BBoolean, BBooleanT}; +use crate::bobject::BObject; + +pub trait BStruct: BObject{ + fn is_struct(&self) -> BBoolean { BBoolean::new(true) } +} \ No newline at end of file diff --git a/btypes_lazy/src/main/rust/btypes/src/btuple.rs b/btypes_lazy/src/main/rust/btypes/src/btuple.rs new file mode 100644 index 0000000000000000000000000000000000000000..31779d4b33902a8e1a064477a9aca0159d74a9d7 --- /dev/null +++ b/btypes_lazy/src/main/rust/btypes/src/btuple.rs @@ -0,0 +1,35 @@ +use crate::bobject::BObject; +use std::fmt; + +#[derive(Default, Debug, Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)] +pub struct BTuple<L: BObject, R: BObject>{ + left_val: L, + right_val: R, +} + +impl<L: BObject, R: BObject> fmt::Display for BTuple<L, R> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + return write!(f, "({} |-> {})", self.left_val, self.right_val); + } +} + +impl<L: BObject, R:BObject> BObject for BTuple<L, R>{} + +impl<L: BObject, R: BObject> BTuple<L, R> { + pub fn new(left: L, right: R) -> BTuple<L, R> { + return BTuple {left_val: left, right_val: right,}; + } + + pub fn from_refs(left: &L, right: &R) -> BTuple<L, R> { + return BTuple {left_val: left.clone(), right_val: right.clone(),}; + } + + pub fn projection1(&self) -> L { + return self.left_val.clone(); + } + + pub fn projection2(&self) -> R { + return self.right_val.clone(); + } + +} diff --git a/btypes_lazy/src/main/rust/btypes/src/butils.rs b/btypes_lazy/src/main/rust/btypes/src/butils.rs new file mode 100644 index 0000000000000000000000000000000000000000..dc5e4835e4e5689e41450769c411309f7667f415 --- /dev/null +++ b/btypes_lazy/src/main/rust/btypes/src/butils.rs @@ -0,0 +1,6 @@ +use crate::bboolean::{BBoolean, BBooleanT}; +use crate::bset::BSet; + +lazy_static! { + pub static ref BOOL: BSet<BBoolean> = BSet::new(vec![BBoolean::new(true), BBoolean::new(false)]); +} \ No newline at end of file diff --git a/btypes_lazy/src/main/rust/btypes/src/lazy_ops/mod.rs b/btypes_lazy/src/main/rust/btypes/src/lazy_ops/mod.rs new file mode 100644 index 0000000000000000000000000000000000000000..032fa0acb3fa7131be974169637c97365c39e609 --- /dev/null +++ b/btypes_lazy/src/main/rust/btypes/src/lazy_ops/mod.rs @@ -0,0 +1 @@ +pub mod set_ops; \ No newline at end of file diff --git a/btypes_lazy/src/main/rust/btypes/src/lazy_ops/set_ops/mod.rs b/btypes_lazy/src/main/rust/btypes/src/lazy_ops/set_ops/mod.rs new file mode 100644 index 0000000000000000000000000000000000000000..c4442fe7273818eb198fbb935b45dd7847d8b3bb --- /dev/null +++ b/btypes_lazy/src/main/rust/btypes/src/lazy_ops/set_ops/mod.rs @@ -0,0 +1 @@ +pub mod setops; \ No newline at end of file diff --git a/btypes_lazy/src/main/rust/btypes/src/lazy_ops/set_ops/setops.rs b/btypes_lazy/src/main/rust/btypes/src/lazy_ops/set_ops/setops.rs new file mode 100644 index 0000000000000000000000000000000000000000..d72d55426bbe28e297419037cdbc87f3b7cb4dac --- /dev/null +++ b/btypes_lazy/src/main/rust/btypes/src/lazy_ops/set_ops/setops.rs @@ -0,0 +1,102 @@ +use std::cmp::Ordering; +use std::fmt; +use std::fmt::{Debug, Formatter}; +use std::marker::PhantomData; +use crate::bobject::BObject; +use crate::bset::BSet; + +pub trait SetOp: SetOpTraits + Debug { + type Item: BObject; + + fn compute(&self, lhs: &BSet<Self::Item>) -> BSet<Self::Item>; + fn clone_box(&self) -> Box<dyn SetOp<Item = Self::Item>>; + + //PartialEq + fn eq(&self, other: &Box<dyn SetOp<Item = Self::Item>>) -> bool; + + //PartialOrd + fn partial_cmp(&self, other: &Box<dyn SetOp<Item = Self::Item>>) -> Option<Ordering>; + + //Ord + fn cmp(&self, other: &Box<dyn SetOp<Item = Self::Item>>) -> Ordering; + fn max(&self, other: &Box<dyn SetOp<Item = Self::Item>>) -> Box<dyn SetOp<Item = Self::Item>>; + fn min(&self, other: &Box<dyn SetOp<Item = Self::Item>>) -> Box<dyn SetOp<Item = Self::Item>>; + fn clamp(&self, min: &Box<dyn SetOp<Item = Self::Item>>, max: &Box<dyn SetOp<Item = Self::Item>>) -> Box<dyn SetOp<Item = Self::Item>>; +} + +pub trait SetOpTraits { + //type Bla: BObject; + + //fn clone_box(&self) -> Box<dyn SetOp<Item = Self::Bla>>; + //fn default_box() -> Box<dyn SetOp>; +} +/* +impl<T> SetOpTraits for T +where T: 'static + SetOp + Clone, +{ + fn clone_box<S: BObject>(&self) -> Box<dyn SetOp<Item = S>> { + Box::new(self.clone()) + } +} +*/ +impl<T: BObject> Clone for Box<dyn SetOp<Item = T>> { + fn clone(&self) -> Self { + self.clone_box() + } +} + +impl<T: BObject> Eq for Box<dyn SetOp<Item=T>> {} + +impl<T: BObject> PartialEq<Self> for Box<dyn SetOp<Item=T>> { + fn eq(&self, other: &Self) -> bool { + self.eq(other) + } +} + +impl<T: BObject> PartialOrd<Self> for Box<dyn SetOp<Item=T>> { + fn partial_cmp(&self, other: &Self) -> Option<Ordering> { + self.partial_cmp(other) + } +} + +impl<T: BObject> Ord for Box<dyn SetOp<Item = T>> { + fn cmp(&self, other: &Self) -> Ordering { + self.cmp(other) + } +} + +impl<T: 'static + BObject> dyn SetOp<Item = T> { + fn default() -> Box<Self> { + Box::new(Identity {phantom: PhantomData}) + } +} + + + + + + +#[derive(Clone)] +pub struct Identity<T: BObject> { + phantom: PhantomData<T>, +} + +impl<T: BObject> Debug for Identity<T> { + fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { + write!(f, "Identity()") + } +} + +impl<T: 'static + BObject> SetOp for Identity<T> { + type Item = T; + + fn compute(&self, lhs: &BSet<T>) -> BSet<T> { + lhs.clone() + } + + fn clone_box(&self) -> Box<dyn SetOp<Item=Self::Item>> { + Box::new(Identity{phantom: PhantomData}) + } +} + +impl<T: 'static + BObject> SetOpTraits for Identity<T>{} \ No newline at end of file diff --git a/btypes_lazy/src/main/rust/btypes/src/lib.rs b/btypes_lazy/src/main/rust/btypes/src/lib.rs new file mode 100644 index 0000000000000000000000000000000000000000..67e1bf40dc81246dc1ddce46c9ac766da5f579eb --- /dev/null +++ b/btypes_lazy/src/main/rust/btypes/src/lib.rs @@ -0,0 +1,14 @@ +#[macro_use] +extern crate lazy_static; + +pub mod bboolean; +pub mod binteger; +pub mod bobject; +pub mod bstruct; +pub mod bset; +pub mod bstring; +pub mod btuple; +pub mod brelation; +pub mod butils; +pub mod orderedhashset; +pub mod lazy_ops; diff --git a/btypes_lazy/src/main/rust/btypes/src/orderedhashset.rs b/btypes_lazy/src/main/rust/btypes/src/orderedhashset.rs new file mode 100644 index 0000000000000000000000000000000000000000..2680018b8716deff8f20ad27b0f484f7ef949a51 --- /dev/null +++ b/btypes_lazy/src/main/rust/btypes/src/orderedhashset.rs @@ -0,0 +1,148 @@ +use std::borrow::Borrow; +use std::collections::hash_map::DefaultHasher; +use std::cell::RefCell; +use std::cmp::Ordering; +use std::hash::{Hash, Hasher}; + +use im::OrdSet; +use im::ordset::Iter; +use crate::bobject::BObject; + +#[derive(Default, Debug, Eq)] +pub struct OrderedHashSet<I: BObject> { + set: OrdSet<I>, + hash_cache: RefCell<Option<u64>>, +} + +impl<I: BObject> Clone for OrderedHashSet<I> { + fn clone(&self) -> Self { + OrderedHashSet { set: self.set.clone(), hash_cache: RefCell::new(self.hash_cache.borrow().clone()) } + } +} + +impl<I: BObject> PartialOrd for OrderedHashSet<I> { + fn partial_cmp(&self, other: &Self) -> Option<Ordering> { self.set.partial_cmp(&other.set) } + fn lt(&self, other: &Self) -> bool { self.set.lt(&other.set) } + fn le(&self, other: &Self) -> bool { self.set.le(&other.set) } + fn gt(&self, other: &Self) -> bool { self.set.gt(&other.set) } + fn ge(&self, other: &Self) -> bool { self.set.ge(&other.set) } +} + +impl<I: BObject> Ord for OrderedHashSet<I> { + fn cmp(&self, other: &Self) -> Ordering { self.set.cmp(&other.set) } + fn max(self, other: Self) -> Self { + match self.cmp(&other) { + Ordering::Less => other, + Ordering::Greater => self, + Ordering::Equal => other, + } + } + fn min(self, other: Self) -> Self { + match self.cmp(&other) { + Ordering::Less => self, + Ordering::Greater => other, + Ordering::Equal => self, + } + } + fn clamp(self, min: Self, max: Self) -> Self { + if self < min { + min + } else if self > max { + max + } else { + self + } + } +} + +//TODO: check if replacing cache with mutex works and does not impact permormance too much +unsafe impl<T: BObject> Sync for OrderedHashSet<T> {} + +impl<I: BObject> PartialEq for OrderedHashSet<I> { + fn eq(&self, other: &Self) -> bool { + self.set.eq(&other.set) + } +} + +impl<I: BObject> Hash for OrderedHashSet<I> { + fn hash<H: Hasher>(self: &OrderedHashSet<I>, state: &mut H) { + let cache = self.hash_cache.borrow().clone(); + let hash: u64; + + if cache.is_none() { + let mut hasher = DefaultHasher::new(); + self.set.hash(&mut hasher); + hash = hasher.finish(); + self.hash_cache.replace(Option::Some(hash)); + } else { + hash = cache.unwrap(); + } + hash.hash(state); + } +} + +impl<A: BObject> IntoIterator for OrderedHashSet<A> { + type Item = A; + type IntoIter = im::ordset::ConsumingIter<A>; + + fn into_iter(self) -> Self::IntoIter { + self.set.into_iter() + } +} + +impl<I: BObject> OrderedHashSet<I> { + pub fn new() -> Self { Self::from_set(OrdSet::new()) } + + pub fn from_set(val: OrdSet<I>) -> Self { OrderedHashSet {set: val, hash_cache: RefCell::new(Option::None)} } + + pub fn unit(item: I) -> Self { Self::from_set(OrdSet::unit(item)) } + + pub fn from(items: Vec<I>) -> Self { Self::from_set(OrdSet::from(items)) } + + pub fn update(&self, item: I) -> Self { Self::from_set(self.set.update(item)) } + + pub fn unions<A: IntoIterator<Item = Self>>(a: A) -> Self { + a.into_iter().fold(Self::new(), Self::union) + } + + pub fn iter(&self) -> Iter<'_, I> { self.set.iter() } + + pub fn len(&self) -> usize { self.set.len() } + pub fn is_empty(&self) -> bool { self.set.is_empty() } + + pub fn contains(&self, value: &I) -> bool { self.set.contains(value) } + pub fn is_subset<RS: Borrow<Self>>(&self, other: RS) -> bool { + let other = other.borrow(); + self.set.is_subset(&other.set) + } + + pub fn insert(&mut self, value: I) -> Option<I> { + self.hash_cache.replace(Option::None); + return self.set.insert(value); + } + + pub fn remove_min(&mut self) -> Option<I> { + self.hash_cache.replace(Option::None); + return self.set.remove_min() + } + + pub fn get_min(&self) -> Option<&I> { self.set.get_min() } + pub fn get_max(&self) -> Option<&I> { self.set.get_max() } + + pub fn union(self, other: Self) -> Self { + self.hash_cache.replace(Option::None); + return Self::from_set(self.set.union(other.set)); + } + + pub fn intersection(self, other: Self) -> Self { + self.hash_cache.replace(Option::None); + return Self::from_set(self.set.intersection(other.set)); + } + + pub fn relative_complement(self, other: Self) -> Self { + self.hash_cache.replace(Option::None); + return Self::from_set(self.set.relative_complement(other.set)); + } + + pub fn get_set(self) -> OrdSet<I> { return self.set } +} \ No newline at end of file