use super::functions::Decidable;
use super::functions::*;
use std::fmt;
#[derive(Debug, Clone)]
pub struct NamedDecision {
pub name: String,
pub decision: Decision<()>,
}
impl NamedDecision {
pub fn new(name: impl Into<String>, decision: Decision<()>) -> Self {
Self {
name: name.into(),
decision,
}
}
pub fn is_true(&self) -> bool {
self.decision.is_true()
}
pub fn summary(&self) -> String {
let verdict = if self.is_true() { "✓" } else { "✗" };
format!("[{verdict}] {}", self.name)
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum BoolReflect {
IsTrue,
IsFalse,
}
impl BoolReflect {
pub fn from_decision(d: &Decision<()>) -> Self {
if d.is_true() {
BoolReflect::IsTrue
} else {
BoolReflect::IsFalse
}
}
pub fn to_bool(&self) -> bool {
*self == BoolReflect::IsTrue
}
}
#[derive(Clone, Debug, Default)]
pub struct DecidableCounter {
pub true_count: usize,
pub false_count: usize,
}
impl DecidableCounter {
pub fn new() -> Self {
Self::default()
}
pub fn record(&mut self, d: &Decision<()>) {
if d.is_true() {
self.true_count += 1;
} else {
self.false_count += 1;
}
}
pub fn total(&self) -> usize {
self.true_count + self.false_count
}
pub fn true_rate(&self) -> f64 {
if self.total() == 0 {
0.0
} else {
(self.true_count as f64 / self.total() as f64) * 100.0
}
}
pub fn all_true(&self) -> bool {
self.false_count == 0 && self.total() > 0
}
pub fn all_false(&self) -> bool {
self.true_count == 0 && self.total() > 0
}
pub fn reset(&mut self) {
self.true_count = 0;
self.false_count = 0;
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum Decision<P> {
IsTrue(P),
IsFalse(String),
}
impl<P> Decision<P> {
pub fn is_true(&self) -> bool {
matches!(self, Decision::IsTrue(_))
}
pub fn is_false(&self) -> bool {
matches!(self, Decision::IsFalse(_))
}
pub fn unwrap(self) -> P {
match self {
Decision::IsTrue(p) => p,
Decision::IsFalse(msg) => panic!("Decision::unwrap on IsFalse: {msg}"),
}
}
pub fn into_option(self) -> Option<P> {
match self {
Decision::IsTrue(p) => Some(p),
Decision::IsFalse(_) => None,
}
}
pub fn map<Q>(self, f: impl FnOnce(P) -> Q) -> Decision<Q> {
match self {
Decision::IsTrue(p) => Decision::IsTrue(f(p)),
Decision::IsFalse(msg) => Decision::IsFalse(msg),
}
}
pub fn and<Q>(self, other: Decision<Q>) -> Decision<(P, Q)> {
match (self, other) {
(Decision::IsTrue(p), Decision::IsTrue(q)) => Decision::IsTrue((p, q)),
(Decision::IsFalse(m), _) | (_, Decision::IsFalse(m)) => Decision::IsFalse(m),
}
}
pub fn or(self, other: Decision<P>) -> Decision<P> {
match self {
Decision::IsTrue(_) => self,
Decision::IsFalse(_) => other,
}
}
pub fn negate(self) -> Decision<String>
where
P: std::fmt::Debug,
{
match self {
Decision::IsTrue(p) => Decision::IsFalse(format!("expected false but got: {p:?}")),
Decision::IsFalse(msg) => Decision::IsTrue(msg),
}
}
pub fn flat_map<Q>(self, f: impl FnOnce(P) -> Decision<Q>) -> Decision<Q> {
match self {
Decision::IsTrue(p) => f(p),
Decision::IsFalse(msg) => Decision::IsFalse(msg),
}
}
pub fn unwrap_or(self, default: P) -> P {
match self {
Decision::IsTrue(p) => p,
Decision::IsFalse(_) => default,
}
}
pub fn unwrap_or_else(self, f: impl FnOnce(String) -> P) -> P {
match self {
Decision::IsTrue(p) => p,
Decision::IsFalse(msg) => f(msg),
}
}
}
impl Decision<bool> {
pub fn to_bool(&self) -> bool {
match self {
Decision::IsTrue(b) => *b,
Decision::IsFalse(_) => false,
}
}
}
#[derive(Clone, Debug)]
pub struct DecisionChain {
steps: Vec<(String, Decision<()>)>,
}
impl DecisionChain {
pub fn new() -> Self {
Self { steps: Vec::new() }
}
pub fn step(mut self, name: impl Into<String>, d: Decision<()>) -> Self {
self.steps.push((name.into(), d));
self
}
pub fn all_passed(&self) -> bool {
self.steps.iter().all(|(_, d)| d.is_true())
}
pub fn first_failure(&self) -> Option<&str> {
self.steps
.iter()
.find(|(_, d)| d.is_false())
.map(|(name, _)| name.as_str())
}
pub fn len(&self) -> usize {
self.steps.len()
}
pub fn is_empty(&self) -> bool {
self.steps.is_empty()
}
pub fn passed_count(&self) -> usize {
self.steps.iter().filter(|(_, d)| d.is_true()).count()
}
pub fn failed_count(&self) -> usize {
self.steps.iter().filter(|(_, d)| d.is_false()).count()
}
}
#[allow(dead_code)]
pub struct DecisionProcedureExt {
procedure_name: String,
complete: bool,
sound: bool,
complexity: String,
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct Not<P> {
pub message: String,
_marker: std::marker::PhantomData<P>,
}
impl<P> Not<P> {
pub fn new(message: impl Into<String>) -> Self {
Self {
message: message.into(),
_marker: std::marker::PhantomData,
}
}
pub fn message(&self) -> &str {
&self.message
}
}
#[allow(dead_code)]
pub struct DecidablePropExt {
name: String,
constructive: bool,
bool_reflect: Option<bool>,
}
#[allow(dead_code)]
pub struct DecidableSetExt<T: Eq> {
elements: Vec<T>,
dec_eq: std::marker::PhantomData<T>,
}
#[derive(Clone, Debug)]
pub struct EqDecision<T> {
pub(super) lhs: T,
pub(super) rhs: T,
}
impl<T: PartialEq + std::fmt::Debug> EqDecision<T> {
pub fn new(lhs: T, rhs: T) -> Self {
Self { lhs, rhs }
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct FiniteSet<T: PartialEq> {
elems: Vec<T>,
}
impl<T: PartialEq> FiniteSet<T> {
pub fn new() -> Self {
Self { elems: Vec::new() }
}
pub fn insert(&mut self, x: T) -> bool {
if self.elems.contains(&x) {
false
} else {
self.elems.push(x);
true
}
}
pub fn contains(&self, x: &T) -> bool {
self.elems.contains(x)
}
pub fn remove(&mut self, x: &T) -> bool {
if let Some(pos) = self.elems.iter().position(|e| e == x) {
self.elems.remove(pos);
true
} else {
false
}
}
pub fn len(&self) -> usize {
self.elems.len()
}
pub fn is_empty(&self) -> bool {
self.elems.is_empty()
}
pub fn iter(&self) -> impl Iterator<Item = &T> {
self.elems.iter()
}
pub fn union(&self, other: &Self) -> Self
where
T: Clone,
{
let mut result = self.clone();
for x in &other.elems {
result.insert(x.clone());
}
result
}
pub fn intersection(&self, other: &Self) -> Self
where
T: Clone,
{
Self {
elems: self
.elems
.iter()
.filter(|x| other.contains(x))
.cloned()
.collect(),
}
}
pub fn difference(&self, other: &Self) -> Self
where
T: Clone,
{
Self {
elems: self
.elems
.iter()
.filter(|x| !other.contains(x))
.cloned()
.collect(),
}
}
pub fn is_subset(&self, other: &Self) -> bool {
self.elems.iter().all(|x| other.contains(x))
}
}
#[derive(Debug, Clone, Default)]
pub struct DecisionTable {
entries: Vec<(String, Decision<()>)>,
}
impl DecisionTable {
pub fn new() -> Self {
Self::default()
}
pub fn insert(&mut self, name: impl Into<String>, d: Decision<()>) {
let name = name.into();
if let Some(entry) = self.entries.iter_mut().find(|(k, _)| k == &name) {
entry.1 = d;
} else {
self.entries.push((name, d));
}
}
pub fn lookup(&self, name: &str) -> Option<&Decision<()>> {
self.entries.iter().find(|(k, _)| k == name).map(|(_, v)| v)
}
pub fn len(&self) -> usize {
self.entries.len()
}
pub fn is_empty(&self) -> bool {
self.entries.is_empty()
}
pub fn iter(&self) -> impl Iterator<Item = (&str, &Decision<()>)> {
self.entries.iter().map(|(k, v)| (k.as_str(), v))
}
}
#[derive(Clone)]
pub struct FnPred<A, F>(pub(super) F, pub(super) std::marker::PhantomData<A>)
where
F: Fn(&A) -> bool;
impl<A, F: Fn(&A) -> bool> FnPred<A, F> {
pub fn new(f: F) -> Self {
Self(f, std::marker::PhantomData)
}
}
#[allow(dead_code)]
pub struct SemiDecidableExt<T> {
predicate: std::marker::PhantomData<T>,
is_total: bool,
}
#[derive(Clone, Debug)]
pub struct LeDecision<T> {
pub(super) lhs: T,
pub(super) rhs: T,
}
impl<T: PartialOrd> LeDecision<T> {
pub fn new(lhs: T, rhs: T) -> Self {
Self { lhs, rhs }
}
}
#[allow(dead_code)]
pub struct HaltingOracleExt {
oracle_name: String,
undecidable: bool,
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub struct Interval {
pub lo: i64,
pub hi: i64,
}
impl Interval {
pub fn new(lo: i64, hi: i64) -> Self {
Self { lo, hi }
}
pub fn point(x: i64) -> Self {
Self { lo: x, hi: x }
}
pub fn contains(&self, x: i64) -> bool {
x >= self.lo && x <= self.hi
}
pub fn is_empty(&self) -> bool {
self.lo > self.hi
}
pub fn len(&self) -> u64 {
if self.is_empty() {
0
} else {
(self.hi - self.lo) as u64 + 1
}
}
pub fn intersect(&self, other: &Interval) -> Interval {
Interval {
lo: self.lo.max(other.lo),
hi: self.hi.min(other.hi),
}
}
pub fn union(&self, other: &Interval) -> Interval {
Interval {
lo: self.lo.min(other.lo),
hi: self.hi.max(other.hi),
}
}
pub fn decide_contains(&self, x: i64) -> Decision<()> {
if self.contains(x) {
Decision::IsTrue(())
} else {
Decision::IsFalse(format!("{x} not in [{}, {}]", self.lo, self.hi))
}
}
}