vivacity_resolver/
decisions.rs1#[derive(Debug, thiserror::Error)]
5#[error("{0}")]
6pub struct SolverBug(pub String);
7
8#[derive(Debug, Clone, Copy)]
9pub struct Decision {
10 pub literal: i64,
11 pub reason: usize,
13}
14
15#[derive(Debug, Clone)]
16pub struct Decisions {
17 map: Vec<i64>,
20 pub queue: Vec<Decision>,
21}
22
23impl Decisions {
24 pub fn new(pool_size: usize) -> Decisions {
25 Decisions {
26 map: vec![0; pool_size + 1],
27 queue: Vec::new(),
28 }
29 }
30
31 fn entry(&self, literal_or_id: i64) -> i64 {
32 let id = literal_or_id.unsigned_abs() as usize;
33 self.map.get(id).copied().unwrap_or(0)
34 }
35
36 pub fn decide(&mut self, literal: i64, level: i64, reason: usize) -> Result<(), SolverBug> {
37 self.add_decision(literal, level)?;
38 self.queue.push(Decision { literal, reason });
39 Ok(())
40 }
41
42 pub fn satisfy(&self, literal: i64) -> bool {
43 let d = self.entry(literal);
44 (literal > 0 && d > 0) || (literal < 0 && d < 0)
45 }
46
47 pub fn conflict(&self, literal: i64) -> bool {
48 let d = self.entry(literal);
49 (d > 0 && literal < 0) || (d < 0 && literal > 0)
50 }
51
52 pub fn decided(&self, literal_or_id: i64) -> bool {
53 self.entry(literal_or_id) != 0
54 }
55
56 pub fn undecided(&self, literal_or_id: i64) -> bool {
57 self.entry(literal_or_id) == 0
58 }
59
60 pub fn decided_install(&self, literal_or_id: i64) -> bool {
61 self.entry(literal_or_id) > 0
62 }
63
64 pub fn decision_level(&self, literal_or_id: i64) -> i64 {
65 self.entry(literal_or_id).abs()
66 }
67
68 pub fn decision_rule(&self, literal_or_id: i64) -> Result<usize, SolverBug> {
70 let id = literal_or_id.abs();
71 self.queue
72 .iter()
73 .find(|d| d.literal.abs() == id)
74 .map(|d| d.reason)
75 .ok_or_else(|| {
76 SolverBug(format!(
77 "Did not find a decision rule using {literal_or_id}"
78 ))
79 })
80 }
81
82 pub fn at_offset(&self, offset: usize) -> Decision {
83 self.queue[offset]
84 }
85
86 pub fn valid_offset(&self, offset: usize) -> bool {
87 offset < self.queue.len()
88 }
89
90 pub fn last_reason(&self) -> usize {
91 self.queue[self.queue.len() - 1].reason
92 }
93
94 pub fn last_literal(&self) -> i64 {
95 self.queue[self.queue.len() - 1].literal
96 }
97
98 pub fn reset_to_offset(&mut self, offset: i64) {
100 while (self.queue.len() as i64) > offset + 1 {
101 let d = self.queue.pop().expect("non-empty");
102 self.map[d.literal.unsigned_abs() as usize] = 0;
103 }
104 }
105
106 pub fn revert_last(&mut self) {
107 let last = self.last_literal();
108 self.map[last.unsigned_abs() as usize] = 0;
109 self.queue.pop();
110 }
111
112 pub fn len(&self) -> usize {
113 self.queue.len()
114 }
115
116 pub fn is_empty(&self) -> bool {
117 self.queue.is_empty()
118 }
119
120 fn add_decision(&mut self, literal: i64, level: i64) -> Result<(), SolverBug> {
121 let id = literal.unsigned_abs() as usize;
122 if id >= self.map.len() {
123 return Err(SolverBug(format!("literal {literal} out of pool")));
124 }
125 let previous = self.map[id];
126 if previous != 0 {
127 return Err(SolverBug(format!(
128 "Trying to decide {literal} on level {level}, even though package {id} was previously decided as {previous}."
129 )));
130 }
131 self.map[id] = if literal > 0 { level } else { -level };
132 Ok(())
133 }
134}