diff --git a/btypes_lazy/src/main/rust/bmachine/Cargo.toml b/btypes_lazy/src/main/rust/bmachine/Cargo.toml new file mode 100644 index 0000000000000000000000000000000000000000..1f4c46e38bde5648b94b4d5e195236ccd4c1d26d --- /dev/null +++ b/btypes_lazy/src/main/rust/bmachine/Cargo.toml @@ -0,0 +1,20 @@ +[package] +name = "bmachine" +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" +threadpool = "1.8.1" +derivative = "2.2.0" +dashmap = "5.1.0" +btypes = { path = "../btypes" } + +[profile.release] +opt-level = 3 + +[profile.dev] +opt-level = 0 diff --git a/btypes_lazy/src/main/rust/btypes/src/bset.rs b/btypes_lazy/src/main/rust/btypes/src/bset.rs index 5d7771a7879e889cf5bf555b02c305c288e5e8fd..ea8a2fe8eb4866129b722ae63e10fe961eab7596 100644 --- a/btypes_lazy/src/main/rust/btypes/src/bset.rs +++ b/btypes_lazy/src/main/rust/btypes/src/bset.rs @@ -6,6 +6,8 @@ use crate::bstring::BString; use crate::bobject::BObject; use crate::btuple::BTuple; use crate::orderedhashset::OrderedHashSet as OrdSet; +use crate::lazy_ops::set_ops::setops::{SetOp, SetOpTraits}; +use crate::lazy_ops::set_ops::union::Union; use std::any::TypeId; use std::borrow::Borrow; @@ -16,7 +18,6 @@ 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; @@ -41,9 +42,7 @@ impl<T: BObject> BSet<T> { const OP_NAME: &'static str = "set"; } -impl<T: BObject> SetOp for BSet<T> { - type Item = T; - +impl<T: 'static + BObject> SetOp for BSet<T> { fn compute(&self, _: &BSet<Self::Item>) -> BSet<Self::Item> { match self.transformation.borrow() { Some(trans) => trans.compute(&self) , //todo save computation? @@ -52,45 +51,80 @@ impl<T: BObject> SetOp for BSet<T> { } fn clone_box(&self) -> Box<dyn SetOp<Item=Self::Item>> { - todo!() + Box::new(self.clone()) } fn get_op_name(&self) -> &str { return BSet::<T>::OP_NAME; } - fn get_rhs(&self) -> Option<&Box<dyn SetOp<Item=Self::Item>>> { - return self.transformation.as_ref(); + fn get_rhs(&self) -> Option<Box<dyn SetOp<Item=Self::Item>>> { + return self.transformation.clone(); + } + + fn to_string(&self, _lhs: Option<&str>) -> String { + 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 + "}"; + match &self.transformation { + Some(op) => return op.to_string(Option::Some(result.as_str())), + None => return result, + } } } -impl<T: BObject> SetOpTraits for BSet<T> { +impl<T: 'static + BObject> SetOpTraits for BSet<T> { + type Item = T; + fn iter_lazy(&self, _lhs: &BSet<Self::Item>) -> Iter<'_, T> { + match &self.transformation { + Some(op) => op.iter_lazy(self), + None => self.iter_directly(), + } + } + + fn contains_lazy(&self, _lhs: &BSet<Self::Item>, o: &Self::Item) -> bool { + match &self.transformation { + Some(op) => op.contains_lazy(self, o), + None => self.contains_directly(o), + } + } + + fn is_empty_lazy(&self, _lhs: &BSet<Self::Item>) -> bool { + match &self.transformation { + Some(op) => op.is_empty_lazy(self), + None => self.is_empty_directly(), + } + } + + fn size_lazy(&self, _lhs: &BSet<Self::Item>) -> usize { + match &self.transformation { + Some(op) => op.size_lazy(self), + None => self.size_directly(), + } + } } 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: 'static + BObject> BObject for BSet<T> {} -impl<T: BObject> TBSet for BSet<T> { +impl<T: 'static + 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> { +impl<T: 'static + 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); + return write!(f, "{}", <BSet<T> as SetOp>::to_string(self, Option::None)); } } @@ -126,20 +160,20 @@ impl<T: 'static + BObject> BSet<T> { return BSet { set: set, transformation: Option::None }; } + pub fn iter(&self) -> Iter<'_, T> { self.iter_lazy(self) } - pub fn iter(&self) -> Iter<'_, T> { - return self.set.iter(); - } + pub fn iter_directly(&self) -> Iter<'_, T> { self.set.iter() } - pub fn size(&self) -> usize { + pub fn size(&self) -> usize { self.size_lazy(self) } + pub fn size_directly(&self) -> usize { return self.set.len(); } - pub fn isEmpty(&self) -> bool { - return self.set.is_empty(); - } + pub fn isEmpty(&self) -> bool { return self.is_empty_lazy(self); } + pub fn is_empty_directly(&self) -> bool { return self.set.is_empty() } - pub fn contains(&self, o: &T) -> bool { + pub fn contains(&self, o: &T) -> bool { self.contains_lazy(self, o) } + pub fn contains_directly(&self, o: &T) -> bool { return self.set.contains(o); } @@ -148,10 +182,15 @@ impl<T: 'static + BObject> BSet<T> { } pub fn difference(&self, set: &BSet<T>) -> BSet<T> { - return BSet{ set: self.set.clone().relative_complement(set.set.clone()), transformation: Option::None }; + let result: OrdSet<T> = self.iter().fold(OrdSet::new(), |r_set, element| if set.contains(element) { r_set } else { r_set.update(element.clone()) }); + return BSet::fromOrdSet(result); } pub fn _union(&self, set: &BSet<T>) -> BSet<T> { + return BSet { set: self.set.clone(), transformation: Option::Some(Box::new(Union::new(set.clone())))} + } + + pub fn real_union(&self, set: &BSet<T>) -> BSet<T> { return BSet{ set: self.set.clone().union(set.set.clone()), transformation: Option::None }; } @@ -168,7 +207,7 @@ impl<T: 'static + BObject> BSet<T> { } pub fn _size(&self) -> BInteger { - return BInteger::new(self.set.len().try_into().unwrap()); + return BInteger::new(self.size().try_into().unwrap()); } pub fn elementOf(&self, object: &T) -> BBoolean { @@ -184,15 +223,15 @@ impl<T: 'static + BObject> BSet<T> { } pub fn notSubset(&self, set: &BSet<T>) -> BBoolean { - return BBoolean::new(!self.set.is_subset(&set.set)); + return self.subset(set).not(); } pub fn strictSubset(&self, set: &BSet<T>) -> BBoolean { - return BBoolean::new(self.set.len() < set.set.len() && self.set.is_subset(&set.set)); + return BBoolean::new(self.size() < set.size() && self.subset(set)); } pub fn strictNotSubset(&self, set: &BSet<T>) -> BBoolean { - return BBoolean::new(self.set.len() == set.set.len() || !self.set.is_subset(&set.set)); + return BBoolean::new(self.size() >= set.size() || !self.subset(set)); } pub fn fin(&self) -> BSet<BSet<T>> { @@ -235,7 +274,7 @@ impl<T: 'static + BObject> BSet<T> { 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(); + return self.iter().nth(rng.gen_range(0..self.set.len())).unwrap().clone(); } pub fn equal(&self, other: &BSet<T>) -> BBoolean { diff --git a/btypes_lazy/src/main/rust/btypes/src/lazy_ops/set_ops/identity.rs b/btypes_lazy/src/main/rust/btypes/src/lazy_ops/set_ops/identity.rs new file mode 100644 index 0000000000000000000000000000000000000000..e88fb8ae9cc262aad73fa1def659a40b05b221b7 --- /dev/null +++ b/btypes_lazy/src/main/rust/btypes/src/lazy_ops/set_ops/identity.rs @@ -0,0 +1,50 @@ +use crate::bobject::BObject; +use crate::bset::BSet; +use crate::lazy_ops::set_ops::setops::{SetOp, SetOpTraits}; + +use std::fmt; +use std::fmt::{Debug, Formatter}; +use std::marker::PhantomData; + + +#[derive(Clone)] +pub struct Identity<T: BObject> { + phantom: PhantomData<T>, +} + +impl<T: BObject> Identity<T> { + const OP_NAME: &'static str = "Identity"; +} + +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> { + + 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}) + } + + fn get_op_name(&self) -> &str { + return Identity::<T>::OP_NAME; + } + + fn get_rhs(&self) -> Option<Box<dyn SetOp<Item=Self::Item>>> { + return Option::None; + } +} + +impl<T: 'static + BObject> SetOpTraits for Identity<T>{ + type Item = T; + + fn contains_lazy(&self, lhs: &BSet<Self::Item>, o: &Self::Item) -> bool { lhs.contains_directly(o) } + fn is_empty_lazy(&self, lhs: &BSet<Self::Item>) -> bool { lhs.is_empty_directly() } + fn size_lazy(&self, lhs: &BSet<Self::Item>) -> usize { lhs.size_directly() } +} \ 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 index c4442fe7273818eb198fbb935b45dd7847d8b3bb..6ee6fe5523a65fca3f8fb0bbc15d23715008ceac 100644 --- 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 @@ -1 +1,3 @@ -pub mod setops; \ No newline at end of file +pub mod setops; +//pub mod identity; +pub mod union; \ 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 index 787ae5c0bef310d8d8426f39a33390acd7b97688..faceceac4efc2b60360b07df9929f4932e689a44 100644 --- 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 @@ -1,18 +1,37 @@ use std::cmp::Ordering; -use std::fmt; -use std::fmt::{Debug, Formatter}; -use std::marker::PhantomData; +use std::fmt::{Debug}; +use std::iter::Chain; +use im::ordset::Iter; + 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>>; fn get_op_name(&self) -> &str; - fn get_rhs(&self) -> Option<&Box<dyn SetOp<Item = Self::Item>>>; + fn get_rhs(&self) -> Option<Box<dyn SetOp<Item = Self::Item>>>; + + fn to_string(&self, lhs: Option<&str>) -> String { + let mut result = format!("{}(", self.get_op_name()); + let mut has_lhs = false; + if lhs.is_some() { + result.push_str(lhs.unwrap()); + has_lhs = true; + } + match self.get_rhs() { + Some(v) => { + if has_lhs { result.push_str(", "); } + result.push_str(format!("{}", v.to_string(Option::None)).as_str()) + }, + None => {}, + } + result.push_str(")"); + + return result; + } //PartialEq fn eq_box(&self, other: &Box<dyn SetOp<Item = Self::Item>>) -> bool { @@ -71,12 +90,25 @@ pub trait SetOp: SetOpTraits + Debug { } pub trait SetOpTraits { - //type Bla: BObject; + type Item: BObject; - //fn clone_box(&self) -> Box<dyn SetOp<Item = Self::Bla>>; - //fn default_box() -> Box<dyn SetOp>; + fn iter_lazy(&self, lhs: &BSet<Self::Item>) -> Box<dyn Iterator<Item=Self::Item> + '_>; + fn contains_lazy(&self, lhs: &BSet<Self::Item>, o:&Self::Item) -> bool; + fn is_empty_lazy(&self, lhs: &BSet<Self::Item>) -> bool; + fn size_lazy(&self, lhs: &BSet<Self::Item>) -> usize; } /* +struct IterWrapper<T: BObject> { + chain_iter: Option<Chain<Iter<T>, Iter<T>>>, +} + +impl<T: BObject> IterWrapper<T> { + pub fn from_chain_iter(iter: Chain<Iter<T>, Iter<T>>) { + IterWrapper { chain_iter: Option::Some(iter) } + } +} +*/ +/* impl<T> SetOpTraits for T where T: 'static + SetOp + Clone, { @@ -116,45 +148,4 @@ impl<T: 'static + BObject> Default for Box<dyn SetOp<Item = T>> { Box::new(Identity {phantom: PhantomData}) } } -*/ - - - - - -#[derive(Clone)] -pub struct Identity<T: BObject> { - phantom: PhantomData<T>, -} - -impl<T: BObject> Identity<T> { - const OP_NAME: &'static str = "Identity"; -} - -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}) - } - - fn get_op_name(&self) -> &str { - return Identity::<T>::OP_NAME; - } - - fn get_rhs(&self) -> Option<&Box<dyn SetOp<Item=Self::Item>>> { - return Option::None; - } -} - -impl<T: 'static + BObject> SetOpTraits for Identity<T>{} \ No newline at end of file +*/ \ No newline at end of file diff --git a/btypes_lazy/src/main/rust/btypes/src/lazy_ops/set_ops/union.rs b/btypes_lazy/src/main/rust/btypes/src/lazy_ops/set_ops/union.rs new file mode 100644 index 0000000000000000000000000000000000000000..a8117a7d1900f66065b6e9338851c53ebf3ae3d1 --- /dev/null +++ b/btypes_lazy/src/main/rust/btypes/src/lazy_ops/set_ops/union.rs @@ -0,0 +1,77 @@ +use std::cell::RefCell; +use std::convert::TryInto; +use crate::bobject::BObject; +use crate::bset::BSet; +use crate::lazy_ops::set_ops::setops::{SetOp, SetOpTraits}; + +use std::fmt; +use std::fmt::{Debug, Formatter}; +use std::iter::Chain; +use std::ops::Not; +use im::ordset::Iter; + +#[derive(Clone)] +pub struct Union<T: BObject> { + rhs: RefCell<BSet<T>>, + rhs_is_reduced: RefCell<bool>, +} + +impl<T: BObject> Union<T> { + const OP_NAME: &'static str = "Union"; +} + +impl<T: 'static + BObject> Debug for Union<T> { + fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { + write!(f, "Union({})", self.rhs.borrow()) + } +} + +impl<T: BObject> Union<T> { + pub fn new(rhs: BSet<T>) -> Union<T> { + Union {rhs: RefCell::new(rhs), rhs_is_reduced: RefCell::new(false)} + } +} + +impl<T: 'static + BObject> SetOpTraits for Union<T>{ + type Item = T; + + fn iter_lazy(&self, lhs: &BSet<Self::Item>) -> Chain<Iter<T>, Iter<T>> { + return lhs.iter_directly().chain(self.rhs.borrow().iter()); + } + + fn contains_lazy(&self, lhs: &BSet<Self::Item>, o: &Self::Item) -> bool { + lhs.contains_directly(o) || self.rhs.borrow().contains_directly(o) + } + + fn is_empty_lazy(&self, lhs: &BSet<Self::Item>) -> bool { + lhs.is_empty_directly() && self.rhs.borrow().is_empty_directly() + } + + fn size_lazy(&self, lhs: &BSet<Self::Item>) -> usize { + if (*self.rhs_is_reduced.borrow()).not() { + let new_rhs = self.rhs.borrow().difference(lhs); + self.rhs.replace(new_rhs); + self.rhs_is_reduced.replace(true); + } + return lhs.size_directly() + self.rhs.borrow().size_directly(); + } +} + +impl<T: 'static + BObject> SetOp for Union<T> { + fn compute(&self, lhs: &BSet<T>) -> BSet<T> { + lhs.real_union(&self.rhs.borrow()) + } + + fn clone_box(&self) -> Box<dyn SetOp<Item=Self::Item>> { + Box::new(Union{rhs: RefCell::new(self.rhs.borrow().clone()), + rhs_is_reduced: RefCell::new(*self.rhs_is_reduced.borrow())}) + } + + fn get_op_name(&self) -> &str { + return Union::<T>::OP_NAME; + } + + fn get_rhs(&self) -> Option<Box<dyn SetOp<Item=Self::Item>>> { + return Option::Some(self.rhs.borrow().clone_box()); + } +} \ No newline at end of file