Working
This commit is contained in:
183
src/prover/constraints.rs
Normal file
183
src/prover/constraints.rs
Normal file
@ -0,0 +1,183 @@
|
||||
use std::fmt::Display;
|
||||
|
||||
use litemap::LiteMap;
|
||||
use winnow::Str;
|
||||
|
||||
use crate::ast::Predicate;
|
||||
use crate::ast::Variable;
|
||||
use crate::prover::constraints;
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct Constraints
|
||||
{
|
||||
set: LiteMap<Variable, Predicate>,
|
||||
}
|
||||
|
||||
impl Constraints
|
||||
{
|
||||
pub fn none() -> Self
|
||||
{
|
||||
Constraints {
|
||||
set: LiteMap::new(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn with(variable: Variable, predicate: Predicate) -> Self
|
||||
{
|
||||
let mut c = Constraints::none();
|
||||
c.set.insert(variable, predicate);
|
||||
c
|
||||
}
|
||||
|
||||
pub fn try_append(&mut self, variable: &Variable, predicate: &Predicate) -> bool
|
||||
{
|
||||
if let Some(other_predicate) = self.set.get(variable)
|
||||
{
|
||||
// If variable is already contrained, we need to check if both contraints are
|
||||
// contradictory
|
||||
|
||||
// Try to unify both predicates
|
||||
let unification = predicate.matches(other_predicate);
|
||||
if let Some(unification_contraints) = unification
|
||||
{
|
||||
// Instead of adding the variable = predicates contraint,
|
||||
// We can try adding the unification contraints which is implicitely the same
|
||||
if self.try_merge(&unification_contraints)
|
||||
{
|
||||
self.set.insert(variable.clone(), predicate.clone());
|
||||
true
|
||||
}
|
||||
else
|
||||
{
|
||||
false
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Unification is impossible, variable = predicates is contradictory under self
|
||||
false
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// No constraint
|
||||
self.set.insert(variable.clone(), predicate.clone());
|
||||
true
|
||||
}
|
||||
}
|
||||
|
||||
pub fn try_merge(&mut self, constraints: &Constraints) -> bool
|
||||
{
|
||||
// Trying to merge, is just trying to add all of the constraints into self
|
||||
let mut ok = self.clone();
|
||||
for (var, pred) in constraints.set.iter()
|
||||
{
|
||||
if !ok.try_append(var, pred)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
*self = ok;
|
||||
true
|
||||
}
|
||||
|
||||
pub fn and(&self, constraints: &Constraints) -> Option<Constraints>
|
||||
{
|
||||
let mut new_contraints = self.clone();
|
||||
let valid = new_contraints.try_merge(constraints);
|
||||
if valid { Some(new_contraints) } else { None }
|
||||
}
|
||||
|
||||
pub fn simplified(&self) -> Constraints
|
||||
{
|
||||
let mut max_sub = Constraints::none();
|
||||
for (var, pred) in self.set.iter()
|
||||
{
|
||||
max_sub.set.insert(var.clone(), pred.substitute(self));
|
||||
}
|
||||
|
||||
let mut stripped = max_sub.clone();
|
||||
'outer: for (var, _) in max_sub.set.iter()
|
||||
{
|
||||
if var.chars().next().is_some_and(|x| x == '_')
|
||||
{
|
||||
for (_, other_pred) in max_sub.set.iter()
|
||||
{
|
||||
if other_pred.contains_variable(var)
|
||||
{
|
||||
continue 'outer;
|
||||
}
|
||||
}
|
||||
stripped.set.remove(var);
|
||||
}
|
||||
}
|
||||
|
||||
stripped
|
||||
}
|
||||
}
|
||||
|
||||
impl Predicate
|
||||
{
|
||||
pub fn substitute(&self, constraints: &Constraints) -> Predicate
|
||||
{
|
||||
match self
|
||||
{
|
||||
Predicate::Variable(name) =>
|
||||
{
|
||||
if let Some(pred) = constraints.set.get(name)
|
||||
{
|
||||
let max_sub = pred.substitute(constraints);
|
||||
max_sub
|
||||
}
|
||||
else
|
||||
{
|
||||
Predicate::Variable(name.clone())
|
||||
}
|
||||
}
|
||||
Predicate::Fixed(name, predicates) => Predicate::Fixed(
|
||||
name.clone(),
|
||||
predicates
|
||||
.iter()
|
||||
.map(|x| x.substitute(constraints))
|
||||
.collect(),
|
||||
),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn contains_variable(&self, name: &String) -> bool
|
||||
{
|
||||
match self
|
||||
{
|
||||
Predicate::Variable(var_name) => name == var_name,
|
||||
Predicate::Fixed(_, predicates) => predicates
|
||||
.iter()
|
||||
.find(|x| x.contains_variable(name))
|
||||
.is_some(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for Constraints
|
||||
{
|
||||
fn default() -> Self
|
||||
{
|
||||
Self::none()
|
||||
}
|
||||
}
|
||||
|
||||
impl Display for Constraints
|
||||
{
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result
|
||||
{
|
||||
let len = self.set.len();
|
||||
for (i, (var, pred)) in self.set.iter().enumerate()
|
||||
{
|
||||
write!(f, "{} = {}", var, pred)?;
|
||||
if i != len - 1
|
||||
{
|
||||
write!(f, ", ")?;
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
0
src/prover/trace.rs
Normal file
0
src/prover/trace.rs
Normal file
65
src/prover/unification.rs
Normal file
65
src/prover/unification.rs
Normal file
@ -0,0 +1,65 @@
|
||||
use std::process::Output;
|
||||
|
||||
use log::debug;
|
||||
|
||||
use crate::ast::Predicate;
|
||||
use crate::prover::constraints::Constraints;
|
||||
|
||||
impl Predicate
|
||||
{
|
||||
/// Checks if `self` can be unified with `other`
|
||||
///
|
||||
/// returns `Some(constraints)` if the unification is valid under `constraints`
|
||||
/// returns `None` if the predicate cannot be unified against the other
|
||||
pub fn matches(&self, other: &Predicate) -> Option<Constraints>
|
||||
{
|
||||
debug!("Unifying {} against {}", self, other);
|
||||
match self
|
||||
{
|
||||
Predicate::Variable(variable) =>
|
||||
{
|
||||
// We are trying to see if X (any) matches the other Predicate.
|
||||
// This is always true if X = other_predicate
|
||||
Some(Constraints::with(variable.clone(), other.clone()))
|
||||
}
|
||||
|
||||
Predicate::Fixed(name, arguments) =>
|
||||
{
|
||||
match other
|
||||
{
|
||||
Predicate::Variable(var) =>
|
||||
{
|
||||
// We are trying to see if something like "predicate(..., ...)" matches X
|
||||
// (any)
|
||||
// This is always true
|
||||
Some(Constraints::with(var.clone(), self.clone()))
|
||||
}
|
||||
// Match pred(X, Y, Z, ...) with pred(_X, _Y, _Z, ...)
|
||||
Predicate::Fixed(other_name, other_arguments)
|
||||
if other_name == name && other_arguments.len() == arguments.len() =>
|
||||
{
|
||||
// If there is no arguments, no constraints
|
||||
if arguments.is_empty()
|
||||
{
|
||||
return Some(Constraints::none());
|
||||
}
|
||||
|
||||
// We unify with other only if our arguments unify with theirs
|
||||
arguments
|
||||
.iter()
|
||||
.zip(other_arguments.iter())
|
||||
.map(|(ours, theirs)| ours.matches(theirs))
|
||||
.reduce(|a, b| match (a, b)
|
||||
{
|
||||
(Some(c1), Some(c2)) => c1.and(&c2),
|
||||
_ => None,
|
||||
})
|
||||
.unwrap_or(None)
|
||||
}
|
||||
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user