1use crate::term::{Args, Arity, Fresh, Term};
3use crate::Lit;
4use alloc::{boxed::Box, vec::Vec};
5use core::fmt::{self, Display};
6use core::hash::Hash;
7use core::ops::Neg;
8use hashbrown::HashMap;
9
10#[derive(Clone, Debug, PartialEq, Eq)]
12pub enum Fof<A, V> {
13 Atom(A),
15 Neg(Box<Fof<A, V>>),
17 Bin(Box<Fof<A, V>>, Op, Box<Fof<A, V>>),
19 BinA(OpA, Vec<Fof<A, V>>),
21 Quant(Quantifier, V, Box<Fof<A, V>>),
23}
24
25#[derive(Clone, Debug, PartialEq, Eq)]
27pub enum FofAtom<P, C, V> {
28 Atom(Lit<P, C, V>),
30 EqTm(Term<C, V>, Term<C, V>),
32}
33
34#[derive(Clone, Debug, PartialEq, Eq)]
36pub enum Nnf<L, V, Q> {
37 Lit(L),
39 BinA(OpA, Vec<Nnf<L, V, Q>>),
41 Quant(Q, V, Box<Nnf<L, V, Q>>),
43}
44
45#[derive(Clone, Debug, PartialEq, Eq)]
47pub enum Cnf<L> {
48 Conj(Vec<Cnf<L>>),
50 Disj(Dnf<L>),
52}
53
54#[derive(Clone, Debug, PartialEq, Eq)]
56pub enum Dnf<L> {
57 Lit(L),
59 Disj(Vec<Dnf<L>>),
61}
62
63#[derive(Copy, Clone, Debug, PartialEq, Eq)]
65pub enum Op {
66 Impl,
68 EqFm,
70}
71
72#[derive(Copy, Clone, Debug, PartialEq, Eq)]
74pub enum OpA {
75 Conj,
77 Disj,
79}
80
81#[derive(Copy, Clone, Debug, PartialEq, Eq)]
83pub enum Quantifier {
84 Forall,
86 Exists,
88}
89
90#[derive(Copy, Clone, Debug, PartialEq, Eq)]
94pub struct Forall;
95
96impl Neg for OpA {
97 type Output = Self;
98
99 fn neg(self) -> Self {
100 match self {
101 Self::Conj => Self::Disj,
102 Self::Disj => Self::Conj,
103 }
104 }
105}
106
107impl Neg for Quantifier {
108 type Output = Self;
109
110 fn neg(self) -> Self {
111 match self {
112 Self::Forall => Self::Exists,
113 Self::Exists => Self::Forall,
114 }
115 }
116}
117
118impl<Atom: Display, V: Display> Display for Fof<Atom, V> {
119 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
120 use Fof::*;
121 match self {
122 Atom(a) => a.fmt(f),
123 Neg(fm) => write!(f, "¬ {}", fm),
124 Bin(l, o, r) => write!(f, "({} {} {})", l, o, r),
125 BinA(o, fms) => o.fmt_args(fms, f),
126 Quant(q, v, fm) => write!(f, "{} {}. {}", q, v, fm),
127 }
128 }
129}
130
131impl<L: Display, V: Display, Q: Display> Display for Nnf<L, V, Q> {
132 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
133 use Nnf::*;
134 match self {
135 Lit(lit) => lit.fmt(f),
136 BinA(o, fms) => o.fmt_args(fms, f),
137 Quant(q, v, fm) => write!(f, "{} {}. {}", q, v, fm),
138 }
139 }
140}
141
142impl<L: Display> Display for Cnf<L> {
143 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
144 use Cnf::*;
145 match self {
146 Conj(fms) => OpA::Conj.fmt_args(fms, f),
147 Disj(disj) => disj.fmt(f),
148 }
149 }
150}
151
152impl<L: Display> Display for Dnf<L> {
153 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
154 use Dnf::*;
155 match self {
156 Lit(lit) => lit.fmt(f),
157 Disj(fms) => OpA::Disj.fmt_args(fms, f),
158 }
159 }
160}
161
162impl<P: Display, C: Display, V: Display> Display for FofAtom<P, C, V> {
163 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
164 match self {
165 Self::Atom(a) => a.fmt(f),
166 Self::EqTm(l, r) => write!(f, "{} = {}", l, r),
167 }
168 }
169}
170
171impl Display for Op {
172 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
173 match self {
174 Op::Impl => write!(f, "⇒"),
175 Op::EqFm => write!(f, "⇔"),
176 }
177 }
178}
179
180impl Display for OpA {
181 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
182 match self {
183 OpA::Conj => write!(f, "∧"),
184 OpA::Disj => write!(f, "∨"),
185 }
186 }
187}
188
189impl Display for Quantifier {
190 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
191 match self {
192 Quantifier::Forall => write!(f, "∀"),
193 Quantifier::Exists => write!(f, "∃"),
194 }
195 }
196}
197
198impl Display for Forall {
199 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
200 Quantifier::Forall.fmt(f)
201 }
202}
203
204impl<A, V> Neg for Fof<A, V> {
205 type Output = Self;
206 fn neg(self) -> Self {
207 Self::Neg(Box::new(self))
208 }
209}
210
211impl<L: Neg<Output = L>, V, Q: Neg<Output = Q>> Neg for Nnf<L, V, Q> {
212 type Output = Self;
213 fn neg(self) -> Self {
214 match self {
215 Self::Lit(l) => Self::Lit(-l),
216 Self::BinA(op, fms) => Self::BinA(-op, fms.into_iter().map(|fm| -fm).collect()),
217 Self::Quant(q, v, fm) => Self::Quant(-q, v, Box::new(-*fm)),
218 }
219 }
220}
221
222impl<A, V> core::ops::BitAnd for Fof<A, V> {
223 type Output = Self;
224 fn bitand(self, rhs: Self) -> Self {
225 Self::bina(self, OpA::Conj, rhs)
226 }
227}
228
229impl<A, V> core::ops::BitOr for Fof<A, V> {
230 type Output = Self;
231 fn bitor(self, rhs: Self) -> Self {
232 Self::bina(self, OpA::Disj, rhs)
233 }
234}
235
236impl<L, V, Q> core::ops::BitAnd for Nnf<L, V, Q> {
237 type Output = Self;
238 fn bitand(self, rhs: Self) -> Self {
239 Self::bina(self, OpA::Conj, rhs)
240 }
241}
242
243impl<L, V, Q> core::ops::BitOr for Nnf<L, V, Q> {
244 type Output = Self;
245 fn bitor(self, rhs: Self) -> Self {
246 Self::bina(self, OpA::Disj, rhs)
247 }
248}
249
250impl<L> core::ops::BitAnd for Cnf<L> {
251 type Output = Self;
252 fn bitand(self, rhs: Self) -> Self {
253 match rhs {
254 Self::Conj(fms) => join(self, fms, Self::Conj),
255 _ => Self::Conj(Vec::from([self, rhs])),
256 }
257 }
258}
259
260impl<L: Clone> core::ops::BitOr for Cnf<L> {
261 type Output = Self;
262 fn bitor(self, rhs: Self) -> Self {
263 match (self, rhs) {
264 (Self::Conj(lc), r) => Self::conjs(lc.into_iter().map(|ln| ln | r.clone())),
265 (l, Self::Conj(rc)) => Self::conjs(rc.into_iter().map(|rn| l.clone() | rn)),
266 (Self::Disj(ld), Self::Disj(rd)) => Self::Disj(ld | rd),
267 }
268 }
269}
270
271impl<L> core::ops::BitOr for Dnf<L> {
272 type Output = Self;
273 fn bitor(self, rhs: Self) -> Self {
274 match rhs {
275 Self::Disj(fms) => join(self, fms, Self::Disj),
276 _ => Self::Disj(Vec::from([self, rhs])),
277 }
278 }
279}
280
281impl<A, V> Fof<A, V> {
282 pub fn bin(l: Self, o: Op, r: Self) -> Self {
284 Self::Bin(Box::new(l), o, Box::new(r))
285 }
286
287 pub fn bina(l: Self, o: OpA, r: Self) -> Self {
293 match r {
294 Self::BinA(op, fms) if o == op => join(l, fms, |fms| Self::BinA(o, fms)),
295 _ => Self::BinA(o, Vec::from([l, r])),
296 }
297 }
298
299 pub fn binas(o: OpA, fms: impl DoubleEndedIterator<Item = Self>) -> Self {
301 fms.rev()
302 .reduce(|acc, x| Self::bina(x, o, acc))
303 .unwrap_or_else(|| Self::BinA(o, Vec::new()))
304 }
305
306 pub fn imp(l: Self, r: Self) -> Self {
308 Self::bin(l, Op::Impl, r)
309 }
310
311 pub fn quant(q: Quantifier, v: V, fm: Self) -> Self {
313 Self::Quant(q, v, Box::new(fm))
314 }
315
316 pub fn forall(v: V, fm: Self) -> Self {
318 Self::quant(Quantifier::Forall, v, fm)
319 }
320
321 pub fn foralls(vs: impl Iterator<Item = V>, fm: Self) -> Self {
323 vs.fold(fm, |fm, v| Self::forall(v, fm))
324 }
325
326 pub fn add_premise(self, premise: Self) -> Self {
328 match self {
329 Self::Bin(a, Op::Impl, b) => Self::imp(premise & *a, *b),
330 _ => Self::imp(premise, self),
331 }
332 }
333
334 pub fn mark_impl(self, fm: impl Fn() -> Self) -> (bool, Self) {
339 match self {
340 Self::Bin(a, Op::Impl, c) => (true, Self::imp(*a & fm(), fm() & *c)),
341 _ => (false, self),
342 }
343 }
344
345 pub fn map_atoms<B>(self, f: &mut impl FnMut(A) -> B) -> Fof<B, V> {
347 use Fof::*;
348 match self {
349 Atom(a) => Atom(f(a)),
350 Neg(fm) => -fm.map_atoms(f),
351 Bin(l, op, r) => Fof::bin(l.map_atoms(f), op, r.map_atoms(f)),
352 BinA(o, fms) => BinA(o, fms.into_iter().map(|fm| fm.map_atoms(f)).collect()),
353 Quant(q, v, fm) => Fof::Quant(q, v, Box::new(fm.map_atoms(f))),
354 }
355 }
356
357 pub fn map_vars<W>(self, f: &mut impl FnMut(V) -> W) -> Fof<A, W> {
359 use Fof::*;
360 match self {
361 Atom(a) => Atom(a),
362 Neg(fm) => -fm.map_vars(f),
363 Bin(l, o, r) => Fof::bin(l.map_vars(f), o, r.map_vars(f)),
364 BinA(o, fms) => BinA(o, fms.into_iter().map(|fm| fm.map_vars(f)).collect()),
365 Quant(q, v, fm) => Quant(q, f(v), Box::new(fm.map_vars(f))),
366 }
367 }
368
369 pub fn atoms(&self) -> Box<dyn Iterator<Item = &A> + '_> {
371 use Fof::*;
372 match self {
373 Atom(a) => Box::new(core::iter::once(a)),
374 Neg(fm) | Quant(_, _, fm) => fm.atoms(),
375 Bin(l, _, r) => Box::new(l.atoms().chain(r.atoms())),
376 BinA(_, fms) => Box::new(fms.iter().flat_map(|fm| fm.atoms())),
377 }
378 }
379}
380
381impl<P, C, V> Fof<FofAtom<P, C, V>, V> {
382 pub fn atom(p: P, args: Args<C, V>) -> Self {
384 Self::Atom(FofAtom::Atom(Lit::new(p, args)))
385 }
386
387 pub fn eqtm(l: Term<C, V>, r: Term<C, V>) -> Self {
389 Self::Atom(FofAtom::EqTm(l, r))
390 }
391}
392
393impl<A: Clone + Neg<Output = A>, V: Clone> Fof<A, V> {
394 pub fn qnnf(self, f: &impl Fn(bool, Self, Op, Self) -> Self) -> Nnf<A, V, Quantifier> {
396 let qnnf = |fm: Self| fm.qnnf(f);
397 use Fof::*;
398 match self {
399 Atom(a) => Nnf::Lit(a),
400 BinA(op, fms) => Nnf::BinA(op, fms.into_iter().map(qnnf).collect()),
401 Quant(q, v, t) => Nnf::Quant(q, v, Box::new(qnnf(*t))),
402 Bin(l, op, r) => qnnf(f(true, *l, op, *r)),
403 Neg(fm) => match *fm {
404 Neg(t) => qnnf(*t),
405 Atom(a) => Nnf::Lit(-a),
406 BinA(op, fms) => Nnf::BinA(-op, fms.into_iter().map(|fm| qnnf(-fm)).collect()),
407 Quant(q, v, t) => Nnf::Quant(-q, v, Box::new(qnnf(-*t))),
408 Bin(l, op, r) => qnnf(f(false, *l, op, *r)),
409 },
410 }
411 }
412
413 pub fn unfold_eqfm_disj_conj(pol: bool, l: Self, op: Op, r: Self) -> Self {
417 match (pol, op) {
418 (true, Op::Impl) => -l | r,
419 (false, Op::Impl) => l & -r,
420 (true, Op::EqFm) => (l.clone() & r.clone()) | (-l & -r),
422 (false, Op::EqFm) => (l.clone() & -r.clone()) | (-l & r),
423 }
424 }
425
426 pub fn unfold_eqfm_conj_impl(pol: bool, l: Self, op: Op, r: Self) -> Self {
430 match (pol, op) {
431 (true, Op::Impl) => -l | r,
432 (false, Op::Impl) => l & -r,
433 (true, Op::EqFm) => Self::imp(l.clone(), r.clone()) & Self::imp(r, l),
435 (false, Op::EqFm) => -(Self::imp(l.clone(), r.clone()) & Self::imp(r, l)),
436 }
437 }
438}
439
440impl<P, C, V> FofAtom<P, C, V> {
441 pub fn map_vars<W>(self, f: &mut impl Fn(V) -> W) -> FofAtom<P, C, W> {
443 use FofAtom::*;
444 let mut mv = |v| Term::V(f(v));
445 match self {
446 Atom(lit) => Atom(lit.map_args(|tms| tms.map_vars(&mut mv))),
447 EqTm(l, r) => EqTm(l.map_vars(&mut mv), r.map_vars(&mut mv)),
448 }
449 }
450
451 pub fn vars(&self) -> Box<dyn Iterator<Item = &V> + '_> {
453 use FofAtom::*;
454 match self {
455 Atom(lit) => Box::new(lit.args().iter().flat_map(|tms| tms.vars())),
456 EqTm(l, r) => Box::new(l.vars().chain(r.vars())),
457 }
458 }
459
460 pub fn to_lit(self, eq: impl Fn() -> P) -> Lit<P, C, V> {
463 match self {
464 Self::Atom(lit) => lit,
465 Self::EqTm(l, r) => Lit::new(eq(), Args::from([l, r])),
466 }
467 }
468}
469
470impl<L, V, Q> Nnf<L, V, Q> {
471 #[cfg(feature = "order")]
473 pub fn order(self) -> (Self, num_bigint::BigUint) {
474 use num_traits::{One, Zero};
475 use Nnf::*;
476 match self {
477 BinA(op, fms) => {
478 let neutral = match op {
479 OpA::Conj => One::one(),
480 OpA::Disj => Zero::zero(),
481 };
482 let comb = match op {
483 OpA::Conj => |l, r| l * r,
484 OpA::Disj => |l, r| l + r,
485 };
486 let fms = fms.into_iter().rev().map(|fm| fm.order());
487 fms.reduce(|acc, x| {
488 let (l, r) = if x.1 > acc.1 {
489 (acc.0, x.0)
490 } else {
491 (x.0, acc.0)
492 };
493 (Self::bina(l, op, r), comb(acc.1, x.1))
494 })
495 .unwrap_or_else(|| (BinA(op, Vec::new()), neutral))
496 }
497 Quant(q, v, fm) => {
498 let (fm, size) = fm.order();
499 (Quant(q, v, Box::new(fm)), size)
500 }
501 Lit(_) => (self, One::one()),
502 }
503 }
504}
505
506impl<L, V, Q> Nnf<L, V, Q> {
507 pub fn bina(l: Self, o: OpA, r: Self) -> Self {
512 match r {
513 Self::BinA(op, fms) if o == op => join(l, fms, |fms| Self::BinA(o, fms)),
514 _ => Self::BinA(o, Vec::from([l, r])),
515 }
516 }
517
518 pub fn binas(o: OpA, fms: impl DoubleEndedIterator<Item = Self>) -> Self {
521 fms.rev()
522 .reduce(|acc, x| Self::bina(x, o, acc))
523 .unwrap_or_else(|| Self::BinA(o, Vec::new()))
524 }
525
526 pub fn map_literals<M>(self, f: &mut impl FnMut(L) -> M) -> Nnf<M, V, Q> {
528 match self {
529 Self::Lit(l) => Nnf::Lit(f(l)),
530 Self::BinA(op, fms) => {
531 Nnf::BinA(op, fms.into_iter().map(|fm| fm.map_literals(f)).collect())
532 }
533 Self::Quant(q, v, fm) => Nnf::Quant(q, v, Box::new(fm.map_literals(f))),
534 }
535 }
536}
537
538impl<L: Clone, V: Clone> Nnf<L, V, Forall> {
539 pub fn cnf_disj(self, other: Self) -> Cnf<L> {
541 use Nnf::{BinA, Quant};
542 match (self, other) {
543 (Quant(Forall, _, l), r) => l.cnf_disj(r),
544 (l, Quant(Forall, _, r)) => l.cnf_disj(*r),
545 (BinA(OpA::Conj, lc), r) => Cnf::conjs(lc.into_iter().map(|ln| ln.cnf_disj(r.clone()))),
546 (l, BinA(OpA::Conj, rc)) => Cnf::conjs(rc.into_iter().map(|rn| l.clone().cnf_disj(rn))),
547 (l, r) => l.cnf() | r.cnf(),
548 }
549 }
550
551 pub fn cnf(self) -> Cnf<L> {
553 use Nnf::*;
554 match self {
555 Quant(Forall, _, fm) => fm.cnf(),
556 BinA(OpA::Conj, fms) => Cnf::conjs(fms.into_iter().map(|fm| fm.cnf())),
557 BinA(OpA::Disj, fms) => {
558 let mut fms = fms.into_iter();
559 match fms.next() {
560 None => Cnf::Disj(Dnf::Disj(Vec::new())),
561 Some(fm1) => fm1.cnf_disj(Self::binas(OpA::Disj, fms)),
562 }
563 }
564 Lit(l) => Cnf::Disj(Dnf::Lit(l)),
565 }
566 }
567}
568
569type Arities<T> = Vec<(T, Arity)>;
570
571impl<P: Eq, C: Eq, V> Fof<FofAtom<P, C, V>, V> {
572 pub fn predconst_unique(&self) -> (Arities<&P>, Arities<&C>) {
574 use Fof::*;
575 match self {
576 Atom(FofAtom::Atom(a)) => (
577 Vec::from([(a.head(), a.args().len())]),
578 a.args().const_unique(),
579 ),
580 Atom(FofAtom::EqTm(l, r)) => {
581 let mut cl = l.const_unique();
582 let cr = r.const_unique();
583 crate::union1(&mut cl, cr);
584 (Vec::new(), cl)
585 }
586 Bin(l, _, r) => {
587 let (mut pl, mut cl) = l.predconst_unique();
588 let (pr, cr) = r.predconst_unique();
589 crate::union1(&mut pl, pr);
590 crate::union1(&mut cl, cr);
591 (pl, cl)
592 }
593 BinA(_, fms) => fms
594 .iter()
595 .rev()
596 .fold((Vec::new(), Vec::new()), |(pr, cr), x| {
597 let (mut pl, mut cl) = x.predconst_unique();
598 crate::union1(&mut pl, pr);
599 crate::union1(&mut cl, cr);
600 (pl, cl)
601 }),
602 Neg(fm) | Quant(_, _, fm) => fm.predconst_unique(),
603 }
604 }
605}
606
607impl<P, C, V: Clone + Eq + Hash, Q> Nnf<Lit<P, C, V>, V, Q> {
608 pub fn fresh_vars<W: Clone + Fresh>(
610 self,
611 map: &mut HashMap<V, W>,
612 st: &mut W::State,
613 ) -> Nnf<Lit<P, C, W>, W, Q> {
614 use Nnf::*;
615 match self {
616 Lit(lit) => Lit(lit.fresh_vars(map, st)),
617 BinA(o, fms) => BinA(
618 o,
619 fms.into_iter().map(|fm| fm.fresh_vars(map, st)).collect(),
620 ),
621 Quant(q, v, fm) => {
622 let i = W::fresh(st);
623 let old = map.insert(v.clone(), i.clone());
624 let fm = fm.fresh_vars(map, st);
625 match old {
626 Some(old) => map.insert(v, old),
627 None => map.remove(&v),
628 };
629 Quant(q, i, Box::new(fm))
630 }
631 }
632 }
633}
634
635pub struct SkolemState<C: Fresh, V> {
637 universal: Vec<V>,
639 existential: HashMap<V, Term<C, V>>,
641 fresh: C::State,
643}
644
645impl<C: Fresh, V> SkolemState<C, V> {
646 pub fn new(fresh: C::State) -> Self {
648 Self {
649 universal: Vec::new(),
650 existential: HashMap::new(),
651 fresh,
652 }
653 }
654}
655
656impl<P, C: Clone + Fresh, V: Clone + Eq + Hash> Nnf<Lit<P, C, V>, V, Quantifier> {
657 pub fn skolem_outer(self, st: &mut SkolemState<C, V>) -> Nnf<Lit<P, C, V>, V, Forall> {
664 use Nnf::*;
665 match self {
666 Lit(lit) => Lit(lit.map_args(|tms| tms.subst(&st.existential))),
667 BinA(o, fms) => BinA(o, fms.into_iter().map(|fm| fm.skolem_outer(st)).collect()),
668 Quant(Quantifier::Forall, v, fm) => {
669 st.universal.push(v);
670 let fm = fm.skolem_outer(st);
671 let v = st.universal.pop().unwrap();
672 Quant(Forall, v, Box::new(fm))
673 }
674 Quant(Quantifier::Exists, v, fm) => {
675 let skolem = Term::skolem(&mut st.fresh, st.universal.clone());
676 assert!(!st.existential.contains_key(&v));
677 st.existential.insert(v.clone(), skolem);
678 let fm = fm.skolem_outer(st);
679 st.existential.remove(&v);
680 fm
681 }
682 }
683 }
684}
685
686impl<L> Cnf<L> {
687 pub fn conjs(fms: impl DoubleEndedIterator<Item = Self>) -> Self {
689 fms.rev()
690 .reduce(|acc, x| x & acc)
691 .unwrap_or_else(|| Self::Conj(Vec::new()))
692 }
693}
694
695impl OpA {
696 fn fmt_args<T: Display>(self, fms: &[T], f: &mut fmt::Formatter<'_>) -> fmt::Result {
697 let mut fms = fms.iter();
698 match (self, fms.next()) {
699 (OpA::Conj, None) => write!(f, "⊤"),
700 (OpA::Disj, None) => write!(f, "⊥"),
701 (o, Some(fm1)) => {
702 write!(f, "({}", fm1)?;
703 fms.try_for_each(|fm| write!(f, " {} {}", o, fm))?;
704 write!(f, ")")
705 }
706 }
707 }
708}
709
710pub fn join<T>(x: T, mut ys: Vec<T>, f: impl Fn(Vec<T>) -> T) -> T {
712 if ys.is_empty() {
713 x
714 } else {
715 ys.insert(0, x);
716 f(ys)
717 }
718}