optimizations

This commit is contained in:
Mark Thom
2017-03-22 22:30:45 -06:00
parent 540a5b805f
commit 9362aa6af3
7 changed files with 147 additions and 37 deletions

2
Cargo.lock generated
View File

@@ -1,6 +1,6 @@
[root]
name = "rusty-wam"
version = "0.5.0"
version = "0.5.3"
dependencies = [
"lalrpop 0.12.5 (registry+https://github.com/rust-lang/crates.io-index)",
"lalrpop-util 0.12.5 (registry+https://github.com/rust-lang/crates.io-index)",

View File

@@ -1,6 +1,6 @@
[package]
name = "rusty-wam"
version = "0.5.0"
version = "0.5.4"
authors = ["Mark Thom"]
build = "build.rs"

View File

@@ -11,8 +11,8 @@ pure Prolog.
Pure Prolog is implemented as a simple REPL. "Pure Prolog" is Prolog
without cut, meta- or extra-logical operators, or side effects of any
kind. In terms of the tutorial pacing, the work has progressed to the
middle of section 5.2. Atoms and lists are the only two data types
currently supported.
to the end of section 5.3, skipping past 5.4. Atoms and lists
are the only two data types currently supported.
## Tutorial
To enter a multi-clause predicate, the brackets ":{" and "}:" are used

View File

@@ -80,6 +80,10 @@ impl VarReg {
}
}
pub fn is_temp(self) -> bool {
!self.norm().is_perm()
}
pub fn root_register(self) -> usize {
match self {
VarReg::ArgAndNorm(_, root) => root,
@@ -126,10 +130,11 @@ pub enum FactInstruction {
GetList(Level, RegType),
GetStructure(Level, Atom, usize, RegType),
GetValue(RegType, usize),
GetVariable(RegType, usize),
GetVariable(RegType, usize),
UnifyConstant(Constant),
UnifyVariable(RegType),
UnifyValue(RegType)
UnifyValue(RegType),
UnifyVoid(usize)
}
pub enum QueryInstruction {
@@ -140,7 +145,8 @@ pub enum QueryInstruction {
PutVariable(RegType, usize),
SetConstant(Constant),
SetVariable(RegType),
SetValue(RegType)
SetValue(RegType),
SetVoid(usize)
}
pub enum ChoiceInstruction {

View File

@@ -11,9 +11,10 @@ trait CompilationTarget<'a> {
fn iter(&'a Term) -> Self::Iterator;
fn to_structure(Level, Atom, usize, RegType) -> Self;
fn to_constant(Level, Constant, RegType) -> Self;
fn to_list(Level, RegType) -> Self;
fn to_structure(Level, Atom, usize, RegType) -> Self;
fn to_void(usize) -> Self;
fn constant_subterm(Constant) -> Self;
@@ -33,18 +34,22 @@ impl<'a> CompilationTarget<'a> for FactInstruction {
term.breadth_first_iter()
}
fn to_structure(lvl: Level, atom: Atom, arity: usize, reg: RegType) -> Self {
FactInstruction::GetStructure(lvl, atom, arity, reg)
}
fn to_constant(lvl: Level, constant: Constant, reg: RegType) -> Self {
FactInstruction::GetConstant(lvl, constant, reg)
}
fn to_structure(lvl: Level, atom: Atom, arity: usize, reg: RegType) -> Self {
FactInstruction::GetStructure(lvl, atom, arity, reg)
}
fn to_list(lvl: Level, reg: RegType) -> Self {
FactInstruction::GetList(lvl, reg)
}
fn to_void(subterms: usize) -> Self {
FactInstruction::UnifyVoid(subterms)
}
fn constant_subterm(constant: Constant) -> Self {
FactInstruction::UnifyConstant(constant)
}
@@ -76,7 +81,7 @@ impl<'a> CompilationTarget<'a> for QueryInstruction {
fn iter(term: &'a Term) -> Self::Iterator {
term.post_order_iter()
}
fn to_structure(lvl: Level, atom: Atom, arity: usize, reg: RegType) -> Self {
QueryInstruction::PutStructure(lvl, atom, arity, reg)
}
@@ -89,6 +94,10 @@ impl<'a> CompilationTarget<'a> for QueryInstruction {
QueryInstruction::PutList(lvl, reg)
}
fn to_void(subterms: usize) -> Self {
QueryInstruction::SetVoid(subterms)
}
fn constant_subterm(constant: Constant) -> Self {
QueryInstruction::SetConstant(constant)
}
@@ -145,7 +154,7 @@ impl<'a> TermMarker<'a> {
fn insert(&mut self, var: &'a Var, r: VarReg) {
self.bindings.insert(var, r);
}
fn mark_non_var(&mut self, lvl: Level, cell: &Cell<RegType>) {
let reg_type = cell.get();
@@ -212,18 +221,18 @@ impl<'a> TermMarker<'a> {
reg
}
};
self.insert(var, reg);
self.insert(var, reg);
reg
}
fn mark_anon_var(&mut self, lvl: Level) -> VarReg {
let inner_reg = {
let temp = self.temp_c;
self.temp_c += 1;
RegType::Temp(temp)
};
match lvl {
Level::Deep => VarReg::Norm(inner_reg),
Level::Shallow => {
@@ -233,7 +242,11 @@ impl<'a> TermMarker<'a> {
}
}
}
fn advance_arg(&mut self) {
self.arg_c += 1;
}
fn advance_at_head(&mut self, term: &'a Term) {
self.arg_c = 1;
self.temp_c = max(term.subterms(), self.temp_c) + 1;
@@ -266,6 +279,46 @@ impl<'a> CodeGenerator<'a> {
&self.marker.bindings
}
#[allow(dead_code)]
fn count_vars(term: &Term) -> HashMap<&Var, usize> {
let mut var_count = HashMap::new();
for term in term.breadth_first_iter() {
if let TermRef::Var(_, _, ref var) = term {
let entry = var_count.entry(*var).or_insert(0);
*entry += 1;
}
}
var_count
}
#[allow(dead_code)]
fn all_singleton_vars(terms: &Vec<Box<Term>>,
var_count: &HashMap<&Var, usize>)
-> bool
{
for term in terms {
match term.as_ref() {
&Term::AnonVar => {},
&Term::Var(ref cell, ref var) if cell.get().is_temp() =>
if var_count.get(var).unwrap() != &1 {
return false;
},
_ => return false
}
}
true
}
#[allow(dead_code)]
fn void_subterms<Target>(subterms: usize) -> Target
where Target: CompilationTarget<'a>
{
Target::to_void(subterms)
}
fn to_structure<Target>(&mut self,
lvl: Level,
cell: &'a Cell<RegType>,
@@ -305,10 +358,10 @@ impl<'a> CodeGenerator<'a> {
self.marker.mark_non_var(Level::Deep, cell);
Target::constant_subterm(constant.clone())
}
fn anon_var_term<Target>(&mut self, lvl: Level) -> Target
where Target: CompilationTarget<'a>
{
{
let reg = self.marker.mark_anon_var(lvl);
match reg {
@@ -318,7 +371,7 @@ impl<'a> CodeGenerator<'a> {
Target::subterm_to_variable(norm)
}
}
fn var_term<Target>(&mut self,
lvl: Level,
cell: &'a Cell<VarReg>,
@@ -371,17 +424,26 @@ impl<'a> CodeGenerator<'a> {
}
}
fn compile_target<Target>(&mut self, term: &'a Term) -> Vec<Target>
fn compile_target<Target>(&mut self, term: &'a Term, has_exposed_vars: bool)
-> Vec<Target>
where Target: CompilationTarget<'a>
{
let iter = Target::iter(term);
let mut target = Vec::new();
let var_count = Self::count_vars(term);
for term in iter {
match term {
TermRef::Clause(lvl, cell, atom, terms) => {
target.push(self.to_structure(lvl, cell, atom, terms.len()));
if !has_exposed_vars {
if Self::all_singleton_vars(terms, &var_count) {
target.push(Self::void_subterms(terms.len()));
continue;
}
}
for subterm in terms {
target.push(self.subterm_to_instr(subterm.as_ref()));
}
@@ -394,8 +456,13 @@ impl<'a> CodeGenerator<'a> {
},
TermRef::Constant(lvl @ Level::Shallow, cell, constant) =>
target.push(self.to_constant(lvl, cell, constant)),
TermRef::AnonVar(lvl @ Level::Shallow) =>
target.push(self.anon_var_term(lvl)),
TermRef::AnonVar(lvl @ Level::Shallow) => {
if has_exposed_vars {
target.push(self.anon_var_term(lvl));
} else {
self.marker.advance_arg();
}
},
TermRef::Var(lvl @ Level::Shallow, ref cell, ref var) =>
target.push(self.var_term(lvl, cell, var)),
_ => {}
@@ -480,15 +547,15 @@ impl<'a> CodeGenerator<'a> {
body.push(Line::Control(ControlInstruction::Allocate(perm_vars)));
self.marker.advance(p0);
body.push(Line::Fact(self.compile_target(p0)));
body.push(Line::Fact(self.compile_target(p0, false)));
self.marker.advance_at_head(p1);
body.push(Line::Query(self.compile_target(p1)));
body.push(Line::Query(self.compile_target(p1, false)));
Self::add_conditional_call(&mut body, p1);
body = clauses.iter()
.map(|ref term| self.compile_query(term))
.map(|ref term| self.compile_internal_query(term))
.fold(body, |mut body, ref mut cqs| {
body.append(cqs);
body
@@ -501,17 +568,26 @@ impl<'a> CodeGenerator<'a> {
pub fn compile_fact(&mut self, term: &'a Term) -> Code {
self.marker.advance(term);
let mut compiled_fact = vec![Line::Fact(self.compile_target(term))];
let mut compiled_fact = vec![Line::Fact(self.compile_target(term, false))];
let proceed = Line::Control(ControlInstruction::Proceed);
compiled_fact.push(proceed);
compiled_fact
}
fn compile_internal_query(&mut self, term: &'a Term) -> Code {
self.marker.advance(term);
let mut compiled_query = vec![Line::Query(self.compile_target(term, false))];
Self::add_conditional_call(&mut compiled_query, term);
compiled_query
}
pub fn compile_query(&mut self, term: &'a Term) -> Code {
self.marker.advance(term);
let mut compiled_query = vec![Line::Query(self.compile_target(term))];
let mut compiled_query = vec![Line::Query(self.compile_target(term, true))];
Self::add_conditional_call(&mut compiled_query, term);
compiled_query

View File

@@ -14,7 +14,7 @@ impl fmt::Display for Constant {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
&Constant::Atom(ref atom) =>
write!(f, "{}", atom),
write!(f, "{}", atom),
&Constant::EmptyList =>
write!(f, "[]")
}
@@ -45,7 +45,9 @@ impl fmt::Display for FactInstruction {
&FactInstruction::UnifyVariable(ref r) =>
write!(f, "unify_variable {}", r),
&FactInstruction::UnifyValue(ref r) =>
write!(f, "unify_value {}", r)
write!(f, "unify_value {}", r),
&FactInstruction::UnifyVoid(n) =>
write!(f, "unify_void {}", n)
}
}
}
@@ -74,7 +76,9 @@ impl fmt::Display for QueryInstruction {
&QueryInstruction::SetVariable(ref r) =>
write!(f, "set_variable {}", r),
&QueryInstruction::SetValue(ref r) =>
write!(f, "set_value {}", r)
write!(f, "set_value {}", r),
&QueryInstruction::SetVoid(n) =>
write!(f, "set_void {}", n)
}
}
}
@@ -207,7 +211,7 @@ pub fn eval(wam: &mut Machine, buffer: &str) -> EvalResult
&Ok(TopLevel::Predicate(ref clauses)) => {
if is_consistent(clauses) {
let compiled_pred = cg.compile_predicate(clauses);
wam.add_predicate(clauses, compiled_pred);
wam.add_predicate(clauses, compiled_pred);
EvalResult::EntrySuccess
} else {
@@ -229,8 +233,8 @@ Each predicate must have the same name and arity.";
EvalResult::EntrySuccess
},
&Ok(TopLevel::Query(ref query)) => {
let compiled_query = cg.compile_query(&query);
wam.run_query(compiled_query, &cg)
let compiled_query = cg.compile_query(&query);
wam.run_query(compiled_query, &cg)
},
&Err(_) => {
println!("Grammatical error of some kind!");
@@ -251,7 +255,7 @@ pub fn print(wam: &mut Machine, result: EvalResult) {
'outer: loop {
let mut result = EvalResult::QueryFailure;
let bindings = wam.heap_view(&heap_locs);
let stdin = stdin();
let mut stdout = stdout().into_raw_mode().unwrap();

View File

@@ -585,6 +585,21 @@ impl MachineState {
};
self.s += 1;
},
&FactInstruction::UnifyVoid(n) => {
match self.mode {
MachineMode::Read =>
self.s += n,
MachineMode::Write => {
let h = self.h;
for i in h .. h + n {
self.heap.push(HeapCellValue::Ref(Ref::HeapCell(i)));
}
self.h += n;
}
};
}
};
}
@@ -628,6 +643,15 @@ impl MachineState {
self.h += 1;
},
&QueryInstruction::SetVoid(n) => {
let h = self.h;
for i in h .. h + n {
self.heap.push(HeapCellValue::Ref(Ref::HeapCell(i)));
}
self.h += n;
}
}
}