]> Repositorios git - scryer-prolog.git/commitdiff
use branch numbers to detect branch subsumption
authorMark Thom <[email protected]>
Wed, 10 Dec 2025 07:14:24 +0000 (23:14 -0800)
committerMark Thom <[email protected]>
Thu, 15 Jan 2026 04:34:06 +0000 (20:34 -0800)
src/codegen.rs
src/debray_allocator.rs
src/forms.rs
src/iterators.rs
src/machine/disjuncts.rs
src/variable_records.rs

index 67ba2dbfd9145200ef1c189151bc92b1b773de6f..19d056d6edad1f071bcc5bef2bd61ca400f87c71 100644 (file)
@@ -994,20 +994,27 @@ impl CodeGenerator {
                     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);
index 7fe37259034e1114ceca393a91527a741298a666..d214b8c7f7cdc9cedda6cd0ca67154a8f9a5a2be 100644 (file)
@@ -1,6 +1,6 @@
 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::*;
@@ -24,24 +24,26 @@ pub struct BranchOccurrences {
     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
@@ -49,7 +51,7 @@ impl BranchOccurrences {
             .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);
     }
 }
@@ -76,19 +78,6 @@ impl DerefMut for BranchStack {
 }
 
 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,
@@ -97,7 +86,7 @@ impl BranchStack {
         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,
         }
@@ -109,27 +98,26 @@ impl BranchStack {
         }
     }
 
-    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]
@@ -235,12 +223,12 @@ impl DebrayAllocator {
                 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 {
@@ -531,11 +519,11 @@ impl DebrayAllocator {
                     ..
                 },
             ) => {
-                *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!()
@@ -557,8 +545,8 @@ impl DebrayAllocator {
             ) => {
                 // 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) {
@@ -605,7 +593,7 @@ impl DebrayAllocator {
                 {
                     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)
                 }
             }
@@ -640,7 +628,7 @@ impl DebrayAllocator {
                 {
                     Target::subterm_to_value(r)
                 } else {
-                    *deep_safety = VarSafetyStatus::unneeded(branch_designator);
+                    *deep_safety = VarSafetyStatus::unneeded(&branch_designator);
                     Target::unsafe_subterm_to_value(r)
                 }
             }
@@ -651,7 +639,7 @@ impl DebrayAllocator {
                 {
                     Target::subterm_to_value(r)
                 } else {
-                    *safety = VarSafetyStatus::unneeded(branch_designator);
+                    *safety = VarSafetyStatus::unneeded(&branch_designator);
                     Target::unsafe_subterm_to_value(r)
                 }
             }
index ae9b829de06c5bb9934921369c56042b71d550b2..447328f7651be1e99bee2d6c1518a1c0a9a1ad06 100644 (file)
@@ -18,9 +18,11 @@ use indexmap::{IndexMap, IndexSet};
 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;
 
@@ -128,10 +130,86 @@ impl ChunkType {
     }
 }
 
+#[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)]
@@ -165,21 +243,22 @@ impl ChunkedTermVec {
     }
 
     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]),
                 };
index e3a2ccbdb2f217055aac2d637c2e647b4daee259..0aa7bd3895a7005d5e14e6abe281d39abad24f78 100644 (file)
@@ -319,15 +319,28 @@ pub(crate) fn breadth_first_iter(
 #[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)]
@@ -338,8 +351,8 @@ pub(crate) struct ClauseIterator<'a> {
 
 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);
         }
     }
 
@@ -370,7 +383,9 @@ impl<'a> ClauseIterator<'a> {
 
         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;
                 }
                 _ => {
@@ -399,9 +414,9 @@ impl<'a> Iterator for ClauseIterator<'a> {
                     }
 
                     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 });
@@ -411,11 +426,15 @@ impl<'a> Iterator for ClauseIterator<'a> {
                 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 {
@@ -425,14 +444,21 @@ impl<'a> Iterator for ClauseIterator<'a> {
                     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(),
+                    });
                 }
             }
         }
index 4ecac7bca2415e06f42b5f3992f1f6b3b0442f8c..95f4ae5fb1dab5f99cbf2c45eb2fdfd136a30539 100644 (file)
@@ -6,79 +6,16 @@ use crate::machine::loader::*;
 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,
@@ -140,12 +77,13 @@ pub struct ClassifyInfo {
 }
 
 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 },
@@ -154,7 +92,6 @@ enum TraversalState {
     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
 }
@@ -199,7 +136,7 @@ impl VarData {
                 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]),
                     });
@@ -232,11 +169,16 @@ fn merge_branch_seq(branches: impl Iterator<Item = BranchInfo>) -> BranchInfo {
     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!();
     }
@@ -477,9 +419,6 @@ impl VariableClassifier {
                     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());
@@ -488,14 +427,9 @@ impl VariableClassifier {
                 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;
@@ -632,11 +566,10 @@ impl VariableClassifier {
                             ));
 
                             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));
                             }
@@ -655,23 +588,18 @@ impl VariableClassifier {
                             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 {
@@ -690,14 +618,21 @@ impl VariableClassifier {
                             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));
@@ -710,6 +645,7 @@ impl VariableClassifier {
                                 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;
index c918067e4e5c961452d633fd2ce1ff2ec5197e6a..e8a867df6a35e346eab17fe57b8e7c281ebf5020 100644 (file)
@@ -1,9 +1,11 @@
-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)]
@@ -13,20 +15,19 @@ pub struct TempVarData {
     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.
@@ -35,27 +36,27 @@ pub enum VarSafetyStatus {
 }
 
 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,