self.marker.in_tail_position = false;
self.marker.reset_contents();
}
- ClauseItem::FirstBranch(num_branches) => {
+ ClauseItem::FirstBranch {
+ branch_num,
+ num_branches,
+ } => {
branch_code_stack.add_new_branch_stack();
branch_code_stack.add_new_branch();
- self.marker.branch_stack.add_branch_stack(num_branches);
+ self.marker
+ .branch_stack
+ .add_branch_stack(branch_num.clone(), num_branches);
self.marker.add_branch();
}
- ClauseItem::NextBranch => {
+ ClauseItem::NextBranch { branch_num } => {
branch_code_stack.add_new_branch();
self.marker.add_branch();
- self.marker.branch_stack.incr_current_branch();
+ self.marker
+ .branch_stack
+ .incr_current_branch(branch_num.clone());
}
- ClauseItem::BranchEnd(depth) => {
+ ClauseItem::BranchEnd { depth } => {
if !clause_iter.in_tail_position() {
let subsumed_hits =
branch_code_stack.push_missing_vars(depth, &mut self.marker);
use crate::allocator::*;
use crate::codegen::SubsumedBranchHits;
-use crate::forms::{GenContext, Level};
+use crate::forms::{BranchNumber, GenContext, Level};
use crate::instructions::*;
use crate::machine::disjuncts::VarData;
use crate::parser::ast::*;
pub shallow_safety: BitSet<usize>, // unset means safe, set means unsafe (after the branch merge)
pub deep_safety: BitSet<usize>,
pub num_branches: usize,
- pub current_branch: usize,
+ pub current_branch_idx: usize,
+ pub current_branch_num: BranchNumber,
pub subsumed_hits: SubsumedBranchHits,
}
impl BranchOccurrences {
- fn new(num_branches: usize) -> Self {
+ fn new(current_branch_num: BranchNumber, num_branches: usize) -> Self {
Self {
hits: BranchHits::with_hasher(FxBuildHasher::default()),
shallow_safety: BitSet::default(),
deep_safety: BitSet::default(),
num_branches,
- current_branch: 0,
+ current_branch_idx: 0,
+ current_branch_num,
subsumed_hits: SubsumedBranchHits::with_hasher(FxBuildHasher::default()),
}
}
pub(crate) fn add_branch_occurrence(&mut self, var_num: usize) {
- debug_assert!(self.current_branch < self.num_branches);
+ debug_assert!(self.current_branch_idx < self.num_branches);
let num_branches = self.num_branches;
let entry = self
.entry(var_num)
.or_insert_with(|| BitVec::repeat(false, num_branches));
- entry.set(self.current_branch, true);
+ entry.set(self.current_branch_idx, true);
self.subsumed_hits.insert(var_num);
}
}
}
impl BranchStack {
- fn branch_subsumes(&self, branch: &BranchDesignator, sub_branch: &BranchDesignator) -> bool {
- if branch.branch_stack_num < sub_branch.branch_stack_num {
- if branch.branch_stack_num == 0 {
- true
- } else {
- let idx = branch.branch_stack_num - 1;
- self[idx].current_branch == branch.branch_num
- }
- } else {
- branch == sub_branch
- }
- }
-
fn safety_unneeded_in_branch(
&self,
safety: &VarSafetyStatus,
match safety {
VarSafetyStatus::Needed => false,
VarSafetyStatus::LocallyUnneeded(planter_branch) => {
- self.branch_subsumes(planter_branch, branch)
+ planter_branch.branch_num.has_as_subbranch(&branch.branch_num)
}
VarSafetyStatus::GloballyUnneeded => true,
}
}
}
- pub(crate) fn add_branch_stack(&mut self, num_branches: usize) {
- self.push(BranchOccurrences::new(num_branches));
+ pub(crate) fn add_branch_stack(&mut self, branch_num: BranchNumber, num_branches: usize) {
+ self.push(BranchOccurrences::new(branch_num, num_branches));
}
pub(crate) fn current_branch_designator(&self) -> BranchDesignator {
- let branch_stack_num = self.len();
let branch_num = self
.last()
- .map(|occurrences| occurrences.current_branch)
- .unwrap_or(0);
+ .map(|occurrences| occurrences.current_branch_num.clone())
+ .unwrap_or_else(|| BranchNumber::default());
BranchDesignator {
- branch_stack_num,
branch_num,
}
}
#[inline]
- pub(crate) fn incr_current_branch(&mut self) {
+ pub(crate) fn incr_current_branch(&mut self, branch_num: BranchNumber) {
let branch_occurrences = self.last_mut().unwrap();
- branch_occurrences.current_branch += 1;
+ branch_occurrences.current_branch_idx += 1;
+ branch_occurrences.current_branch_num = branch_num;
}
#[inline]
VarAlloc::Perm(_, allocation) => {
let shallow_safety = VarSafetyStatus::needed_if(
shallow_safety.contains(var_num),
- branch_designator,
+ &branch_designator,
);
let deep_safety = VarSafetyStatus::needed_if(
deep_safety.contains(var_num),
- branch_designator,
+ &branch_designator,
);
if running_count < num_occurrences {
..
},
) => {
- *deep_safety = VarSafetyStatus::unneeded(branch_designator);
- *shallow_safety = VarSafetyStatus::unneeded(branch_designator);
+ *deep_safety = VarSafetyStatus::unneeded(&branch_designator);
+ *shallow_safety = VarSafetyStatus::unneeded(&branch_designator);
}
VarAlloc::Temp { safety, .. } => {
- *safety = VarSafetyStatus::unneeded(branch_designator);
+ *safety = VarSafetyStatus::unneeded(&branch_designator);
}
_ => {
unreachable!()
) => {
// GetVariable in head chunk is considered safe.
if lvl == Level::Deep {
- *deep_safety = VarSafetyStatus::unneeded(branch_designator);
- *shallow_safety = VarSafetyStatus::unneeded(branch_designator);
+ *deep_safety = VarSafetyStatus::unneeded(&branch_designator);
+ *shallow_safety = VarSafetyStatus::unneeded(&branch_designator);
} else if term_loc == GenContext::Head {
*shallow_safety = VarSafetyStatus::GloballyUnneeded;
} else if let Some(&temp_var_num) = self.shallow_temp_mappings.get(&self.arg_c) {
{
Target::argument_to_value(r, arg_c)
} else {
- *shallow_safety = VarSafetyStatus::unneeded(branch_designator);
+ *shallow_safety = VarSafetyStatus::unneeded(&branch_designator);
Target::unsafe_argument_to_value(r, arg_c)
}
}
{
Target::subterm_to_value(r)
} else {
- *deep_safety = VarSafetyStatus::unneeded(branch_designator);
+ *deep_safety = VarSafetyStatus::unneeded(&branch_designator);
Target::unsafe_subterm_to_value(r)
}
}
{
Target::subterm_to_value(r)
} else {
- *safety = VarSafetyStatus::unneeded(branch_designator);
+ *safety = VarSafetyStatus::unneeded(&branch_designator);
Target::unsafe_subterm_to_value(r)
}
}
use ordered_float::OrderedFloat;
use std::cell::Cell;
+use std::cmp::Ordering;
use std::collections::VecDeque;
use std::convert::TryFrom;
use std::fmt;
+use std::hash::{Hash, Hasher};
use std::ops::{AddAssign, Deref, DerefMut};
use std::path::PathBuf;
}
}
+#[derive(Debug, Clone)] //, PartialOrd, PartialEq, Eq, Hash)]
+pub(crate) struct BranchNumber {
+ pub(crate) branch_num: Rational,
+ pub(crate) delta: Rational,
+}
+
+impl Default for BranchNumber {
+ fn default() -> Self {
+ Self {
+ branch_num: Rational::from(0),
+ delta: Rational::from(1u64 << 31),
+ }
+ }
+}
+
+impl PartialEq<BranchNumber> for BranchNumber {
+ #[inline]
+ fn eq(&self, rhs: &BranchNumber) -> bool {
+ self.branch_num == rhs.branch_num
+ }
+}
+
+impl Eq for BranchNumber {}
+
+impl Hash for BranchNumber {
+ #[inline(always)]
+ fn hash<H: Hasher>(&self, hasher: &mut H) {
+ self.branch_num.hash(hasher)
+ }
+}
+
+impl PartialOrd<BranchNumber> for BranchNumber {
+ #[inline]
+ fn partial_cmp(&self, rhs: &BranchNumber) -> Option<Ordering> {
+ self.branch_num.partial_cmp(&rhs.branch_num)
+ }
+}
+
+impl BranchNumber {
+ pub(crate) fn has_as_subbranch(&self, other: &Self) -> bool {
+ let delta_ratio = &self.delta / &other.delta;
+
+ if !delta_ratio.denominator().is_one() {
+ return false;
+ }
+
+ other.branch_num >= self.branch_num && other.branch_num < &self.branch_num + &self.delta
+ }
+
+ pub(crate) fn split(&self) -> BranchNumber {
+ BranchNumber {
+ branch_num: self.branch_num.clone() + &self.delta / Rational::from(2),
+ delta: &self.delta / Rational::from(4),
+ }
+ }
+
+ pub(crate) fn incr_by_delta(&self) -> BranchNumber {
+ BranchNumber {
+ branch_num: self.branch_num.clone() + &self.delta,
+ delta: self.delta.clone(),
+ }
+ }
+
+ pub(crate) fn halve_delta(&self) -> BranchNumber {
+ BranchNumber {
+ branch_num: self.branch_num.clone(),
+ delta: &self.delta / Rational::from(2),
+ }
+ }
+}
+
#[derive(Debug)]
pub enum ChunkedTerms {
- Branch(Vec<VecDeque<ChunkedTerms>>),
- Chunk { terms: VecDeque<QueryTerm> },
+ Branch {
+ branch_nums: Vec<BranchNumber>,
+ arms: Vec<VecDeque<ChunkedTerms>>,
+ },
+ Chunk {
+ terms: VecDeque<QueryTerm>,
+ },
}
#[derive(Debug)]
}
pub fn reserve_branch(&mut self, capacity: usize) {
- self.chunk_vec
- .push_back(ChunkedTerms::Branch(Vec::with_capacity(capacity)));
+ self.chunk_vec.push_back(ChunkedTerms::Branch {
+ branch_nums: Vec::with_capacity(capacity),
+ arms: Vec::with_capacity(capacity),
+ });
}
#[inline]
pub fn add_chunk(&mut self) {
- let chunk = ChunkedTerms::Chunk {
+ self.chunk_vec.push_back(ChunkedTerms::Chunk {
terms: VecDeque::from(vec![]),
- };
- self.chunk_vec.push_back(chunk);
+ });
}
pub fn push_chunk_term(&mut self, term: QueryTerm) {
match self.chunk_vec.back_mut() {
- Some(ChunkedTerms::Branch(_)) => {
+ Some(ChunkedTerms::Branch { .. }) => {
let chunk = ChunkedTerms::Chunk {
terms: VecDeque::from(vec![term]),
};
#[derive(Debug, Copy, Clone)]
enum ClauseIteratorState<'a> {
RemainingChunks(&'a VecDeque<ChunkedTerms>, usize),
- RemainingBranches(&'a Vec<VecDeque<ChunkedTerms>>, usize),
+ RemainingBranches(
+ &'a Vec<BranchNumber>,
+ &'a Vec<VecDeque<ChunkedTerms>>,
+ usize,
+ ),
}
#[derive(Debug, Clone)]
pub(crate) enum ClauseItem<'a> {
- FirstBranch(usize),
- NextBranch,
- BranchEnd(usize),
- Chunk { terms: &'a VecDeque<QueryTerm> },
+ FirstBranch {
+ branch_num: &'a BranchNumber,
+ num_branches: usize,
+ },
+ NextBranch {
+ branch_num: &'a BranchNumber,
+ },
+ BranchEnd {
+ depth: usize,
+ },
+ Chunk {
+ terms: &'a VecDeque<QueryTerm>,
+ },
}
#[derive(Debug)]
fn state_from_chunked_terms(chunk_vec: &VecDeque<ChunkedTerms>) -> ClauseIteratorState<'_> {
if chunk_vec.len() == 1 {
- if let Some(ChunkedTerms::Branch(ref branches)) = chunk_vec.front() {
- return ClauseIteratorState::RemainingBranches(branches, 0);
+ if let Some(ChunkedTerms::Branch { branch_nums, arms }) = chunk_vec.front() {
+ return ClauseIteratorState::RemainingBranches(branch_nums, arms, 0);
}
}
while let Some(state) = self.state_stack.pop() {
match state {
- ClauseIteratorState::RemainingBranches(terms, focus) if terms.len() == focus => {
+ ClauseIteratorState::RemainingBranches(_branch_nums, terms, focus)
+ if terms.len() == focus =>
+ {
depth += 1;
}
_ => {
}
match &chunks[focus] {
- ChunkedTerms::Branch(branches) => {
+ ChunkedTerms::Branch { branch_nums, arms } => {
self.state_stack
- .push(ClauseIteratorState::RemainingBranches(branches, 0));
+ .push(ClauseIteratorState::RemainingBranches(branch_nums, arms, 0));
}
ChunkedTerms::Chunk { ref terms } => {
return Some(ClauseItem::Chunk { terms });
ClauseIteratorState::RemainingChunks(chunks, focus) => {
debug_assert_eq!(chunks.len(), focus);
}
- ClauseIteratorState::RemainingBranches(branches, focus)
+ ClauseIteratorState::RemainingBranches(branch_nums, branches, focus)
if focus < branches.len() =>
{
self.state_stack
- .push(ClauseIteratorState::RemainingBranches(branches, focus + 1));
+ .push(ClauseIteratorState::RemainingBranches(
+ branch_nums,
+ branches,
+ focus + 1,
+ ));
let state = state_from_chunked_terms(&branches[focus]);
if let ClauseIteratorState::RemainingChunks(..) = &state {
self.state_stack.push(state);
return if focus == 0 {
- Some(ClauseItem::FirstBranch(branches.len()))
+ Some(ClauseItem::FirstBranch {
+ branch_num: &branch_nums[0],
+ num_branches: branches.len(),
+ })
} else {
- Some(ClauseItem::NextBranch)
+ Some(ClauseItem::NextBranch {
+ branch_num: &branch_nums[focus],
+ })
};
}
- ClauseIteratorState::RemainingBranches(branches, focus) => {
+ ClauseIteratorState::RemainingBranches(_branch_nums, branches, focus) => {
debug_assert_eq!(branches.len(), focus);
- return Some(ClauseItem::BranchEnd(self.branch_end_depth()));
+ return Some(ClauseItem::BranchEnd {
+ depth: self.branch_end_depth(),
+ });
}
}
}
use crate::machine::machine_errors::CompilationError;
use crate::machine::preprocessor::*;
use crate::parser::ast::*;
-use crate::parser::dashu::Rational;
use crate::variable_records::*;
use dashu::Integer;
use indexmap::{IndexMap, IndexSet};
use std::cell::Cell;
-use std::cmp::Ordering;
use std::collections::VecDeque;
-use std::hash::{Hash, Hasher};
+use std::hash::Hash;
use std::ops::{Deref, DerefMut};
-#[derive(Debug, Clone)] //, PartialOrd, PartialEq, Eq, Hash)]
-pub struct BranchNumber {
- branch_num: Rational,
- delta: Rational,
-}
-
-impl Default for BranchNumber {
- fn default() -> Self {
- Self {
- branch_num: Rational::from(1u64 << 63),
- delta: Rational::from(1),
- }
- }
-}
-
-impl PartialEq<BranchNumber> for BranchNumber {
- #[inline]
- fn eq(&self, rhs: &BranchNumber) -> bool {
- self.branch_num == rhs.branch_num
- }
-}
-
-impl Eq for BranchNumber {}
-
-impl Hash for BranchNumber {
- #[inline(always)]
- fn hash<H: Hasher>(&self, hasher: &mut H) {
- self.branch_num.hash(hasher)
- }
-}
-
-impl PartialOrd<BranchNumber> for BranchNumber {
- #[inline]
- fn partial_cmp(&self, rhs: &BranchNumber) -> Option<Ordering> {
- self.branch_num.partial_cmp(&rhs.branch_num)
- }
-}
-
-impl BranchNumber {
- fn split(&self) -> BranchNumber {
- BranchNumber {
- branch_num: self.branch_num.clone() + &self.delta / Rational::from(2),
- delta: &self.delta / Rational::from(4),
- }
- }
-
- fn incr_by_delta(&self) -> BranchNumber {
- BranchNumber {
- branch_num: self.branch_num.clone() + &self.delta,
- delta: self.delta.clone(),
- }
- }
-
- fn halve_delta(&self) -> BranchNumber {
- BranchNumber {
- branch_num: self.branch_num.clone(),
- delta: &self.delta / Rational::from(2),
- }
- }
-}
-
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct VarInfo {
var_ptr: VarPtr,
}
enum TraversalState {
- // construct a QueryTerm::Branch with number of disjuncts, reset
- // the chunk type to that of the chunk preceding the disjunct and the chunk_num.
+ // pop the latest branch number from the root set and use it to construct a QueryTerm::Branch
+ // with number of disjuncts, reset the chunk type to that of the chunk preceding the disjunct
+ // and the chunk_num.
BuildDisjunct(usize),
+ BuildFinalDisjunct(usize),
// add the last disjunct to a QueryTerm::Branch, continuing from
// where it leaves off.
- BuildFinalDisjunct(usize),
Fail,
GetCutPoint { var_num: usize, prev_b: bool },
Cut { var_num: usize, is_global: bool },
Term(Term),
OverrideGlobalCutVar(usize),
ResetGlobalCutVarOverride(Option<usize>),
- RemoveBranchNum, // pop the current_branch_num and from the root set.
AddBranchNum(BranchNumber), // set current_branch_num, add it to the root set
RepBranchNum(BranchNumber), // replace current_branch_num and the latest in the root set
}
VarAlloc::Perm(0, PermVarAllocation::Pending);
match build_stack.front_mut() {
- Some(ChunkedTerms::Branch(_)) => {
+ Some(ChunkedTerms::Branch { .. }) => {
build_stack.push_front(ChunkedTerms::Chunk {
terms: VecDeque::from(vec![term]),
});
branch_info
}
-fn flatten_into_disjunct(build_stack: &mut ChunkedTermVec, preceding_len: usize) {
+fn flatten_into_disjunct(
+ build_stack: &mut ChunkedTermVec,
+ branch_num: BranchNumber,
+ preceding_len: usize,
+) {
let branch_vec = build_stack.drain(preceding_len + 1..).collect();
- if let ChunkedTerms::Branch(ref mut disjuncts) = &mut build_stack[preceding_len] {
- disjuncts.push(branch_vec);
+ if let ChunkedTerms::Branch { branch_nums, arms } = &mut build_stack[preceding_len] {
+ branch_nums.push(branch_num);
+ arms.push(branch_vec);
} else {
unreachable!();
}
self.root_set.insert(branch_num.clone());
self.current_branch_num = branch_num;
}
- TraversalState::RemoveBranchNum => {
- self.root_set.pop();
- }
TraversalState::RepBranchNum(branch_num) => {
self.root_set.pop();
self.root_set.insert(branch_num.clone());
TraversalState::ResetCallPolicy(call_policy) => {
self.call_policy = call_policy;
}
- TraversalState::BuildDisjunct(preceding_len) => {
- flatten_into_disjunct(&mut build_stack, preceding_len);
-
- self.current_chunk_type = ChunkType::Mid;
- self.current_chunk_num += 1;
- }
- TraversalState::BuildFinalDisjunct(preceding_len) => {
- flatten_into_disjunct(&mut build_stack, preceding_len);
+ TraversalState::BuildDisjunct(preceding_len) | TraversalState::BuildFinalDisjunct(preceding_len) => {
+ let branch_num = self.root_set.pop().unwrap();
+ flatten_into_disjunct(&mut build_stack, branch_num, preceding_len);
self.current_chunk_type = ChunkType::Mid;
self.current_chunk_num += 1;
));
let iter = branches.into_iter().zip(branch_numbers.into_iter());
- let final_disjunct_loc = state_stack.len();
+ let final_disjunct_loc = state_stack.len();
for (term, branch_num) in iter.rev() {
state_stack.push(TraversalState::BuildDisjunct(build_stack_len));
- state_stack.push(TraversalState::RemoveBranchNum);
state_stack.push(TraversalState::Term(term));
state_stack.push(TraversalState::AddBranchNum(branch_num));
}
let then_term = terms.pop().unwrap();
let if_term = terms.pop().unwrap();
- let prev_b = if matches!(
- state_stack.last(),
- Some(TraversalState::RemoveBranchNum)
- ) {
- // check if the second-to-last element
- // is a regular BuildDisjunct, as we
- // don't want to add GetPrevLevel in
- // case of a TrustMe.
- match state_stack.iter().rev().nth(1) {
- Some(&TraversalState::BuildDisjunct(preceding_len)) => {
- preceding_len + 1 == build_stack.len()
- }
- _ => false,
- }
- } else {
- false
- };
+ let prev_b =
+ if let Some(&TraversalState::BuildDisjunct(preceding_len)) =
+ state_stack.last()
+ {
+ // check if the second-to-last element
+ // is a regular BuildDisjunct, as we
+ // don't want to add GetPrevLevel in
+ // case of a TrustMe.
+ preceding_len + 1 == build_stack.len()
+ } else {
+ false
+ };
state_stack.push(TraversalState::Term(then_term));
state_stack.push(TraversalState::Cut {
let not_term = terms.pop().unwrap();
let build_stack_len = build_stack.len();
+ let first_branch_num = self.current_branch_num.split();
+ let second_branch_num = first_branch_num.incr_by_delta();
+
build_stack.reserve_branch(2);
+ state_stack.push(TraversalState::RepBranchNum(
+ self.current_branch_num.halve_delta(),
+ ));
state_stack.push(TraversalState::BuildFinalDisjunct(build_stack_len));
state_stack.push(TraversalState::Term(Term::Clause(
Cell::default(),
atom!("$succeed"),
vec![],
)));
+ state_stack.push(TraversalState::AddBranchNum(second_branch_num));
state_stack.push(TraversalState::BuildDisjunct(build_stack_len));
state_stack.push(TraversalState::Fail);
state_stack.push(TraversalState::CutPrev(self.var_num));
var_num: self.var_num,
prev_b: false,
});
+ state_stack.push(TraversalState::AddBranchNum(first_branch_num));
self.current_chunk_type = ChunkType::Mid;
self.current_chunk_num += 1;
-use crate::forms::GenContext;
+use crate::forms::{BranchNumber, GenContext};
use crate::parser::ast::*;
use bit_set::*;
use fxhash::FxBuildHasher;
use indexmap::{IndexMap, IndexSet};
+use num_order::NumOrd;
+
use std::ops::{Deref, DerefMut};
#[derive(Debug, Clone)]
pub(crate) conflict_set: BitSet<usize>,
}
-#[derive(Debug, Clone, Copy, PartialEq, Eq)]
+#[derive(Debug, Clone, PartialEq, Eq)]
pub struct BranchDesignator {
- pub branch_stack_num: usize,
- pub branch_num: usize,
+ pub branch_num: BranchNumber,
}
impl BranchDesignator {
#[inline]
pub fn is_sub_branch(&self) -> bool {
- self.branch_stack_num > 0
+ self.branch_num.branch_num.num_gt(&0)
}
}
-#[derive(Debug, Clone, Copy)]
+#[derive(Debug, Clone)]
pub enum VarSafetyStatus {
Needed,
// which branch planted the last unsafe guarded instruction? It may still be needed.
}
impl VarSafetyStatus {
- pub(crate) fn unneeded(current_branch: BranchDesignator) -> Self {
+ pub(crate) fn unneeded(current_branch: &BranchDesignator) -> Self {
if current_branch.is_sub_branch() {
- VarSafetyStatus::LocallyUnneeded(current_branch)
+ VarSafetyStatus::LocallyUnneeded(current_branch.clone())
} else {
VarSafetyStatus::GloballyUnneeded
}
}
#[inline]
- pub(crate) fn needed_if(needed: bool, branch_designator: BranchDesignator) -> Self {
+ pub(crate) fn needed_if(needed: bool, branch_designator: &BranchDesignator) -> Self {
if needed {
VarSafetyStatus::Needed
- } else if branch_designator.branch_stack_num == 0 {
+ } else if branch_designator.branch_num.branch_num.num_eq(&0) {
VarSafetyStatus::GloballyUnneeded
} else {
- VarSafetyStatus::LocallyUnneeded(branch_designator)
+ VarSafetyStatus::LocallyUnneeded(branch_designator.clone())
}
}
}
-#[derive(Debug, Clone, Copy)]
+#[derive(Debug, Clone)]
pub enum PermVarAllocation {
Done {
shallow_safety: VarSafetyStatus,