negation reordering

main
Ziyang Hu 2 years ago
parent 3c2f8c6b0b
commit 439b237723

@ -1,10 +1,10 @@
## TODO ## TODO
* [x] predicates * [x] predicates
* [ ] negation * [x] negation
* [ ] disjunction
* [ ] aggregation * [ ] aggregation
* [ ] stratum * [ ] stratum
* [ ] disjunction
* [ ] magic sets * [ ] magic sets
* [ ] function symbol * [ ] function symbol
* [ ] arithmetic * [ ] arithmetic

@ -53,6 +53,17 @@ impl Expr {
let result = self.eval(&Tuple(vec![]))?; let result = self.eval(&Tuple(vec![]))?;
mem::swap(self, &mut Expr::Const(result)); mem::swap(self, &mut Expr::Const(result));
} }
// nested not's can accumulate during conversion to normal form
if let Expr::Apply(op1, arg1) = self {
if op1.name == "OP_NOT" {
if let Some(Expr::Apply(op2, arg2)) = arg1.first() {
if op2.name == "OP_NOT" {
let mut new_self = arg2[0].clone();
mem::swap(self, &mut new_self);
}
}
}
}
} }
Ok(()) Ok(())
} }

@ -1,5 +1,6 @@
use std::collections::btree_map::Entry; use std::collections::btree_map::Entry;
use std::collections::{BTreeMap, BTreeSet}; use std::collections::{BTreeMap, BTreeSet};
use std::iter;
use anyhow::Result; use anyhow::Result;
use itertools::Itertools; use itertools::Itertools;
@ -33,13 +34,14 @@ impl SessionTx {
.map(|o| self.parse_rule_definition(o, default_vld)); .map(|o| self.parse_rule_definition(o, default_vld));
let mut collected: BTreeMap<Keyword, Vec<Rule>> = BTreeMap::new(); let mut collected: BTreeMap<Keyword, Vec<Rule>> = BTreeMap::new();
for res in rules { for res in rules {
let (name, rule) = res?; for (name, rule) in res? {
match collected.entry(name) { match collected.entry(name) {
Entry::Vacant(e) => { Entry::Vacant(e) => {
e.insert(vec![rule]); e.insert(vec![rule]);
} }
Entry::Occupied(mut e) => { Entry::Occupied(mut e) => {
e.get_mut().push(rule); e.get_mut().push(rule);
}
} }
} }
} }
@ -234,7 +236,7 @@ impl SessionTx {
&mut self, &mut self,
payload: &JsonValue, payload: &JsonValue,
default_vld: Validity, default_vld: Validity,
) -> Result<(Keyword, Rule)> { ) -> Result<impl Iterator<Item = (Keyword, Rule)>> {
let rule_name = payload.get("rule").ok_or_else(|| { let rule_name = payload.get("rule").ok_or_else(|| {
QueryCompilationError::UnexpectedForm( QueryCompilationError::UnexpectedForm(
payload.clone(), payload.clone(),
@ -307,52 +309,50 @@ impl SessionTx {
.into()); .into());
} }
Ok(( Ok(iter::once((
rule_name, rule_name,
Rule { Rule {
head: rule_head, head: rule_head,
body: rule_body, body: rule_body,
vld, vld,
}, },
)) )))
} }
fn reorder_rule_body_for_negations(clauses: Vec<Atom>) -> Result<Vec<Atom>> { fn reorder_rule_body_for_negations(clauses: Vec<Atom>) -> Result<Vec<Atom>> {
let (predicates, others): (Vec<_>, _) = clauses.into_iter().partition(|a| a.is_predicate()); let (negations, others): (Vec<_>, _) = clauses.into_iter().partition(|a| a.is_negation());
let mut predicates_with_meta = predicates let mut seen_bindings = BTreeSet::new();
for a in &others {
a.collect_bindings(&mut seen_bindings);
}
let mut negations_with_meta = negations
.into_iter() .into_iter()
.map(|p| { .map(|p| {
let p = p.into_predicate().unwrap(); let p = p.into_negation().unwrap();
let bindings = p.bindings(); let mut bindings = Default::default();
(Some(p), bindings) p.collect_bindings(&mut bindings);
let valid_bindings: BTreeSet<_> = bindings.intersection(&seen_bindings).cloned().collect();
(Some(p), valid_bindings)
}) })
.collect_vec(); .collect_vec();
let mut seen_bindings = BTreeSet::new();
let mut ret = vec![]; let mut ret = vec![];
seen_bindings.clear();
for a in others { for a in others {
a.collect_bindings(&mut seen_bindings); a.collect_bindings(&mut seen_bindings);
ret.push(a); ret.push(a);
for (pred, pred_bindings) in predicates_with_meta.iter_mut() { for (negated, pred_bindings) in negations_with_meta.iter_mut() {
if pred.is_none() { if negated.is_none() {
continue; continue;
} }
if seen_bindings.is_superset(pred_bindings) { if seen_bindings.is_superset(pred_bindings) {
let pred = pred.take().unwrap(); let negated = negated.take().unwrap();
ret.push(Atom::Predicate(pred)); ret.push(Atom::Logical(LogicalAtom::Negation(Box::new(negated))));
} }
} }
} }
for (p, bindings) in predicates_with_meta { Ok(ret)
if let Some(p) = p {
let diff = bindings.difference(&seen_bindings).cloned().collect();
return Err(QueryCompilationError::UnsafeBindingInPredicate(p, diff).into());
}
}
// Ok(ret)
todo!()
} }
fn reorder_rule_body_for_predicates(clauses: Vec<Atom>) -> Result<Vec<Atom>> { fn reorder_rule_body_for_predicates(clauses: Vec<Atom>) -> Result<Vec<Atom>> {
let (predicates, others): (Vec<_>, _) = clauses.into_iter().partition(|a| a.is_predicate()); let (predicates, others): (Vec<_>, _) = clauses.into_iter().partition(|a| a.is_predicate());
let mut predicates_with_meta = predicates let mut predicates_with_meta = predicates

@ -137,12 +137,21 @@ impl Atom {
pub(crate) fn is_predicate(&self) -> bool { pub(crate) fn is_predicate(&self) -> bool {
matches!(self, Atom::Predicate(_)) matches!(self, Atom::Predicate(_))
} }
pub(crate) fn is_negation(&self) -> bool {
matches!(self, Atom::Logical(LogicalAtom::Negation(_)))
}
pub(crate) fn into_predicate(self) -> Option<Expr> { pub(crate) fn into_predicate(self) -> Option<Expr> {
match self { match self {
Atom::Predicate(e) => Some(e), Atom::Predicate(e) => Some(e),
_ => None, _ => None,
} }
} }
pub(crate) fn into_negation(self) -> Option<Atom> {
match self {
Atom::Logical(LogicalAtom::Negation(a)) => Some(*a),
_ => None
}
}
pub(crate) fn collect_bindings(&self, coll: &mut BTreeSet<Keyword>) { pub(crate) fn collect_bindings(&self, coll: &mut BTreeSet<Keyword>) {
match self { match self {
Atom::AttrTriple(a) => { Atom::AttrTriple(a) => {
@ -486,7 +495,43 @@ impl SessionTx {
ret = ret.neg_join(right, join_left_keys, join_right_keys); ret = ret.neg_join(right, join_left_keys, join_right_keys);
} }
(Term::Var(e_kw), Term::Var(v_kw)) => { (Term::Var(e_kw), Term::Var(v_kw)) => {
return Err(QueryCompilationError::NegationSafety(vec![e_kw.clone(), v_kw.clone()]).into()) let mut join_left_keys = vec![];
let mut join_right_keys = vec![];
if e_kw == v_kw {
unimplemented!();
}
let e_kw = {
if seen_variables.contains(&e_kw) {
let ret = gen_temp_kw();
join_left_keys.push(e_kw.clone());
join_right_keys.push(ret.clone());
ret
} else {
seen_variables.insert(e_kw.clone());
e_kw.clone()
}
};
let v_kw = {
if seen_variables.contains(v_kw) {
let ret = gen_temp_kw();
join_left_keys.push(v_kw.clone());
join_right_keys.push(ret.clone());
ret
} else {
seen_variables.insert(v_kw.clone());
v_kw.clone()
}
};
if join_right_keys.is_empty() {
return Err(QueryCompilationError::NegationSafety(vec![e_kw.clone(), v_kw.clone()]).into());
}
let right = Relation::triple(a_triple.attr.clone(), vld, e_kw, v_kw);
if ret.is_unit() {
ret = right;
} else {
debug_assert_eq!(join_left_keys.len(), join_right_keys.len());
ret = ret.neg_join(right, join_left_keys, join_right_keys);
}
} }
(Term::Const(eid), Term::Const(val)) => { (Term::Const(eid), Term::Const(val)) => {
let (left_var_1, left_var_2) = (gen_temp_kw(), gen_temp_kw()); let (left_var_1, left_var_2) = (gen_temp_kw(), gen_temp_kw());

@ -145,7 +145,8 @@ fn creation() {
{"not_exists": ["?a", "person.last_name", "Goodman"]}, {"not_exists": ["?a", "person.last_name", "Goodman"]},
{"pred": "Neq", "args": ["?n", {"pred": "StrCat", "args": ["A", "l", "i", "c", "e"]}]}, {"pred": "Neq", "args": ["?n", {"pred": "StrCat", "args": ["A", "l", "i", "c", "e"]}]},
{"rule": "ff", "args": [{"person.id": "alice_amorist"}, "?a"]}, {"rule": "ff", "args": [{"person.id": "alice_amorist"}, "?a"]},
["?a", "person.first_name", "?n"]] ["?a", "person.first_name", "?n"]
]
} }
], ],
"out": {"friend": {"pull": "?a", "spec": ["person.first_name"]}} "out": {"friend": {"pull": "?a", "spec": ["person.first_name"]}}

Loading…
Cancel
Save