1use std::num::NonZeroUsize;
2
3#[cfg(feature = "mem_dbg")]
4use mem_dbg::{MemDbg, MemSize};
5
6use crate::{BoxSlice, IString, NonMaxU32};
7use crate::{Result, StringTable};
8
9use super::{ENodeIdx, EqGivenIdx, EqTransIdx, LitIdx, TheoryKind};
10
11#[cfg_attr(feature = "mem_dbg", derive(MemSize, MemDbg))]
15#[derive(Debug, Clone, PartialEq)]
16pub enum EqualityExpl {
17 Root {
18 id: ENodeIdx,
19 },
20 Literal {
21 from: ENodeIdx,
22 eq: LitIdx,
24 to: ENodeIdx,
25 },
26 Congruence {
27 from: ENodeIdx,
28 arg_eqs: Box<[(ENodeIdx, ENodeIdx)]>,
29 to: ENodeIdx,
30 uses: Vec<BoxSlice<EqTransIdx>>,
32 },
33 Theory {
34 from: ENodeIdx,
35 theory: TheoryKind,
36 to: ENodeIdx,
37 },
38 Axiom {
39 from: ENodeIdx,
40 to: ENodeIdx,
41 },
42 Unknown {
43 kind: IString,
44 from: ENodeIdx,
45 args: BoxSlice<IString>,
46 to: ENodeIdx,
47 },
48}
49
50impl EqualityExpl {
51 pub fn is_trivial(&self) -> bool {
52 self.from() == self.to()
53 }
54 pub fn from(&self) -> ENodeIdx {
55 use EqualityExpl::*;
56 match *self {
57 Root { id } => id,
58 Literal { from, .. }
59 | Congruence { from, .. }
60 | Theory { from, .. }
61 | Axiom { from, .. }
62 | Unknown { from, .. } => from,
63 }
64 }
65 pub fn to(&self) -> ENodeIdx {
66 use EqualityExpl::*;
67 match *self {
68 Root { id } => id,
69 Literal { to, .. }
70 | Congruence { to, .. }
71 | Theory { to, .. }
72 | Axiom { to, .. }
73 | Unknown { to, .. } => to,
74 }
75 }
76 pub fn walk_any(&self, from: ENodeIdx) -> ENodeIdx {
77 let Some(to) = self.walk(from, true).or_else(|| self.walk(from, false)) else {
78 panic!(
79 "walking from {from} with {} <--> {}",
80 self.from(),
81 self.to()
82 );
83 };
84 to
85 }
86 pub fn walk(&self, from: ENodeIdx, fwd: bool) -> Option<ENodeIdx> {
87 if fwd {
88 (self.from() == from).then(|| self.to())
89 } else {
90 (self.to() == from).then(|| self.from())
91 }
92 }
93 pub fn kind(&self) -> core::result::Result<&'static str, IString> {
94 let kind = match *self {
95 EqualityExpl::Root { .. } => "root",
96 EqualityExpl::Literal { .. } => "literal",
97 EqualityExpl::Congruence { .. } => "congruence",
98 EqualityExpl::Theory { .. } => "theory",
99 EqualityExpl::Axiom { .. } => "axiom",
100 EqualityExpl::Unknown { kind, .. } => return Err(kind),
101 };
102 Ok(kind)
103 }
104 pub fn kind_str<'a>(&self, strings: &'a StringTable) -> &'a str {
105 self.kind().unwrap_or_else(|kind| &strings[*kind])
106 }
107}
108
109#[cfg_attr(feature = "mem_dbg", derive(MemSize, MemDbg))]
112#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
113#[derive(Debug)]
114pub struct TransitiveExpl {
115 pub path: Box<[TransitiveExplSegment]>,
116 pub given_len: Option<NonZeroUsize>,
117 pub to: ENodeIdx,
118}
119type BackwardIter<'a> = std::iter::Map<
120 std::iter::Rev<std::iter::Copied<std::slice::Iter<'a, TransitiveExplSegment>>>,
121 fn(TransitiveExplSegment) -> TransitiveExplSegment,
122>;
123#[derive(Clone)]
124pub enum TransitiveExplIter<'a> {
125 Forward(std::iter::Copied<std::slice::Iter<'a, TransitiveExplSegment>>),
126 Backward(BackwardIter<'a>),
127}
128impl Iterator for TransitiveExplIter<'_> {
129 type Item = TransitiveExplSegment;
130 fn next(&mut self) -> Option<Self::Item> {
131 match self {
132 Self::Forward(iter) => iter.next(),
133 Self::Backward(iter) => iter.next(),
134 }
135 }
136}
137
138impl TransitiveExpl {
139 pub fn new(
140 i: impl ExactSizeIterator<Item = TransitiveExplSegment>,
141 given_len: NonZeroUsize,
142 to: ENodeIdx,
143 ) -> Result<Self> {
144 let mut path = Vec::new();
145 path.try_reserve_exact(i.len())?;
146 path.extend(i);
147 Ok(Self {
148 path: path.into_boxed_slice(),
149 given_len: Some(given_len),
150 to,
151 })
152 }
153 pub fn error(from: ENodeIdx, to: ENodeIdx) -> Self {
154 Self {
155 path: Box::new([TransitiveExplSegment {
156 forward: true,
157 kind: TransitiveExplSegmentKind::Error(from),
158 }]),
159 given_len: None,
160 to,
161 }
162 }
163 pub fn all(&self, fwd: bool) -> TransitiveExplIter<'_> {
164 let iter = self.path.iter().copied();
165 if fwd {
166 TransitiveExplIter::Forward(iter)
167 } else {
168 TransitiveExplIter::Backward(TransitiveExplSegment::rev(iter))
169 }
170 }
171 pub fn error_from(&self) -> Option<ENodeIdx> {
172 self.given_len.is_none().then(|| match self.path[0].kind {
173 TransitiveExplSegmentKind::Error(from) => from,
174 _ => panic!("expected error segment"),
175 })
176 }
177}
178
179#[cfg_attr(feature = "mem_dbg", derive(MemSize, MemDbg))]
180#[cfg_attr(feature = "mem_dbg", copy_type)]
181#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
182#[derive(Debug, Clone, Copy)]
183pub struct TransitiveExplSegment {
184 pub forward: bool,
185 pub kind: TransitiveExplSegmentKind,
186}
187impl TransitiveExplSegment {
188 pub fn rev<I: Iterator<Item = TransitiveExplSegment> + std::iter::DoubleEndedIterator>(
189 iter: I,
190 ) -> std::iter::Map<std::iter::Rev<I>, fn(TransitiveExplSegment) -> TransitiveExplSegment> {
191 iter.rev().map(TransitiveExplSegment::rev_single)
194 }
195 fn rev_single(mut self) -> Self {
196 self.forward = !self.forward;
197 self
198 }
199}
200
201pub type EqGivenUse = (EqGivenIdx, Option<NonMaxU32>);
202
203#[cfg_attr(feature = "mem_dbg", derive(MemSize, MemDbg))]
204#[cfg_attr(feature = "mem_dbg", copy_type)]
205#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
206#[derive(Debug, Clone, Copy)]
207pub enum TransitiveExplSegmentKind {
208 Given(EqGivenUse),
209 Transitive(EqTransIdx),
210 Error(ENodeIdx),
211}
212impl TransitiveExplSegmentKind {
213 pub fn given(self) -> Option<EqGivenUse> {
214 match self {
215 Self::Given(eq_use) => Some(eq_use),
216 _ => None,
217 }
218 }
219}