From: Mark Thom Date: Sat, 29 Apr 2017 22:52:08 +0000 (-0600) Subject: add fixtures X-Git-Tag: v0.8.110~741 X-Git-Url: https://git.sagredo.dev/?a=commitdiff_plain;h=1bdc539c25feec81c221718551d515a14f7bf0d1;p=scryer-prolog.git add fixtures --- diff --git a/src/prolog/fixtures.rs b/src/prolog/fixtures.rs new file mode 100644 index 00000000..e5637683 --- /dev/null +++ b/src/prolog/fixtures.rs @@ -0,0 +1,279 @@ +use prolog::ast::*; + +use std::cell::Cell; +use std::collections::{BTreeMap, BTreeSet, HashMap}; +use std::collections::btree_map::{IntoIter, IterMut, Values}; +use std::mem::swap; +use std::vec::Vec; + +pub type OccurrenceSet = BTreeSet<(GenContext, usize)>; + +pub struct TempVarData { + last_term_arity: usize, + use_set: OccurrenceSet, + no_use_set: BTreeSet, + conflict_set: BTreeSet +} + +// labeled with chunk_num and temp offset (unassigned if 0). +pub enum VarData { + Perm(usize), Temp(usize, usize, TempVarData) +} + +// labeled with chunk numbers. +pub enum VarStatus { + Perm(usize), Temp(usize, TempVarData) // Perm(chunk_num) | Temp(chunk_num, _) +} + +impl VarData { + pub fn as_reg_type(&self) -> RegType { + match self { + &VarData::Temp(_, r, _) => RegType::Temp(r), + &VarData::Perm(r) => RegType::Perm(r) + } + } +} + +impl TempVarData { + fn new(last_term_arity: usize) -> Self { + TempVarData { + last_term_arity: last_term_arity, + use_set: BTreeSet::new(), + no_use_set: BTreeSet::new(), + conflict_set: BTreeSet::new() + } + } + + fn uses_reg(&self, reg: usize) -> bool { + for &(_, nreg) in self.use_set.iter() { + if reg == nreg { + return true; + } + } + + return false; + } + + fn populate_conflict_set(&mut self) { + if self.last_term_arity > 0 { + let arity = self.last_term_arity; + let mut conflict_set : BTreeSet = (1..arity).collect(); + + for &(_, reg) in self.use_set.iter() { + conflict_set.remove(®); + } + + self.conflict_set = conflict_set; + } + } +} + +type VariableFixture<'a> = (VarStatus, Vec<&'a Cell>); +pub struct VariableFixtures<'a>(BTreeMap<&'a Var, VariableFixture<'a>>); + +impl<'a> VariableFixtures<'a> +{ + pub fn new() -> Self { + VariableFixtures(BTreeMap::new()) + } + + pub fn insert(&mut self, var: &'a Var, vs: VariableFixture<'a>) { + self.0.insert(var, vs); + } + + // computes no_use and conflict sets for all temp vars. + pub fn populate_restricting_sets(&mut self) + { + // three stages: + // 1. move the use sets of each variable to a local HashMap, use_set + // (iterate mutably, swap mutable refs). + // 2. drain use_set. For each use set of U, add into the + // no-use sets of appropriate variables T /= U. + // 3. Move the use sets back to their original locations in the fixture. + // Compute the conflict set of u. + + // 1. + let mut use_sets : HashMap<&'a Var, OccurrenceSet> = HashMap::new(); + + for (ref var, &mut (ref mut var_status, _)) in self.iter_mut() { + if let &mut VarStatus::Temp(_, ref mut var_data) = var_status { + let mut use_set = OccurrenceSet::new(); + + swap(&mut var_data.use_set, &mut use_set); + use_sets.insert(var, use_set); + } + } + + for (u, use_set) in use_sets.drain() { + // 2. + for &(term_loc, reg) in use_set.iter() { + if let GenContext::Last(cn_u) = term_loc { + for (ref t, &mut (ref mut var_status, _)) in self.iter_mut() { + if let &mut VarStatus::Temp(cn_t, ref mut t_data) = var_status { + if cn_u == cn_t && *u != ***t { + if !t_data.uses_reg(reg) { + t_data.no_use_set.insert(reg); + } + } + } + } + } + } + + // 3. + match self.get_mut(u) { + Some(&mut (VarStatus::Temp(_, ref mut u_data), _)) => { + u_data.use_set = use_set; + u_data.populate_conflict_set(); + }, + _ => {} + }; + } + } + + fn get_mut(&mut self, u: &'a Var) -> Option<&mut VariableFixture<'a>> { + self.0.get_mut(u) + } + + fn iter_mut(&mut self) -> IterMut<&'a Var, VariableFixture<'a>> { + self.0.iter_mut() + } + + fn record_temp_info(&mut self, + tvd: &mut TempVarData, + arg_c: usize, + term_loc: GenContext) + { + match term_loc { + GenContext::Head | GenContext::Last(_) => { + tvd.use_set.insert((term_loc, arg_c)); + }, + _ => {} + }; + } + + pub fn vars_above_threshold(&self, index: usize) -> usize + { + let mut var_count = 0; + + for &(ref var_status, _) in self.values() { + if let &VarStatus::Perm(i) = var_status { + if i > index { + var_count += 1; + } + } + } + + var_count + } + + pub fn mark_vars_in_chunk(&mut self, + term: &'a Term, + last_term_arity: usize, + chunk_num: usize, + term_loc: GenContext) + { + let mut arg_c = 1; + + for term_ref in term.breadth_first_iter() { + if let TermRef::Var(lvl, cell, var) = term_ref { + let mut status = self.0.remove(var) + .unwrap_or((VarStatus::Temp(chunk_num, TempVarData::new(last_term_arity)), + Vec::new())); + + status.1.push(cell); + + match status.0 { + VarStatus::Temp(cn, ref mut tvd) if cn == chunk_num => { + if let Level::Shallow = lvl { + self.record_temp_info(tvd, arg_c, term_loc); + } + }, + _ => status.0 = VarStatus::Perm(chunk_num) + }; + + self.0.insert(var, status); + } + + if let Level::Shallow = term_ref.level() { + arg_c += 1; + } + } + } + + pub fn into_iter(self) -> IntoIter<&'a Var, VariableFixture<'a>> { + self.0.into_iter() + } + + fn values(&self) -> Values<&'a Var, VariableFixture<'a>> { + self.0.values() + } + + pub fn set_perm_vals(&self, has_deep_cuts: bool) + { + let mut values_vec : Vec<_> = self.values() + .filter_map(|ref v| { + match &v.0 { + &VarStatus::Perm(i) => Some((i, &v.1)), + _ => None + } + }) + .collect(); + + values_vec.sort_by_key(|ref v| v.0); + + let offset = has_deep_cuts as usize; + + for (i, (_, cells)) in values_vec.into_iter().rev().enumerate() { + for cell in cells { + cell.set(VarReg::Norm(RegType::Perm(i + 1 + offset))); + } + } + } + + pub fn mark_unsafe_query_vars(&self, head: &Term, query: &mut CompiledQuery) + { + let mut unsafe_vars = HashMap::new(); + + for &(_, ref cb) in self.values() { + if !cb.is_empty() { + let index = cb.first().unwrap().get().norm(); + unsafe_vars.insert(index, false); + } + } + + for term_ref in head.breadth_first_iter() { + match term_ref { + TermRef::Var(_, cell, _) => { + unsafe_vars.remove(&cell.get().norm()); + }, + _ => {} + }; + } + + for query_instr in query.iter_mut() { + match query_instr { + &mut QueryInstruction::PutValue(RegType::Perm(i), arg) => + if let Some(found) = unsafe_vars.get_mut(&RegType::Perm(i)) { + if !*found { + *found = true; + *query_instr = QueryInstruction::PutUnsafeValue(i, arg); + } + }, + &mut QueryInstruction::SetVariable(reg) + | &mut QueryInstruction::PutVariable(reg, _) => + if let Some(found) = unsafe_vars.get_mut(®) { + *found = true; + }, + &mut QueryInstruction::SetValue(reg) => + if let Some(found) = unsafe_vars.get_mut(®) { + if !*found { + *found = true; + *query_instr = QueryInstruction::SetLocalValue(reg); + } + }, + _ => {} + }; + } + } +}