use std::borrow::Cow;
use std::fmt::{Display, Formatter};
use crate::formulas::{EncodedFormula, FormulaFactory, Variable};
use super::formula::ToFormula;
use super::formula_cache::formula_encoding::{Encoding, FormulaEncoding};
use super::{FormulaType, VarType};
#[derive(Copy, Clone, Hash, Eq, PartialEq, Ord, PartialOrd, Debug)]
pub enum LitType {
Pos(VarType),
Neg(VarType),
}
#[derive(Hash, Eq, PartialEq, Copy, Clone, Debug, Ord, PartialOrd)]
pub enum Literal {
Pos(Variable),
Neg(Variable),
}
impl Literal {
pub const fn new(variable: Variable, phase: bool) -> Self {
if phase {
Self::Pos(variable)
} else {
Self::Neg(variable)
}
}
pub const fn variable(&self) -> Variable {
match self {
Self::Pos(v) | Self::Neg(v) => *v,
}
}
pub const fn phase(&self) -> bool {
match self {
Self::Pos(_) => true,
Self::Neg(_) => false,
}
}
pub fn name<'a>(&self, f: &'a FormulaFactory) -> Cow<'a, str> {
self.variable().name(f)
}
pub fn aux_name(&self, f: &FormulaFactory) -> Option<String> {
self.variable().aux_name(f)
}
#[must_use]
pub const fn negate(&self) -> Self {
Self::new(self.variable(), !self.phase())
}
pub fn to_string_lit<'a>(&self, f: &'a FormulaFactory) -> StringLiteral<'a> {
StringLiteral { name: self.name(f), phase: self.phase() }
}
pub fn to_string(&self, f: &FormulaFactory) -> String {
let sign = if self.phase() { "" } else { "~" };
format!("{sign}{}", self.name(f))
}
}
impl From<Literal> for EncodedFormula {
fn from(lit: Literal) -> Self {
let (index, ty) = match lit {
Literal::Pos(var) => (var.index(), LitType::Pos(var.var_type())),
Literal::Neg(var) => (var.index(), LitType::Neg(var.var_type())),
};
Self::from(FormulaEncoding::encode(index, FormulaType::Lit(ty), true))
}
}
impl ToFormula for Literal {
fn to_formula(&self, _: &FormulaFactory) -> EncodedFormula {
(*self).into()
}
}
#[derive(PartialOrd, PartialEq, Ord, Eq, Debug, Clone)]
pub struct StringLiteral<'a> {
pub name: Cow<'a, str>,
pub phase: bool,
}
impl<'a> StringLiteral<'a> {
pub fn new(name: &'a str, phase: bool) -> Self {
StringLiteral { name: Cow::from(name), phase }
}
pub fn new_owned(name: String, phase: bool) -> Self {
StringLiteral { name: Cow::from(name), phase }
}
pub fn new_variable(name: &'a str) -> Self {
StringLiteral::new(name, true)
}
pub fn new_variable_owned(name: String) -> Self {
StringLiteral::new_owned(name, true)
}
pub fn to_literal(&self, f: &FormulaFactory) -> Literal {
f.lit(&self.name, self.phase)
}
}
pub trait ToStringLiteral {
fn to_string_literal(self) -> StringLiteral<'static>;
}
impl ToStringLiteral for String {
fn to_string_literal(self) -> StringLiteral<'static> {
let trimmed = self.trim();
if trimmed.starts_with('~') || trimmed.starts_with('-') {
StringLiteral::new_owned(trimmed[1..].into(), false)
} else {
StringLiteral::new_owned(trimmed.into(), true)
}
}
}
impl<'a> ToFormula for StringLiteral<'a> {
fn to_formula(&self, f: &FormulaFactory) -> EncodedFormula {
f.literal(&self.name, self.phase)
}
}
impl<'a> Display for StringLiteral<'a> {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
write!(f, "{}{}", if self.phase { "" } else { "~" }, self.name)
}
}