commit 2e061e32bd370e1a0eefd30a6f2779cf1939808b Author: Spencer Killen Date: Thu Dec 21 01:28:16 2023 -0700 temp diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..ea8c4bf --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +/target diff --git a/Cargo.lock b/Cargo.lock new file mode 100644 index 0000000..cbbd195 --- /dev/null +++ b/Cargo.lock @@ -0,0 +1,25 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "either" +version = "1.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a26ae43d7bcc3b814de94796a5e736d4029efb0ee900c12e2d54c993ad1a1e07" + +[[package]] +name = "finset-lattice-experiments" +version = "0.1.0" +dependencies = [ + "itertools", +] + +[[package]] +name = "itertools" +version = "0.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "25db6b064527c5d482d0423354fcd07a89a2dfe07b67892e62411946db7f07b0" +dependencies = [ + "either", +] diff --git a/Cargo.toml b/Cargo.toml new file mode 100644 index 0000000..483ee99 --- /dev/null +++ b/Cargo.toml @@ -0,0 +1,9 @@ +[package] +name = "finset-lattice-experiments" +version = "0.1.0" +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +itertools = "0.12.0" diff --git a/src/main.rs b/src/main.rs new file mode 100644 index 0000000..f671a4d --- /dev/null +++ b/src/main.rs @@ -0,0 +1,286 @@ +use std::{fmt::Display, iter::repeat}; + +use itertools::Itertools; + +enum IncrementResult { + Overflow, + Good, +} +use IncrementResult::*; + +trait Incrementable { + fn increment(&mut self) -> IncrementResult; +} + +#[derive(Debug, Default, Clone)] +struct Atom { + smaller: Vec, +} + +impl Incrementable for Atom { + fn increment(&mut self) -> IncrementResult { + for a in &mut self.smaller { + *a = !*a; + if *a { + return Good; + } + } + return Overflow; + } +} + +#[derive(Debug, Default)] +struct Lattice { + order: Vec, +} + +trait LatticeAbstract { + fn le(&self, a: usize, b: usize) -> bool; + fn grow(&mut self); +} + +impl Display for Lattice { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + for (i, atom) in self.order.iter().enumerate() { + let s = atom + .smaller + .iter() + .map(|&b| if b { "1 " } else { "0 " }) + .collect::(); + writeln!(f, "{}: {}", i, s)?; + } + Ok(()) + } +} + +impl Incrementable for Lattice { + fn increment(&mut self) -> IncrementResult { + for atom in &mut self.order { + if let Good = atom.increment() { + return Good; + } + } + return Overflow; + } +} + +impl Lattice +where + Self: LatticeAbstract, +{ + fn next_lattice(&mut self) { + self.increment(); + while !self.is_lattice() { + if let Overflow = self.increment() { + self.grow(); + } + } + } + fn ge(&self, a: usize, b: usize) -> bool { + return self.le(b, a); + } + // The underlying ordering might not be transitive, this makes it so + fn le_transitive(&self, a: usize, b: usize) -> bool { + if self.le(a, b) { + return true; + } + for (b, &active) in self.order[b].smaller.iter().enumerate() { + if active && self.le_transitive(a, b) { + return true; + } + } + return false; + } + fn is_transitive(&self) -> bool { + for (i, j) in (0..self.order.len()).cartesian_product(0..self.order.len()) { + if !self.le(i, j) && self.le_transitive(i, j) { + return false; + } + } + return true; + } + fn is_bounded(&self, subset: &Vec, bound_candidates: C, rel: F) -> bool + where + C: Iterator, + F: Fn(&Self, usize, usize) -> bool, + { + let mut bound: Option = None; + for new_bound in bound_candidates { + let is_bound = || subset.iter().all(|&el| rel(self, el, new_bound)); + if let Some(old_bound) = bound { + if rel(self, old_bound, new_bound) { + continue; + } else if rel(self, new_bound, old_bound) { + panic!("Bound candidates must be sorted topologically"); + } else if is_bound() { + return false; + } + } else if is_bound() { + bound = Some(new_bound); + } + } + return true; + } + + fn is_lattice(&self) -> bool { + if !self.is_transitive() { + return false; + } + // A top/bottom element are inherent as are partial order conditions. + // Lattice condition can only fail if a set of elements have non comparable upper/lower bounds + // Possible optimization: a lack of LUB might imply no GLB so may only need to check one of them + let mut subsets = (0..self.order.len()).powerset(); + subsets.next(); // Skip the empty set + for subset in subsets { + if !self.is_bounded(&subset, 0..self.order.len(), Lattice::le) { + return false; + } + if !self.is_bounded(&subset, (0..self.order.len()).rev(), Lattice::ge) { + return false; + } + } + return true; + } +} + +impl LatticeAbstract for Lattice { + fn le(&self, a: usize, b: usize) -> bool { + if a == b { + return true; + } + if a > b { + return false; + } + if self.order[b].smaller[a] { + return true; + } + return false; + } + fn grow(&mut self) { + self.order = vec![Default::default(); self.order.len() + 1]; + for (i, atom) in self.order.iter_mut().enumerate() { + *atom = Atom { + smaller: vec![false; i], + } + } + } +} + +fn main() { + let mut lattice = Lattice::default(); + for (i, _) in repeat(0).enumerate() { + print!("{}", lattice); + println!("iteration {}", i); + lattice.next_lattice(); + } +} + +#[cfg(test)] +mod tests { + use super::*; + use std::error::Error; + + #[test] + fn test_is_lattice() -> Result<(), Box> { + let lattice = Lattice { + order: vec![ + Atom { smaller: vec![] }, + Atom { + smaller: vec![true], + }, + Atom { + smaller: vec![true, false], + }, + ], + }; + assert!(lattice.is_lattice()); + let lattice = Lattice { + order: vec![ + Atom { smaller: vec![] }, + Atom { + smaller: vec![false], + }, + Atom { + smaller: vec![true, true], + }, + ], + }; + assert!(lattice.is_lattice()); + Ok(()) + } + #[test] + fn test_is_not_lattice() -> Result<(), Box> { + let lattice = Lattice { + order: vec![ + Atom { smaller: vec![] }, + Atom { + smaller: vec![true], + }, + Atom { + smaller: vec![false, true], + }, + ], + }; + assert!(!lattice.is_transitive()); + let lattice = Lattice { + order: vec![ + Atom { smaller: vec![] }, + Atom { + smaller: vec![false], + }, + Atom { + smaller: vec![true, true], + }, + Atom { + smaller: vec![true, true, false], + }, + ], + }; + assert!(lattice.is_transitive()); + assert!(!lattice.is_lattice()); + Ok(()) + } +} + +// struct Operator<'a> { +// lattice: &'a Lattice, +// top: Vec, +// ul: Vec, +// ur: Vec, +// dl: Vec, +// dr: Vec, +// bot: Vec, +// } + +// impl<'a> Operator<'a> { +// fn new(lattice: &'a Lattice) -> Self { +// Operator { +// lattice, +// top: vec![false; lattice.order.len()], +// ul: vec![false; lattice.order.len()], +// ur: vec![false; lattice.order.len()], +// dl: vec![false; lattice.order.len()], +// dr: vec![false; lattice.order.len()], +// bot: vec![false; lattice.order.len()], +// } +// } +// fn increment(&mut self) { +// let mut data = [ +// &mut self.bot, +// &mut self.dr, +// &mut self.dl, +// &mut self.ur, +// &mut self.ul, +// &mut self.top, +// ]; +// data[4][0] = false; +// for (i, el) in data.iter_mut().enumerate() { +// for a in el.iter_mut() { +// *a = !*a; +// if *a { +// return; +// } +// } +// } +// } +// }