1use crate::memory::Offset;
4use derive_more::Add;
5use serde_derive::{Deserialize, Serialize};
6use static_assertions::const_assert;
7use std::{
8 convert::{TryFrom, TryInto},
9 fmt,
10 io::{self, Write},
11 mem::{align_of, size_of},
12 ops::{Add, AddAssign, Sub, SubAssign},
13};
14
15use crate::literal::Literal;
16
17#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Clone, Copy, Add, Hash, Default)]
19pub struct Clause {
20 pub index: ClauseIdentifierType,
21}
22
23pub type ClauseIdentifierType = u32;
25
26impl Clause {
27 pub fn new(index: ClauseIdentifierType) -> Clause {
31 requires!(index <= Clause::MAX_ID);
32 Clause { index }
33 }
34 pub fn from_usize(index: usize) -> Clause {
38 requires!(index < ClauseIdentifierType::max_value().try_into().unwrap());
39 Clause::new(index as ClauseIdentifierType)
40 }
41 pub fn range(start: impl Offset, end: impl Offset) -> impl Iterator<Item = Clause> {
43 const_assert!(size_of::<usize>() >= size_of::<ClauseIdentifierType>());
44 (start.as_offset()..end.as_offset()).map(Clause::from_usize)
45 }
46 pub const MAX_ID: ClauseIdentifierType = Tagged32::MAX_PAYLOAD - 1;
48 pub const DOES_NOT_EXIST: Clause = Clause {
52 index: Clause::MAX_ID + 1,
53 };
54 pub const UNINITIALIZED: Clause = Clause {
57 index: Clause::MAX_ID + 2,
58 };
59}
60
61impl Offset for Clause {
62 fn as_offset(&self) -> usize {
63 self.index as usize
64 }
65}
66
67impl Add<ClauseIdentifierType> for Clause {
68 type Output = Clause;
69 fn add(self, value: ClauseIdentifierType) -> Clause {
70 Clause::new(self.index + value)
71 }
72}
73
74impl AddAssign<ClauseIdentifierType> for Clause {
75 fn add_assign(&mut self, value: ClauseIdentifierType) {
76 self.index += value;
77 }
78}
79
80impl Sub<ClauseIdentifierType> for Clause {
81 type Output = Clause;
82 fn sub(self, value: ClauseIdentifierType) -> Clause {
83 Clause::new(self.index - value)
84 }
85}
86
87impl SubAssign<ClauseIdentifierType> for Clause {
88 fn sub_assign(&mut self, value: ClauseIdentifierType) {
89 self.index -= value;
90 }
91}
92
93impl fmt::Display for Clause {
94 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
95 write!(f, "{}", self.index)
96 }
97}
98
99#[derive(Debug, PartialEq, Eq, Clone, Copy, Default)]
110pub struct ProofStep(Tagged32);
111
112impl ProofStep {
113 pub fn lemma(clause: Clause) -> ProofStep {
115 ProofStep(Tagged32::new(clause.index))
116 }
117 pub fn deletion(clause: Clause) -> ProofStep {
119 ProofStep(Tagged32::new(clause.index).with_bit1())
120 }
121 pub fn is_deletion(self) -> bool {
123 self.0.bit1()
124 }
125 pub fn clause(self) -> Clause {
127 Clause {
128 index: self.0.payload(),
129 }
130 }
131}
132
133#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
147pub struct Reason(TaggedUSize);
148
149impl Reason {
150 pub fn invalid() -> Reason {
152 Reason(TaggedUSize::new(0))
153 }
154 pub fn assumed() -> Reason {
156 Reason(TaggedUSize::new(0).with_bit1())
157 }
158 pub fn forced(offset: usize) -> Reason {
161 Reason(
162 TaggedUSize::new(offset.try_into().unwrap())
163 .with_bit1()
164 .with_bit2(),
165 )
166 }
167 pub fn is_assumed(self) -> bool {
169 invariant!(self != Reason::invalid());
170 !self.0.bit2()
171 }
172 pub fn offset(self) -> usize {
175 invariant!(self != Reason::invalid());
176 invariant!(self != Reason::assumed());
177 self.0.payload() as usize
178 }
179}
180
181impl fmt::Display for Reason {
182 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
183 write!(
184 f,
185 "{}",
186 if self.is_assumed() {
187 "Assumption".into()
188 } else {
189 format!("Forced by clause {}", self.offset())
190 }
191 )
192 }
193}
194
195#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Default)]
207pub struct LRATDependency(Tagged32);
208
209impl LRATDependency {
210 pub fn unit_in_inference(clause: Clause) -> LRATDependency {
213 LRATDependency(Tagged32::new(clause.index as u32))
214 }
215 pub fn is_unit_in_inference(self) -> bool {
217 !self.0.bit1() && !self.0.bit2()
218 }
219 pub fn forced_unit(clause: Clause) -> LRATDependency {
222 LRATDependency(Tagged32::new(clause.index as u32).with_bit1())
223 }
224 pub fn is_forced_unit(self) -> bool {
226 self.0.bit1() && !self.0.bit2()
227 }
228 pub fn resolution_candidate(clause: Clause) -> LRATDependency {
230 LRATDependency(Tagged32::new(clause.index as u32).with_bit1().with_bit2())
231 }
232 pub fn is_resolution_candidate(self) -> bool {
234 self.0.bit1() && self.0.bit2()
235 }
236 pub fn clause(self) -> Clause {
238 Clause {
239 index: self.0.payload(),
240 }
241 }
242}
243
244#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Default)]
256pub struct LRATLiteral(Tagged32);
257
258impl LRATLiteral {
259 pub fn resolution_candidate(clause: Clause) -> LRATLiteral {
261 LRATLiteral(Tagged32::new(clause.index as u32))
262 }
263 pub fn is_resolution_candidate(self) -> bool {
265 !self.0.bit1() && !self.0.bit2()
266 }
267 pub fn hint(clause: Clause) -> LRATLiteral {
269 LRATLiteral(Tagged32::new(clause.index as u32).with_bit1())
270 }
271 pub fn is_hint(self) -> bool {
273 self.0.bit1() && !self.0.bit2()
274 }
275 pub fn zero() -> LRATLiteral {
277 LRATLiteral(Tagged32::new(0).with_bit1().with_bit2())
278 }
279 pub fn is_zero(self) -> bool {
281 self.0.bit1() && self.0.bit2()
282 }
283 pub fn clause(self) -> Clause {
285 requires!(!self.is_zero());
286 Clause {
287 index: self.0.payload(),
288 }
289 }
290}
291
292#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
294pub struct GRATLiteral(pub i32);
295
296impl GRATLiteral {
297 pub const ZERO: Self = Self(0);
298 pub const UNIT_PROP: Self = Self(1);
299 pub const DELETION: Self = Self(2);
300 pub const RUP_LEMMA: Self = Self(3);
301 pub const RAT_LEMMA: Self = Self(4);
302 pub const CONFLICT: Self = Self(5);
303 pub const RAT_COUNTS: Self = Self(6);
304 pub fn from_clause(clause: Clause) -> GRATLiteral {
306 requires!(clause.index + 1 < ClauseIdentifierType::max_value());
307 Self((clause.index + 1) as i32)
308 }
309 pub fn to_clause(self) -> Clause {
311 requires!(self.0 != 0);
312 Clause::new(ClauseIdentifierType::try_from(self.0).unwrap() - 1)
313 }
314}
315
316impl fmt::Display for GRATLiteral {
317 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
318 write!(f, "{}", self.0)
319 }
320}
321
322#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Clone, Copy, Default)]
324pub struct Tagged32(u32);
325
326impl Tagged32 {
327 const MASK: u32 = Tagged32::MASK1 | Tagged32::MASK2;
329 const MASK1: u32 = 0x80_00_00_00;
331 const MASK2: u32 = 0x40_00_00_00;
333 const MAX_PAYLOAD: u32 = u32::max_value() & !Tagged32::MASK;
335
336 pub fn new(payload: u32) -> Tagged32 {
337 requires!(payload <= Tagged32::MAX_PAYLOAD);
338 Tagged32(payload)
339 }
340 pub fn with_bit1(self) -> Tagged32 {
341 Tagged32(self.0 | Tagged32::MASK1)
342 }
343 pub fn with_bit2(self) -> Tagged32 {
344 Tagged32(self.0 | Tagged32::MASK2)
345 }
346 pub fn payload(self) -> u32 {
347 self.0 & !Tagged32::MASK
348 }
349 pub fn bit1(self) -> bool {
350 self.0 & Tagged32::MASK1 != 0
351 }
352 pub fn bit2(self) -> bool {
353 self.0 & Tagged32::MASK2 != 0
354 }
355}
356
357#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Clone, Copy, Default)]
359pub struct TaggedUSize(usize);
360
361impl TaggedUSize {
362 const MASK: usize = TaggedUSize::MASK1 | TaggedUSize::MASK2;
363 pub const MASK1: usize = 1 << (size_of::<usize>() * 8 - 1);
364 pub const MASK2: usize = 1 << (size_of::<usize>() * 8 - 2);
365 const MAX_PAYLOAD: usize = usize::max_value() & !TaggedUSize::MASK;
366
367 pub fn new(payload: usize) -> TaggedUSize {
368 requires!(payload <= TaggedUSize::MAX_PAYLOAD);
369 TaggedUSize(payload)
370 }
371 pub fn with_bit1(self) -> TaggedUSize {
372 TaggedUSize(self.0 | TaggedUSize::MASK1)
373 }
374 pub fn with_bit2(self) -> TaggedUSize {
375 TaggedUSize(self.0 | TaggedUSize::MASK2)
376 }
377 pub fn payload(self) -> usize {
378 self.0 & !TaggedUSize::MASK
379 }
380 pub fn bit1(self) -> bool {
381 self.0 & TaggedUSize::MASK1 != 0
382 }
383 pub fn bit2(self) -> bool {
384 self.0 & TaggedUSize::MASK2 != 0
385 }
386}
387
388#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
390pub enum RedundancyProperty {
391 RAT,
392 PR,
393}
394
395impl fmt::Display for RedundancyProperty {
396 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
397 write!(
398 f,
399 "{}",
400 match self {
401 RedundancyProperty::RAT => "RAT",
402 RedundancyProperty::PR => "PR",
403 }
404 )
405 }
406}
407
408#[allow(dead_code)]
410fn assert_primitive_sizes() {
411 const_assert!(size_of::<crate::literal::Literal>() == 4);
412 const_assert!(size_of::<Clause>() == 4);
413 const_assert!(size_of::<LRATDependency>() == 4);
414 const_assert!(size_of::<LRATLiteral>() == 4);
415 const_assert!(size_of::<ProofStep>() == 4);
416 const_assert!(size_of::<Reason>() == size_of::<usize>());
417 const_assert!(align_of::<Reason>() == align_of::<usize>());
418}
419
420pub fn write_clause<'a, T>(file: &mut impl Write, clause: T) -> io::Result<()>
424where
425 T: Iterator<Item = &'a Literal>,
426{
427 for &literal in clause {
428 if literal != Literal::BOTTOM {
429 write!(file, "{} ", literal)?;
430 }
431 }
432 write!(file, "0")
433}
434
435pub fn puts_clause<'a, T>(clause: T)
437where
438 T: IntoIterator<Item = &'a Literal>,
439{
440 for &literal in clause.into_iter() {
441 if literal != Literal::BOTTOM {
442 puts!("{} ", literal);
443 }
444 }
445 puts!("0")
446}
447
448pub fn puts_clause_with_id<'a, T>(clause: Clause, literals: T)
450where
451 T: IntoIterator<Item = &'a Literal>,
452{
453 puts!("[{}] ", clause);
454 puts_clause(literals);
455}
456
457pub fn puts_clause_with_id_and_witness(clause: Clause, literals: &[Literal], witness: &[Literal]) {
460 let witness_head = witness.first().cloned();
464 puts!("[{}] ", clause);
465 for &literal in literals {
466 if literal != Literal::BOTTOM && Some(literal) != witness_head {
467 puts!("{} ", literal);
468 }
469 }
470 puts_clause(witness);
471}