Implemented a different way to index clauses

This commit is contained in:
notoria
2020-12-19 14:52:38 +01:00
parent 22ffb1f53f
commit 657e4f12bb
6 changed files with 137 additions and 47 deletions

View File

@@ -857,21 +857,28 @@ impl<'a, TermMarker: Allocator<'a>> CodeGenerator<TermMarker> {
Ok(code) Ok(code)
} }
fn split_predicate(clauses: &Vec<PredicateClause>) -> Vec<(usize, usize)> { fn split_predicate(clauses: &Vec<PredicateClause>, optimal_index: Option<usize>) -> Vec<(usize, usize)> {
let mut subseqs = Vec::new(); let mut subseqs = Vec::new();
let mut left_index = 0; let mut left_index = 0;
for (right_index, clause) in clauses.iter().enumerate() { if let Some(optimal_i) = optimal_index {
match clause.first_arg() { for (right_index, clause) in clauses.iter().enumerate() {
Some(&Term::Var(_, _)) | Some(&Term::AnonVar) => { if clause.args().is_none() {
if left_index < right_index { continue;
subseqs.push((left_index, right_index)); }
} if let Some(arg) = clause.args().unwrap().iter().nth(optimal_i) {
match **arg {
subseqs.push((right_index, right_index + 1)); Term::Var(..) | Term::AnonVar => {
left_index = right_index + 1; if left_index < right_index {
subseqs.push((left_index, right_index));
}
subseqs.push((right_index, right_index + 1));
left_index = right_index + 1;
}
_ => (),
}
} }
_ => {}
} }
} }
@@ -901,6 +908,7 @@ impl<'a, TermMarker: Allocator<'a>> CodeGenerator<TermMarker> {
fn compile_pred_subseq<'b: 'a>( fn compile_pred_subseq<'b: 'a>(
&mut self, &mut self,
clauses: &'b [PredicateClause], clauses: &'b [PredicateClause],
optimal_index: Option<usize>,
) -> Result<Code, ParserError> { ) -> Result<Code, ParserError> {
let mut code_body = Vec::new(); let mut code_body = Vec::new();
let mut code_offsets = CodeOffsets::new(); let mut code_offsets = CodeOffsets::new();
@@ -910,9 +918,9 @@ impl<'a, TermMarker: Allocator<'a>> CodeGenerator<TermMarker> {
for (i, clause) in clauses.iter().enumerate() { for (i, clause) in clauses.iter().enumerate() {
self.marker.reset(); self.marker.reset();
let mut clause_code = match clause { let mut clause_code = match *clause {
&PredicateClause::Fact(ref fact, ..) => self.compile_fact(fact), PredicateClause::Fact(ref fact, ..) => self.compile_fact(fact),
&PredicateClause::Rule(ref rule, ..) => self.compile_rule(rule)?, PredicateClause::Rule(ref rule, ..) => self.compile_rule(rule)?,
}; };
if num_clauses > 1 { if num_clauses > 1 {
@@ -925,17 +933,28 @@ impl<'a, TermMarker: Allocator<'a>> CodeGenerator<TermMarker> {
code_body.push(Line::Choice(choice)); code_body.push(Line::Choice(choice));
} }
clause.first_arg().map(|arg| { if let Some(optimal_i) = optimal_index {
let index = code_body.len(); let arg = match clause.args() {
code_offsets.index_term(arg, index); Some(args) => match args.iter().nth(optimal_i) {
}); Some(term) => Some(term),
None => None,
},
None => None,
};
if let Some(arg) = arg {
let index = code_body.len();
code_offsets.index_term(arg, index);
}
}
code_body.append(&mut clause_code); code_body.append(&mut clause_code);
} }
let mut code = Vec::new(); let mut code = Vec::new();
code_offsets.add_indices(&mut code, code_body); if let Some(optimal_i) = optimal_index {
code_offsets.add_indices(&mut code, code_body, optimal_i + 1);
}
Ok(code) Ok(code)
} }
@@ -944,11 +963,48 @@ impl<'a, TermMarker: Allocator<'a>> CodeGenerator<TermMarker> {
clauses: &'b Vec<PredicateClause>, clauses: &'b Vec<PredicateClause>,
) -> Result<Code, ParserError> { ) -> Result<Code, ParserError> {
let mut code = Vec::new(); let mut code = Vec::new();
let split_pred = Self::split_predicate(&clauses); let mut optimal_index = None;
let has_args = match clauses.first() {
Some(clause) => match clause.args() {
Some(args) => !args.is_empty(),
None => false,
},
None => false,
};
if has_args {
for clause in clauses.iter() {
let args = clause.args().unwrap();
for (i, arg) in args.iter().enumerate() {
if let Some(optimal_index) = optimal_index {
if i >= optimal_index {
break;
}
}
match **arg {
Term::AnonVar | Term::Var(..) => (),
_ => {
match optimal_index {
Some(ref mut optimal_i) => *optimal_i = i,
None => optimal_index = Some(i),
}
break;
}
}
}
}
}
match optimal_index {
// No good index or no argument, default to 0.
// TODO: Why?
None => optimal_index = Some(0),
Some(_) => (),
}
let split_pred = Self::split_predicate(&clauses, optimal_index);
let multi_seq = split_pred.len() > 1; let multi_seq = split_pred.len() > 1;
for (l, r) in split_pred { for (l, r) in split_pred {
let mut code_segment = self.compile_pred_subseq(&clauses[l..r])?; let mut code_segment =
self.compile_pred_subseq(&clauses[l..r], optimal_index)?;
if multi_seq { if multi_seq {
let choice = match l { let choice = match l {

View File

@@ -339,6 +339,19 @@ impl PredicateClause {
} }
} }
// TODO: add this to `Term` in `prolog_parser` like `first_arg`.
pub fn args(&self) -> Option<&[Box<Term>]> {
match *self {
PredicateClause::Fact(ref term, ..) => {
match term {
Term::Clause(_, _, args, _) => Some(&args),
_ => None,
}
},
PredicateClause::Rule(ref rule, ..) => Some(&rule.head.1),
}
}
pub fn arity(&self) -> usize { pub fn arity(&self) -> usize {
match self { match self {
&PredicateClause::Fact(ref term, ..) => { &PredicateClause::Fact(ref term, ..) => {

View File

@@ -237,12 +237,17 @@ impl CodeOffsets {
fn switch_on_constant( fn switch_on_constant(
con_ind: IndexMap<Constant, ThirdLevelIndex>, con_ind: IndexMap<Constant, ThirdLevelIndex>,
prelude: &mut CodeDeque, prelude: &mut CodeDeque,
optimal_index: usize,
) -> IntIndex { ) -> IntIndex {
let con_ind = Self::second_level_index(con_ind, prelude); let con_ind = Self::second_level_index(con_ind, prelude);
if con_ind.len() > 1 { if con_ind.len() > 1 {
let index = Self::flatten_index(con_ind, prelude.len()); let index = Self::flatten_index(con_ind, prelude.len());
let instr = IndexingInstruction::SwitchOnConstant(index.len(), index); let instr = IndexingInstruction::SwitchOnConstant(
optimal_index,
index.len(),
index
);
prelude.push_front(Line::from(instr)); prelude.push_front(Line::from(instr));
@@ -259,12 +264,17 @@ impl CodeOffsets {
fn switch_on_structure( fn switch_on_structure(
str_ind: IndexMap<(ClauseName, usize), ThirdLevelIndex>, str_ind: IndexMap<(ClauseName, usize), ThirdLevelIndex>,
prelude: &mut CodeDeque, prelude: &mut CodeDeque,
optimal_index: usize,
) -> IntIndex { ) -> IntIndex {
let str_ind = Self::second_level_index(str_ind, prelude); let str_ind = Self::second_level_index(str_ind, prelude);
if str_ind.len() > 1 { if str_ind.len() > 1 {
let index = Self::flatten_index(str_ind, prelude.len()); let index = Self::flatten_index(str_ind, prelude.len());
let instr = IndexingInstruction::SwitchOnStructure(index.len(), index); let instr = IndexingInstruction::SwitchOnStructure(
optimal_index,
index.len(),
index
);
prelude.push_front(Line::from(instr)); prelude.push_front(Line::from(instr));
@@ -325,7 +335,7 @@ impl CodeOffsets {
} }
} }
pub fn add_indices(self, code: &mut Code, mut code_body: Code) { pub fn add_indices(self, code: &mut Code, mut code_body: Code, optimal_index: usize) {
if self.no_indices() { if self.no_indices() {
*code = code_body; *code = code_body;
return; return;
@@ -334,8 +344,10 @@ impl CodeOffsets {
let mut prelude = VecDeque::new(); let mut prelude = VecDeque::new();
let lst_loc = Self::switch_on_list(self.lists, &mut prelude); let lst_loc = Self::switch_on_list(self.lists, &mut prelude);
let str_loc = Self::switch_on_structure(self.structures, &mut prelude); let str_loc =
let con_loc = Self::switch_on_constant(self.constants, &mut prelude); Self::switch_on_structure(self.structures, &mut prelude, optimal_index);
let con_loc =
Self::switch_on_constant(self.constants, &mut prelude, optimal_index);
let prelude_length = prelude.len(); let prelude_length = prelude.len();
@@ -355,8 +367,13 @@ impl CodeOffsets {
let con_loc = Self::switch_on_con_offset_from(con_loc, prelude.len()); let con_loc = Self::switch_on_con_offset_from(con_loc, prelude.len());
let lst_loc = Self::switch_on_lst_offset_from(lst_loc, prelude.len()); let lst_loc = Self::switch_on_lst_offset_from(lst_loc, prelude.len());
let switch_instr = let switch_instr = IndexingInstruction::SwitchOnTerm(
IndexingInstruction::SwitchOnTerm(prelude.len() + 1, con_loc, lst_loc, str_loc); optimal_index,
prelude.len() + 1,
con_loc,
lst_loc,
str_loc
);
prelude.push_front(Line::from(switch_instr)); prelude.push_front(Line::from(switch_instr));

View File

@@ -143,6 +143,7 @@ impl IndexedChoiceInstruction {
} }
} }
/// A `Line` is an instruction (cf. page 98 of wambook).
#[derive(Debug)] #[derive(Debug)]
pub enum Line { pub enum Line {
Arithmetic(ArithmeticInstruction), Arithmetic(ArithmeticInstruction),
@@ -424,11 +425,13 @@ impl ControlInstruction {
} }
} }
/// `IndexingInstruction` cf. page 110 of wambook.
#[derive(Debug)] #[derive(Debug)]
pub enum IndexingInstruction { pub enum IndexingInstruction {
SwitchOnTerm(usize, usize, usize, usize), // The first index is the optimal argument being indexed.
SwitchOnConstant(usize, IndexMap<Constant, usize>), SwitchOnTerm(usize, usize, usize, usize, usize),
SwitchOnStructure(usize, IndexMap<(ClauseName, usize), usize>), SwitchOnConstant(usize, usize, IndexMap<Constant, usize>),
SwitchOnStructure(usize, usize, IndexMap<(ClauseName, usize), usize>),
} }
impl From<IndexingInstruction> for Line { impl From<IndexingInstruction> for Line {
@@ -440,25 +443,26 @@ impl From<IndexingInstruction> for Line {
impl IndexingInstruction { impl IndexingInstruction {
pub fn to_functor(&self) -> MachineStub { pub fn to_functor(&self) -> MachineStub {
match self { match self {
&IndexingInstruction::SwitchOnTerm(vars, constants, lists, structures) => { &IndexingInstruction::SwitchOnTerm(arg, vars, constants, lists, structures) => {
functor!( functor!(
"switch_on_term", "switch_on_term",
[integer(vars), [integer(arg),
integer(vars),
integer(constants), integer(constants),
integer(lists), integer(lists),
integer(structures)] integer(structures)]
) )
} }
&IndexingInstruction::SwitchOnConstant(constants, _) => { &IndexingInstruction::SwitchOnConstant(arg, constants, _) => {
functor!( functor!(
"switch_on_constant", "switch_on_constant",
[integer(constants)] [integer(arg), integer(constants)]
) )
} }
&IndexingInstruction::SwitchOnStructure(structures, _) => { &IndexingInstruction::SwitchOnStructure(arg, structures, _) => {
functor!( functor!(
"switch_on_structure", "switch_on_structure",
[integer(structures)] [integer(arg), integer(structures)]
) )
} }
} }

View File

@@ -1392,8 +1392,8 @@ impl MachineState {
pub(super) pub(super)
fn execute_indexing_instr(&mut self, instr: &IndexingInstruction) { fn execute_indexing_instr(&mut self, instr: &IndexingInstruction) {
match instr { match instr {
&IndexingInstruction::SwitchOnTerm(v, c, l, s) => { &IndexingInstruction::SwitchOnTerm(arg, v, c, l, s) => {
let addr = self[temp_v!(1)]; let addr = self[temp_v!(arg)];
let addr = self.store(self.deref(addr)); let addr = self.store(self.deref(addr));
let offset = match addr { let offset = match addr {
@@ -1423,8 +1423,8 @@ impl MachineState {
o => self.p += o, o => self.p += o,
}; };
} }
&IndexingInstruction::SwitchOnConstant(_, ref hm) => { &IndexingInstruction::SwitchOnConstant(arg, _, ref hm) => {
let addr = self[temp_v!(1)]; let addr = self[temp_v!(arg)];
let addr = self.store(self.deref(addr)); let addr = self.store(self.deref(addr));
let offset = let offset =
@@ -1445,8 +1445,8 @@ impl MachineState {
o => self.p += o, o => self.p += o,
}; };
} }
&IndexingInstruction::SwitchOnStructure(_, ref hm) => { &IndexingInstruction::SwitchOnStructure(arg, _, ref hm) => {
let a1 = self.registers[1]; let a1 = self.registers[arg];
let addr = self.store(self.deref(a1)); let addr = self.store(self.deref(a1));
let offset = match addr { let offset = match addr {

View File

@@ -276,13 +276,13 @@ impl fmt::Display for ChoiceInstruction {
impl fmt::Display for IndexingInstruction { impl fmt::Display for IndexingInstruction {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self { match self {
&IndexingInstruction::SwitchOnTerm(v, c, l, s) => { &IndexingInstruction::SwitchOnTerm(a, v, c, l, s) => {
write!(f, "switch_on_term {}, {}, {}, {}", v, c, l, s) write!(f, "switch_on_term {}, {}, {}, {}, {}", a, v, c, l, s)
} }
&IndexingInstruction::SwitchOnConstant(num_cs, _) => { &IndexingInstruction::SwitchOnConstant(_, num_cs, _) => {
write!(f, "switch_on_constant {}", num_cs) write!(f, "switch_on_constant {}", num_cs)
} }
&IndexingInstruction::SwitchOnStructure(num_ss, _) => { &IndexingInstruction::SwitchOnStructure(_, num_ss, _) => {
write!(f, "switch_on_structure {}", num_ss) write!(f, "switch_on_structure {}", num_ss)
} }
} }