#[allow(unused_imports)]
use crate::prelude::*;
use core::ops::Not;
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)]
pub struct Var(pub u32);
impl Var {
#[must_use]
pub const fn new(idx: u32) -> Self {
Self(idx)
}
#[must_use]
pub const fn index(self) -> usize {
self.0 as usize
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct Lit(u32);
impl Lit {
#[must_use]
pub const fn pos(var: Var) -> Self {
Self(var.0 << 1)
}
#[must_use]
pub const fn neg(var: Var) -> Self {
Self((var.0 << 1) | 1)
}
#[must_use]
pub fn from_dimacs(lit: i32) -> Self {
debug_assert!(lit != 0);
let var = Var::new(lit.unsigned_abs() - 1);
if lit > 0 {
Self::pos(var)
} else {
Self::neg(var)
}
}
#[must_use]
pub fn to_dimacs(self) -> i32 {
let var = (self.var().0 + 1) as i32;
if self.is_pos() { var } else { -var }
}
#[must_use]
pub const fn var(self) -> Var {
Var(self.0 >> 1)
}
#[must_use]
pub const fn is_pos(self) -> bool {
(self.0 & 1) == 0
}
#[must_use]
pub const fn is_neg(self) -> bool {
(self.0 & 1) == 1
}
#[must_use]
pub const fn negate(self) -> Self {
Self(self.0 ^ 1)
}
#[must_use]
pub const fn sign(self) -> bool {
self.is_pos()
}
#[must_use]
pub const fn code(self) -> u32 {
self.0
}
#[must_use]
pub const fn from_code(code: u32) -> Self {
Self(code)
}
#[must_use]
pub const fn index(self) -> usize {
self.0 as usize
}
}
impl Not for Lit {
type Output = Self;
fn not(self) -> Self::Output {
self.negate()
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum LBool {
True,
False,
Undef,
}
impl LBool {
#[must_use]
pub const fn from_bool(b: bool) -> Self {
if b { Self::True } else { Self::False }
}
#[must_use]
pub const fn is_defined(self) -> bool {
!matches!(self, Self::Undef)
}
#[must_use]
pub const fn is_true(self) -> bool {
matches!(self, Self::True)
}
#[must_use]
pub const fn is_false(self) -> bool {
matches!(self, Self::False)
}
#[must_use]
pub const fn negate(self) -> Self {
match self {
Self::True => Self::False,
Self::False => Self::True,
Self::Undef => Self::Undef,
}
}
}
impl From<bool> for LBool {
fn from(b: bool) -> Self {
Self::from_bool(b)
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_literal_creation() {
let var = Var::new(0);
let pos = Lit::pos(var);
let neg = Lit::neg(var);
assert!(pos.is_pos());
assert!(neg.is_neg());
assert_eq!(pos.var(), var);
assert_eq!(neg.var(), var);
assert_eq!(pos.negate(), neg);
assert_eq!(neg.negate(), pos);
}
#[test]
fn test_dimacs_conversion() {
let lit = Lit::from_dimacs(1);
assert!(lit.is_pos());
assert_eq!(lit.var(), Var::new(0));
assert_eq!(lit.to_dimacs(), 1);
let lit = Lit::from_dimacs(-2);
assert!(lit.is_neg());
assert_eq!(lit.var(), Var::new(1));
assert_eq!(lit.to_dimacs(), -2);
}
#[test]
fn test_lbool() {
assert!(LBool::True.is_true());
assert!(LBool::False.is_false());
assert!(!LBool::Undef.is_defined());
assert_eq!(LBool::True.negate(), LBool::False);
assert_eq!(LBool::False.negate(), LBool::True);
assert_eq!(LBool::Undef.negate(), LBool::Undef);
}
}