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 {
const IDEMPOTENT: bool = true;
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 {
const IDEMPOTENT: bool = true;
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 super::{AlgebraicResult, SetLattice, COUNTER_IDENT, SELF_IDENT};
use crate::ring::{DistributiveLattice, Lattice};
use std::collections::{HashMap, HashSet};
use std::fmt::Debug;
type NestedSetMap = HashMap<u8, HashSet<u16>>;
fn assert_binary_result<T>(
result: AlgebraicResult<T>,
self_value: &T,
counter_value: &T,
expected: &T,
allow_counter_identity: bool,
context: &str,
) where
T: Clone + Default + Eq + Debug,
{
match &result {
AlgebraicResult::None => {
assert_eq!(expected, &T::default(), "{context}: None result");
}
AlgebraicResult::Identity(mask) => {
assert_ne!(*mask, 0, "{context}: zero identity mask");
assert_eq!(
*mask & !(SELF_IDENT | COUNTER_IDENT),
0,
"{context}: identity mask sets an out-of-arity bit"
);
if !allow_counter_identity {
assert_eq!(
*mask & COUNTER_IDENT,
0,
"{context}: non-commutative operation returned counter identity"
);
}
if *mask & SELF_IDENT != 0 {
assert_eq!(self_value, expected, "{context}: self identity mismatch");
}
if *mask & COUNTER_IDENT != 0 {
assert_eq!(
counter_value, expected,
"{context}: counter identity mismatch"
);
}
}
AlgebraicResult::Element(_) => {}
}
let actual = result.unwrap_or([self_value, counter_value], T::default());
assert_eq!(actual, *expected, "{context}: materialized result");
}
fn normalize_nested_map(map: &NestedSetMap) -> NestedSetMap {
map.iter()
.filter(|(_, values)| !values.is_empty())
.map(|(key, values)| (*key, values.clone()))
.collect()
}
fn assert_nested_result(
result: AlgebraicResult<NestedSetMap>,
self_value: &NestedSetMap,
counter_value: &NestedSetMap,
expected: &NestedSetMap,
allow_counter_identity: bool,
context: &str,
) {
match &result {
AlgebraicResult::None => {
assert!(expected.is_empty(), "{context}: None result");
}
AlgebraicResult::Identity(mask) => {
assert_ne!(*mask, 0, "{context}: zero identity mask");
assert_eq!(
*mask & !(SELF_IDENT | COUNTER_IDENT),
0,
"{context}: identity mask sets an out-of-arity bit"
);
if !allow_counter_identity {
assert_eq!(
*mask & COUNTER_IDENT,
0,
"{context}: non-commutative operation returned counter identity"
);
}
if *mask & SELF_IDENT != 0 {
assert_eq!(
normalize_nested_map(self_value),
*expected,
"{context}: self identity mismatch"
);
}
if *mask & COUNTER_IDENT != 0 {
assert_eq!(
normalize_nested_map(counter_value),
*expected,
"{context}: counter identity mismatch"
);
}
}
AlgebraicResult::Element(_) => {}
}
let actual = result.unwrap_or([self_value, counter_value], NestedSetMap::new());
assert_eq!(
normalize_nested_map(&actual),
*expected,
"{context}: materialized result"
);
}
fn mixed(seed: u64) -> u64 {
let mut x = seed.wrapping_add(0x9e37_79b9_7f4a_7c15);
x = (x ^ (x >> 30)).wrapping_mul(0xbf58_476d_1ce4_e5b9);
x = (x ^ (x >> 27)).wrapping_mul(0x94d0_49bb_1331_11eb);
x ^ (x >> 31)
}
fn generated_set(seed: u64, salt: u64) -> HashSet<u16> {
let mut set = HashSet::new();
for value in 0..48 {
if mixed(seed ^ salt ^ ((value as u64) << 32)) % 5 < 2 {
set.insert(value);
}
}
set
}
fn generated_nested_map(seed: u64, salt: u64) -> NestedSetMap {
let mut map = NestedSetMap::new();
for key in 0..8 {
let key_seed = mixed(seed ^ salt ^ ((key as u64) << 24));
if key_seed % 4 == 0 {
continue;
}
let mut values = HashSet::new();
for value in 0..16 {
if mixed(key_seed ^ ((value as u64) << 32)) % 5 < 2 {
values.insert(value);
}
}
if key_seed % 31 == 0 {
values.clear();
}
map.insert(key, values);
}
map
}
fn nested_join(a: &NestedSetMap, b: &NestedSetMap) -> NestedSetMap {
let mut result = normalize_nested_map(a);
for (key, values) in b {
if values.is_empty() {
continue;
}
result
.entry(*key)
.or_default()
.extend(values.iter().copied());
}
result
}
fn nested_meet(a: &NestedSetMap, b: &NestedSetMap) -> NestedSetMap {
let mut result = NestedSetMap::new();
for (key, a_values) in a {
let Some(b_values) = b.get(key) else {
continue;
};
let values = a_values
.intersection(b_values)
.copied()
.collect::<HashSet<_>>();
if !values.is_empty() {
result.insert(*key, values);
}
}
result
}
fn nested_subtract(a: &NestedSetMap, b: &NestedSetMap) -> NestedSetMap {
let mut result = NestedSetMap::new();
for (key, a_values) in a {
let values = if let Some(b_values) = b.get(key) {
a_values.difference(b_values).copied().collect()
} else {
a_values.clone()
};
if !values.is_empty() {
result.insert(*key, values);
}
}
result
}
#[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));
}
#[test]
fn seeded_hash_set_operations_match_set_oracle() {
#[cfg(miri)]
const SEEDS: u64 = 1;
#[cfg(not(miri))]
const SEEDS: u64 = 256;
for seed in 0..SEEDS {
let a = generated_set(seed, 0x243f_6a88_85a3_08d3);
let b = generated_set(seed, 0x1319_8a2e_0370_7344);
let expected_join = a.union(&b).copied().collect::<HashSet<_>>();
assert_binary_result(
a.pjoin(&b),
&a,
&b,
&expected_join,
true,
&format!("HashSet join seed {seed}"),
);
let mut join_in_place = a.clone();
join_in_place.join_into(b.clone());
assert_eq!(
join_in_place, expected_join,
"HashSet join_into seed {seed}"
);
let expected_meet = a.intersection(&b).copied().collect::<HashSet<_>>();
assert_binary_result(
a.pmeet(&b),
&a,
&b,
&expected_meet,
true,
&format!("HashSet meet seed {seed}"),
);
let expected_subtract = a.difference(&b).copied().collect::<HashSet<_>>();
assert_binary_result(
a.psubtract(&b),
&a,
&b,
&expected_subtract,
false,
&format!("HashSet subtract seed {seed}"),
);
}
}
#[test]
fn seeded_hash_map_operations_match_nested_set_oracle() {
#[cfg(miri)]
const SEEDS: u64 = 1;
#[cfg(not(miri))]
const SEEDS: u64 = 256;
for seed in 0..SEEDS {
let a = generated_nested_map(seed, 0x243f_6a88_85a3_08d3);
let b = generated_nested_map(seed, 0x1319_8a2e_0370_7344);
let c = generated_nested_map(seed, 0xa409_3822_299f_31d0);
let expected_join = nested_join(&a, &b);
assert_nested_result(
a.pjoin(&b),
&a,
&b,
&expected_join,
true,
&format!("HashMap join seed {seed}"),
);
let mut join_in_place = a.clone();
join_in_place.join_into(b.clone());
assert_eq!(
normalize_nested_map(&join_in_place),
expected_join,
"HashMap join_into seed {seed}"
);
let expected_meet = nested_meet(&a, &b);
assert_nested_result(
a.pmeet(&b),
&a,
&b,
&expected_meet,
true,
&format!("HashMap meet seed {seed}"),
);
let expected_subtract = nested_subtract(&a, &b);
assert_nested_result(
a.psubtract(&b),
&a,
&b,
&expected_subtract,
false,
&format!("HashMap subtract seed {seed}"),
);
let ab_join = a.pjoin(&b).unwrap_or([&a, &b], NestedSetMap::new());
let expected_chain = nested_subtract(&nested_join(&a, &b), &c);
assert_nested_result(
ab_join.psubtract(&c),
&ab_join,
&c,
&expected_chain,
false,
&format!("HashMap chained join/subtract seed {seed}"),
);
}
}
#[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);
a.0.insert("C", HashMap::new());
b.0.insert("C", HashMap::new());
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()); a.0.remove("C");
b.0.remove("C");
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);
}
}