#[cfg(feature = "mem_dbg")]
use mem_dbg::{MemDbg, MemSize};
use crate::{BoxSlice, Error, NonMaxU32, Result};
use std::fmt;
use super::{
ENode, ENodeIdx, EqTransIdx, MatchIdx, PatternIdx, ProofIdx, QuantIdx, QuantPat, StackIdx,
TermId, TermIdx,
};
#[cfg_attr(feature = "mem_dbg", derive(MemSize, MemDbg))]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[derive(Debug, Clone)]
pub struct Match {
pub kind: MatchKind,
pub blamed: Box<[Blame]>,
pub frame: StackIdx,
}
impl Match {
pub fn pattern_matches(&self) -> impl Iterator<Item = &Blame> {
self.blamed.iter()
}
}
#[cfg_attr(feature = "mem_dbg", derive(MemSize, MemDbg))]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[derive(Debug, Clone, Hash, Eq, PartialEq)]
pub enum MatchKind {
MBQI {
quant: QuantIdx,
bound_terms: BoxSlice<ENodeIdx>,
},
TheorySolving {
axiom_id: TermId,
bound_terms: BoxSlice<TermIdx>,
rewrite_of: Option<TermIdx>,
},
Axiom {
axiom: QuantIdx,
pattern: PatternIdx,
bound_terms: BoxSlice<TermIdx>,
},
Quantifier {
quant: QuantIdx,
pattern: PatternIdx,
bound_terms: BoxSlice<ENodeIdx>,
},
}
#[derive(Debug, Clone, Copy)]
pub struct BoundVars<'a, T: Copy>(&'a [T]);
impl<'a, T: Copy> BoundVars<'a, T> {
pub fn get(&self, idx: NonMaxU32) -> Option<T> {
self.0.get(idx.get() as usize).copied()
}
}
impl MatchKind {
pub fn quant_pat(&self) -> Option<QuantPat> {
self.quant_idx().map(|quant| QuantPat {
quant,
pat: self.pattern(),
})
}
pub fn quant_idx(&self) -> Option<QuantIdx> {
match self {
Self::MBQI { quant, .. }
| Self::Axiom { axiom: quant, .. }
| Self::Quantifier { quant, .. } => Some(*quant),
_ => None,
}
}
pub fn pattern(&self) -> Option<PatternIdx> {
match self {
Self::MBQI { .. } | Self::TheorySolving { .. } => None,
Self::Axiom { pattern, .. } | Self::Quantifier { pattern, .. } => Some(*pattern),
}
}
pub fn bound_terms<T>(
&self,
enode: impl Fn(ENodeIdx) -> T,
term: impl Fn(TermIdx) -> T,
) -> Box<[T]> {
match self {
Self::MBQI { bound_terms, .. } | Self::Quantifier { bound_terms, .. } => {
bound_terms.iter().map(|&x| enode(x)).collect()
}
Self::TheorySolving { bound_terms, .. } | Self::Axiom { bound_terms, .. } => {
bound_terms.iter().map(|&x| term(x)).collect()
}
}
}
pub fn is_discovered(&self) -> bool {
self.quant_idx().is_none()
}
pub fn is_mbqi(&self) -> bool {
matches!(self, Self::MBQI { .. })
}
pub fn rewrite_of(&self) -> Option<TermIdx> {
match self {
Self::TheorySolving { rewrite_of, .. } => *rewrite_of,
_ => None,
}
}
pub fn bound_term<'a>(
&self,
to_tidx: impl Fn(ENodeIdx) -> &'a ENode,
qvar: NonMaxU32,
) -> Option<TermIdx> {
match self {
Self::MBQI { bound_terms, .. } | Self::Quantifier { bound_terms, .. } => {
BoundVars(bound_terms)
.get(qvar)
.map(to_tidx)
.map(|e| e.owner)
}
Self::TheorySolving { bound_terms, .. } | Self::Axiom { bound_terms, .. } => {
BoundVars(bound_terms).get(qvar)
}
}
}
pub fn quant_and_enodes(&self) -> Option<(QuantIdx, BoundVars<'_, ENodeIdx>)> {
match self {
Self::MBQI { quant, bound_terms }
| Self::Quantifier {
quant, bound_terms, ..
} => Some((*quant, BoundVars(bound_terms))),
Self::TheorySolving { .. } | Self::Axiom { .. } => None,
}
}
}
#[cfg_attr(feature = "mem_dbg", derive(MemSize, MemDbg))]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct Blame {
pub coupling: Coupling,
pub enode: ENodeIdx,
pub equalities: BoxSlice<EqTransIdx>,
}
#[cfg_attr(feature = "mem_dbg", derive(MemSize, MemDbg))]
#[cfg_attr(feature = "mem_dbg", copy_type)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum Coupling {
Exact,
SwappedEqs,
MissingEqs,
AddedEqs,
Error,
}
impl Blame {
pub fn is_complete(&self) -> bool {
matches!(
self.coupling,
Coupling::Exact | Coupling::SwappedEqs | Coupling::MissingEqs
)
}
}
#[cfg_attr(feature = "mem_dbg", derive(MemSize, MemDbg))]
#[cfg_attr(feature = "mem_dbg", copy_type)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct Fingerprint(pub u64);
impl Fingerprint {
pub fn parse(value: &str) -> Result<Self> {
u64::from_str_radix(value.strip_prefix("0x").unwrap_or(value), 16)
.map(Self)
.map_err(Error::InvalidFingerprint)
}
pub fn is_zero(&self) -> bool {
self.0 == 0
}
}
impl std::ops::Deref for Fingerprint {
type Target = u64;
fn deref(&self) -> &Self::Target {
&self.0
}
}
impl fmt::Display for Fingerprint {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{:x}", self.0)
}
}
#[cfg_attr(feature = "mem_dbg", derive(MemSize, MemDbg))]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[derive(Debug, Clone)]
pub struct Instantiation {
pub match_: MatchIdx,
pub kind: InstantiationKind,
pub yields_terms: BoxSlice<ENodeIdx>,
pub frame: StackIdx,
}
#[cfg_attr(feature = "mem_dbg", derive(MemSize, MemDbg))]
#[cfg_attr(feature = "mem_dbg", copy_type)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[derive(Debug, Clone, Copy)]
pub enum InstantiationKind {
Axiom { body: TermIdx },
NonAxiom {
fingerprint: Fingerprint,
z3_generation: NonMaxU32,
proof: InstProofLink,
},
}
impl InstantiationKind {
pub fn fingerprint(&self) -> Fingerprint {
match self {
Self::NonAxiom { fingerprint, .. } => *fingerprint,
_ => Fingerprint(0),
}
}
pub fn z3_generation(&self) -> Option<NonMaxU32> {
match self {
Self::NonAxiom { z3_generation, .. } => Some(*z3_generation),
_ => None,
}
}
pub fn proof(&self) -> Option<ProofIdx> {
match self {
Self::NonAxiom {
proof: InstProofLink::HasProof(proof),
..
} => Some(*proof),
_ => None,
}
}
}
#[cfg_attr(feature = "mem_dbg", derive(MemSize, MemDbg))]
#[cfg_attr(feature = "mem_dbg", copy_type)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[derive(Debug, Clone, Copy)]
pub enum InstProofLink {
HasProof(ProofIdx),
ProofsDisabled(Option<TermIdx>),
}