Working
This commit is contained in:
112
src/ast.rs
Normal file
112
src/ast.rs
Normal file
@ -0,0 +1,112 @@
|
||||
use std::fmt::Display;
|
||||
|
||||
pub type Variable = String;
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct Module
|
||||
{
|
||||
pub clauses: Vec<Clause>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct Clause
|
||||
{
|
||||
pub head: Predicate,
|
||||
pub body: Option<Body>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub enum Body
|
||||
{
|
||||
Term(Predicate),
|
||||
And(Vec<Body>),
|
||||
Or(Vec<Body>),
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub enum Predicate
|
||||
{
|
||||
Variable(Variable), // Upercase variable like X
|
||||
Fixed(String, Vec<Predicate>),
|
||||
}
|
||||
|
||||
impl Display for Body
|
||||
{
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result
|
||||
{
|
||||
match self
|
||||
{
|
||||
Body::Term(predicate) => write!(f, "{}", predicate),
|
||||
Body::And(items) | Body::Or(items) =>
|
||||
{
|
||||
let len = items.len();
|
||||
for (i, item) in items.iter().enumerate()
|
||||
{
|
||||
write!(f, "{}", item)?;
|
||||
if i != len - 1
|
||||
{
|
||||
write!(f, ",")?;
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Display for Predicate
|
||||
{
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result
|
||||
{
|
||||
match self
|
||||
{
|
||||
Predicate::Variable(variable) => write!(f, "{}", variable),
|
||||
Predicate::Fixed(name, predicates) =>
|
||||
{
|
||||
write!(f, "{}", name)?;
|
||||
if !predicates.is_empty()
|
||||
{
|
||||
write!(f, "(")?;
|
||||
let len = predicates.len();
|
||||
for (i, predicate) in predicates.iter().enumerate()
|
||||
{
|
||||
write!(f, "{}", predicate)?;
|
||||
if i != len - 1
|
||||
{
|
||||
write!(f, ", ")?;
|
||||
}
|
||||
}
|
||||
write!(f, ")")
|
||||
}
|
||||
else
|
||||
{
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Display for Clause
|
||||
{
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result
|
||||
{
|
||||
write!(f, "{}", self.head)?;
|
||||
self.body
|
||||
.as_ref()
|
||||
.map_or_else(|| Ok(()), |body| write!(f, ":- {}", body))?;
|
||||
write!(f, ".")
|
||||
}
|
||||
}
|
||||
|
||||
impl Display for Module
|
||||
{
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result
|
||||
{
|
||||
for clause in self.clauses.iter()
|
||||
{
|
||||
writeln!(f, "{}", clause)?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
3
src/lib.rs
Normal file
3
src/lib.rs
Normal file
@ -0,0 +1,3 @@
|
||||
pub mod ast;
|
||||
pub mod parsing;
|
||||
pub mod prover;
|
||||
35
src/main.rs
35
src/main.rs
@ -1,4 +1,37 @@
|
||||
use picolog::ast::Body;
|
||||
use picolog::ast::Module;
|
||||
use picolog::ast::Predicate;
|
||||
|
||||
fn main()
|
||||
{
|
||||
println!("Hello, world!");
|
||||
env_logger::builder()
|
||||
.filter_level(log::LevelFilter::Debug)
|
||||
.format_timestamp(None)
|
||||
.init();
|
||||
//println!("{:#?}", Module::parse_from_file("1.pl"));
|
||||
let module: Module = "
|
||||
integer(zero).
|
||||
integer(s(X)) :- integer(X).
|
||||
|
||||
add(X, zero, X).
|
||||
add(X, s(Y), Z) :- add(s(X), Y, Z).
|
||||
|
||||
mult(zero, X, zero).
|
||||
mult(s(Y), X, Z) :- mult(Y, X, W), add(W, X, Z).
|
||||
"
|
||||
.into();
|
||||
|
||||
//let prop: Body = "integer(s(zero))".into();
|
||||
let prop: Body = "mult(X, s(s(s(zero))), s(s(s(s(s(s(s(s(s(zero))))))))))".into();
|
||||
for c in module.prove(&prop)
|
||||
{
|
||||
println!("true:");
|
||||
println!("{}", c.simplified());
|
||||
let _ = std::io::stdin().read_line(&mut String::new());
|
||||
}
|
||||
// let p: Predicate = "add(s(zero), zero, Y)".into();
|
||||
// let p1: Predicate = "add(X, zero, X)".into();
|
||||
// // let p: Predicate = "integer(s(zero))".into();
|
||||
// // let p1: Predicate = "integer(s(X))".into();
|
||||
// println!("{}", p.matches(&p1).unwrap());
|
||||
}
|
||||
|
||||
124
src/parsing.rs
Normal file
124
src/parsing.rs
Normal file
@ -0,0 +1,124 @@
|
||||
use std::path::Path;
|
||||
|
||||
use winnow::Parser;
|
||||
use winnow::Result;
|
||||
use winnow::ascii::alphanumeric0;
|
||||
use winnow::ascii::multispace0;
|
||||
use winnow::combinator::alt;
|
||||
use winnow::combinator::delimited;
|
||||
use winnow::combinator::opt;
|
||||
use winnow::combinator::separated;
|
||||
use winnow::combinator::seq;
|
||||
use winnow::error::ContextError;
|
||||
|
||||
use crate::ast::Body;
|
||||
use crate::ast::Clause;
|
||||
use crate::ast::Module;
|
||||
use crate::ast::Predicate;
|
||||
|
||||
pub fn predicate_parse(input: &mut &str) -> Result<Predicate>
|
||||
{
|
||||
let ident = alphanumeric0.parse_next(input)?;
|
||||
|
||||
// Check if output is a variable
|
||||
if ident.chars().next().is_some_and(|char| char.is_uppercase())
|
||||
{
|
||||
Ok(Predicate::Variable(String::from(ident)))
|
||||
}
|
||||
else
|
||||
{
|
||||
let arguments = delimited(
|
||||
("(", multispace0),
|
||||
separated(1.., predicate_parse, (multispace0, ",", multispace0)),
|
||||
(multispace0, ")"),
|
||||
)
|
||||
.parse_next(input)
|
||||
.unwrap_or(Vec::new());
|
||||
Ok(Predicate::Fixed(String::from(ident), arguments))
|
||||
}
|
||||
}
|
||||
|
||||
fn body_parse_or(input: &mut &str) -> Result<Body>
|
||||
{
|
||||
separated(
|
||||
1..,
|
||||
alt((
|
||||
delimited("(", body_parse, ")"),
|
||||
predicate_parse.map(Body::Term),
|
||||
)),
|
||||
(multispace0, ";", multispace0),
|
||||
)
|
||||
.map(Body::Or)
|
||||
.parse_next(input)
|
||||
}
|
||||
|
||||
pub fn body_parse(input: &mut &str) -> Result<Body>
|
||||
{
|
||||
// Parse and
|
||||
separated(1.., body_parse_or, (multispace0, ",", multispace0))
|
||||
.map(Body::And)
|
||||
.parse_next(input)
|
||||
}
|
||||
|
||||
pub fn clause_parse(input: &mut &str) -> Result<Clause>
|
||||
{
|
||||
seq! {
|
||||
Clause
|
||||
{
|
||||
head: predicate_parse,
|
||||
body: opt((multispace0, ":-", multispace0, body_parse).map(|(_, _, _, b)| b)),
|
||||
_: multispace0,
|
||||
_: "."
|
||||
}
|
||||
}
|
||||
.parse_next(input)
|
||||
}
|
||||
|
||||
pub fn module_parse(input: &mut &str) -> Result<Module>
|
||||
{
|
||||
let _: Result<&str, ContextError> = multispace0.parse_next(input);
|
||||
separated(0.., clause_parse, multispace0)
|
||||
.map(|clauses| Module { clauses })
|
||||
.parse_next(input)
|
||||
}
|
||||
|
||||
impl<T> From<T> for Module
|
||||
where
|
||||
T: AsRef<str>,
|
||||
{
|
||||
fn from(value: T) -> Self
|
||||
{
|
||||
let mut str: &str = value.as_ref();
|
||||
module_parse.parse_next(&mut str).unwrap()
|
||||
}
|
||||
}
|
||||
|
||||
impl Module
|
||||
{
|
||||
pub fn parse_from_file<P: AsRef<Path>>(path: P) -> Self
|
||||
{
|
||||
std::fs::read_to_string(path).unwrap().into()
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> From<T> for Predicate
|
||||
where
|
||||
T: AsRef<str>,
|
||||
{
|
||||
fn from(value: T) -> Self
|
||||
{
|
||||
let mut str: &str = value.as_ref();
|
||||
predicate_parse.parse_next(&mut str).unwrap()
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> From<T> for Body
|
||||
where
|
||||
T: AsRef<str>,
|
||||
{
|
||||
fn from(value: T) -> Self
|
||||
{
|
||||
let mut str: &str = value.as_ref();
|
||||
body_parse.parse_next(&mut str).unwrap()
|
||||
}
|
||||
}
|
||||
382
src/prover.rs
Normal file
382
src/prover.rs
Normal file
@ -0,0 +1,382 @@
|
||||
pub mod constraints;
|
||||
pub mod trace;
|
||||
pub mod unification;
|
||||
|
||||
use std::cell::Cell;
|
||||
use std::collections::VecDeque;
|
||||
use std::rc::Rc;
|
||||
|
||||
use litemap::LiteMap;
|
||||
use log::info;
|
||||
|
||||
use crate::ast::Body;
|
||||
use crate::ast::Clause;
|
||||
use crate::ast::Module;
|
||||
use crate::ast::Predicate;
|
||||
use crate::prover::constraints::Constraints;
|
||||
|
||||
#[derive(Clone, Copy, Debug, Default)]
|
||||
pub struct Counter(usize);
|
||||
|
||||
#[derive(Clone, Debug, Default)]
|
||||
pub struct GlobalCounter(Rc<Cell<usize>>);
|
||||
|
||||
impl GlobalCounter
|
||||
{
|
||||
pub fn new() -> GlobalCounter
|
||||
{
|
||||
GlobalCounter(Rc::new(Cell::new(0)))
|
||||
}
|
||||
|
||||
pub fn get(&self) -> usize
|
||||
{
|
||||
let val = self.0.get();
|
||||
self.0.set(val + 1);
|
||||
val
|
||||
}
|
||||
|
||||
pub fn snapshot(&self) -> Counter
|
||||
{
|
||||
Counter(self.0.get())
|
||||
}
|
||||
|
||||
pub fn restore(&mut self, snapshot: Counter)
|
||||
{
|
||||
self.0.set(snapshot.0);
|
||||
}
|
||||
}
|
||||
|
||||
pub struct BodyProver<'a>
|
||||
{
|
||||
module: &'a Module,
|
||||
constraints: Constraints,
|
||||
|
||||
prover: Box<dyn Iterator<Item = Constraints> + 'a>,
|
||||
}
|
||||
|
||||
pub struct PredicateProver<'a>
|
||||
{
|
||||
module: &'a Module,
|
||||
predicate: Predicate,
|
||||
constraints: Constraints,
|
||||
counter_snapshot: Counter,
|
||||
|
||||
global_counter: GlobalCounter,
|
||||
current_clause: usize,
|
||||
sub_proof: Option<BodyProver<'a>>,
|
||||
}
|
||||
|
||||
pub struct AndProver<'a>
|
||||
{
|
||||
module: &'a Module,
|
||||
bodies: Vec<Body>,
|
||||
constraints: Constraints,
|
||||
|
||||
global_counter: GlobalCounter,
|
||||
sub_proofs: VecDeque<(Counter, BodyProver<'a>)>,
|
||||
}
|
||||
|
||||
impl BodyProver<'_>
|
||||
{
|
||||
pub fn new<'a>(
|
||||
module: &'a Module,
|
||||
global_counter: GlobalCounter,
|
||||
body: Body,
|
||||
constraints: Constraints,
|
||||
) -> BodyProver<'a>
|
||||
{
|
||||
let prover: Box<dyn Iterator<Item = Constraints>> = match &body
|
||||
{
|
||||
Body::Term(predicate) => Box::new(PredicateProver::new(
|
||||
module,
|
||||
global_counter,
|
||||
predicate.clone(),
|
||||
constraints.clone(),
|
||||
)),
|
||||
Body::And(items) => Box::new(AndProver::new(
|
||||
module,
|
||||
global_counter,
|
||||
items.clone(),
|
||||
constraints.clone(),
|
||||
)),
|
||||
Body::Or(items) => Box::new(BodyProver::new(
|
||||
module,
|
||||
global_counter,
|
||||
items[0].clone(),
|
||||
constraints.clone(),
|
||||
)),
|
||||
};
|
||||
info!(target: "BodyProver", "Proving {}", body);
|
||||
BodyProver {
|
||||
module,
|
||||
constraints,
|
||||
prover,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl PredicateProver<'_>
|
||||
{
|
||||
pub fn new<'a>(
|
||||
module: &'a Module,
|
||||
global_counter: GlobalCounter,
|
||||
predicate: Predicate,
|
||||
constraints: Constraints,
|
||||
) -> PredicateProver<'a>
|
||||
{
|
||||
info!(target: "PredicateProver", "Proving {}", predicate);
|
||||
PredicateProver {
|
||||
module,
|
||||
predicate,
|
||||
constraints,
|
||||
current_clause: 0,
|
||||
sub_proof: None,
|
||||
counter_snapshot: global_counter.snapshot(),
|
||||
global_counter,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl AndProver<'_>
|
||||
{
|
||||
pub fn new<'a>(
|
||||
module: &'a Module,
|
||||
global_counter: GlobalCounter,
|
||||
bodies: Vec<Body>,
|
||||
constraints: Constraints,
|
||||
) -> AndProver<'a>
|
||||
{
|
||||
assert!(!bodies.is_empty());
|
||||
|
||||
AndProver {
|
||||
module,
|
||||
sub_proofs: VecDeque::from(vec![(
|
||||
global_counter.snapshot(),
|
||||
BodyProver::new(
|
||||
module,
|
||||
global_counter.clone(),
|
||||
bodies[0].clone(),
|
||||
constraints.clone(),
|
||||
),
|
||||
)]),
|
||||
bodies,
|
||||
constraints,
|
||||
global_counter,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Iterator for PredicateProver<'_>
|
||||
{
|
||||
type Item = Constraints;
|
||||
|
||||
fn next(&mut self) -> Option<Self::Item>
|
||||
{
|
||||
match self.sub_proof.as_mut()
|
||||
{
|
||||
None =>
|
||||
{
|
||||
if self.current_clause == self.module.clauses.len()
|
||||
{
|
||||
None
|
||||
}
|
||||
else
|
||||
{
|
||||
let clause = &self.module.clauses[self.current_clause]
|
||||
.make_unique(self.global_counter.clone());
|
||||
info!(target: "PredicateProver", "Unifying '{}' against '{}'", self.predicate, clause);
|
||||
let uni = self.predicate.matches(&clause.head);
|
||||
let full_constraints = uni.and_then(|x| x.and(&self.constraints));
|
||||
|
||||
if let Some(c) = &full_constraints
|
||||
{
|
||||
info!(target: "PredicateProver", " => {}", c);
|
||||
}
|
||||
else
|
||||
{
|
||||
info!(target: "PredicateProver", " => (Can't unify)");
|
||||
}
|
||||
match full_constraints
|
||||
{
|
||||
Some(constraints) if clause.body.is_none() =>
|
||||
{
|
||||
self.current_clause += 1;
|
||||
Some(constraints)
|
||||
}
|
||||
Some(constraints) =>
|
||||
{
|
||||
self.current_clause += 1;
|
||||
self.counter_snapshot = self.global_counter.snapshot();
|
||||
self.sub_proof = Some(BodyProver::new(
|
||||
self.module,
|
||||
self.global_counter.clone(),
|
||||
clause.body.clone().unwrap(),
|
||||
constraints,
|
||||
));
|
||||
self.next()
|
||||
}
|
||||
None =>
|
||||
{
|
||||
self.current_clause += 1;
|
||||
self.next()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Some(prover) =>
|
||||
{
|
||||
let next = prover.next();
|
||||
match next
|
||||
{
|
||||
Some(constraints) => Some(constraints),
|
||||
None =>
|
||||
{
|
||||
self.global_counter.restore(self.counter_snapshot);
|
||||
self.sub_proof = None;
|
||||
self.next()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Iterator for BodyProver<'_>
|
||||
{
|
||||
type Item = Constraints;
|
||||
fn next(&mut self) -> Option<Constraints>
|
||||
{
|
||||
self.prover.next()
|
||||
}
|
||||
}
|
||||
|
||||
impl Iterator for AndProver<'_>
|
||||
{
|
||||
type Item = Constraints;
|
||||
|
||||
fn next(&mut self) -> Option<Self::Item>
|
||||
{
|
||||
if self.sub_proofs.is_empty()
|
||||
{
|
||||
return None;
|
||||
}
|
||||
|
||||
let (current_proof_snap, mut current_proof) = self.sub_proofs.pop_back().unwrap();
|
||||
|
||||
match current_proof.next()
|
||||
{
|
||||
Some(constraints) =>
|
||||
{
|
||||
if self.sub_proofs.len() == self.bodies.len() - 1
|
||||
{
|
||||
self.sub_proofs
|
||||
.push_back((current_proof_snap, current_proof));
|
||||
Some(constraints)
|
||||
}
|
||||
else
|
||||
{
|
||||
self.sub_proofs
|
||||
.push_back((current_proof_snap, current_proof));
|
||||
self.sub_proofs.push_back((
|
||||
self.global_counter.snapshot(),
|
||||
BodyProver::new(
|
||||
self.module,
|
||||
self.global_counter.clone(),
|
||||
self.bodies[self.sub_proofs.len()].clone(),
|
||||
constraints,
|
||||
),
|
||||
));
|
||||
self.next()
|
||||
}
|
||||
}
|
||||
None =>
|
||||
{
|
||||
self.global_counter.restore(current_proof_snap);
|
||||
self.next()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Module
|
||||
{
|
||||
pub fn prove<'a>(&'a self, body: &'a Body) -> BodyProver<'a>
|
||||
{
|
||||
BodyProver::new(
|
||||
self,
|
||||
GlobalCounter::new(),
|
||||
body.clone(),
|
||||
Constraints::none(),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
impl Clause
|
||||
{
|
||||
pub fn make_unique(&self, counter: GlobalCounter) -> Clause
|
||||
{
|
||||
let mut unique_map = LiteMap::new();
|
||||
Clause {
|
||||
head: self.head.make_unique(counter.clone(), &mut unique_map),
|
||||
body: self
|
||||
.body
|
||||
.as_ref()
|
||||
.map(|body| body.make_unique(counter.clone(), &mut unique_map)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Body
|
||||
{
|
||||
pub fn make_unique(
|
||||
&self,
|
||||
counter: GlobalCounter,
|
||||
unique_map: &mut LiteMap<String, usize>,
|
||||
) -> Body
|
||||
{
|
||||
match self
|
||||
{
|
||||
Body::Term(predicate) => Body::Term(predicate.make_unique(counter.clone(), unique_map)),
|
||||
Body::And(items) => Body::And(
|
||||
items
|
||||
.iter()
|
||||
.map(|x| x.make_unique(counter.clone(), unique_map))
|
||||
.collect(),
|
||||
),
|
||||
Body::Or(items) => Body::Or(
|
||||
items
|
||||
.iter()
|
||||
.map(|x| x.make_unique(counter.clone(), unique_map))
|
||||
.collect(),
|
||||
),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Predicate
|
||||
{
|
||||
pub fn make_unique(
|
||||
&self,
|
||||
counter: GlobalCounter,
|
||||
unique_map: &mut LiteMap<String, usize>,
|
||||
) -> Self
|
||||
{
|
||||
match self
|
||||
{
|
||||
Predicate::Variable(name) => Predicate::Variable(format!(
|
||||
"_{}[{}]",
|
||||
name,
|
||||
unique_map
|
||||
.entry(name.clone())
|
||||
.or_insert_with(|| counter.get())
|
||||
)),
|
||||
Predicate::Fixed(name, predicates) => Predicate::Fixed(
|
||||
name.clone(),
|
||||
predicates
|
||||
.iter()
|
||||
.map(|x| x.make_unique(counter.clone(), unique_map))
|
||||
.collect(),
|
||||
),
|
||||
}
|
||||
}
|
||||
}
|
||||
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