use std::collections::{HashMap, HashSet};
use std::hash::Hash;
#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
pub enum AlgebraicResult<V> {
#[default]
None,
Identity(u64),
Element(V),
}
pub const SELF_IDENT: u64 = 0x1;
pub const COUNTER_IDENT: u64 = 0x2;
impl<V> AlgebraicResult<V> {
#[inline]
pub fn is_none(&self) -> bool {
matches!(self, AlgebraicResult::None)
}
#[inline]
pub fn is_identity(&self) -> bool {
matches!(self, AlgebraicResult::Identity(_))
}
#[inline]
pub fn is_element(&self) -> bool {
matches!(self, AlgebraicResult::Element(_))
}
#[inline]
pub fn identity_mask(&self) -> Option<u64> {
match self {
Self::None => None,
Self::Identity(mask) => Some(*mask),
Self::Element(_) => None,
}
}
#[inline]
pub fn invert_identity(self) -> Self {
match self {
Self::None => AlgebraicResult::None,
Self::Identity(mask) => {
let new_mask = ((mask & SELF_IDENT) << 1) | ((mask & COUNTER_IDENT) >> 1);
AlgebraicResult::Identity(new_mask)
},
Self::Element(v) => AlgebraicResult::Element(v),
}
}
#[inline]
pub fn map<U, F>(self, f: F) -> AlgebraicResult<U>
where F: FnOnce(V) -> U,
{
match self {
Self::None => AlgebraicResult::None,
Self::Identity(mask) => AlgebraicResult::Identity(mask),
Self::Element(v) => AlgebraicResult::Element(f(v)),
}
}
#[inline]
pub fn as_ref(&self) -> AlgebraicResult<&V> {
match *self {
Self::Element(ref v) => AlgebraicResult::Element(v),
Self::None => AlgebraicResult::None,
Self::Identity(mask) => AlgebraicResult::Identity(mask),
}
}
#[inline]
pub fn map_into_option<IdentF>(self, ident_f: IdentF) -> Option<V>
where IdentF: FnOnce(usize) -> Option<V>
{
match self {
Self::Element(v) => Some(v),
Self::None => None,
Self::Identity(mask) => ident_f(mask.trailing_zeros() as usize),
}
}
#[inline]
pub fn into_option<I: AsRef<[VRef]>, VRef: std::borrow::Borrow<V>>(self, idents: I) -> Option<V>
where V: Clone
{
match self {
Self::Element(v) => Some(v),
Self::None => None,
Self::Identity(mask) => {
let idents = idents.as_ref();
Some(idents[mask.trailing_zeros() as usize].borrow().clone())
},
}
}
#[inline]
pub fn unwrap<I: AsRef<[VRef]>, VRef: std::borrow::Borrow<V>>(self, idents: I) -> V
where V: Clone
{
match self {
Self::Element(v) => v,
Self::None => panic!(),
Self::Identity(mask) => {
let idents = idents.as_ref();
idents[mask.trailing_zeros() as usize].borrow().clone()
},
}
}
#[inline]
pub fn unwrap_or_else<IdentF, NoneF>(self, ident_f: IdentF, none_f: NoneF) -> V
where
IdentF: FnOnce(usize) -> V,
NoneF: FnOnce() -> V
{
match self {
Self::Element(v) => v,
Self::None => none_f(),
Self::Identity(mask) => ident_f(mask.trailing_zeros() as usize),
}
}
#[inline]
pub fn unwrap_or<I: AsRef<[VRef]>, VRef: std::borrow::Borrow<V>>(self, idents: I, none: V) -> V
where V: Clone
{
match self {
Self::Element(v) => v,
Self::None => none,
Self::Identity(mask) => {
let idents = idents.as_ref();
idents[mask.trailing_zeros() as usize].borrow().clone()
},
}
}
#[inline]
pub fn merge<BV, U, MergeF, AIdent, BIdent>(self, b: AlgebraicResult<BV>, self_idents: AIdent, b_idents: BIdent, merge_f: MergeF) -> AlgebraicResult<U>
where
MergeF: FnOnce(Option<V>, Option<BV>) -> AlgebraicResult<U>,
AIdent: FnOnce(usize) -> Option<V>,
BIdent: FnOnce(usize) -> Option<BV>,
{
match self {
Self::None => {
match b {
AlgebraicResult::None => AlgebraicResult::None,
AlgebraicResult::Element(b_v) => merge_f(None, Some(b_v)),
AlgebraicResult::Identity(b_mask) => {
let self_ident = self_idents(0);
if self_ident.is_none() {
AlgebraicResult::Identity(b_mask)
} else {
let b_v = b_idents(b_mask.trailing_zeros() as usize);
merge_f(None, b_v)
}
},
}
},
Self::Identity(self_mask) => {
match b {
AlgebraicResult::None => {
let b_ident = b_idents(0);
if b_ident.is_none() {
AlgebraicResult::Identity(self_mask)
} else {
let self_v = self_idents(self_mask.trailing_zeros() as usize);
merge_f(self_v, None)
}
},
AlgebraicResult::Element(b_v) => {
let self_v = self_idents(self_mask.trailing_zeros() as usize);
merge_f(self_v, Some(b_v))
},
AlgebraicResult::Identity(b_mask) => {
let combined_mask = self_mask & b_mask;
if combined_mask > 0 {
AlgebraicResult::Identity(combined_mask)
} else {
let self_v = self_idents(self_mask.trailing_zeros() as usize);
let b_v = b_idents(b_mask.trailing_zeros() as usize);
merge_f(self_v, b_v)
}
}
}
},
Self::Element(self_v) => {
match b {
AlgebraicResult::None => merge_f(Some(self_v), None),
AlgebraicResult::Element(b_v) => merge_f(Some(self_v), Some(b_v)),
AlgebraicResult::Identity(b_mask) => {
let b_v = b_idents(b_mask.trailing_zeros() as usize);
merge_f(Some(self_v), b_v)
}
}
}
}
}
#[inline]
pub fn from_status<F>(status: AlgebraicStatus, element_f: F) -> Self
where F: FnOnce() -> V
{
match status {
AlgebraicStatus::None => Self::None,
AlgebraicStatus::Identity => Self::Identity(SELF_IDENT),
AlgebraicStatus::Element => Self::Element(element_f())
}
}
#[inline]
pub fn status(&self) -> AlgebraicStatus {
match self {
AlgebraicResult::None => AlgebraicStatus::None,
AlgebraicResult::Element(_) => AlgebraicStatus::Element,
AlgebraicResult::Identity(mask) => {
if mask & SELF_IDENT > 0 {
AlgebraicStatus::Identity
} else {
AlgebraicStatus::Element
}
}
}
}
}
impl<V> AlgebraicResult<Option<V>> {
#[inline]
pub fn flatten(self) -> AlgebraicResult<V> {
match self {
Self::Element(v) => {
match v {
Some(v) => AlgebraicResult::Element(v),
None => AlgebraicResult::None
}
},
Self::None => AlgebraicResult::None,
Self::Identity(mask) => AlgebraicResult::Identity(mask),
}
}
}
#[derive(Clone, Copy, Default, Debug, PartialEq, Eq, PartialOrd, Ord)]
pub enum AlgebraicStatus {
#[default]
Element,
Identity,
None,
}
impl AlgebraicStatus {
#[inline]
pub fn is_none(&self) -> bool {
matches!(self, Self::None)
}
#[inline]
pub fn is_identity(&self) -> bool {
matches!(self, Self::Identity)
}
#[inline]
pub fn is_element(&self) -> bool {
matches!(self, Self::Element)
}
#[inline]
pub fn merge(self, b: Self, self_none: bool, b_none: bool) -> AlgebraicStatus {
match self {
Self::None => match b {
Self::None => Self::None,
Self::Element => Self::Element,
Self::Identity => if self_none {
Self::Identity
} else {
Self::Element
},
},
Self::Identity => match b {
Self::Element => Self::Element,
Self::Identity => Self::Identity,
Self::None => if b_none {
Self::Identity
} else {
Self::Element
},
},
Self::Element => Self::Element
}
}
}
impl<V> From<FatAlgebraicResult<V>> for AlgebraicResult<V> {
#[inline]
fn from(src: FatAlgebraicResult<V>) -> Self {
if src.identity_mask > 0 {
AlgebraicResult::Identity(src.identity_mask)
} else {
match src.element {
Some(element) => AlgebraicResult::Element(element),
None => AlgebraicResult::None
}
}
}
}
#[derive(Clone, Copy, Default, Debug, PartialEq, Eq)]
pub(crate) struct FatAlgebraicResult<V> {
pub identity_mask: u64,
pub element: Option<V>,
}
impl<V> FatAlgebraicResult<V> {
#[inline(always)]
pub(crate) const fn new(identity_mask: u64, element: Option<V>) -> Self {
Self {identity_mask, element}
}
#[inline]
pub(crate) fn from_binary_op_result(result: AlgebraicResult<V>, a: &V, b: &V) -> Self
where V: Clone
{
match result {
AlgebraicResult::None => FatAlgebraicResult::none(),
AlgebraicResult::Element(v) => FatAlgebraicResult::element(v),
AlgebraicResult::Identity(mask) => {
debug_assert!(mask <= (SELF_IDENT | COUNTER_IDENT));
if mask & SELF_IDENT > 0 {
FatAlgebraicResult::new(mask, Some(a.clone()))
} else {
debug_assert_eq!(mask, COUNTER_IDENT);
FatAlgebraicResult::new(mask, Some(b.clone()))
}
}
}
}
#[inline]
pub fn map<U, F>(self, f: F) -> FatAlgebraicResult<U>
where F: FnOnce(V) -> U,
{
FatAlgebraicResult::<U> {
identity_mask: self.identity_mask,
element: self.element.map(f)
}
}
#[inline(always)]
pub(crate) const fn none() -> Self {
Self {identity_mask: 0, element: None}
}
#[inline(always)]
pub(crate) fn element(e: V) -> Self {
Self {identity_mask: 0, element: Some(e)}
}
pub fn join(self, arg: &V, arg_idx: usize) -> Self where V: Lattice + Clone {
match self.element {
None => {
Self::new(self.identity_mask | 1 << arg_idx, Some(arg.clone()))
},
Some(self_element) => match self_element.pjoin(&arg) {
AlgebraicResult::None => Self::none(),
AlgebraicResult::Element(e) => Self::element(e),
AlgebraicResult::Identity(mask) => {
if mask & SELF_IDENT > 0 {
let new_mask = self.identity_mask | ((mask & COUNTER_IDENT) << (arg_idx-1));
Self::new(new_mask, Some(self_element))
} else {
debug_assert!(mask & COUNTER_IDENT > 0);
let new_mask = (mask & COUNTER_IDENT) << (arg_idx-1);
Self::new(new_mask, Some(arg.clone()))
}
}
}
}
}
}
pub trait Lattice {
fn pjoin(&self, other: &Self) -> AlgebraicResult<Self> where Self: Sized;
fn join_into(&mut self, other: Self) -> AlgebraicStatus where Self: Sized {
let result = self.pjoin(&other);
in_place_default_impl(result, self, other, |_s| {}, |e| e)
}
fn pmeet(&self, other: &Self) -> AlgebraicResult<Self> where Self: Sized;
fn join_all<S: AsRef<Self>, Args: AsRef<[S]>>(xs: Args) -> AlgebraicResult<Self> where Self: Sized + Clone {
let mut iter = xs.as_ref().into_iter().enumerate();
let mut result = match iter.next() {
None => return AlgebraicResult::None,
Some((_, first)) => FatAlgebraicResult::new(SELF_IDENT, Some(first.as_ref().clone())),
};
for (i, next) in iter {
result = result.join(next.as_ref(), i);
}
result.into()
}
}
fn in_place_default_impl<SelfT, OtherT, ConvertF, DefaultF>(result: AlgebraicResult<SelfT>, self_ref: &mut SelfT, other: OtherT, default_f: DefaultF, convert_f: ConvertF) -> AlgebraicStatus
where
DefaultF: FnOnce(&mut SelfT),
ConvertF: Fn(OtherT) -> SelfT
{
match result {
AlgebraicResult::None => {
default_f(self_ref);
AlgebraicStatus::None
},
AlgebraicResult::Element(v) => {
*self_ref = v;
AlgebraicStatus::Element
},
AlgebraicResult::Identity(mask) => {
if mask & SELF_IDENT > 0 {
AlgebraicStatus::Identity
} else {
*self_ref = convert_f(other);
AlgebraicStatus::Element
}
},
}
}
pub trait LatticeRef {
type T;
fn pjoin(&self, other: &Self) -> AlgebraicResult<Self::T>;
fn pmeet(&self, other: &Self) -> AlgebraicResult<Self::T>;
}
pub trait DistributiveLattice {
fn psubtract(&self, other: &Self) -> AlgebraicResult<Self> where Self: Sized;
}
pub trait DistributiveLatticeRef {
type T;
fn psubtract(&self, other: &Self) -> AlgebraicResult<Self::T>;
}
pub(crate) trait Quantale {
fn prestrict(&self, other: &Self) -> AlgebraicResult<Self> where Self: Sized;
}
pub(crate) trait HeteroLattice<OtherT> {
fn pjoin(&self, other: &OtherT) -> AlgebraicResult<Self> where Self: Sized;
fn join_into(&mut self, other: OtherT) -> AlgebraicStatus where Self: Sized {
let result = self.pjoin(&other);
in_place_default_impl(result, self, other, |_s| {}, |e| Self::convert(e))
}
fn pmeet(&self, other: &OtherT) -> AlgebraicResult<Self> where Self: Sized;
fn convert(other: OtherT) -> Self;
}
pub(crate) trait HeteroDistributiveLattice<OtherT> {
fn psubtract(&self, other: &OtherT) -> AlgebraicResult<Self> where Self: Sized;
}
pub(crate) trait HeteroQuantale<OtherT> {
fn prestrict(&self, other: &OtherT) -> AlgebraicResult<Self> where Self: Sized;
}
impl<V: Lattice + Clone> Lattice for Option<V> {
fn pjoin(&self, other: &Option<V>) -> AlgebraicResult<Self> {
match self {
None => match other {
None => { AlgebraicResult::None }
Some(_) => { AlgebraicResult::Identity(COUNTER_IDENT) }
},
Some(l) => match other {
None => { AlgebraicResult::Identity(SELF_IDENT) }
Some(r) => { l.pjoin(r).map(|result| Some(result)) }
}
}
}
fn join_into(&mut self, other: Self) -> AlgebraicStatus {
match self {
None => { match other {
None => AlgebraicStatus::None,
Some(r) => {
*self = Some(r);
AlgebraicStatus::Element
}
} }
Some(l) => match other {
None => AlgebraicStatus::Identity,
Some(r) => {
l.join_into(r)
}
}
}
}
fn pmeet(&self, other: &Option<V>) -> AlgebraicResult<Option<V>> {
match self {
None => { AlgebraicResult::None }
Some(l) => {
match other {
None => { AlgebraicResult::None }
Some(r) => l.pmeet(r).map(|result| Some(result))
}
}
}
}
}
impl<V: DistributiveLattice + Clone> DistributiveLattice for Option<V> {
fn psubtract(&self, other: &Self) -> AlgebraicResult<Self> {
match self {
None => { AlgebraicResult::None }
Some(s) => {
match other {
None => { AlgebraicResult::Identity(SELF_IDENT) }
Some(o) => { s.psubtract(o).map(|v| Some(v)) }
}
}
}
}
}
#[test]
fn option_subtract_test() {
assert_eq!(Some(()).psubtract(&Some(())), AlgebraicResult::None);
assert_eq!(Some(()).psubtract(&None), AlgebraicResult::Identity(SELF_IDENT));
assert_eq!(Some(Some(())).psubtract(&Some(Some(()))), AlgebraicResult::None);
assert_eq!(Some(Some(())).psubtract(&None), AlgebraicResult::Identity(SELF_IDENT));
assert_eq!(Some(Some(())).psubtract(&Some(None)), AlgebraicResult::Identity(SELF_IDENT));
assert_eq!(Some(Some(Some(()))).psubtract(&Some(Some(None))), AlgebraicResult::Identity(SELF_IDENT));
assert_eq!(Some(Some(Some(()))).psubtract(&Some(Some(Some(())))), AlgebraicResult::None);
}
impl<V: Lattice + Clone> LatticeRef for Option<&V> {
type T = Option<V>;
fn pjoin(&self, other: &Self) -> AlgebraicResult<Self::T> {
match self {
None => { match other {
None => { AlgebraicResult::None }
Some(_) => { AlgebraicResult::Identity(COUNTER_IDENT) }
} }
Some(l) => match other {
None => { AlgebraicResult::Identity(SELF_IDENT) }
Some(r) => { l.pjoin(r).map(|result| Some(result)) }
}
}
}
fn pmeet(&self, other: &Option<&V>) -> AlgebraicResult<Option<V>> {
match self {
None => { AlgebraicResult::None }
Some(l) => {
match other {
None => { AlgebraicResult::None }
Some(r) => l.pmeet(r).map(|result| Some(result))
}
}
}
}
}
impl<V: DistributiveLattice + Clone> DistributiveLatticeRef for Option<&V> {
type T = Option<V>;
fn psubtract(&self, other: &Self) -> AlgebraicResult<Self::T> {
match self {
None => { AlgebraicResult::None }
Some(s) => {
match other {
None => { AlgebraicResult::Identity(SELF_IDENT) }
Some(o) => { s.psubtract(o).map(|v| Some(v)) }
}
}
}
}
}
impl <V: Lattice> Lattice for Box<V> {
fn pjoin(&self, other: &Self) -> AlgebraicResult<Self> {
self.as_ref().pjoin(other.as_ref()).map(|result| Box::new(result))
}
fn pmeet(&self, other: &Self) -> AlgebraicResult<Self> {
self.as_ref().pmeet(other.as_ref()).map(|result| Box::new(result))
}
}
impl<V: DistributiveLattice> DistributiveLattice for Box<V> {
fn psubtract(&self, other: &Self) -> AlgebraicResult<Self> {
self.as_ref().psubtract(other.as_ref()).map(|result| Box::new(result))
}
}
impl <V: Lattice> LatticeRef for &V {
type T = V;
fn pjoin(&self, other: &Self) -> AlgebraicResult<Self::T> {
(**self).pjoin(other)
}
fn pmeet(&self, other: &Self) -> AlgebraicResult<Self::T> {
(**self).pmeet(other)
}
}
impl<V: DistributiveLattice> DistributiveLatticeRef for &V {
type T = V;
fn psubtract(&self, other: &Self) -> AlgebraicResult<Self::T> {
(**self).psubtract(other)
}
}
impl DistributiveLattice for () {
fn psubtract(&self, _other: &Self) -> AlgebraicResult<Self> where Self: Sized {
AlgebraicResult::None
}
}
impl Lattice for () {
fn pjoin(&self, _other: &Self) -> AlgebraicResult<Self> { AlgebraicResult::Identity(SELF_IDENT | COUNTER_IDENT) }
fn pmeet(&self, _other: &Self) -> AlgebraicResult<Self> { AlgebraicResult::Identity(SELF_IDENT | COUNTER_IDENT) }
}
impl Lattice for usize {
fn pjoin(&self, _other: &usize) -> AlgebraicResult<usize> { AlgebraicResult::Identity(SELF_IDENT) }
fn pmeet(&self, _other: &usize) -> AlgebraicResult<usize> { AlgebraicResult::Identity(SELF_IDENT) }
}
impl Lattice for u64 {
fn pjoin(&self, _other: &u64) -> AlgebraicResult<u64> { AlgebraicResult::Identity(SELF_IDENT) }
fn pmeet(&self, _other: &u64) -> AlgebraicResult<u64> { AlgebraicResult::Identity(SELF_IDENT) }
}
impl DistributiveLattice for u64 {
fn psubtract(&self, other: &Self) -> AlgebraicResult<Self> where Self: Sized {
if self == other { AlgebraicResult::None }
else { AlgebraicResult::Element(*self) }
}
}
impl Lattice for u32 {
fn pjoin(&self, _other: &u32) -> AlgebraicResult<u32> { AlgebraicResult::Identity(SELF_IDENT) }
fn pmeet(&self, _other: &u32) -> AlgebraicResult<u32> { AlgebraicResult::Identity(SELF_IDENT) }
}
impl Lattice for u16 {
fn pjoin(&self, _other: &u16) -> AlgebraicResult<u16> { AlgebraicResult::Identity(SELF_IDENT) }
fn pmeet(&self, _other: &u16) -> AlgebraicResult<u16> { AlgebraicResult::Identity(SELF_IDENT) }
}
impl DistributiveLattice for u16 {
fn psubtract(&self, other: &Self) -> AlgebraicResult<Self> {
if self == other { AlgebraicResult::None }
else { AlgebraicResult::Element(*self) }
}
}
impl Lattice for u8 {
fn pjoin(&self, _other: &u8) -> AlgebraicResult<u8> { AlgebraicResult::Identity(SELF_IDENT) }
fn pmeet(&self, _other: &u8) -> AlgebraicResult<u8> { AlgebraicResult::Identity(SELF_IDENT) }
}
impl DistributiveLattice for bool {
fn psubtract(&self, other: &bool) -> AlgebraicResult<Self> {
if *self == *other {
AlgebraicResult::None
} else {
AlgebraicResult::Identity(SELF_IDENT)
}
}
}
impl Lattice for bool {
fn pjoin(&self, other: &bool) -> AlgebraicResult<bool> {
if !*self && *other {
AlgebraicResult::Identity(COUNTER_IDENT) } else {
AlgebraicResult::Identity(SELF_IDENT)
}
}
fn pmeet(&self, other: &bool) -> AlgebraicResult<bool> {
if *self && !*other {
AlgebraicResult::Identity(COUNTER_IDENT) } else {
AlgebraicResult::Identity(SELF_IDENT)
}
}
}
pub trait SetLattice {
type K: Clone + Eq;
type V: Clone;
type Iter<'a>: Iterator<Item=(&'a Self::K, &'a Self::V)> where Self: 'a, Self::V: 'a, Self::K: 'a;
fn with_capacity(capacity: usize) -> Self;
fn len(&self) -> usize;
fn is_empty(&self) -> bool;
fn contains_key(&self, key: &Self::K) -> bool;
fn insert(&mut self, key: Self::K, val: Self::V);
fn remove(&mut self, key: &Self::K);
fn get(&self, key: &Self::K) -> Option<&Self::V>;
fn replace(&mut self, key: &Self::K, val: Self::V);
fn iter<'a>(&'a self) -> Self::Iter<'a>;
fn shrink_to_fit(&mut self);
}
#[macro_export]
macro_rules! set_lattice {
( $type_ident:ident $(< $( $lt:tt $( : $clt:tt $(+ $dlt:tt )* )? ),+ >)? ) => {
impl $(< $( $lt $( : $clt $(+ $dlt )* )? ),+ >)? $crate::ring::Lattice for $type_ident $(< $( $lt ),+ >)? where Self: $crate::ring::SetLattice, <Self as $crate::ring::SetLattice>::V: $crate::ring::Lattice {
fn pjoin(&self, other: &Self) -> $crate::ring::AlgebraicResult<Self> {
let self_len = $crate::ring::SetLattice::len(self);
let other_len = $crate::ring::SetLattice::len(other);
let mut result = <Self as $crate::ring::SetLattice>::with_capacity(self_len.max(other_len));
let mut is_ident = self_len >= other_len;
let mut is_counter_ident = self_len <= other_len;
for (key, self_val) in $crate::ring::SetLattice::iter(self) {
if let Some(other_val) = $crate::ring::SetLattice::get(other, key) {
let inner_result = self_val.pjoin(other_val);
$crate::ring::set_lattice_update_ident_flags_with_result(
&mut result, inner_result, key, self_val, other_val, &mut is_ident, &mut is_counter_ident
);
} else {
$crate::ring::SetLattice::insert(&mut result, key.clone(), self_val.clone());
is_counter_ident = false;
}
}
for (key, value) in SetLattice::iter(other) {
if !$crate::ring::SetLattice::contains_key(self, key) {
$crate::ring::SetLattice::insert(&mut result, key.clone(), value.clone());
is_ident = false;
}
}
$crate::ring::set_lattice_integrate_into_result(result, is_ident, is_counter_ident, self_len, other_len)
}
fn pmeet(&self, other: &Self) -> $crate::ring::AlgebraicResult<Self> {
let mut result = <Self as $crate::ring::SetLattice>::with_capacity(0);
let mut is_ident = true;
let mut is_counter_ident = true;
let (smaller, larger, switch) = if $crate::ring::SetLattice::len(self) < $crate::ring::SetLattice::len(other) {
(self, other, false)
} else {
(other, self, true)
};
for (key, self_val) in $crate::ring::SetLattice::iter(smaller) {
if let Some(other_val) = $crate::ring::SetLattice::get(larger, key) {
let inner_result = self_val.pmeet(other_val);
$crate::ring::set_lattice_update_ident_flags_with_result(
&mut result, inner_result, key, self_val, other_val, &mut is_ident, &mut is_counter_ident
);
} else {
is_ident = false;
}
}
if switch {
core::mem::swap(&mut is_ident, &mut is_counter_ident);
}
$crate::ring::set_lattice_integrate_into_result(result, is_ident, is_counter_ident, self.len(), other.len())
}
}
}
}
#[inline]
#[doc(hidden)]
pub fn set_lattice_update_ident_flags_with_result<S: SetLattice>(
result_set: &mut S,
result: AlgebraicResult<S::V>,
key: &S::K,
self_val: &S::V,
other_val: &S::V,
is_ident: &mut bool,
is_counter_ident: &mut bool
) {
match result {
AlgebraicResult::None => {
*is_ident = false;
*is_counter_ident = false;
},
AlgebraicResult::Element(new_val) => {
*is_ident = false;
*is_counter_ident = false;
result_set.insert(key.clone(), new_val);
},
AlgebraicResult::Identity(mask) => {
if mask & SELF_IDENT > 0 {
result_set.insert(key.clone(), self_val.clone());
} else {
*is_ident = false;
}
if mask & COUNTER_IDENT > 0 {
if mask & SELF_IDENT == 0 {
result_set.insert(key.clone(), other_val.clone());
}
} else {
*is_counter_ident = false;
}
}
}
}
#[inline]
#[doc(hidden)]
pub fn set_lattice_integrate_into_result<S: SetLattice>(
result_set: S,
is_ident: bool,
is_counter_ident: bool,
self_set_len: usize,
other_set_len: usize,
) -> AlgebraicResult<S> {
let result_len = result_set.len();
if result_len == 0 {
AlgebraicResult::None
} else {
let mut ident_mask = 0;
if is_ident && self_set_len == result_len {
ident_mask |= SELF_IDENT;
}
if is_counter_ident && other_set_len == result_len {
ident_mask |= COUNTER_IDENT;
}
if ident_mask > 0 {
AlgebraicResult::Identity(ident_mask)
} else {
AlgebraicResult::Element(result_set)
}
}
}
#[macro_export]
macro_rules! set_dist_lattice {
( $type_ident:ident $(< $( $lt:tt $( : $clt:tt $(+ $dlt:tt )* )? ),+ >)? ) => {
impl $(< $( $lt $( : $clt $(+ $dlt )* )? ),+ >)? $crate::ring::DistributiveLattice for $type_ident $(< $( $lt ),+ >)? where Self: $crate::ring::SetLattice + Clone, <Self as $crate::ring::SetLattice>::V: $crate::ring::DistributiveLattice {
fn psubtract(&self, other: &Self) -> $crate::ring::AlgebraicResult<Self> {
let mut is_ident = true;
let mut result = self.clone();
if $crate::ring::SetLattice::len(self) > $crate::ring::SetLattice::len(other) {
for (key, other_val) in $crate::ring::SetLattice::iter(other) {
if let Some(self_val) = $crate::ring::SetLattice::get(self, key) {
set_lattice_subtract_element(&mut result, key, self_val, other_val, &mut is_ident)
}
}
} else {
for (key, self_val) in $crate::ring::SetLattice::iter(self) {
if let Some(other_val) = $crate::ring::SetLattice::get(other, key) {
set_lattice_subtract_element(&mut result, key, self_val, other_val, &mut is_ident)
}
}
}
if $crate::ring::SetLattice::len(&result) == 0 {
$crate::ring::AlgebraicResult::None
} else if is_ident {
$crate::ring::AlgebraicResult::Identity(SELF_IDENT)
} else {
$crate::ring::SetLattice::shrink_to_fit(&mut result);
$crate::ring::AlgebraicResult::Element(result)
}
}
}
}
}
#[inline]
fn set_lattice_subtract_element<S: SetLattice>(
result_set: &mut S,
key: &S::K,
self_val: &S::V,
other_val: &S::V,
is_ident: &mut bool,
) where S::V: DistributiveLattice {
match self_val.psubtract(other_val) {
AlgebraicResult::Element(new_val) => {
SetLattice::replace(result_set, key, new_val);
*is_ident = false;
},
AlgebraicResult::Identity(mask) => {
debug_assert_eq!(mask, SELF_IDENT);
},
AlgebraicResult::None => {
SetLattice::remove(result_set, key);
*is_ident = false;
}
}
}
impl<K: Clone + Eq + Hash, V: Clone + Lattice> SetLattice for HashMap<K, V> {
type K = K;
type V = V;
type Iter<'a> = std::collections::hash_map::Iter<'a, K, V> where K: 'a, V: 'a;
fn with_capacity(capacity: usize) -> Self { Self::with_capacity(capacity) }
fn len(&self) -> usize { self.len() }
fn is_empty(&self) -> bool { self.is_empty() }
fn contains_key(&self, key: &Self::K) -> bool { self.contains_key(key) }
fn insert(&mut self, key: Self::K, val: Self::V) { self.insert(key, val); }
fn get(&self, key: &Self::K) -> Option<&Self::V> { self.get(key) }
fn replace(&mut self, key: &Self::K, val: Self::V) { *self.get_mut(key).unwrap() = val }
fn remove(&mut self, key: &Self::K) { self.remove(key); }
fn iter<'a>(&'a self) -> Self::Iter<'a> { self.iter() }
fn shrink_to_fit(&mut self) { self.shrink_to_fit(); }
}
set_lattice!(HashMap<K, V>);
set_dist_lattice!(HashMap<K, V>);
impl<K: Clone + Eq + Hash> SetLattice for HashSet<K> {
type K = K;
type V = ();
type Iter<'a> = HashSetIterWrapper<'a, K> where K: 'a;
fn with_capacity(capacity: usize) -> Self { Self::with_capacity(capacity) }
fn len(&self) -> usize { self.len() }
fn is_empty(&self) -> bool { self.is_empty() }
fn contains_key(&self, key: &Self::K) -> bool { self.contains(key) }
fn insert(&mut self, key: Self::K, _val: Self::V) { self.insert(key); }
fn get(&self, key: &Self::K) -> Option<&Self::V> { self.get(key).map(|_| &()) }
fn replace(&mut self, key: &Self::K, _val: Self::V) { debug_assert!(self.contains(key)); }
fn remove(&mut self, key: &Self::K) { self.remove(key); }
fn iter<'a>(&'a self) -> Self::Iter<'a> { HashSetIterWrapper(self.iter()) }
fn shrink_to_fit(&mut self) { self.shrink_to_fit(); }
}
pub struct HashSetIterWrapper<'a, K> (std::collections::hash_set::Iter<'a, K>);
impl<'a, K> Iterator for HashSetIterWrapper<'a, K> {
type Item = (&'a K, &'a());
fn next(&mut self) -> Option<(&'a K, &'a())> {
self.0.next().map(|key| (key, &()))
}
}
set_lattice!(HashSet<K>);
set_dist_lattice!(HashSet<K>);
#[cfg(test)]
mod tests {
use std::collections::{HashSet, HashMap};
use crate::ring::Lattice;
use super::{AlgebraicResult, SetLattice, SELF_IDENT, COUNTER_IDENT};
#[test]
fn set_lattice_join_test1() {
let mut a = HashSet::new();
let mut b = HashSet::new();
let joined_result = a.pjoin(&b);
assert_eq!(joined_result, AlgebraicResult::None);
a.insert("A");
b.insert("B");
let joined_result = a.pjoin(&b);
assert!(joined_result.is_element());
let joined = joined_result.unwrap([&a, &b]);
assert_eq!(joined.len(), 2);
assert!(joined.get("A").is_some());
assert!(joined.get("B").is_some());
a.insert("C");
let joined_result = a.pjoin(&b);
assert!(joined_result.is_element());
let joined = joined_result.unwrap([&a, &b]);
assert_eq!(joined.len(), 3);
b.insert("D");
b.insert("F");
b.insert("H");
let joined_result = a.pjoin(&b);
assert!(joined_result.is_element());
let joined = joined_result.unwrap([&a, &b]);
assert_eq!(joined.len(), 6);
let joined_result = joined.pjoin(&b);
assert_eq!(joined_result, AlgebraicResult::Identity(SELF_IDENT));
let joined_result = b.pjoin(&joined);
assert_eq!(joined_result, AlgebraicResult::Identity(COUNTER_IDENT));
let joined_result = joined.pjoin(&joined);
assert_eq!(joined_result, AlgebraicResult::Identity(SELF_IDENT | COUNTER_IDENT));
}
#[test]
fn set_lattice_meet_test1() {
let mut a = HashSet::new();
let mut b = HashSet::new();
a.insert("A");
b.insert("B");
let meet_result = a.pmeet(&b);
assert_eq!(meet_result, AlgebraicResult::None);
a.insert("A");
a.insert("C");
b.insert("B");
b.insert("C");
let meet_result = a.pmeet(&b);
assert!(meet_result.is_element());
let meet = meet_result.unwrap([&a, &b]);
assert_eq!(meet.len(), 1);
assert!(meet.get("A").is_none());
assert!(meet.get("B").is_none());
assert!(meet.get("C").is_some());
a.insert("D");
let meet_result = a.pmeet(&b);
assert!(meet_result.is_element());
let meet = meet_result.unwrap([&a, &b]);
assert_eq!(meet.len(), 1);
b.insert("D");
b.insert("E");
b.insert("F");
let meet_result = a.pmeet(&b);
assert!(meet_result.is_element());
let meet = meet_result.unwrap([&a, &b]);
assert_eq!(meet.len(), 2);
let meet_result = meet.pmeet(&b);
assert_eq!(meet_result, AlgebraicResult::Identity(SELF_IDENT));
let meet_result = b.pmeet(&meet);
assert_eq!(meet_result, AlgebraicResult::Identity(COUNTER_IDENT));
let meet_result = meet.pmeet(&meet);
assert_eq!(meet_result, AlgebraicResult::Identity(SELF_IDENT | COUNTER_IDENT));
}
#[derive(Clone, Debug)]
struct Map<'a>(HashMap::<&'a str, HashMap<&'a str, ()>>); impl<'a> SetLattice for Map<'a> {
type K = &'a str;
type V = HashMap<&'a str, ()>; type Iter<'it> = std::collections::hash_map::Iter<'it, Self::K, Self::V> where Self: 'it, Self::K: 'it, Self::V: 'it;
fn with_capacity(capacity: usize) -> Self { Map(HashMap::with_capacity(capacity)) }
fn len(&self) -> usize { self.0.len() }
fn is_empty(&self) -> bool { self.0.is_empty() }
fn contains_key(&self, key: &Self::K) -> bool { self.0.contains_key(key) }
fn insert(&mut self, key: Self::K, val: Self::V) { self.0.insert(key, val); }
fn get(&self, key: &Self::K) -> Option<&Self::V> { self.0.get(key) }
fn replace(&mut self, key: &Self::K, val: Self::V) { self.0.replace(key, val) }
fn remove(&mut self, key: &Self::K) { self.0.remove(key); }
fn iter<'it>(&'it self) -> Self::Iter<'it> { self.0.iter() }
fn shrink_to_fit(&mut self) { self.0.shrink_to_fit(); }
}
set_lattice!(Map<'a>);
#[test]
fn set_lattice_join_test2() {
let mut a = Map::with_capacity(1);
let mut b = Map::with_capacity(1);
let mut inner_map_1 = HashMap::with_capacity(1);
inner_map_1.insert("1", ());
a.0.insert("A", inner_map_1.clone());
b.0.insert("B", inner_map_1);
let joined_result = a.pjoin(&b);
assert!(joined_result.is_element());
let joined = joined_result.unwrap([&a, &b]);
assert_eq!(joined.len(), 2);
assert!(joined.get(&"A").is_some());
assert!(joined.get(&"B").is_some());
assert!(joined.get(&"C").is_none());
let mut inner_map_2 = HashMap::with_capacity(1);
inner_map_2.insert("2", ());
b.0.remove("B");
b.0.insert("A", inner_map_2);
let joined_result = a.pjoin(&b);
assert!(joined_result.is_element());
let joined = joined_result.unwrap([&a, &b]);
assert_eq!(joined.len(), 1);
let joined_inner = joined.get(&"A").unwrap();
assert_eq!(joined_inner.len(), 2);
assert!(joined_inner.get(&"1").is_some());
assert!(joined_inner.get(&"2").is_some());
let joined_result = joined.pjoin(&a);
assert_eq!(joined_result.identity_mask().unwrap(), SELF_IDENT);
let joined_result = b.pjoin(&joined);
assert_eq!(joined_result.identity_mask().unwrap(), COUNTER_IDENT);
}
#[test]
fn set_lattice_meet_test2() {
let mut a = Map::with_capacity(1);
let mut b = Map::with_capacity(1);
let mut inner_map_a = HashMap::new();
inner_map_a.insert("a", ());
let mut inner_map_b = HashMap::new();
inner_map_b.insert("b", ());
let mut inner_map_c = HashMap::new();
inner_map_c.insert("c", ());
a.0.insert("A", inner_map_a.clone());
a.0.insert("C", inner_map_c.clone());
b.0.insert("B", inner_map_b.clone());
b.0.insert("C", inner_map_c.clone());
let meet_result = a.pmeet(&b);
assert!(meet_result.is_element());
let meet = meet_result.unwrap([&a, &b]);
assert_eq!(meet.len(), 1);
assert!(meet.get(&"A").is_none());
assert!(meet.get(&"B").is_none());
assert!(meet.get(&"C").is_some());
let mut inner_map_1 = HashMap::with_capacity(1);
inner_map_1.insert("1", ());
a.0.insert("A", inner_map_1);
let mut inner_map_2 = HashMap::with_capacity(1);
inner_map_2.insert("2", ());
b.0.remove("B");
b.0.remove("C");
b.0.insert("A", inner_map_2.clone());
let meet_result = a.pmeet(&b);
assert!(meet_result.is_none());
inner_map_2.insert("1", ());
b.0.insert("A", inner_map_2);
let meet_result = a.pmeet(&b);
assert!(meet_result.is_element());
let meet = meet_result.unwrap([&a, &b]);
assert_eq!(meet.len(), 1);
let meet_inner = meet.get(&"A").unwrap();
assert_eq!(meet_inner.len(), 1);
assert!(meet_inner.get(&"1").is_some());
assert!(meet_inner.get(&"2").is_none());
let meet_result = meet.pmeet(&a);
assert_eq!(meet_result.identity_mask().unwrap(), SELF_IDENT);
let meet_result = b.pmeet(&meet);
assert_eq!(meet_result.identity_mask().unwrap(), COUNTER_IDENT);
}
}