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] [root]
name = "rusty-wam" name = "rusty-wam"
version = "0.5.0" version = "0.5.3"
dependencies = [ dependencies = [
"lalrpop 0.12.5 (registry+https://github.com/rust-lang/crates.io-index)", "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)", "lalrpop-util 0.12.5 (registry+https://github.com/rust-lang/crates.io-index)",

View File

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

View File

@@ -11,8 +11,8 @@ pure Prolog.
Pure Prolog is implemented as a simple REPL. "Pure Prolog" is 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 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 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 to the end of section 5.3, skipping past 5.4. Atoms and lists
currently supported. are the only two data types currently supported.
## Tutorial ## Tutorial
To enter a multi-clause predicate, the brackets ":{" and "}:" are used 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 { pub fn root_register(self) -> usize {
match self { match self {
VarReg::ArgAndNorm(_, root) => root, VarReg::ArgAndNorm(_, root) => root,
@@ -126,10 +130,11 @@ pub enum FactInstruction {
GetList(Level, RegType), GetList(Level, RegType),
GetStructure(Level, Atom, usize, RegType), GetStructure(Level, Atom, usize, RegType),
GetValue(RegType, usize), GetValue(RegType, usize),
GetVariable(RegType, usize), GetVariable(RegType, usize),
UnifyConstant(Constant), UnifyConstant(Constant),
UnifyVariable(RegType), UnifyVariable(RegType),
UnifyValue(RegType) UnifyValue(RegType),
UnifyVoid(usize)
} }
pub enum QueryInstruction { pub enum QueryInstruction {
@@ -140,7 +145,8 @@ pub enum QueryInstruction {
PutVariable(RegType, usize), PutVariable(RegType, usize),
SetConstant(Constant), SetConstant(Constant),
SetVariable(RegType), SetVariable(RegType),
SetValue(RegType) SetValue(RegType),
SetVoid(usize)
} }
pub enum ChoiceInstruction { pub enum ChoiceInstruction {

View File

@@ -11,9 +11,10 @@ trait CompilationTarget<'a> {
fn iter(&'a Term) -> Self::Iterator; fn iter(&'a Term) -> Self::Iterator;
fn to_structure(Level, Atom, usize, RegType) -> Self;
fn to_constant(Level, Constant, RegType) -> Self; fn to_constant(Level, Constant, RegType) -> Self;
fn to_list(Level, 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; fn constant_subterm(Constant) -> Self;
@@ -33,18 +34,22 @@ impl<'a> CompilationTarget<'a> for FactInstruction {
term.breadth_first_iter() 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 { fn to_constant(lvl: Level, constant: Constant, reg: RegType) -> Self {
FactInstruction::GetConstant(lvl, constant, reg) 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 { fn to_list(lvl: Level, reg: RegType) -> Self {
FactInstruction::GetList(lvl, reg) FactInstruction::GetList(lvl, reg)
} }
fn to_void(subterms: usize) -> Self {
FactInstruction::UnifyVoid(subterms)
}
fn constant_subterm(constant: Constant) -> Self { fn constant_subterm(constant: Constant) -> Self {
FactInstruction::UnifyConstant(constant) FactInstruction::UnifyConstant(constant)
} }
@@ -76,7 +81,7 @@ impl<'a> CompilationTarget<'a> for QueryInstruction {
fn iter(term: &'a Term) -> Self::Iterator { fn iter(term: &'a Term) -> Self::Iterator {
term.post_order_iter() term.post_order_iter()
} }
fn to_structure(lvl: Level, atom: Atom, arity: usize, reg: RegType) -> Self { fn to_structure(lvl: Level, atom: Atom, arity: usize, reg: RegType) -> Self {
QueryInstruction::PutStructure(lvl, atom, arity, reg) QueryInstruction::PutStructure(lvl, atom, arity, reg)
} }
@@ -89,6 +94,10 @@ impl<'a> CompilationTarget<'a> for QueryInstruction {
QueryInstruction::PutList(lvl, reg) QueryInstruction::PutList(lvl, reg)
} }
fn to_void(subterms: usize) -> Self {
QueryInstruction::SetVoid(subterms)
}
fn constant_subterm(constant: Constant) -> Self { fn constant_subterm(constant: Constant) -> Self {
QueryInstruction::SetConstant(constant) QueryInstruction::SetConstant(constant)
} }
@@ -145,7 +154,7 @@ impl<'a> TermMarker<'a> {
fn insert(&mut self, var: &'a Var, r: VarReg) { fn insert(&mut self, var: &'a Var, r: VarReg) {
self.bindings.insert(var, r); self.bindings.insert(var, r);
} }
fn mark_non_var(&mut self, lvl: Level, cell: &Cell<RegType>) { fn mark_non_var(&mut self, lvl: Level, cell: &Cell<RegType>) {
let reg_type = cell.get(); let reg_type = cell.get();
@@ -212,18 +221,18 @@ impl<'a> TermMarker<'a> {
reg reg
} }
}; };
self.insert(var, reg); self.insert(var, reg);
reg reg
} }
fn mark_anon_var(&mut self, lvl: Level) -> VarReg { fn mark_anon_var(&mut self, lvl: Level) -> VarReg {
let inner_reg = { let inner_reg = {
let temp = self.temp_c; let temp = self.temp_c;
self.temp_c += 1; self.temp_c += 1;
RegType::Temp(temp) RegType::Temp(temp)
}; };
match lvl { match lvl {
Level::Deep => VarReg::Norm(inner_reg), Level::Deep => VarReg::Norm(inner_reg),
Level::Shallow => { 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) { fn advance_at_head(&mut self, term: &'a Term) {
self.arg_c = 1; self.arg_c = 1;
self.temp_c = max(term.subterms(), self.temp_c) + 1; self.temp_c = max(term.subterms(), self.temp_c) + 1;
@@ -266,6 +279,46 @@ impl<'a> CodeGenerator<'a> {
&self.marker.bindings &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, fn to_structure<Target>(&mut self,
lvl: Level, lvl: Level,
cell: &'a Cell<RegType>, cell: &'a Cell<RegType>,
@@ -305,10 +358,10 @@ impl<'a> CodeGenerator<'a> {
self.marker.mark_non_var(Level::Deep, cell); self.marker.mark_non_var(Level::Deep, cell);
Target::constant_subterm(constant.clone()) Target::constant_subterm(constant.clone())
} }
fn anon_var_term<Target>(&mut self, lvl: Level) -> Target fn anon_var_term<Target>(&mut self, lvl: Level) -> Target
where Target: CompilationTarget<'a> where Target: CompilationTarget<'a>
{ {
let reg = self.marker.mark_anon_var(lvl); let reg = self.marker.mark_anon_var(lvl);
match reg { match reg {
@@ -318,7 +371,7 @@ impl<'a> CodeGenerator<'a> {
Target::subterm_to_variable(norm) Target::subterm_to_variable(norm)
} }
} }
fn var_term<Target>(&mut self, fn var_term<Target>(&mut self,
lvl: Level, lvl: Level,
cell: &'a Cell<VarReg>, 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> where Target: CompilationTarget<'a>
{ {
let iter = Target::iter(term); let iter = Target::iter(term);
let mut target = Vec::new(); let mut target = Vec::new();
let var_count = Self::count_vars(term);
for term in iter { for term in iter {
match term { match term {
TermRef::Clause(lvl, cell, atom, terms) => { TermRef::Clause(lvl, cell, atom, terms) => {
target.push(self.to_structure(lvl, cell, atom, terms.len())); 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 { for subterm in terms {
target.push(self.subterm_to_instr(subterm.as_ref())); target.push(self.subterm_to_instr(subterm.as_ref()));
} }
@@ -394,8 +456,13 @@ impl<'a> CodeGenerator<'a> {
}, },
TermRef::Constant(lvl @ Level::Shallow, cell, constant) => TermRef::Constant(lvl @ Level::Shallow, cell, constant) =>
target.push(self.to_constant(lvl, cell, constant)), target.push(self.to_constant(lvl, cell, constant)),
TermRef::AnonVar(lvl @ Level::Shallow) => TermRef::AnonVar(lvl @ Level::Shallow) => {
target.push(self.anon_var_term(lvl)), 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) => TermRef::Var(lvl @ Level::Shallow, ref cell, ref var) =>
target.push(self.var_term(lvl, cell, 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))); body.push(Line::Control(ControlInstruction::Allocate(perm_vars)));
self.marker.advance(p0); 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); 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); Self::add_conditional_call(&mut body, p1);
body = clauses.iter() 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| { .fold(body, |mut body, ref mut cqs| {
body.append(cqs); body.append(cqs);
body body
@@ -501,17 +568,26 @@ impl<'a> CodeGenerator<'a> {
pub fn compile_fact(&mut self, term: &'a Term) -> Code { pub fn compile_fact(&mut self, term: &'a Term) -> Code {
self.marker.advance(term); 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); let proceed = Line::Control(ControlInstruction::Proceed);
compiled_fact.push(proceed); compiled_fact.push(proceed);
compiled_fact 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 { pub fn compile_query(&mut self, term: &'a Term) -> Code {
self.marker.advance(term); 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); Self::add_conditional_call(&mut compiled_query, term);
compiled_query compiled_query

View File

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

View File

@@ -585,6 +585,21 @@ impl MachineState {
}; };
self.s += 1; 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; 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;
}
} }
} }