use std::{
collections::HashMap,
iter,
};
use razor_fol::syntax::V;
use crate::chase::{
r#impl::{
basic, reference,
reference::{WitnessTerm, Element},
},
Rel, Observation, EvaluateResult,
ModelTrait, StrategyTrait, EvaluatorTrait, BounderTrait,
};
use itertools::{Itertools, Either};
pub struct Evaluator {}
impl<'s, Stg: StrategyTrait<Item=&'s Sequent>, B: BounderTrait> EvaluatorTrait<'s, Stg, B> for Evaluator {
type Sequent = Sequent;
type Model = Model;
fn evaluate(
&self,
initial_model: &Model,
strategy: &mut Stg,
bounder: Option<&B>,
) -> Option<EvaluateResult<Model>> {
let mut result = EvaluateResult::new();
let domain: Vec<&Element> = initial_model.domain();
let domain_size = domain.len();
for sequent in strategy {
let vars = &sequent.free_vars;
let vars_size = vars.len();
if domain_size == 0 && vars_size > 0 {
continue; }
let mut assignment: Vec<usize> = iter::repeat(0).take(vars_size).collect();
while {
let mut assignment_map: HashMap<&V, Element> = HashMap::new();
for i in 0..vars_size {
assignment_map.insert(vars.get(i).unwrap(), (*domain.get(assignment[i]).unwrap()).clone());
}
let assignment_func = |v: &V| assignment_map.get(v).unwrap().clone();
let observe_literal = make_observe_literal(assignment_func);
let body: Vec<Observation<WitnessTerm>> = sequent.body_literals
.iter().map(&observe_literal).collect();
let head: Vec<Vec<Observation<WitnessTerm>>> = sequent.head_literals
.iter().map(|l| l.iter().map(&observe_literal).collect()).collect();
if body.iter().all(|o| initial_model.is_observed(o))
&& !head.iter().any(|os| os.iter().all(|o| initial_model.is_observed(o))) {
if head.is_empty() {
return None; } else {
if result.open_models.is_empty() {
result.open_models.push(initial_model.clone());
}
let models: Vec<Either<Model, Model>> = result.open_models.iter().flat_map(|m| {
let ms: Vec<Either<Model, Model>> = if let Some(bounder) = bounder {
let extend = make_bounded_extend(bounder, m);
head.iter().map(extend).collect()
} else {
let extend = make_extend(m);
head.iter().map(extend).collect()
};
ms
}).collect();
result.open_models.clear();
models.into_iter().for_each(|m| result.append(m));
}
}
domain_size > 0 && next_assignment(&mut assignment, domain_size - 1)
} {}
}
return Some(result);
}
}
fn make_extend<'m>(
model: &'m Model
) -> impl FnMut(&'m Vec<Observation<WitnessTerm>>) -> Either<Model, Model>
{
move |os: &'m Vec<Observation<WitnessTerm>>| {
let mut model = model.clone();
os.iter().foreach(|o| model.observe(o));
Either::Left(model)
}
}
fn make_bounded_extend<'m, B: BounderTrait>(
bounder: &'m B,
model: &'m Model,
) -> impl FnMut(&'m Vec<Observation<WitnessTerm>>) -> Either<Model, Model>
{
move |os: &Vec<Observation<WitnessTerm>>| {
let mut model = model.clone();
let mut modified = false;
os.iter().foreach(|o| {
if bounder.bound(&model, o) {
if !model.is_observed(o) {
modified = true;
}
} else {
if !model.is_observed(o) {
model.observe(o);
}
}
});
if modified {
Either::Right(model)
} else {
Either::Left(model)
}
}
}
fn make_observe_literal(assignment_func: impl Fn(&V) -> Element)
-> impl Fn(&Literal) -> Observation<WitnessTerm> {
move |lit: &Literal| {
match lit {
basic::Literal::Atm { predicate, terms } => {
let terms = terms
.into_iter()
.map(|t| WitnessTerm::witness(t, &assignment_func))
.collect();
Observation::Fact { relation: Rel(predicate.0.clone()), terms }
}
basic::Literal::Eql { left, right } => {
let left = WitnessTerm::witness(left, &assignment_func);
let right = WitnessTerm::witness(right, &assignment_func);
Observation::Identity { left, right }
}
}
}
}
fn next_assignment(vec: &mut Vec<usize>, last: usize) -> bool {
let len = vec.len();
for i in 0..len {
if vec[i] != last {
vec[i] += 1;
return true;
} else {
vec[i] = 0;
}
}
false
}
pub type Sequent = basic::Sequent;
pub type Literal = basic::Literal;
pub type Model = reference::Model;
#[cfg(test)]
mod test_batch {
use super::{Evaluator, next_assignment};
use crate::chase::r#impl::reference::Model;
use crate::chase::r#impl::basic::Sequent;
use razor_fol::syntax::Theory;
use crate::chase::{
SchedulerTrait, StrategyTrait, strategy::{Bootstrap, Fair},
scheduler::FIFO, bounder::DomainSize, chase_all,
};
use crate::test_prelude::*;
use std::collections::HashSet;
use std::fs;
#[test]
fn test_next_assignment() {
{
let mut assignment = vec![];
assert_eq!(false, next_assignment(&mut assignment, 1));
assert!(assignment.is_empty());
}
{
let mut assignment = vec![0];
assert_eq!(true, next_assignment(&mut assignment, 1));
assert_eq!(vec![1], assignment);
}
{
let mut assignment = vec![1];
assert_eq!(false, next_assignment(&mut assignment, 1));
assert_eq!(vec![0], assignment);
}
{
let mut assignment = vec![0, 1];
assert_eq!(true, next_assignment(&mut assignment, 1));
assert_eq!(vec![1, 1], assignment);
}
{
let mut assignment = vec![1, 1];
assert_eq!(true, next_assignment(&mut assignment, 2));
assert_eq!(vec![2, 1], assignment);
}
{
let mut assignment = vec![2, 1];
assert_eq!(true, next_assignment(&mut assignment, 2));
assert_eq!(vec![0, 2], assignment);
}
{
let mut assignment = vec![2, 2];
assert_eq!(false, next_assignment(&mut assignment, 2));
assert_eq!(vec![0, 0], assignment);
}
{
let mut counter = 1;
let mut vec = vec![0, 0, 0, 0, 0];
while next_assignment(&mut vec, 4) {
counter += 1;
}
assert_eq!(3125, counter);
}
}
fn run_test(theory: &Theory) -> Vec<Model> {
let geometric_theory = theory.gnf();
let sequents: Vec<Sequent> = geometric_theory
.formulae
.iter()
.map(|f| f.into()).collect();
let evaluator = Evaluator {};
let strategy: Bootstrap<Sequent, Fair<Sequent>> = Bootstrap::new(sequents.iter().collect());
let mut scheduler = FIFO::new();
let bounder: Option<&DomainSize> = None;
scheduler.add(Model::new(), strategy);
chase_all(&mut scheduler, &evaluator, bounder)
}
#[test]
fn test() {
println!("{}", std::env::current_dir().unwrap().to_str().unwrap());
for item in fs::read_dir("../theories/core").unwrap() {
let theory = read_theory_from_file(item.unwrap().path().to_str().unwrap());
let basic_models = solve_basic(&theory);
let test_models = run_test(&theory);
let basic_models: HashSet<String> = basic_models.into_iter().map(|m| print_basic_model(m)).collect();
let test_models: HashSet<String> = test_models.into_iter().map(|m| print_reference_model(m)).collect();
assert_eq!(basic_models, test_models);
}
}
}