Skip to content
Snippets Groups Projects
Commit f22c53c7 authored by Cookiebowser's avatar Cookiebowser
Browse files

added bitarray impl for set/relation

parent f91832e5
Branches
No related tags found
No related merge requests found
Showing
with 1352 additions and 6 deletions
[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
[[bin]]
name = "bmachine"
test = false
bench = false
[dependencies]
btypes = { path = "../btypes_bitvec" }
[dependencies.bitvec]
version = "1"
default-features = false
features = []
[profile.release]
#opt-level = 3
panic = "abort"
#lto = 'fat'
codegen-units = 1
debug = true
lto = true
opt-level = "s"
[profile.dev]
opt-level = 0
panic = "abort"
[profile.test]
panic = "abort"
\ No newline at end of file
[toolchain]
channel = "nightly"
\ No newline at end of file
[package]
name = "bmachine_mc"
version = "0.1.0"
edition = "2018"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
btypes = { path = "../btypes_bitvec" }
threadpool = "1.8.1"
dashmap = "~5.1.0"
derivative = "2.2.0"
[profile.release]
#opt-level = 3
panic = "abort"
#lto = 'fat'
codegen-units = 1
debug = true
lto = true
opt-level = "s"
[profile.dev]
opt-level = 0
panic = "abort"
[profile.test]
panic = "abort"
\ No newline at end of file
[toolchain]
channel = "nightly"
\ No newline at end of file
...@@ -92,7 +92,7 @@ impl<L, const LS: usize, R, const RS: usize, const SIZE: usize, const REL_SIZE: ...@@ -92,7 +92,7 @@ impl<L, const LS: usize, R, const RS: usize, const SIZE: usize, const REL_SIZE:
let mut result_arr = [false; SIZE]; let mut result_arr = [false; SIZE];
for idx in 0..SIZE { for idx in 0..SIZE {
let crel = Self::from_idx(idx); let crel = Self::from_idx(idx);
result_arr[idx] = self.subset(&crel); result_arr[idx] = crel.subset(&self);
} }
return BSet::<Self, SIZE>::const_from_arr(result_arr); return BSet::<Self, SIZE>::const_from_arr(result_arr);
} }
......
[package]
name = "btypes"
version = "0.1.0"
edition = "2018"
[dependencies.bitvec]
version = "1"
default-features = false
features = []
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
#![ allow( dead_code ) ]
use crate::bset::{BSet, SetItem};
pub type BBoolean = bool;
impl SetItem<2> for BBoolean {
fn from_idx(idx: usize) -> Self {
match idx {
0 => false,
1 => true,
_ => panic!("Bool index {:?} out of range!", idx)
}
}
fn as_idx(&self) -> usize {
if *self { 1 } else { 0 }
}
}
pub const BOOL: BSet<bool, 2> = BSet::full();//BSet::const_from_arr([true, true]);
pub trait BBool {
fn new(val: bool) -> BBoolean;
fn equal(&self, other: &Self) -> bool;
fn or(&self, other: &Self) -> Self;
fn xor(&self, other: &Self) -> Self;
fn and(&self, other: &Self) -> Self;
fn not(&self) -> Self;
fn implies<F: FnOnce() -> bool>(&self, other: F) -> Self;
fn equivalent(&self, other: &Self) -> Self;
fn unequal(&self, other: &Self) -> Self;
}
impl BBool for bool {
fn new(val: bool) -> BBoolean { val }
fn equal(&self, other: &Self) -> bool { *self == *other }
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<F: FnOnce() -> bool>(&self, other: F) -> Self { !*self || other() }
fn equivalent(&self, other: &Self) -> Self { *self == *other }
fn unequal(&self, other: &Self) -> Self { *self != *other }
}
\ No newline at end of file
#![allow(non_snake_case, non_camel_case_types)]
use core::convert::TryInto;
use crate::bboolean::BBoolean;
use crate::bset::{BSet, SetItem};
pub type BInteger = i128;
pub type set_BInteger = BSet<BInteger, INTEGER_SIZE>;
pub const LOWER_BOUND: BInteger = -10;
pub const UPPER_BOUND: BInteger = 20;
pub const INTEGER_SIZE: usize = 31; //UB - LB + 1
pub trait BInt {
fn equal(&self, other: &Self) -> bool;
fn unequal(&self, other: &Self) -> bool;
fn greater(&self, other: &Self) -> bool;
fn greaterEqual(&self, other: &Self) -> bool;
fn less(&self, other: &Self) -> bool;
fn lessEqual(&self, other: &Self) -> bool;
fn plus(&self, other: &Self) -> Self;
fn minus(&self, other: &Self) -> Self;
fn multiply(&self, other: &Self) -> Self;
fn divide(&self, other: &Self) -> Self;
fn modulo(&self, other: &Self) -> Self;
fn power(&self, exp: &Self) -> Self;
fn negative(&self) -> Self;
fn pred(&self) -> Self;
fn succ(&self) -> Self;
fn from(source: BInteger) -> Self;
fn new(source: BInteger) -> Self;
fn isInteger(&self) -> BBoolean { true }
fn isNotInteger(&self) -> BBoolean { false }
fn isNatural(&self) -> BBoolean;
fn isNotNatural(&self) -> BBoolean;
fn isNatural1(&self) -> BBoolean;
fn isNotNatural1(&self) -> BBoolean;
}
impl BInt for BInteger {
fn equal(&self, other: &Self) -> bool { self.eq(&other) }
fn unequal(&self, other: &Self) -> bool { !self.eq(&other) }
fn greater(&self, other: &Self) -> bool { self > other }
fn greaterEqual(&self, other: &Self) -> bool { self >= other }
fn less(&self, other: &Self) -> bool { self < other }
fn lessEqual(&self, other: &Self) -> bool { self <= other }
fn plus(&self, other: &Self) -> Self { self + other }
fn minus(&self, other: &Self) -> Self { self - other }
fn multiply(&self, other: &Self) -> Self { self * other }
fn divide(&self, other: &Self) -> Self { self / other }
fn modulo(&self, other: &Self) -> Self { self % other }
fn power(&self, exp: &Self) -> Self {
if exp < &0 { panic!("Power with negative exponent!") }
let u32_exp: u32 = exp.unsigned_abs().try_into().unwrap();
return self.pow(u32_exp);
}
fn negative(&self) -> Self { -self }
fn pred(&self) -> Self { self - 1 }
fn succ(&self) -> Self { self + 1 }
fn from(source: BInteger) -> Self { source }
fn new(source: BInteger) -> Self { source }
fn isNatural(&self) -> BBoolean { return *self >= 0; }
fn isNotNatural(&self) -> BBoolean { return *self < 0; }
fn isNatural1(&self) -> BBoolean { return *self > 0; }
fn isNotNatural1(&self) -> BBoolean { return *self < 1; }
}
impl SetItem<INTEGER_SIZE> for BInteger {
fn as_idx(&self) -> usize {
if self < &LOWER_BOUND || self > &UPPER_BOUND {
panic!("Integer {} out of Integer bounds!", self);
}
return (self - LOWER_BOUND).try_into().unwrap();
}
fn from_idx(idx: usize) -> Self {
if idx > INTEGER_SIZE {
panic!("Integer-index {} is too large!", idx);
}
let bint_idx: BInteger = idx.try_into().unwrap();
return bint_idx + LOWER_BOUND;
}
}
#![ allow( non_snake_case) ]
use core::convert::TryInto;
use core::marker::PhantomData;
use core::ops::{BitAnd, BitOrAssign};
use bitvec::mem;
use bitvec::array::BitArray;
use bitvec::prelude::Lsb0;
use crate::bboolean::BBoolean;
use crate::binteger::{BInt, BInteger};
use crate::bset::{BSet, PowSetItem, Set, SetItem};
#[derive(Debug, Clone, Eq, PartialEq, Hash, PartialOrd, Ord)]
pub struct BRelation<L: SetItem<LS>, const LS: usize, R: SetItem<RS>, const RS: usize, const REL_SIZE: usize>
where [usize; mem::elts::<usize>(LS*RS)]: Sized {
rel: BitArray<[usize; mem::elts::<usize>(LS*RS)], Lsb0>, // indexing: rel[l_idx*RS + r_idx]
_p: core::marker::PhantomData<L>,
_p2: core::marker::PhantomData<R>,
}
impl<L, const LS: usize, R, const RS: usize, const REL_SIZE: usize> Default for BRelation<L, LS, R, RS, REL_SIZE>
where L: SetItem<LS>,
R: SetItem<RS>,
[usize; mem::elts::<usize>(LS*RS)]: Sized {
fn default() -> Self {
BRelation { rel: BitArray::ZERO, _p: PhantomData, _p2: PhantomData }
}
}
pub trait RelLeftItem<const LEFT_SIZE: usize, RightItem: SetItem<RIGHT_SIZE>, const RIGHT_SIZE: usize, const REL_VARIANTS: usize, const REL_SIZE: usize>: SetItem<LEFT_SIZE> {
type RelEnum: PowSetItem<REL_VARIANTS, REL_SIZE>;
fn rel_to_idx(rel_arr: [[bool; RIGHT_SIZE]; LEFT_SIZE]) -> usize {
let mut flat_arr = [false; REL_SIZE];
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);
}
fn idx_to_rel(idx: usize) -> [[bool; RIGHT_SIZE]; LEFT_SIZE] {
let flat_arr = Self::RelEnum::idx_to_arr(idx);
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 * RIGHT_SIZE + right_idx];
}
}
return result;
}
}
impl<L, const LS: usize, R, const RS: usize, const SIZE: usize, const REL_SIZE: usize> SetItem<SIZE> for BRelation<L, LS, R, RS, REL_SIZE>
where L: SetItem<LS> + RelLeftItem<LS, R, RS, SIZE, REL_SIZE>,
R: SetItem<RS>,
[usize; mem::elts::<usize>(LS*RS)]: Sized {
fn as_idx(&self) -> usize {
let mut rel_arr: [[bool; RS]; LS] = [[false; RS]; LS];
for l_idx in 0..LS {
let left_idx = l_idx * RS;
for r_idx in 0..RS {
rel_arr[l_idx][r_idx] = self.rel[left_idx + r_idx];
}
}
return L::rel_to_idx(rel_arr);
}
fn from_idx(idx: usize) -> Self {
let mut res = BitArray::<[usize; mem::elts::<usize>(LS*RS)], Lsb0>::ZERO;
let rel_arr: [[bool; RS]; LS] = L::idx_to_rel(idx);
for l_idx in 0..LS {
let left_idx = l_idx * RS;
for r_idx in 0..RS {
res.set(left_idx + r_idx, rel_arr[l_idx][r_idx]);
}
}
return BRelation { rel: res, _p: PhantomData, _p2: PhantomData };
}
}
pub trait RelPowAble<const REL_VARIANTS: usize, const REL_SIZE: usize>: SetItem<REL_VARIANTS>
where [usize; mem::elts::<usize>(REL_VARIANTS)]: Sized {
fn pow(&self) -> BSet<Self, REL_VARIANTS>;
fn pow1(&self) -> BSet<Self, REL_VARIANTS>;
}
impl<L, const LS: usize, R, const RS: usize, const SIZE: usize, const REL_SIZE: usize> RelPowAble<SIZE, REL_SIZE> for BRelation<L, LS, R, RS, REL_SIZE>
where L: SetItem<LS> + RelLeftItem<LS, R, RS, SIZE, REL_SIZE>,
R: SetItem<RS>,
[usize; mem::elts::<usize>(LS)]: Sized,
[usize; mem::elts::<usize>(RS)]: Sized,
[usize; mem::elts::<usize>(SIZE)]: Sized,
[usize; mem::elts::<usize>(LS*RS)]: Sized {
fn pow(&self) -> BSet<Self, SIZE> {
let mut result_arr = [false; SIZE];
for idx in 0..SIZE {
let crel = Self::from_idx(idx);
result_arr[idx] = crel.subset(&self);
}
return BSet::<Self, SIZE>::from_arr(result_arr);
}
fn pow1(&self) -> BSet<Self, SIZE> {
let mut result_arr = self.pow().as_arr();
let empty_self = Self::empty();
let empty_idx = empty_self.as_idx();
result_arr[empty_idx] = false;
return BSet::from_arr(result_arr);
}
}
pub trait TBRelation {
fn isPartialInteger(&self) -> BBoolean { false }
fn checkDomainInteger(&self) -> BBoolean { false }
fn isPartialNatural(&self) -> BBoolean { false }
fn checkDomainNatural(&self) -> BBoolean { false }
fn isPartialNatural1(&self) -> BBoolean { false }
fn checkDomainNatural1(&self) -> BBoolean { false }
fn checkRangeInteger(&self) -> BBoolean { false }
fn checkRangeNatural(&self) -> BBoolean { false }
fn checkRangeNatural1(&self) -> BBoolean { false }
fn checkDomainString(&self) -> BBoolean { false }
fn isPartialString(&self) -> BBoolean { false }
fn checkRangeString(&self) -> BBoolean { false }
fn checkDomainStruct(&self) -> BBoolean { false }
fn isPartialStruct(&self) -> BBoolean { false }
fn checkRangeStruct(&self) -> BBoolean { false }
}
impl<L: SetItem<LS>, const LS: usize, R: SetItem<RS>, const RS: usize, const REL_SIZE: usize> TBRelation for BRelation<L, LS, R, RS, REL_SIZE>
where [usize; mem::elts::<usize>(LS*RS)]: Sized {}
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>,
[usize; mem::elts::<usize>(LS)]: Sized,
[usize; mem::elts::<usize>(RS)]: Sized,
[usize; mem::elts::<usize>(LS*RS)]: Sized {
pub const fn empty() -> Self {
BRelation { rel: BitArray::ZERO, _p: PhantomData, _p2: PhantomData }
}
pub const fn copy(&self) -> Self {
BRelation { rel: self.rel, _p: PhantomData, _p2: PhantomData }
}
pub fn slice_as_array(&self, left_idx: usize) -> [bool; RS] {
let l_idx = left_idx*RS;
let mut result = [false; RS];
for i in 0..RS { result[i] = self.rel[l_idx+i]; }
return result;
}
//TODO: pub fn iter(&self) -> BRelIter<L, LS, R, RS> { BRelIter::new(self.rel) }
pub fn _override_single(&self, left_item: L, right_item: R) -> Self {
let mut result = self.copy();
let left_idx = left_item.as_idx();
let right_idx = right_item.as_idx();
result.rel[left_idx*RS .. (left_idx*RS + RS-1)].fill(false);
result.rel.set(left_idx*RS + right_idx, true);
return result;
}
pub fn add_tuple(&mut self, left_item: &L, right_item: &R) {
//println!("adding tuple ({:?},{:?}), idx = [{}][{}]", left_item, right_item, left_item.as_idx(), right_item.as_idx());
self.rel.set(left_item.as_idx()*RS + right_item.as_idx(), true);
}
//b2program has this name hardcoded...
pub fn functionCall(&self, key: &L) -> R {
let l_idx = key.as_idx()*RS;
for i in 0..RS {
if self.rel[l_idx+i] { return R::from_idx(i) }
}
panic!("ERROR: key {:?} not found in set!", key);
}
/*
pub fn fcall_to_set(&self, key: L) -> BSet<R, RS> {
let l_idx = key.as_idx()*RS;
let mut res = [false; RS];
for i in 0..RS {
res[i] = self.rel[l_idx+i];
}
return BSet::from_arr(res);
}
*/
pub fn card(&self) -> BInteger {
return self.rel[0 .. RS*LS].count_ones().try_into().unwrap();
}
//this name is also hard-coded...
//checks if self.domain is a subset of the given set
pub fn checkDomain(&self, domain: &BSet<L, LS>) -> bool {
for left_idx in 0..LS {
if !domain.contains_idx(left_idx) && self.rel[left_idx * RS..(left_idx + 1) * RS].any() {
return false;
}
}
return true
}
pub fn isPartial(&self, domain: &BSet<L, LS>) -> bool { self.checkDomain(domain) }
pub fn isTotal(&self, domain: &BSet<L, LS>) -> bool {
for left_idx in 0..LS {
// self.domain.contains(left_idx) <=> domain.contains(left_idx)
if domain.contains_idx(left_idx) != self.rel[left_idx * RS..(left_idx + 1) * RS].any() {
return false;
}
}
return true
}
//this name is also hard-coded...
//checks if self.range is a subset of the given set
pub fn checkRange(&self, range: &BSet<R, RS>) -> bool {
let range_arr = range.as_bitarray();
for left_idx in 0..LS {
let current_range = &self.rel[left_idx * RS..(left_idx + 1) * RS];
if (range_arr & current_range) != current_range {
return false;
}
}
return true
}
//this name is also hard-coded...
//checks if for each L there is at most one R
pub fn isFunction(&self) -> bool {
for left_idx in 0..LS {
if self.rel[left_idx*RS .. (left_idx+1)*RS].count_ones() > 1 { return false; }
}
return true;
}
//checks f(x1) = f(x2) => x1 = x2
pub fn isInjection(&self) -> bool {
let mut checked = BitArray::<[usize; mem::elts::<usize>(RS)], Lsb0>::ZERO; //stores all the R's that were already 'used'
for i in 0..LS {
let current_slice = &self.rel[i*RS .. (i+1)*RS];
if checked.bitand(current_slice).any() { return false; } // one R of current slice is already in checked -> no injection
checked |= current_slice;
}
return true;
}
pub fn domain(&self) -> BSet<L, LS> {
let mut result = BitArray::<[usize; mem::elts::<usize>(LS)], Lsb0>::ZERO;
for i in 0..LS {
result.set(i, self.rel[i*RS .. (i+1)*RS].any());
}
return BSet::<L, LS>::from_bitarray(result);
}
pub fn range(&self) -> BSet<R, RS> {
let mut result = BitArray::<[usize; mem::elts::<usize>(RS)], Lsb0>::ZERO;
for left_idx in 0..LS {
result |= &self.rel[left_idx*RS .. (left_idx+1)*RS];
}
return BSet::<R, RS>::from_bitarray(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> {
let right_arr = right_set.as_bitarray();
let mut bit_mask = BitArray::<[usize; mem::elts::<usize>(RS)], Lsb0>::ZERO;
let mut result = Self::empty();
for l_idx in 0..LS {
bit_mask.fill(left_set.contains_idx(l_idx));
result.rel[l_idx*RS .. (l_idx+1)*RS].copy_from_bitslice(&(right_arr & bit_mask));
}
return result;
}
pub fn inverse(&self) -> BRelation<R, RS, L, LS, REL_SIZE>
where [usize; mem::elts::<usize>(RS*LS)]: Sized {
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.set(right_idx*LS + left_idx, self.rel[left_idx*RS + 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*RS .. (left_idx+1)*RS].fill(false); }
}
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*RS .. (left_idx+1)*RS].fill(false); }
}
return result;
}
pub fn rangeRestriction(&self, range_set: &BSet<R, RS>) -> Self {
let mut result = self.copy();
let range_arr = range_set.as_bitarray();
for left_idx in 0..LS {
//retain only elements that are in self *and* in range_set
result.rel[left_idx*RS .. (left_idx+1)*RS] &= range_arr;
}
return result;
}
pub fn rangeSubstraction(&self, range_set: &BSet<R, RS>) -> Self {
let mut result = self.copy();
let not_range_arr = !range_set.as_bitarray();
for left_idx in 0..LS {
//retain only elements that are in self *but not* in range_set
result.rel[left_idx*RS .. (left_idx+1)*RS] &= not_range_arr;
}
return result;
}
pub fn relationImage(&self, result_domain: &BSet<L, LS>) -> BSet<R, RS> {
let mut result_arr = BitArray::<[usize; mem::elts::<usize>(RS)], Lsb0>::ZERO;
for left_idx in 0..LS {
if result_domain.contains_idx(left_idx) {
result_arr.bitor_assign(&self.rel[left_idx*RS .. (left_idx+1)*RS]);
}
}
return BSet::<R, RS>::from_bitarray(result_arr);
}
pub fn intersect(&self, other: &Self) -> Self {
let mut result = self.copy();
result.rel &= other.rel;
return result;
}
pub fn difference(&self, other: &Self) -> Self {
let mut result = self.copy();
result.rel &= !other.rel;
return result;
}
pub fn union(&self, other: &Self) -> Self {
let mut result = self.copy();
result.rel |= other.rel;
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()*RS + v.as_idx()];
}
pub fn noElementOf(&self, (k, v): &(L, R)) -> BBoolean {
return !self.rel[k.as_idx()*RS + v.as_idx()];
}
//subset or equal
pub fn subset(&self, other: &Self) -> BBoolean {
return (other.rel & self.rel) == self.rel;
}
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 {
let other_slice = &other.rel[left_idx*RS .. (left_idx+1)*RS];
if other_slice.any() { result.rel[left_idx*RS .. (left_idx+1)*RS].copy_from_bitslice(other_slice); }
}
return result;
}
//TODO: directProduct/ParallelProduct maybe?
pub fn composition<NewR, const NEW_RS: usize, const PARAM_TOTAL: usize, const NEW_TOTAL: usize>(&self, arg: &BRelation<R, RS, NewR, NEW_RS, PARAM_TOTAL>) -> BRelation<L, LS, NewR, NEW_RS, NEW_TOTAL>
where NewR: SetItem<NEW_RS>,
[usize; mem::elts::<usize>(NEW_RS)]: Sized,
[usize; mem::elts::<usize>(RS*NEW_RS)]: Sized,
[usize; mem::elts::<usize>(LS*NEW_RS)]: Sized {
let mut result = BRelation::<L, LS, NewR, NEW_RS, NEW_TOTAL>::empty();
for left_idx in 0..LS {
let l_idx = left_idx*NEW_RS;
//let mut foo: BitArray<[usize; mem::elts::<usize>(NEW_RS)], Lsb0> = BitArray::ZERO;
for r_idx in 0..RS {
if self.rel[l_idx+r_idx] { result.rel[l_idx .. l_idx+NEW_RS] |= &arg.rel[r_idx*NEW_RS .. (r_idx+1)*NEW_RS]; }
}
//result.rel[l_idx .. l_idx+NEW_RS].copy_from_bitslice(&foo);
}
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...
//BRelation<L,R> -> BRelation<L, BTuple<L, R>>
//BSet<BTuple<L, R>>
//TODO: support const-params in template? maybe compiler can figure them out itself?
pub fn fnc<NewR, const NEW_RS: usize, const NEW_REL_TOTAL: usize>(&self) -> BRelation<L, LS, NewR, NEW_RS, NEW_REL_TOTAL>
where NewR: Set<RS> + SetItem<NEW_RS>, //BRelation<L, LS, BSet<R, RS>, NewRS, newRelTotal
[usize; mem::elts::<usize>(NEW_RS)]: Sized,
[usize; mem::elts::<usize>(LS*NEW_RS)]: Sized {
let mut result = BRelation::<L, LS, NewR, NEW_RS, NEW_REL_TOTAL>::empty();
for left_idx in 0..LS {
let result_set: [bool; RS] = self.slice_as_array(left_idx);
if !result_set.contains(&true) { continue; } // dont create mappings to empty set
result.rel.set(left_idx*LS + NewR::from_arr(result_set).as_idx(), true);
}
return result;
}
//pub fn nondeterminism(&self) -> (L, R) {
// !todo!(RNG does not work without std/external crates)
//}
pub fn isTotalInteger(&self) -> BBoolean { return false; }
pub fn isTotalNatural(&self) -> BBoolean { return false; }
pub fn isTotalNatural1(&self) -> BBoolean { return false; }
pub fn isTotalString(&self) -> BBoolean { return false; }
pub fn isTotalStruct(&self) -> BBoolean { return false; }
pub fn isRelation(&self) -> BBoolean { return true;}
pub fn isSurjection(&self, range: &BSet<R, RS>) -> BBoolean { return self.range().equal(range); }
pub fn isSurjectionInteger(&self) -> BBoolean { return false; }
pub fn isSurjectionNatural(&self) -> BBoolean { return false; }
pub fn isSurjectionNatural1(&self) -> BBoolean { return false; }
pub fn isSurjectionString(&self) -> BBoolean { return false; }
pub fn isSurjectionStruct(&self) -> BBoolean { return false; }
pub fn isBijection(&self, range: &BSet<R, RS>) -> BBoolean { return self.isSurjection(range) && self.isInjection(); }
pub fn isBijectionInteger(&self) -> BBoolean { return false; }
pub fn isBijectionNatural(&self) -> BBoolean { return false; }
pub fn isBijectionNatural1(&self) -> BBoolean { return false; }
pub fn isBijectionString(&self) -> BBoolean { return false; }
pub fn isBijectionStruct(&self) -> BBoolean { return false; }
}
impl<L, const LS: usize, const REL_SIZE: usize> BRelation<L, LS, L, LS, REL_SIZE>
where L: SetItem<LS>,
[usize; mem::elts::<usize>(LS)]: Sized,
[usize; mem::elts::<usize>(LS*LS)]: Sized {
pub fn identity(set: &BSet<L, LS>) -> Self {
let mut result = Self::empty();
for i in 0..LS {
if set.contains_idx(i) { result.rel.set(i*(LS+1), true); }
}
return result;
}
pub fn iterate(&self, n: &BInteger) -> Self {
return (0..*n).fold(BRelation::identity(&self.domain().union(&self.range())),
|rel, _| rel.composition(self));
}
pub fn closure(&self) -> Self { return self.closure_closure1(false); }
pub fn closure1(&self) -> Self { return self.closure_closure1(true); }
fn closure_closure1(&self, is_closure1: bool) -> Self {
let mut result = if is_closure1 { Self::empty() } else { self.iterate(&0) };
let mut current_iteration = self.iterate(&1);
let mut next_result = result.union(&current_iteration);
while !result.equal(&next_result) {
result = next_result;
current_iteration = current_iteration.composition(self);
next_result = result.union(&current_iteration);
}
return result;
}
}
//Sequence
impl<L, const LS: usize, R, const RS: usize, const REL_SIZE: usize> BRelation<L, LS, R, RS, REL_SIZE>
where L: SetItem<LS> + BInt,
R: SetItem<RS>,
[usize; mem::elts::<usize>(LS)]: Sized,
[usize; mem::elts::<usize>(RS)]: Sized,
[usize; mem::elts::<usize>(LS*RS)]: Sized {
pub fn first(&self) -> R { self.functionCall(&L::from(1)) }
pub fn last(&self) -> R { self.functionCall(&L::from(self.card())) }
pub fn size(&self) -> BInteger { self.card() }
pub fn concat(&self, other: &Self) -> Self {
let mut result = self.copy();
let self_size = self.size();
for i in 1..=other.size() {
result.add_tuple(&L::from(self_size + i), &other.functionCall(&L::from(i)));
}
return result;
}
pub fn prepend(&self, e: &R) -> Self {
let mut result = Self::empty();
result.add_tuple(&L::from(1), e);
return result.concat(self);
}
pub fn append(&self, e: &R) -> Self {
let mut result = self.copy();
result.add_tuple(&L::from(self.size()+1), e);
return result;
}
pub fn reverse(&self) -> Self {
let mut result = Self::empty();
let self_size = self.size();
for i in 1..=self_size {
result.add_tuple(&L::from(i), &self.functionCall(&L::from(self_size - i + 1)))
}
return result;
}
pub fn front(&self) -> Self {
return self.take(&self.size().pred());
}
pub fn tail(&self) -> Self {
return self.drop(&1);
}
pub fn take(&self, n: &BInteger) -> Self {
let mut result = self.copy();
for i in (*n+1)..=self.size() {
let i_as_l = L::from(i);
result.rel.set(i_as_l.as_idx()*RS + self.functionCall(&i_as_l).as_idx(), false);
}
return result;
}
pub fn drop(&self, n: &BInteger) -> Self {
let mut result = Self::empty();
for i in (*n+1)..=self.size() {
result.add_tuple(&L::from(i-(*n)), &self.functionCall(&L::from(i)))
}
return result;
}
pub fn isPartialInteger(&self) -> BBoolean { 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, 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> + BInt,
[usize; mem::elts::<usize>(LS)]: Sized,
[usize; mem::elts::<usize>(RS)]: Sized,
[usize; mem::elts::<usize>(LS*RS)]: Sized {
pub fn checkRangeInteger(&self) -> BBoolean { true }
pub fn checkRangeNatural(&self) -> BBoolean { return self.range().subsetOfNatural(); }
pub fn checkRangeNatural1(&self) -> BBoolean { return self.range().subsetOfNatural1(); }
}
pub struct BRelIter<L: SetItem<LS>, const LS: usize, R: SetItem<RS>, const RS: usize> {
brel: [[bool; RS]; LS],
c_l: usize,
c_r: usize,
_p: PhantomData<L>,
_p2: PhantomData<R>,
}
impl<L: SetItem<LS>, const LS: usize, R: SetItem<RS>, const RS: usize> BRelIter<L, LS, R, RS> {
pub const fn new(arr: [[bool; RS]; LS]) -> Self { BRelIter { brel: arr, c_l: 0, c_r: 0, _p: PhantomData, _p2: PhantomData } }
}
impl<L: SetItem<LS>, const LS: usize, R: SetItem<RS>, const RS: usize> Iterator for BRelIter<L, LS, R, RS> {
type Item = (L, R);
fn next(&mut self) -> Option<Self::Item> {
while self.c_l < LS {
while self.c_r < RS {
if self.brel[self.c_l][self.c_r] {
self.c_r += 1;
return Option::Some((L::from_idx(self.c_l), R::from_idx(self.c_r-1)));
}
self.c_r += 1;
}
self.c_l += 1;
self.c_r = 0;
}
return Option::None;
}
}
/* // Does not work in stable rust
impl<L, const LS: usize, R, const RS: usize, const TOTAL: usize, const INNER_RS: usize> BRelation<L, LS, R, RS, TOTAL>
where L: SetItem<LS>,
R: SetItem<RS> + Set<RS>,
R::ItemType: SetItem<INNER_RS>{
pub fn rel<const NEWSIZE: usize>(&self) -> BRelation<L, LS, R::ItemType, INNER_RS, NEWSIZE> {
let result = BRelation::<L, LS, R::ItemType, R::ItemType::VARIS, NEWSIZE>::empty();
return result;
}
}
*/
/* //Needs SetItem on (L, R)/BTuple
impl<L, const LS: usize, R, const RS: usize, const REL_SIZE: usize> Set<REL_SIZE> for BRelation<L, LS, R, RS, REL_SIZE>
where L: SetItem<LS>,
R: SetItem<RS> {
}
*/
#[macro_export]
macro_rules! brel {
($rel_type:ty $( ,$e:expr )* ) => {
{
let mut __temp_gen_rel__ = <$rel_type>::empty();
$(
__temp_gen_rel__.add_tuple(&$e.0, &$e.1);
)*
__temp_gen_rel__
}
};
}
\ No newline at end of file
#![ allow( non_snake_case) ]
use core::fmt::Debug;
use core::marker::PhantomData;
use bitvec::array::BitArray;
use bitvec::mem;
use bitvec::prelude::Lsb0;
use crate::bboolean::BBoolean;
use crate::binteger;
use crate::binteger::{BInt, BInteger, set_BInteger};
use crate::brelation::BRelation;
/// Used to map an Enum to the position in a Set of it's type. \
/// This is necessary since, even though a [BSet] is alway represented as a flat, 1D-array,
/// we want to interact with the Set via more readable names, like the Enum itself. \
/// Especially when it comes to nested sets, we need to be able to consistently convert the subsets
/// into the corresponding array-index. This Trait, with its associated functions, allows us
/// (and Rust) to make sure that such a conversion[^note] always exists and is consistent.
///
/// Ex.: Assume the EnumeratedSet `Counters = {C1, C2, C3}` \
/// This will lead to the following enum in Rust (excerpt):
/// ```rust
/// pub enum Counters {
/// C1 = 0,
/// C2 = 1,
/// C3 = 2,
/// }
/// impl SetItem<3> for Counters{/*...*/}
/// type set_Counters = BSet<Counters, 3>;
/// ```
/// If we now create a set with that type, we can add elements to it simply by using these enums.
/// ```rust
/// let c: set_Counters = set_Counters::empty();
/// c.add(Counters::C2);
/// ```
///
/// [^note]: This conversion always goes in both directions, from enum to index and from index to enum.
pub trait SetItem<const VARIANTS: usize>: Default + Debug {
/// Number of variations this SetItem has (i.e. size of the biggest set of this type)
const VARIANTS: usize = VARIANTS;
/// converts this SetItem into the index it corresponds to in any [BSet] of its type.
fn as_idx(&self) -> usize;
/// converts an index of any [BSet] of this SetItem's type into the SetItem. \
/// Note: this is the inverse to [SetItem::as_idx], `set_item = SetItem::from_idx(set_item.as_idx())`
fn from_idx(idx: usize) -> Self;
}
pub trait Set<const SIZE: usize>: Default {
type ItemType: SetItem<SIZE>;
fn as_arr(&self) -> [bool; SIZE];
fn as_bitarray(&self) -> BitArray<[usize; mem::elts::<usize>(SIZE)], Lsb0>;
fn from_arr(arr: [bool; SIZE]) -> Self;
fn contains_idx(&self, idx: usize) -> bool;
//checks if self is a subset of other
fn subset_of(&self, other: &Self) -> bool;
}
#[derive(Debug, Clone, Eq, PartialEq, Hash, PartialOrd, Ord)]
pub struct BSet<I: SetItem<SIZE>, const SIZE: usize>
where [usize; mem::elts::<usize>(SIZE)]: Sized {
arr: BitArray<[usize; mem::elts::<usize>(SIZE)], Lsb0>,
//arr: BitArray<[usize; {SIZE - 1}], Lsb0>,
_p: PhantomData<I>,
}
impl<I: SetItem<SIZE>, const SIZE: usize> Default for BSet<I, SIZE>
where [usize; mem::elts::<usize>(SIZE)]: Sized {
fn default() -> Self { BSet { arr: BitArray::ZERO, _p: PhantomData } }
}
impl<I: SetItem<SIZE>, const SIZE: usize> Set<SIZE> for BSet<I, SIZE>
where [usize; mem::elts::<usize>(SIZE)]: Sized {
type ItemType = I;
fn as_arr(&self) -> [bool; SIZE] {
let mut result = [false; SIZE];
for i in 0..SIZE { result[i] = self.arr[i]; }
return result;
}
fn as_bitarray(&self) -> BitArray<[usize; mem::elts::<usize>(SIZE)], Lsb0> { return self.arr.clone(); }
fn from_arr(arr: [bool; SIZE]) -> Self {
let mut bit_arr = BitArray::ZERO;
for i in 0..SIZE {
bit_arr.set(i, arr[i]);
}
return BSet { arr: bit_arr, _p: PhantomData };
}
fn contains_idx(&self, idx: usize) -> bool { self.arr[idx] }
fn subset_of(&self, other: &Self) -> bool {
return self.arr.eq(&(self.arr & other.arr));
}
}
/// Used to link the Enum-representation of a Set to the Enum-representation of it's subtype wich
/// allows the use of [BSet]s as [SetItem]s.
///
/// In the generated code, we want to be able to use [BSet]s themselves as SetItems.
/// This way, we can write `let some_set: BSet<BSet<Counters>>` which not only makes the type
/// itself more readable, but any methods on `some_set` automatically use the 'correct' types. (i.e.
/// iterating through the elements of `some_set` would automatically iterate through elements of type
/// `BSet<Counters>`, instead of some enum-type.
///
/// To do this, [BSet] has to implement the [SetItem]-trait, which in turn requires an enum defining
/// every possible variation of that Set. Unfortunately, we cannot implement that trait for the
/// specific [BSet]s which need it during code-generation (Rust does not allow implementing external-traits
/// for external structs). \
/// However, we can implement the trait for [BSet] generically by defining some requirements that are
/// needed for the implementation to work correctly. This requirement is the existence of an enum
/// that fully represents the Set (i.e. carries one element for each possible SubSet). \
/// That enum is then linked to the enum of it's subtype via this [PowSetItem]-trait, which the
/// Rust-compiler can use to generate the specific impl's of the given Set (via the impl-definitions
/// defined below).
///
/// todo(): example?
///
///
/// SETVARIANTS-parameter is necessary to pass value along to SetItem-impl
/// (caclulation on the fly is not possible (yet, generic_const_exprs is unstable/nightly)
pub trait PowSetItem<const SETVARIANTS: usize, const ITEMVARIANTS: usize> {
//const SETVARIANTS: usize = SETVARIANTS;
//Implemented on top of SetItems, connects a SetItem to the Enum-representation of its Set
//SetRepr used to impl PowSetItem for BSet
type SetRepr: SetItem<SETVARIANTS>;
fn arr_to_idx(set_arr: [bool; ITEMVARIANTS]) -> usize;
fn idx_to_arr(idx: usize) -> [bool; ITEMVARIANTS];
}
impl<const SIZE: usize, const POWSIZE: usize, I> SetItem<POWSIZE> for BSet<I, SIZE>
where I: SetItem<SIZE> + PowSetItem<POWSIZE, SIZE>,
[usize; mem::elts::<usize>(SIZE)]: Sized {
fn as_idx(&self) -> usize { I::arr_to_idx(self.as_arr()) }
fn from_idx(idx: usize) -> Self { Self::from_arr(I::idx_to_arr(idx)) }
}
impl<const SETVARIANTS: usize, const ITEMVARIANTS: usize, const A: usize, I> PowSetItem<SETVARIANTS, ITEMVARIANTS> for BSet<I, A>
where I: SetItem<A> + PowSetItem<ITEMVARIANTS, A>,
I::SetRepr: SetItem<ITEMVARIANTS> + PowSetItem<SETVARIANTS, ITEMVARIANTS>,
[usize; mem::elts::<usize>(A)]: Sized {
type SetRepr = <<I as PowSetItem<ITEMVARIANTS, A>>::SetRepr as PowSetItem<SETVARIANTS, ITEMVARIANTS>>::SetRepr;
fn arr_to_idx(set_arr: [bool; ITEMVARIANTS]) -> usize { I::SetRepr::arr_to_idx(set_arr) }
fn idx_to_arr(idx: usize) -> [bool; ITEMVARIANTS] { I::SetRepr::idx_to_arr(idx) }
}
pub trait PowAble<const SETLEN: usize, const ITEMVARS: usize>: Set<SETLEN> + SetItem<ITEMVARS>
where [usize; mem::elts::<usize>(ITEMVARS)]: Sized{
fn pow(&self) -> BSet<Self, ITEMVARS>;
fn pow1(&self) -> BSet<Self, ITEMVARS>;
fn fin(&self) -> BSet<Self, ITEMVARS> { self.pow() }
fn fin1(&self) -> BSet<Self, ITEMVARS> { self.pow1() }
}
/// To generate the powerset of a BSet we need the corresponding enum already generated.
/// This is the case if the BSet implements the [SetItem]-trait, so here we generically implement
/// the pow-function for any struct that implements [Set] and [SetItem]
/// (In theory, this would then automatically extend to BRelations as well, if we implement the traits there)
impl<const SETLEN: usize, const ITEMVARS: usize , I> PowAble<SETLEN, ITEMVARS> for I
where I: Set<SETLEN> + SetItem<ITEMVARS>,
[usize; mem::elts::<usize>(ITEMVARS)]: Sized {
fn pow(&self) -> BSet<Self, ITEMVARS> {
let mut result = BSet::<Self, ITEMVARS>::empty();
for idx in 0..ITEMVARS {
let a = Self::from_idx(idx);
if a.subset_of(self) { result.arr.set(idx, true); }
}
return result;
}
fn pow1(&self) -> BSet<Self, ITEMVARS> {
let mut result = self.pow();
//remove empty set (usually, the index should always be 0, but this ensures that we get the correct one)
result.arr.set(Self::from_arr([false; SETLEN]).as_idx(), false);
return result;
}
}
impl<I: SetItem<SIZE>, const SIZE: usize> BSet<I, SIZE>
where [usize; mem::elts::<usize>(SIZE)]: Sized {
pub const fn empty() -> Self { BSet { arr: BitArray::ZERO, _p: PhantomData } }
pub const fn full() -> Self {
let mut res = Self::empty();
res.arr.data = [usize::MAX; mem::elts::<usize>(SIZE)];
return res;
}
pub fn from_bitarray(arr: BitArray<[usize; mem::elts::<usize>(SIZE)], Lsb0>) -> Self { BSet { arr, _p: PhantomData } }
pub const fn copy(&self) -> Self { BSet { arr: self.arr, _p: PhantomData } }
pub fn from_arr(arr: [bool; SIZE]) -> Self { <Self as Set<SIZE>>::from_arr(arr) }
pub fn iter(&self) -> BSetIter<I, SIZE> { BSetIter::new(self.as_arr()) } //TODO!
pub fn add(&mut self, element: I) { self.arr.set(element.as_idx(), true); }
pub fn add_idx(&mut self, idx: usize) { self.arr.set(idx, true); }
pub fn is_empty(&self) -> bool { self.arr.is_empty() }
pub fn equal(&self, other: &Self) -> BBoolean { self.arr.eq(&other.arr) }
pub fn unequal(&self, other: &Self) -> BBoolean { !self.arr.eq(&other.arr) }
pub fn card(&self) -> BInteger {
return self.arr.iter().fold(0,
|size, next_item| if *next_item { size + 1 }
else { size });
}
pub fn subset(&self, other: &Self) -> BBoolean { self.subset_of(other) }
pub fn strictSubset(&self, other: &Self) -> BBoolean { self.card() < other.card() && self.subset_of(other) }
pub fn notSubset(&self, other: &Self) -> BBoolean { !self.subset_of(other) }
pub fn strictNotSubset(&self, other: &Self) -> BBoolean { self.card() >= other.card() || self.notSubset(other) }
pub fn union(&self, other: &Self) -> Self {
return BSet { arr: self.arr | other.arr, _p: PhantomData };
}
pub fn difference(&self, other: &Self) -> Self {
return BSet { arr: self.arr ^ (self.arr & other.arr), _p: PhantomData };
}
pub fn intersect(&self, other: &Self) -> Self {
return BSet { arr: self.arr & other.arr, _p: PhantomData };
}
//name hard-coded in b2program
pub fn elementOf(&self, element: &I) -> BBoolean { self.arr[element.as_idx()] }
pub fn notElementOf(&self, element: &I) -> BBoolean { !self.arr[element.as_idx()] }
//TODO: nondeterminism needs external libraries
pub fn interval(a: &BInteger, b: &BInteger) -> binteger::set_BInteger {
let mut result = set_BInteger::empty();
for idx in a.as_idx()..=b.as_idx() {
result.arr.set(idx, true);
}
return result;
}
pub const fn equalInteger(&self) -> BBoolean { false }
pub const fn unequalInteger(&self) -> BBoolean { true }
pub const fn equalNatural(&self) -> BBoolean { false }
pub const fn unequalNatural(&self) -> BBoolean { true }
pub const fn equalNatural1(&self) -> BBoolean { false }
pub const fn unequalNatural1(&self) -> BBoolean { true }
pub const fn equalString(&self) -> BBoolean { false }
pub const fn unequalString(&self) -> BBoolean { true }
pub const fn equalStruct(&self) -> BBoolean { false }
pub const fn unequalStruct(&self) -> BBoolean { true }
pub const fn subsetOfString(&self) -> BBoolean { false } //TODO?
pub const fn strictSubsetOfString(&self) -> BBoolean { return self.subsetOfString(); }
pub const fn notSubsetOfString(&self) -> BBoolean { return !self.subsetOfString(); }
pub const fn notStrictSubsetOfString(&self) -> BBoolean { return !self.strictSubsetOfString(); }
pub const fn subsetOfStruct(&self) -> BBoolean { false } //TODO?
pub const fn strictsubsetOfStruct(&self) -> BBoolean { return self.subsetOfStruct(); }
pub const fn notsubsetOfStruct(&self) -> BBoolean { return !self.subsetOfStruct(); }
pub const fn notStrictsubsetOfStruct(&self) -> BBoolean { return !self.strictsubsetOfStruct(); }
//equals BRelation.checkDomain(BSet)
pub fn check_domain_of<R, const RS: usize, const TOTAL_REL: usize>(&self, of: &BRelation<I, SIZE, R, RS, TOTAL_REL>) -> BBoolean
where R: SetItem<RS>,
[usize; mem::elts::<usize>(RS)]: Sized,
[usize; mem::elts::<usize>(SIZE*RS)]: Sized {
return self.is_superset(&of.domain());
}
//equals BRelation.checkRange(BSet)
pub fn check_range_of<L, const LS: usize, const TOTAL_REL: usize>(&self, of: &BRelation<L, LS, I, SIZE, TOTAL_REL>) -> BBoolean
where L: SetItem<LS>,
[usize; mem::elts::<usize>(LS)]: Sized,
[usize; mem::elts::<usize>(LS*SIZE)]: Sized {
return self.is_superset(&of.range());
}
pub fn check_partial_of<R: SetItem<RS>, const RS: usize, const TOTAL_REL: usize>(&self, of: &BRelation<I, SIZE, R, RS, TOTAL_REL>) -> BBoolean
where R: SetItem<RS>,
[usize; mem::elts::<usize>(RS)]: Sized,
[usize; mem::elts::<usize>(SIZE*RS)]: Sized {
return self.is_superset(&of.domain());
}
pub fn is_superset(&self, other: &Self) -> BBoolean { return other.subset(self); }
pub fn check_total_of<R: SetItem<RS>, const RS: usize, const TOTAL_REL: usize>(&self, of: &BRelation<I, SIZE, R, RS, TOTAL_REL>) -> BBoolean
where R: SetItem<RS>,
[usize; mem::elts::<usize>(RS)]: Sized,
[usize; mem::elts::<usize>(SIZE*RS)]: Sized {
return self.equal(&of.domain());
}
}
impl <I: SetItem<SIZE> + BInt, const SIZE: usize> BSet<I, SIZE>
where [usize; mem::elts::<usize>(SIZE)]: Sized {
pub const fn subsetOfInteger(&self) -> BBoolean { true }
pub const fn notSubsetOfInteger(&self) -> BBoolean { !self.subsetOfInteger() }
pub const fn strictSubsetOfInteger(&self) -> BBoolean { self.subsetOfInteger() }
pub fn notStrictSubsetOfInteger(&self) -> BBoolean { !self.strictSubsetOfInteger() }
pub fn subsetOfNatural(&self) -> BBoolean {
if binteger::LOWER_BOUND < 0 { // if LB >= 0, every Int-set only holds Integers >= 0
for idx in 0..BInteger::as_idx(&0) {
if self.arr[idx] { return false; }
}
}
return true;
}
pub fn notSubsetOfNatural(&self) -> BBoolean { !self.subsetOfNatural() }
pub fn strictSubsetOfNatural(&self) -> BBoolean { self.subsetOfNatural() }
pub fn notStrictSubsetOfNatural(&self) -> BBoolean { self.strictSubsetOfNatural() }
pub fn subsetOfNatural1(&self) -> BBoolean {
if binteger::LOWER_BOUND < 1 {
for idx in 0..BInteger::as_idx(&1) {
if self.arr[idx] { return false; }
}
}
// we could also do self.min() > 0, but that might be slower
return true;
}
pub fn notSubsetOfNatural1(&self) -> BBoolean { !self.subsetOfNatural1() }
pub fn strictSubsetOfNatural1(&self) -> BBoolean { self.subsetOfNatural() }
pub fn notStrictSubsetOfNatural1(&self) -> BBoolean { !self.strictSubsetOfNatural1() }
pub fn _min(&self) -> BInteger {
for idx in 0..SIZE {
if self.arr[idx] { return BInteger::from_idx(idx); }
}
panic!("Called min on empty Set!");
}
pub fn _max(&self) -> BInteger {
for idx in (0..SIZE).rev() {
if self.arr[idx] { return BInteger::from_idx(idx); }
}
panic!("Called max on empty Set!");
}
}
/*
EINT: SetItem<4> + PowSetItem<16, 4>
BSet<EINT, 4>: Set<4> + SetItem<16>
BSet<BSet<Enit, 4>, 16>: Set<16>
*/
pub trait NestedSet<const OUTER_SIZE: usize, const INNER_SIZE: usize>
where Self: Set<OUTER_SIZE>,
Self::ItemType: Set<INNER_SIZE> + SetItem<OUTER_SIZE> {
fn unary_union(&self) -> Self::ItemType { self.unary_combine(|l, r| l || r) }
fn unary_intersect(&self) -> Self::ItemType { self.unary_combine(|l, r| l && r) }
fn unary_combine(&self, comb_fn: fn(left_bool:bool, right_bool: bool) -> bool) -> Self::ItemType;
}
/// Implements functions for nested-Sets.
/// A nested-Set is still just a 1D-array, but the Set-Item implements the Set-trait,
/// so the index can be converted to another 1D-array (this then being the representation of the inners Sets)
///
/// Because Rust is a bit constrained in how these implementations can be defined, we need to use
/// a trait to define how the specific Set should look, and then implement that trait generically for
/// any I that conforms to further constrictions.
/// (This will ulitmately only apply to BSets where the inner-type is also a BSet.)
impl<const OUTER_SIZE: usize, const INNER_SIZE: usize, I> NestedSet<OUTER_SIZE, INNER_SIZE> for I
where I: Set<OUTER_SIZE>,
I::ItemType: Set<INNER_SIZE> + SetItem<OUTER_SIZE>{
fn unary_combine(&self, comb_fn: fn(left_bool:bool, right_bool: bool) -> bool) -> I::ItemType {
let mut result_arr = [false; INNER_SIZE]; // empty array representation of the inner settype
for outer_idx in 0..OUTER_SIZE {
if self.contains_idx(outer_idx) {
let inner_set_arr = I::ItemType::from_idx(outer_idx).as_arr(); // array representation of the current inner-set
for inner_idx in 0..INNER_SIZE { result_arr[inner_idx] = comb_fn(result_arr[inner_idx], inner_set_arr[inner_idx]); } // logical combination between the arrays (or = union; and = intersection between sets)
}
}
return I::ItemType::from_arr(result_arr);
}
}
pub struct BSetIter<I: SetItem<SIZE>, const SIZE: usize> {
bset: [bool; SIZE],
c: usize,
_p: PhantomData<I>,
}
impl<I: SetItem<SIZE>, const SIZE: usize> BSetIter<I, SIZE> {
pub const fn new(arr: [bool; SIZE]) -> Self { BSetIter { bset: arr, c: 0, _p: PhantomData } }
}
impl<I: SetItem<SIZE>, const SIZE: usize> Iterator for BSetIter<I, SIZE> {
type Item = I;
fn next(&mut self) -> Option<Self::Item> {
while self.c < SIZE {
if self.bset[self.c] {
self.c += 1;
return Option::Some(I::from_idx(self.c-1));
}
self.c += 1;
}
return Option::None;
}
}
/// Macro to simplify the creation of [Bset]s.
/// Originally, this was supposed to only use constant expressions, so that
/// these could be evaluated at compile-time. However, in rust it is currently
/// not possible to define trait-functions as const, which would be necessary to make this
/// work generically.
#[macro_export]
macro_rules! bset {
($set_type:ty$(, $e:expr )* ) => {
{
let mut __temp_gen_arr__ = [false; <$set_type>::VARIANTS];
$(
__temp_gen_arr__[($e).as_idx()] = true;
)*
BSet::<$set_type, { <$set_type>::VARIANTS }>::from_arr(__temp_gen_arr__)
}
};
}
pub trait BTuple<L, R> {
fn projection1(self) -> L;
fn projection2(self) -> R;
}
impl<L, R> BTuple<L, R> for (L, R)
where L: Clone,
R: Clone {
fn projection1(self) -> L { self.0.clone() }
fn projection2(self) -> R { self.1.clone() }
}
//TODO: Somehow impl SetItem
\ No newline at end of file
#![no_std]
#![feature(generic_const_exprs)]
#[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 set;
...@@ -22,12 +22,20 @@ import static org.junit.Assert.*; ...@@ -22,12 +22,20 @@ import static org.junit.Assert.*;
public class TestRSE { public class TestRSE {
final ClassLoader classLoader = this.getClass().getClassLoader(); final ClassLoader classLoader = this.getClass().getClassLoader();
final Path tomlPath = Paths.get(classLoader.getResource("./").toURI()).getParent().getParent().getParent().getParent().resolve(Paths.get("btypes_primitives/src/main/rust_embedded/bmachine/Cargo.toml")); //array
final Path tomlPath_MC = Paths.get(classLoader.getResource("./").toURI()).getParent().getParent().getParent().getParent().resolve(Paths.get("btypes_primitives/src/main/rust_embedded/bmachine_mc/Cargo.toml")); //final Path tomlPath = Paths.get(classLoader.getResource("./").toURI()).getParent().getParent().getParent().getParent().resolve(Paths.get("btypes_primitives/src/main/rust_embedded/bmachine/Cargo.toml"));
final Path rustSrcPath = tomlPath.getParent().resolve(Paths.get("src/")); //bitvec
final Path tomlPath = Paths.get(classLoader.getResource("./").toURI()).getParent().getParent().getParent().getParent().resolve(Paths.get("btypes_primitives/src/main/rust_embedded/bmachine_bitvec/Cargo.toml"));
//final Path tomlPath_MC = Paths.get(classLoader.getResource("./").toURI()).getParent().getParent().getParent().getParent().resolve(Paths.get("btypes_primitives/src/main/rust_embedded/bmachine_mc/Cargo.toml"));
final Path tomlPath_MC = Paths.get(classLoader.getResource("./").toURI()).getParent().getParent().getParent().getParent().resolve(Paths.get("btypes_primitives/src/main/rust_embedded/bmachine_bitvec_mc/Cargo.toml"));
//final Path rustSrcPath = tomlPath.getParent().resolve(Paths.get("src/")); // arrays
final Path rustSrcPath = tomlPath.getParent().resolve(Paths.get("src/")); // bitvec
//final Path rustSrcPath_MC = tomlPath_MC.getParent().resolve(Paths.get("src/"));
final Path rustSrcPath_MC = tomlPath_MC.getParent().resolve(Paths.get("src/")); final Path rustSrcPath_MC = tomlPath_MC.getParent().resolve(Paths.get("src/"));
final Runtime runtime = Runtime.getRuntime(); final Runtime runtime = Runtime.getRuntime();
final Path testFileBasePath = Paths.get(classLoader.getResource("./").toURI()).getParent().getParent().getParent().resolve("resources/test/de/hhu/stups/codegenerator/"); final Path testFileBasePath = Paths.get(classLoader.getResource("./").toURI()).getParent().getParent().getParent().resolve("resources/test/de/hhu/stups/codegenerator/");
//final String cargoChannel = "";
final String cargoChannel = "+nightly";
public TestRSE() throws URISyntaxException, IOException { public TestRSE() throws URISyntaxException, IOException {
Files.createDirectories(rustSrcPath); Files.createDirectories(rustSrcPath);
...@@ -58,7 +66,7 @@ public class TestRSE { ...@@ -58,7 +66,7 @@ public class TestRSE {
public void compileTestFiles(boolean forModelChecking) throws IOException, InterruptedException { public void compileTestFiles(boolean forModelChecking) throws IOException, InterruptedException {
Path usedTomlPath = !forModelChecking ? tomlPath : tomlPath_MC; Path usedTomlPath = !forModelChecking ? tomlPath : tomlPath_MC;
Process process = runtime.exec("cargo build --release --manifest-path " + usedTomlPath); Process process = runtime.exec(String.format("cargo %s build --release --manifest-path %s", cargoChannel, usedTomlPath));
TestHelper.writeInputToSystem(process.getErrorStream()); TestHelper.writeInputToSystem(process.getErrorStream());
TestHelper.writeInputToOutput(process.getErrorStream(), process.getOutputStream()); TestHelper.writeInputToOutput(process.getErrorStream(), process.getOutputStream());
process.waitFor(); process.waitFor();
...@@ -75,7 +83,7 @@ public class TestRSE { ...@@ -75,7 +83,7 @@ public class TestRSE {
Path usedTomlPath = !modelChecking ? tomlPath : tomlPath_MC; Path usedTomlPath = !modelChecking ? tomlPath : tomlPath_MC;
Process executeProcess = runtime.exec("cargo run --release --manifest-path " + usedTomlPath + progArgs); Process executeProcess = runtime.exec(String.format("cargo %s run --release --manifest-path %s %s", cargoChannel, usedTomlPath, progArgs));
executeProcess.waitFor(); executeProcess.waitFor();
String error = TestHelper.streamToString(executeProcess.getErrorStream()); String error = TestHelper.streamToString(executeProcess.getErrorStream());
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment