Skip to main content

oxiz_sat/
target_phase.rs

1//! Target-Based Phase Selection
2//!
3//! This module implements target-based phase selection, an enhancement over
4//! simple phase saving. The idea is to maintain both saved phases and target
5//! phases, using heuristics to decide which to use.
6//!
7//! Target phases are set based on:
8//! - Recently satisfied literals in conflicts
9//! - Literals that appear frequently in learned clauses
10//! - Literals that lead to successful propagations
11//!
12//! Reference: "Target-Oriented Phase Selection" and CryptoMiniSat
13
14use crate::literal::{Lit, Var};
15#[allow(unused_imports)]
16use crate::prelude::*;
17
18/// Phase selection mode
19#[derive(Debug, Clone, Copy, PartialEq, Eq)]
20pub enum PhaseMode {
21    /// Use saved phase (last assigned value)
22    Saved,
23    /// Use target phase (heuristically determined)
24    Target,
25    /// Random phase
26    Random,
27}
28
29/// Statistics for target phase selection
30#[derive(Debug, Default, Clone)]
31pub struct TargetPhaseStats {
32    /// Number of times target phase was used
33    pub target_used: u64,
34    /// Number of times saved phase was used
35    pub saved_used: u64,
36    /// Number of times random phase was used
37    pub random_used: u64,
38    /// Number of target phase updates
39    pub target_updates: u64,
40}
41
42/// Target-based phase selection manager
43pub struct TargetPhaseSelector {
44    /// Saved phases (last assigned value)
45    saved_phase: Vec<bool>,
46    /// Target phases (heuristically determined)
47    target_phase: Vec<bool>,
48    /// Whether to use target phase for each variable
49    use_target: Vec<bool>,
50    /// Decay factor for target phase confidence
51    decay: f64,
52    /// Confidence scores for target phases (higher = more confident)
53    confidence: Vec<f64>,
54    /// Statistics
55    stats: TargetPhaseStats,
56}
57
58impl TargetPhaseSelector {
59    /// Create a new target phase selector
60    pub fn new(num_vars: usize, decay: f64) -> Self {
61        Self {
62            saved_phase: vec![false; num_vars],
63            target_phase: vec![false; num_vars],
64            use_target: vec![false; num_vars],
65            decay,
66            confidence: vec![0.0; num_vars],
67            stats: TargetPhaseStats::default(),
68        }
69    }
70
71    /// Resize for a new number of variables
72    pub fn resize(&mut self, num_vars: usize) {
73        self.saved_phase.resize(num_vars, false);
74        self.target_phase.resize(num_vars, false);
75        self.use_target.resize(num_vars, false);
76        self.confidence.resize(num_vars, 0.0);
77    }
78
79    /// Get statistics
80    #[must_use]
81    pub fn stats(&self) -> &TargetPhaseStats {
82        &self.stats
83    }
84
85    /// Save phase for a variable
86    pub fn save_phase(&mut self, var: Var, phase: bool) {
87        self.saved_phase[var.index()] = phase;
88    }
89
90    /// Set target phase for a variable with confidence boost
91    pub fn set_target(&mut self, var: Var, phase: bool, confidence_boost: f64) {
92        let idx = var.index();
93        self.target_phase[idx] = phase;
94        self.confidence[idx] += confidence_boost;
95
96        // Enable target phase if confidence is high enough
97        if self.confidence[idx] > 1.0 {
98            self.use_target[idx] = true;
99            self.stats.target_updates += 1;
100        }
101    }
102
103    /// Update target phase based on a satisfied literal in conflict analysis
104    pub fn on_conflict_literal(&mut self, lit: Lit) {
105        // When a literal appears in conflict analysis and is satisfied,
106        // we want to encourage that polarity
107        self.set_target(lit.var(), lit.sign(), 0.5);
108    }
109
110    /// Update target phase based on a learned clause
111    pub fn on_learned_clause(&mut self, clause: &[Lit]) {
112        // Literals in short learned clauses are good candidates for target phases
113        if clause.len() <= 5 {
114            for &lit in clause {
115                self.set_target(lit.var(), lit.sign(), 0.2);
116            }
117        }
118    }
119
120    /// Decay all confidence scores
121    pub fn decay_confidence(&mut self) {
122        for conf in &mut self.confidence {
123            *conf *= self.decay;
124            // Reset use_target if confidence drops too low
125            if *conf < 0.5 {
126                // Don't reset immediately, let it decay naturally
127            }
128        }
129    }
130
131    /// Get the phase for a variable
132    pub fn get_phase(&mut self, var: Var, mode: PhaseMode) -> bool {
133        let idx = var.index();
134
135        match mode {
136            PhaseMode::Saved => {
137                self.stats.saved_used += 1;
138                self.saved_phase[idx]
139            }
140            PhaseMode::Target => {
141                if self.use_target[idx] && self.confidence[idx] > 0.5 {
142                    self.stats.target_used += 1;
143                    self.target_phase[idx]
144                } else {
145                    self.stats.saved_used += 1;
146                    self.saved_phase[idx]
147                }
148            }
149            PhaseMode::Random => {
150                self.stats.random_used += 1;
151                // Simple random using var index
152                (idx & 1) == 0
153            }
154        }
155    }
156
157    /// Reset target phases (useful after restarts)
158    pub fn reset_targets(&mut self) {
159        for use_target in &mut self.use_target {
160            *use_target = false;
161        }
162        for conf in &mut self.confidence {
163            *conf = 0.0;
164        }
165    }
166
167    /// Get confidence for a variable
168    #[must_use]
169    pub fn get_confidence(&self, var: Var) -> f64 {
170        self.confidence[var.index()]
171    }
172}
173
174#[cfg(test)]
175mod tests {
176    use super::*;
177
178    #[test]
179    fn test_target_phase_creation() {
180        let selector = TargetPhaseSelector::new(10, 0.95);
181        assert_eq!(selector.saved_phase.len(), 10);
182        assert_eq!(selector.target_phase.len(), 10);
183        assert_eq!(selector.confidence.len(), 10);
184    }
185
186    #[test]
187    fn test_save_phase() {
188        let mut selector = TargetPhaseSelector::new(10, 0.95);
189        let var = Var::new(0);
190
191        selector.save_phase(var, true);
192        assert!(selector.saved_phase[var.index()]);
193
194        let phase = selector.get_phase(var, PhaseMode::Saved);
195        assert!(phase);
196    }
197
198    #[test]
199    fn test_target_phase() {
200        let mut selector = TargetPhaseSelector::new(10, 0.95);
201        let var = Var::new(0);
202
203        // Set target with high confidence
204        selector.set_target(var, true, 2.0);
205
206        let phase = selector.get_phase(var, PhaseMode::Target);
207        assert!(phase);
208        assert!(selector.get_confidence(var) > 1.0);
209    }
210
211    #[test]
212    fn test_confidence_decay() {
213        let mut selector = TargetPhaseSelector::new(10, 0.5);
214        let var = Var::new(0);
215
216        selector.set_target(var, true, 2.0);
217        let initial_conf = selector.get_confidence(var);
218
219        selector.decay_confidence();
220        let decayed_conf = selector.get_confidence(var);
221
222        assert!(decayed_conf < initial_conf);
223        assert!((decayed_conf - initial_conf * 0.5).abs() < 0.001);
224    }
225
226    #[test]
227    fn test_on_conflict_literal() {
228        let mut selector = TargetPhaseSelector::new(10, 0.95);
229        let lit = Lit::pos(Var::new(0));
230
231        selector.on_conflict_literal(lit);
232        assert!(selector.get_confidence(lit.var()) > 0.0);
233    }
234
235    #[test]
236    fn test_reset_targets() {
237        let mut selector = TargetPhaseSelector::new(10, 0.95);
238        let var = Var::new(0);
239
240        selector.set_target(var, true, 2.0);
241        assert!(selector.get_confidence(var) > 0.0);
242
243        selector.reset_targets();
244        assert_eq!(selector.get_confidence(var), 0.0);
245    }
246
247    #[test]
248    fn test_stats() {
249        let mut selector = TargetPhaseSelector::new(10, 0.95);
250        let var = Var::new(0);
251
252        selector.get_phase(var, PhaseMode::Saved);
253        assert_eq!(selector.stats().saved_used, 1);
254
255        selector.get_phase(var, PhaseMode::Random);
256        assert_eq!(selector.stats().random_used, 1);
257    }
258}