negation reordering

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

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

@ -53,6 +53,17 @@ impl Expr {
let result = self.eval(&Tuple(vec![]))?;
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(())
}

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

@ -137,12 +137,21 @@ impl Atom {
pub(crate) fn is_predicate(&self) -> bool {
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> {
match self {
Atom::Predicate(e) => Some(e),
_ => 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>) {
match self {
Atom::AttrTriple(a) => {
@ -486,7 +495,43 @@ impl SessionTx {
ret = ret.neg_join(right, join_left_keys, join_right_keys);
}
(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)) => {
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"]},
{"pred": "Neq", "args": ["?n", {"pred": "StrCat", "args": ["A", "l", "i", "c", "e"]}]},
{"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"]}}

Loading…
Cancel
Save