use std::borrow::Cow;
use std::borrow::Cow::{Borrowed, Owned};
use std::str::FromStr;
use crate::formulas::formula_cache::formula_encoding::Encoding;
use crate::formulas::formula_factory::AUX_PREFIX;
use crate::formulas::{EncodedFormula, FormulaFactory, FormulaType, LitType, Literal, StringLiteral};
use super::formula::ToFormula;
use super::formula_cache::formula_encoding::FormulaEncoding;
#[derive(Copy, Clone, Hash, Eq, PartialEq, Ord, PartialOrd, Debug)]
pub enum VarType {
FF,
Aux(AuxVarType),
}
#[derive(Copy, Clone, Hash, Eq, PartialEq, Ord, PartialOrd, Debug)]
pub enum AuxVarType {
CNF,
CC,
PB,
TMP,
}
impl AuxVarType {
fn prefix(self, id: &str) -> String {
match self {
Self::CNF => format!("{AUX_PREFIX}{id}_CNF_"),
Self::CC => format!("{AUX_PREFIX}{id}_CC_"),
Self::PB => format!("{AUX_PREFIX}{id}_PB_"),
Self::TMP => format!("{AUX_PREFIX}{id}_TMP_"),
}
}
}
impl FromStr for AuxVarType {
type Err = String;
fn from_str(input: &str) -> Result<Self, Self::Err> {
match input {
"CNF" => Ok(Self::CNF),
"CC" => Ok(Self::CC),
"PB" | "TMP" => Ok(Self::PB),
_ => Err(format!("Unknown AuxVarType: {input}")),
}
}
}
#[derive(Hash, Eq, PartialEq, Copy, Clone, Debug, Ord, PartialOrd)]
pub enum Variable {
FF(FormulaEncoding),
Aux(AuxVarType, u64),
}
impl Variable {
pub fn from_index(index: u64) -> Self {
let enc = FormulaEncoding::encode(index, FormulaType::Lit(LitType::Pos(VarType::FF)), true);
Self::FF(enc)
}
pub fn name<'a>(&self, f: &'a FormulaFactory) -> Cow<'a, str> {
match self {
Self::FF(i) => Borrowed(f.var_name(*i)),
Self::Aux(t, i) => Owned(format!("{}{}", t.prefix(&f.id), *i)),
}
}
pub fn aux_name(&self, f: &FormulaFactory) -> Option<String> {
match self {
Self::FF(_) => None,
Self::Aux(t, i) => Some(format!("{}{}", t.prefix(&f.id), *i)),
}
}
pub const fn negate(&self) -> Literal {
Literal::new(*self, false)
}
pub const fn pos_lit(&self) -> Literal {
Literal::Pos(*self)
}
pub const fn neg_lit(&self) -> Literal {
Literal::Neg(*self)
}
pub fn to_string_lit<'a>(&self, f: &'a FormulaFactory) -> StringLiteral<'a> {
StringLiteral { name: self.name(f), phase: true }
}
pub const fn var_type(self) -> VarType {
match self {
Self::FF(_) => VarType::FF,
Self::Aux(ty, _) => VarType::Aux(ty),
}
}
pub(super) fn index(self) -> u64 {
match self {
Self::FF(i) => i.index(),
Self::Aux(_, i) => i,
}
}
}
impl From<Variable> for EncodedFormula {
fn from(var: Variable) -> Self {
Self::from(Literal::new(var, true))
}
}
impl ToFormula for Variable {
fn to_formula(&self, _: &FormulaFactory) -> EncodedFormula {
(*self).into()
}
}
impl TryFrom<FormulaEncoding> for Variable {
type Error = String;
fn try_from(enc: FormulaEncoding) -> Result<Self, Self::Error> {
match enc.formula_type() {
FormulaType::Lit(LitType::Pos(VarType::Aux(aux_type)) | LitType::Neg(VarType::Aux(aux_type))) => {
Ok(Self::Aux(aux_type, enc.index()))
}
FormulaType::Lit(LitType::Pos(VarType::FF) | LitType::Neg(VarType::FF)) => {
Ok(Self::FF(FormulaEncoding::encode(enc.index(), FormulaType::Lit(LitType::Pos(VarType::FF)), true)))
}
_ => Err(format!("Cannot convert {:?} to an variable!", enc.formula_type())),
}
}
}