use std::ops::Not;
use std::ops::Range;
use super::*;
use crate::query::*;
use crate::value::schemas::genid::GenId;
use jerky::bit_vector::Select;
pub struct SuccinctArchiveConstraint<'a, U>
where
U: Universe,
{
variable_e: VariableId,
variable_a: VariableId,
variable_v: VariableId,
archive: &'a SuccinctArchive<U>,
}
impl<'a, U> SuccinctArchiveConstraint<'a, U>
where
U: Universe,
{
pub fn new<V: ValueSchema>(
variable_e: Variable<GenId>,
variable_a: Variable<GenId>,
variable_v: Variable<V>,
archive: &'a SuccinctArchive<U>,
) -> Self {
SuccinctArchiveConstraint {
variable_e: variable_e.index,
variable_a: variable_a.index,
variable_v: variable_v.index,
archive,
}
}
}
fn base_range<U>(universe: &U, a: &BitVector<Rank9SelIndex>, value: &RawValue) -> Range<usize>
where
U: Universe,
{
if let Some(d) = universe.search(value) {
let s = a.select1(d).unwrap() - d;
let e = a.select1(d + 1).unwrap() - (d + 1);
s..e
} else {
0..0
}
}
fn restrict_range<U>(
universe: &U,
a: &BitVector<Rank9SelIndex>,
c: &WaveletMatrix<Rank9SelIndex>,
value: &RawValue,
r: &Range<usize>,
) -> Range<usize>
where
U: Universe,
{
let s = r.start;
let e = r.end;
if let Some(d) = universe.search(value) {
let base = a.select1(d).unwrap() - d;
let s_ = base + c.rank(s, d).unwrap();
let e_ = base + c.rank(e, d).unwrap();
s_..e_
} else {
0..0
}
}
impl<'a, U> Constraint<'a> for SuccinctArchiveConstraint<'a, U>
where
U: Universe,
{
fn variables(&self) -> VariableSet {
let mut variables = VariableSet::new_empty();
variables.set(self.variable_e);
variables.set(self.variable_a);
variables.set(self.variable_v);
variables
}
fn estimate(&self, variable: VariableId, binding: &Binding) -> Option<usize> {
if self.variable_e != variable && self.variable_a != variable && self.variable_v != variable
{
return None;
}
let e_var = self.variable_e == variable;
let a_var = self.variable_a == variable;
let v_var = self.variable_v == variable;
let e_bound = binding.get(self.variable_e);
let a_bound = binding.get(self.variable_a);
let v_bound = binding.get(self.variable_v);
Some(match (e_bound, a_bound, v_bound, e_var, a_var, v_var) {
(None, None, None, true, false, false) => self.archive.entity_count,
(None, None, None, false, true, false) => self.archive.attribute_count,
(None, None, None, false, false, true) => self.archive.value_count,
(Some(e), None, None, false, true, false) => {
let r = base_range(&self.archive.domain, &self.archive.e_a, e);
self.archive.distinct_in(&self.archive.changed_e_a, &r)
}
(Some(e), None, None, false, false, true) => {
let r = base_range(&self.archive.domain, &self.archive.e_a, e);
self.archive.distinct_in(&self.archive.changed_e_v, &r)
}
(None, Some(a), None, true, false, false) => {
let r = base_range(&self.archive.domain, &self.archive.a_a, a);
self.archive.distinct_in(&self.archive.changed_a_e, &r)
}
(None, Some(a), None, false, false, true) => {
let r = base_range(&self.archive.domain, &self.archive.a_a, a);
self.archive.distinct_in(&self.archive.changed_a_v, &r)
}
(None, None, Some(v), true, false, false) => {
let r = base_range(&self.archive.domain, &self.archive.v_a, v);
self.archive.distinct_in(&self.archive.changed_v_e, &r)
}
(None, None, Some(v), false, true, false) => {
let r = base_range(&self.archive.domain, &self.archive.v_a, v);
self.archive.distinct_in(&self.archive.changed_v_a, &r)
}
(None, Some(a), Some(v), true, false, false) => {
let r = base_range(&self.archive.domain, &self.archive.a_a, a);
let r = restrict_range(
&self.archive.domain,
&self.archive.v_a,
&self.archive.aev_c,
v,
&r,
);
r.len()
}
(Some(e), None, Some(v), false, true, false) => {
let r = base_range(&self.archive.domain, &self.archive.e_a, e);
let r = restrict_range(
&self.archive.domain,
&self.archive.v_a,
&self.archive.eav_c,
v,
&r,
);
r.len()
}
(Some(e), Some(a), None, false, false, true) => {
let r = base_range(&self.archive.domain, &self.archive.e_a, e);
let r = restrict_range(
&self.archive.domain,
&self.archive.a_a,
&self.archive.eva_c,
a,
&r,
);
r.len()
}
_ => unreachable!(),
})
}
fn propose(&self, variable: VariableId, binding: &Binding, proposals: &mut Vec<RawValue>) {
if self.variable_e != variable && self.variable_a != variable && self.variable_v != variable
{
return;
}
let e_var = self.variable_e == variable;
let a_var = self.variable_a == variable;
let v_var = self.variable_v == variable;
let e_bound = binding.get(self.variable_e);
let a_bound = binding.get(self.variable_a);
let v_bound = binding.get(self.variable_v);
match (e_bound, a_bound, v_bound, e_var, a_var, v_var) {
(None, None, None, true, false, false) => {
proposals.extend(self.archive.enumerate_domain(&self.archive.e_a))
}
(None, None, None, false, true, false) => {
proposals.extend(self.archive.enumerate_domain(&self.archive.a_a))
}
(None, None, None, false, false, true) => {
proposals.extend(self.archive.enumerate_domain(&self.archive.v_a))
}
(Some(e), None, None, false, true, false) => {
let r = base_range(&self.archive.domain, &self.archive.e_a, e);
proposals.extend(
self.archive
.enumerate_in(
&self.archive.changed_e_a,
&r,
&self.archive.eav_c,
&self.archive.v_a,
)
.map(|i| self.archive.vea_c.access(i).unwrap())
.map(|a| self.archive.domain.access(a)),
)
}
(Some(e), None, None, false, false, true) => {
let r = base_range(&self.archive.domain, &self.archive.e_a, e);
proposals.extend(
self.archive
.enumerate_in(
&self.archive.changed_e_v,
&r,
&self.archive.eva_c,
&self.archive.a_a,
)
.map(|i| self.archive.aev_c.access(i).unwrap())
.map(|v| self.archive.domain.access(v)),
)
}
(None, Some(a), None, true, false, false) => {
let r = base_range(&self.archive.domain, &self.archive.a_a, a);
proposals.extend(
self.archive
.enumerate_in(
&self.archive.changed_a_e,
&r,
&self.archive.aev_c,
&self.archive.v_a,
)
.map(|i| self.archive.vae_c.access(i).unwrap())
.map(|e| self.archive.domain.access(e)),
)
}
(None, Some(a), None, false, false, true) => {
let r = base_range(&self.archive.domain, &self.archive.a_a, a);
proposals.extend(
self.archive
.enumerate_in(
&self.archive.changed_a_v,
&r,
&self.archive.ave_c,
&self.archive.e_a,
)
.map(|i| self.archive.eav_c.access(i).unwrap())
.map(|v| self.archive.domain.access(v)),
)
}
(None, None, Some(v), true, false, false) => {
let r = base_range(&self.archive.domain, &self.archive.v_a, v);
proposals.extend(
self.archive
.enumerate_in(
&self.archive.changed_v_e,
&r,
&self.archive.vea_c,
&self.archive.a_a,
)
.map(|i| self.archive.ave_c.access(i).unwrap())
.map(|e| self.archive.domain.access(e)),
)
}
(None, None, Some(v), false, true, false) => {
let r = base_range(&self.archive.domain, &self.archive.v_a, v);
proposals.extend(
self.archive
.enumerate_in(
&self.archive.changed_v_a,
&r,
&self.archive.vae_c,
&self.archive.e_a,
)
.map(|i| self.archive.eva_c.access(i).unwrap())
.map(|a| self.archive.domain.access(a)),
)
}
(None, Some(a), Some(v), true, false, false) => {
let r = base_range(&self.archive.domain, &self.archive.a_a, a);
proposals.extend(
restrict_range(
&self.archive.domain,
&self.archive.v_a,
&self.archive.aev_c,
v,
&r,
)
.map(|e| self.archive.vae_c.access(e).unwrap())
.unique()
.map(|e| self.archive.domain.access(e)),
)
}
(Some(e), None, Some(v), false, true, false) => {
let r = base_range(&self.archive.domain, &self.archive.e_a, e);
proposals.extend(
restrict_range(
&self.archive.domain,
&self.archive.v_a,
&self.archive.eav_c,
v,
&r,
)
.map(|a| self.archive.vea_c.access(a).unwrap())
.unique()
.map(|a| self.archive.domain.access(a)),
)
}
(Some(e), Some(a), None, false, false, true) => {
let r = base_range(&self.archive.domain, &self.archive.e_a, e);
proposals.extend(
restrict_range(
&self.archive.domain,
&self.archive.a_a,
&self.archive.eva_c,
a,
&r,
)
.map(|v| self.archive.aev_c.access(v).unwrap())
.unique()
.map(|v| self.archive.domain.access(v)),
)
}
_ => unreachable!(),
}
}
fn confirm(&self, variable: VariableId, binding: &Binding, proposals: &mut Vec<RawValue>) {
if self.variable_e != variable && self.variable_a != variable && self.variable_v != variable
{
return;
}
let e_var = self.variable_e == variable;
let a_var = self.variable_a == variable;
let v_var = self.variable_v == variable;
let e_bound = binding.get(self.variable_e);
let a_bound = binding.get(self.variable_a);
let v_bound = binding.get(self.variable_v);
match (e_bound, a_bound, v_bound, e_var, a_var, v_var) {
(None, None, None, true, false, false) => {
proposals.retain(|e| {
base_range(&self.archive.domain, &self.archive.e_a, e)
.is_empty()
.not()
});
}
(None, None, None, false, true, false) => {
proposals.retain(|a| {
base_range(&self.archive.domain, &self.archive.a_a, a)
.is_empty()
.not()
});
}
(None, None, None, false, false, true) => {
proposals.retain(|v| {
base_range(&self.archive.domain, &self.archive.v_a, v)
.is_empty()
.not()
});
}
(Some(e), None, None, false, true, false) => {
let r = base_range(&self.archive.domain, &self.archive.e_a, e);
proposals.retain(|a| {
restrict_range(
&self.archive.domain,
&self.archive.a_a,
&self.archive.eva_c,
a,
&r,
)
.is_empty()
.not()
});
}
(Some(e), None, None, false, false, true) => {
let r = base_range(&self.archive.domain, &self.archive.e_a, e);
proposals.retain(|v| {
restrict_range(
&self.archive.domain,
&self.archive.v_a,
&self.archive.eav_c,
v,
&r,
)
.is_empty()
.not()
});
}
(None, Some(a), None, true, false, false) => {
let r = base_range(&self.archive.domain, &self.archive.a_a, a);
proposals.retain(|e| {
restrict_range(
&self.archive.domain,
&self.archive.e_a,
&self.archive.ave_c,
e,
&r,
)
.is_empty()
.not()
});
}
(None, Some(a), None, false, false, true) => {
let r = base_range(&self.archive.domain, &self.archive.a_a, a);
proposals.retain(|v| {
restrict_range(
&self.archive.domain,
&self.archive.v_a,
&self.archive.aev_c,
v,
&r,
)
.is_empty()
.not()
});
}
(None, None, Some(v), true, false, false) => {
let r = base_range(&self.archive.domain, &self.archive.v_a, v);
proposals.retain(|e| {
restrict_range(
&self.archive.domain,
&self.archive.e_a,
&self.archive.vae_c,
e,
&r,
)
.is_empty()
.not()
});
}
(None, None, Some(v), false, true, false) => {
let r = base_range(&self.archive.domain, &self.archive.v_a, v);
proposals.retain(|a| {
restrict_range(
&self.archive.domain,
&self.archive.a_a,
&self.archive.vea_c,
a,
&r,
)
.is_empty()
.not()
});
}
(None, Some(a), Some(v), true, false, false) => {
let r = base_range(&self.archive.domain, &self.archive.a_a, a);
let r = restrict_range(
&self.archive.domain,
&self.archive.v_a,
&self.archive.aev_c,
v,
&r,
);
proposals.retain(|e| {
restrict_range(
&self.archive.domain,
&self.archive.e_a,
&self.archive.vae_c,
e,
&r,
)
.is_empty()
.not()
});
}
(Some(e), None, Some(v), false, true, false) => {
let r = base_range(&self.archive.domain, &self.archive.e_a, e);
let r = restrict_range(
&self.archive.domain,
&self.archive.v_a,
&self.archive.eav_c,
v,
&r,
);
proposals.retain(|a| {
restrict_range(
&self.archive.domain,
&self.archive.a_a,
&self.archive.vea_c,
a,
&r,
)
.is_empty()
.not()
});
}
(Some(e), Some(a), None, false, false, true) => {
let r = base_range(&self.archive.domain, &self.archive.e_a, e);
let r = restrict_range(
&self.archive.domain,
&self.archive.a_a,
&self.archive.eva_c,
a,
&r,
);
proposals.retain(|v| {
restrict_range(
&self.archive.domain,
&self.archive.v_a,
&self.archive.aev_c,
v,
&r,
)
.is_empty()
.not()
});
}
_ => unreachable!("invalid trible constraint state"),
}
}
}