1use super::contrapositive::PreCp;
2use super::search::{Action, Context, OLitMat};
3use crate::offset::{Offset, Sub};
4use alloc::vec::Vec;
5use core::fmt::{self, Display};
6use core::ops::Neg;
7
8pub type OContra<'t, P, C> = Offset<&'t PreCp<'t, crate::Lit<P, C, usize>, usize>>;
10
11pub enum Proof<'t, P, C> {
13 Lem,
15 Red,
17 Ext(OContra<'t, P, C>, Vec<Self>),
19 Dec(usize, Vec<Self>),
24}
25
26impl<'t, P, C> Proof<'t, P, C> {
27 pub fn from_iter(iter: &mut impl Iterator<Item = Action<'t, P, C>>, off: &mut usize) -> Self {
29 match iter.next().unwrap() {
30 Action::Prove => Self::Lem,
31 Action::Reduce(_, _) => Self::Red,
32 Action::Extend(_, cs, skip) => {
33 let contra = &cs[skip];
34 let ocontra = Offset::new(*off, contra);
35 *off += contra.offset.map(|v| v + 1).unwrap_or(0);
36 let proofs = contra.into_iter().map(|_| Self::from_iter(iter, off));
37 Self::Ext(ocontra, proofs.collect())
38 }
39 Action::Decompose(mat, skip) => {
40 let cl = mat.into_iter().nth(skip).unwrap();
41 let lms = cl.map(|cl| &cl.1).into_iter();
42 let proofs = lms.map(|_| Self::from_iter(iter, off));
43 Self::Dec(skip, proofs.collect())
44 }
45 }
46 }
47
48 pub fn display(&self, lit: OLitMat<'t, P, C>) -> Disp<'_, 't, P, C> {
50 let depth = 0;
51 let proof = self;
52 Disp { depth, lit, proof }
53 }
54}
55
56impl<'t, P: Eq + Neg<Output = P> + Clone, C: Eq> Proof<'t, P, C> {
57 pub fn check(
59 &self,
60 sub: &Sub<'t, C>,
61 lit: OLitMat<'t, P, C>,
62 mut ctx: Context<'t, P, C>,
63 ) -> bool {
64 use crate::LitMat::{Lit, Mat};
65 match (self, lit.transpose()) {
66 (Proof::Lem, Lit(lit)) => ctx.lemmas.iter().any(|lem| lit.eq_mod(sub, lem)),
67 (Proof::Red, Lit(lit)) => ctx.path.iter().any(|path| lit.neg_eq_mod(sub, path)),
68 (Proof::Ext(ocontra, proofs), Lit(lit)) => {
69 ctx.path.push(lit);
70 let rest = ocontra.into_iter();
71 rest.zip(proofs.iter()).all(|(clit, proof)| {
72 let result = proof.check(sub, clit, ctx.clone());
73 if let Lit(clit) = clit.transpose() {
74 ctx.lemmas.push(clit);
75 }
76 result
77 }) && ocontra.map(|cp| cp.contra.lit).neg_eq_mod(sub, &lit)
78 }
79 (Proof::Dec(skip, proofs), Mat(mat)) => {
80 let cl = mat.into_iter().nth(*skip).unwrap();
81 let lms = cl.map(|cl| &cl.1).into_iter();
82 lms.zip(proofs.iter()).all(|(clit, proof)| {
83 let result = proof.check(sub, clit, ctx.clone());
84 if let Lit(clit) = clit.transpose() {
85 ctx.lemmas.push(clit);
86 }
87 result
88 })
89 }
90 _ => panic!("proof step does not fit litmat"),
91 }
92 }
93}
94
95pub struct Disp<'p, 't, P, C> {
97 depth: usize,
98 lit: OLitMat<'t, P, C>,
99 proof: &'p Proof<'t, P, C>,
100}
101
102impl<'p, 't, P: Display + Neg<Output = P> + Clone, C: Display> Display for Disp<'p, 't, P, C> {
103 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
104 write!(f, "{: <1$}", "", self.depth * 2)?;
105 write!(f, "{} ", self.lit)?;
106 use crate::LitMat::{Lit, Mat};
107 match (self.proof, self.lit.transpose()) {
108 (Proof::Lem, Lit(_)) => writeln!(f, "Lem")?,
109 (Proof::Red, Lit(_)) => writeln!(f, "Red")?,
110 (Proof::Ext(contra, proofs), Lit(lit)) => {
111 writeln!(f, "Ext {}{}", -lit.head().clone(), lit.args())?;
112 let depth = self.depth + 1;
113 for (proof, lit) in proofs.iter().zip(contra.into_iter()) {
114 Self { depth, lit, proof }.fmt(f)?
115 }
116 }
117 (Proof::Dec(offset, proofs), Mat(mat)) => {
118 writeln!(f, "Dec {}", offset)?;
119 let depth = self.depth + 1;
120 let cl = mat.into_iter().nth(*offset).unwrap();
121 let lms = cl.map(|cl| &cl.1).into_iter();
122 for (proof, lit) in proofs.iter().zip(lms) {
123 Self { depth, lit, proof }.fmt(f)?
124 }
125 }
126 _ => panic!("proof step does not fit litmat"),
127 }
128 Ok(())
129 }
130}