1#[cfg(feature = "mem_dbg")]
2use mem_dbg::{MemDbg, MemSize};
3
4use crate::{BoxSlice, Error, NonMaxU32, Result};
5use std::fmt;
6
7use super::{
8 ENode, ENodeIdx, EqTransIdx, MatchIdx, PatternIdx, ProofIdx, QuantIdx, QuantPat, StackIdx,
9 TermId, TermIdx,
10};
11
12#[cfg_attr(feature = "mem_dbg", derive(MemSize, MemDbg))]
13#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
14#[derive(Debug, Clone)]
15pub struct Match {
16 pub kind: MatchKind,
17 pub blamed: Box<[Blame]>,
18 pub frame: StackIdx,
19}
20
21impl Match {
22 pub fn pattern_matches(&self) -> impl Iterator<Item = &Blame> {
28 self.blamed.iter()
29 }
30}
31
32#[cfg_attr(feature = "mem_dbg", derive(MemSize, MemDbg))]
33#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
34#[derive(Debug, Clone, Hash, Eq, PartialEq)]
35pub enum MatchKind {
36 MBQI {
37 quant: QuantIdx,
38 bound_terms: BoxSlice<ENodeIdx>,
39 },
40 TheorySolving {
41 axiom_id: TermId,
42 bound_terms: BoxSlice<TermIdx>,
43 rewrite_of: Option<TermIdx>,
44 },
45 Axiom {
46 axiom: QuantIdx,
47 pattern: PatternIdx,
48 bound_terms: BoxSlice<TermIdx>,
49 },
50 Quantifier {
51 quant: QuantIdx,
52 pattern: PatternIdx,
53 bound_terms: BoxSlice<ENodeIdx>,
54 },
55}
56
57#[derive(Debug, Clone, Copy)]
58pub struct BoundVars<'a, T: Copy>(&'a [T]);
59impl<'a, T: Copy> BoundVars<'a, T> {
60 pub fn get(&self, idx: NonMaxU32) -> Option<T> {
61 self.0.get(idx.get() as usize).copied()
62 }
63}
64
65impl MatchKind {
66 pub fn quant_pat(&self) -> Option<QuantPat> {
67 self.quant_idx().map(|quant| QuantPat {
68 quant,
69 pat: self.pattern(),
70 })
71 }
72
73 pub fn quant_idx(&self) -> Option<QuantIdx> {
74 match self {
75 Self::MBQI { quant, .. }
76 | Self::Axiom { axiom: quant, .. }
77 | Self::Quantifier { quant, .. } => Some(*quant),
78 _ => None,
79 }
80 }
81 pub fn pattern(&self) -> Option<PatternIdx> {
82 match self {
83 Self::MBQI { .. } | Self::TheorySolving { .. } => None,
84 Self::Axiom { pattern, .. } | Self::Quantifier { pattern, .. } => Some(*pattern),
85 }
86 }
87
88 pub fn bound_terms<T>(
89 &self,
90 enode: impl Fn(ENodeIdx) -> T,
91 term: impl Fn(TermIdx) -> T,
92 ) -> Box<[T]> {
93 match self {
94 Self::MBQI { bound_terms, .. } | Self::Quantifier { bound_terms, .. } => {
95 bound_terms.iter().map(|&x| enode(x)).collect()
96 }
97 Self::TheorySolving { bound_terms, .. } | Self::Axiom { bound_terms, .. } => {
98 bound_terms.iter().map(|&x| term(x)).collect()
99 }
100 }
101 }
102 pub fn is_discovered(&self) -> bool {
103 self.quant_idx().is_none()
104 }
105 pub fn is_mbqi(&self) -> bool {
106 matches!(self, Self::MBQI { .. })
107 }
108 pub fn rewrite_of(&self) -> Option<TermIdx> {
110 match self {
111 Self::TheorySolving { rewrite_of, .. } => *rewrite_of,
112 _ => None,
113 }
114 }
115
116 pub fn bound_term<'a>(
117 &self,
118 to_tidx: impl Fn(ENodeIdx) -> &'a ENode,
119 qvar: NonMaxU32,
120 ) -> Option<TermIdx> {
121 match self {
122 Self::MBQI { bound_terms, .. } | Self::Quantifier { bound_terms, .. } => {
123 BoundVars(bound_terms)
124 .get(qvar)
125 .map(to_tidx)
126 .map(|e| e.owner)
127 }
128 Self::TheorySolving { bound_terms, .. } | Self::Axiom { bound_terms, .. } => {
129 BoundVars(bound_terms).get(qvar)
130 }
131 }
132 }
133
134 pub fn quant_and_enodes(&self) -> Option<(QuantIdx, BoundVars<'_, ENodeIdx>)> {
135 match self {
136 Self::MBQI { quant, bound_terms }
137 | Self::Quantifier {
138 quant, bound_terms, ..
139 } => Some((*quant, BoundVars(bound_terms))),
140 Self::TheorySolving { .. } | Self::Axiom { .. } => None,
141 }
142 }
143}
144
145#[cfg_attr(feature = "mem_dbg", derive(MemSize, MemDbg))]
149#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
150#[derive(Debug, Clone, PartialEq, Eq, Hash)]
151pub struct Blame {
152 pub coupling: Coupling,
153 pub enode: ENodeIdx,
154 pub equalities: BoxSlice<EqTransIdx>,
155}
156
157#[cfg_attr(feature = "mem_dbg", derive(MemSize, MemDbg))]
158#[cfg_attr(feature = "mem_dbg", copy_type)]
159#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
160#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
161pub enum Coupling {
162 Exact,
165 SwappedEqs,
169 MissingEqs,
172 AddedEqs,
175 Error,
178}
179
180impl Blame {
181 pub fn is_complete(&self) -> bool {
182 matches!(
183 self.coupling,
184 Coupling::Exact | Coupling::SwappedEqs | Coupling::MissingEqs
185 )
186 }
187}
188
189#[cfg_attr(feature = "mem_dbg", derive(MemSize, MemDbg))]
192#[cfg_attr(feature = "mem_dbg", copy_type)]
193#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
194#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
195pub struct Fingerprint(pub u64);
196impl Fingerprint {
197 pub fn parse(value: &str) -> Result<Self> {
198 u64::from_str_radix(value.strip_prefix("0x").unwrap_or(value), 16)
199 .map(Self)
200 .map_err(Error::InvalidFingerprint)
201 }
202 pub fn is_zero(&self) -> bool {
203 self.0 == 0
204 }
205}
206impl std::ops::Deref for Fingerprint {
207 type Target = u64;
208 fn deref(&self) -> &Self::Target {
209 &self.0
210 }
211}
212impl fmt::Display for Fingerprint {
213 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
214 write!(f, "{:x}", self.0)
215 }
216}
217
218#[cfg_attr(feature = "mem_dbg", derive(MemSize, MemDbg))]
220#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
221#[derive(Debug, Clone)]
222pub struct Instantiation {
223 pub match_: MatchIdx,
224 pub kind: InstantiationKind,
225 pub yields_terms: BoxSlice<ENodeIdx>,
229 pub frame: StackIdx,
230}
231
232#[cfg_attr(feature = "mem_dbg", derive(MemSize, MemDbg))]
233#[cfg_attr(feature = "mem_dbg", copy_type)]
234#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
235#[derive(Debug, Clone, Copy)]
236pub enum InstantiationKind {
237 Axiom { body: TermIdx },
241 NonAxiom {
242 fingerprint: Fingerprint,
243 z3_generation: NonMaxU32,
244 proof: InstProofLink,
245 },
246}
247
248impl InstantiationKind {
249 pub fn fingerprint(&self) -> Fingerprint {
250 match self {
251 Self::NonAxiom { fingerprint, .. } => *fingerprint,
252 _ => Fingerprint(0),
253 }
254 }
255
256 pub fn z3_generation(&self) -> Option<NonMaxU32> {
257 match self {
258 Self::NonAxiom { z3_generation, .. } => Some(*z3_generation),
259 _ => None,
260 }
261 }
262
263 pub fn proof(&self) -> Option<ProofIdx> {
264 match self {
265 Self::NonAxiom {
266 proof: InstProofLink::HasProof(proof),
267 ..
268 } => Some(*proof),
269 _ => None,
270 }
271 }
272}
273
274#[cfg_attr(feature = "mem_dbg", derive(MemSize, MemDbg))]
276#[cfg_attr(feature = "mem_dbg", copy_type)]
277#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
278#[derive(Debug, Clone, Copy)]
279pub enum InstProofLink {
280 HasProof(ProofIdx),
283 ProofsDisabled(Option<TermIdx>),
289}