disjunction
parent
439b237723
commit
2aa470d0bb
@ -0,0 +1,137 @@
|
|||||||
|
use anyhow::Result;
|
||||||
|
use itertools::Itertools;
|
||||||
|
|
||||||
|
use crate::data::expr::{get_op, Expr};
|
||||||
|
use crate::query::compile::Atom;
|
||||||
|
|
||||||
|
impl Atom {
|
||||||
|
pub(crate) fn is_disjunction(&self) -> bool {
|
||||||
|
matches!(self, Atom::Disjunction(_))
|
||||||
|
}
|
||||||
|
pub(crate) fn is_conjunction(&self) -> bool {
|
||||||
|
matches!(self, Atom::Conjunction(_))
|
||||||
|
}
|
||||||
|
pub(crate) fn negation_normal_form(self) -> Self {
|
||||||
|
match self {
|
||||||
|
a @ (Atom::AttrTriple(_) | Atom::Rule(_) | Atom::Predicate(_)) => a,
|
||||||
|
Atom::Conjunction(args) => {
|
||||||
|
Atom::Conjunction(args.into_iter().map(|a| a.negation_normal_form()).collect())
|
||||||
|
}
|
||||||
|
Atom::Disjunction(args) => {
|
||||||
|
Atom::Disjunction(args.into_iter().map(|a| a.negation_normal_form()).collect())
|
||||||
|
}
|
||||||
|
Atom::Negation(arg) => match *arg {
|
||||||
|
a @ (Atom::AttrTriple(_) | Atom::Rule(_)) => Atom::Negation(Box::new(a)),
|
||||||
|
Atom::Predicate(p) => Atom::Predicate(p.negate()),
|
||||||
|
Atom::Negation(inner) => inner.negation_normal_form(),
|
||||||
|
Atom::Conjunction(args) => Atom::Disjunction(
|
||||||
|
args.into_iter()
|
||||||
|
.map(|a| Atom::Negation(Box::new(a)).negation_normal_form())
|
||||||
|
.collect(),
|
||||||
|
),
|
||||||
|
Atom::Disjunction(args) => Atom::Conjunction(
|
||||||
|
args.into_iter()
|
||||||
|
.map(|a| Atom::Negation(Box::new(a)).negation_normal_form())
|
||||||
|
.collect(),
|
||||||
|
),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pub(crate) fn disjunctive_normal_form(self) -> Vec<Vec<Self>> {
|
||||||
|
match self.negation_normal_form().do_disjunctive_normal_form() {
|
||||||
|
Atom::Disjunction(atoms) => atoms
|
||||||
|
.into_iter()
|
||||||
|
.map(|a| match a {
|
||||||
|
Atom::Conjunction(v) => v,
|
||||||
|
_ => unreachable!(),
|
||||||
|
})
|
||||||
|
.collect_vec(),
|
||||||
|
_ => unreachable!(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fn get_disjunctive_args(self) -> Option<Vec<Self>> {
|
||||||
|
match self {
|
||||||
|
Atom::Disjunction(v) => Some(v),
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fn get_conjunctive_args(self) -> Option<Vec<Self>> {
|
||||||
|
match self {
|
||||||
|
Atom::Conjunction(v) => Some(v),
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fn do_disjunctive_normal_form(self) -> Self {
|
||||||
|
// invariants: the input is already in negation normal form
|
||||||
|
// the return value is a disjunction of conjunctions, with no nesting
|
||||||
|
match self {
|
||||||
|
// invariant: results is disjunction of conjunctions
|
||||||
|
a @ (Atom::AttrTriple(_) | Atom::Rule(_) | Atom::Predicate(_) | Atom::Negation(_)) => {
|
||||||
|
Atom::Disjunction(vec![Atom::Conjunction(vec![a])])
|
||||||
|
}
|
||||||
|
Atom::Disjunction(args) => {
|
||||||
|
let mut ret = vec![];
|
||||||
|
for arg in args {
|
||||||
|
for a in arg
|
||||||
|
.do_disjunctive_normal_form()
|
||||||
|
.get_disjunctive_args()
|
||||||
|
.unwrap()
|
||||||
|
{
|
||||||
|
ret.push(a);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Atom::Disjunction(ret)
|
||||||
|
}
|
||||||
|
Atom::Conjunction(args) => {
|
||||||
|
let mut args = args.into_iter().map(|a| a.do_disjunctive_normal_form());
|
||||||
|
let mut result = args.next().unwrap();
|
||||||
|
for a in args {
|
||||||
|
result = result.conjunctive_to_disjunctive_de_morgen(a)
|
||||||
|
}
|
||||||
|
result
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fn conjunctive_to_disjunctive_de_morgen(self, other: Self) -> Self {
|
||||||
|
// invariants: self and other are both already in disjunctive normal form, which are to be conjuncted together
|
||||||
|
// the return value must be in disjunctive normal form
|
||||||
|
let mut ret = vec![];
|
||||||
|
let right_args = other
|
||||||
|
.get_disjunctive_args()
|
||||||
|
.unwrap()
|
||||||
|
.into_iter()
|
||||||
|
.map(|a| a.get_conjunctive_args().unwrap())
|
||||||
|
.collect_vec();
|
||||||
|
for left in self.get_disjunctive_args().unwrap() {
|
||||||
|
let left = left.get_conjunctive_args().unwrap();
|
||||||
|
for right in &right_args {
|
||||||
|
let mut current = left.clone();
|
||||||
|
current.extend_from_slice(right);
|
||||||
|
ret.push(Atom::Conjunction(current))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Atom::Disjunction(ret)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use crate::data::expr::Expr;
|
||||||
|
use crate::data::value::DataValue;
|
||||||
|
use crate::query::compile::Atom;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn normal_forms() {
|
||||||
|
let a = Atom::Conjunction(vec![
|
||||||
|
Atom::Disjunction(vec![
|
||||||
|
Atom::Negation(Box::new(Atom::Conjunction(vec![
|
||||||
|
Atom::Negation(Box::new(Atom::Predicate(Expr::Const(DataValue::Int(1))))),
|
||||||
|
Atom::Predicate(Expr::Const(DataValue::Int(2))),
|
||||||
|
]))),
|
||||||
|
Atom::Predicate(Expr::Const(DataValue::Int(3))),
|
||||||
|
]),
|
||||||
|
Atom::Predicate(Expr::Const(DataValue::Int(4))),
|
||||||
|
]);
|
||||||
|
dbg!(a.disjunctive_normal_form());
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue