1#![warn(clippy::all, clippy::pedantic, clippy::nursery, clippy::cargo)]
2#![allow(
3 unsafe_code,
4 clippy::cast_possible_truncation,
5 clippy::cast_possible_wrap
6)]
7
8use crate::sat::literal::{Literal, Variable};
21use crate::sat::solver::Solutions;
22use clap::ValueEnum;
23use core::ops::{Index, IndexMut};
24use itertools::Itertools;
25use rustc_hash::FxHashMap;
26use std::fmt::{Debug, Display};
27use std::hash::Hash;
28
29#[derive(Debug, Clone, PartialEq, Eq, Copy, Default, Hash, PartialOrd, Ord)]
33pub enum VarState {
34 #[default]
36 Unassigned,
37 Assigned(bool),
39}
40
41impl VarState {
42 #[must_use]
48 pub const fn is_assigned(self) -> bool {
49 matches!(self, Self::Assigned(_))
50 }
51
52 #[must_use]
58 pub const fn is_unassigned(self) -> bool {
59 !self.is_assigned()
60 }
61
62 #[must_use]
68 pub const fn is_true(self) -> bool {
69 matches!(self, Self::Assigned(true))
70 }
71
72 #[must_use]
78 pub const fn is_false(self) -> bool {
79 matches!(self, Self::Assigned(false))
80 }
81}
82
83impl From<VarState> for Option<bool> {
84 fn from(s: VarState) -> Self {
89 match s {
90 VarState::Assigned(b) => Some(b),
91 VarState::Unassigned => None,
92 }
93 }
94}
95
96impl From<Option<bool>> for VarState {
97 fn from(b: Option<bool>) -> Self {
102 b.map_or(Self::Unassigned, VarState::Assigned)
103 }
104}
105
106pub trait Assignment:
114 Index<usize, Output = VarState> + IndexMut<usize, Output = VarState> + Debug + Clone
115{
116 fn new(n_vars: usize) -> Self;
124
125 fn num_vars(&self) -> usize;
127
128 fn set(&mut self, var: Variable, b: bool);
135
136 fn reset(&mut self);
138
139 fn assign(&mut self, l: impl Literal) {
148 self.set(l.variable(), l.polarity());
149 }
150
151 fn unassign(&mut self, var: Variable);
157
158 fn get_solutions(&self) -> Solutions;
162
163 fn is_assigned(&self, var: Variable) -> bool {
173 self[var as usize].is_assigned()
174 }
175
176 fn var_value(&self, var: Variable) -> Option<bool> {
187 self[var as usize].into()
188 }
189
190 fn all_assigned(&self) -> bool;
196
197 fn literal_value(&self, l: impl Literal) -> Option<bool> {
208 self.var_value(l.variable()).map(|b| b == l.polarity())
209 }
210
211 fn unassigned(&self) -> impl Iterator<Item = Variable> + '_ {
215 (0..self.num_vars()).filter_map(move |i| {
216 #[allow(clippy::cast_possible_truncation)]
217 let var = i as Variable;
218 if self[var as usize].is_unassigned() {
219 Some(var)
220 } else {
221 None
222 }
223 })
224 }
225}
226
227#[derive(Debug, Clone, PartialEq, Eq, Default)]
234pub struct VecAssignment {
235 states: Vec<VarState>,
237}
238
239impl Index<usize> for VecAssignment {
240 type Output = VarState;
241
242 fn index(&self, index: usize) -> &Self::Output {
250 unsafe { self.states.get_unchecked(index) }
253 }
254}
255
256impl IndexMut<usize> for VecAssignment {
257 fn index_mut(&mut self, index: usize) -> &mut Self::Output {
264 unsafe { self.states.get_unchecked_mut(index) }
267 }
268}
269
270impl Assignment for VecAssignment {
271 fn new(n_vars: usize) -> Self {
274 Self {
275 states: vec![VarState::Unassigned; n_vars],
276 }
277 }
278
279 fn num_vars(&self) -> usize {
280 self.states.len()
281 }
282
283 fn set(&mut self, var: Variable, b: bool) {
284 self[var as usize] = VarState::Assigned(b);
285 }
286
287 fn reset(&mut self) {
288 self.states.fill(VarState::Unassigned);
289 }
290
291 fn unassign(&mut self, var: Variable) {
292 self[var as usize] = VarState::Unassigned;
293 }
294
295 fn get_solutions(&self) -> Solutions {
296 Solutions::new(
297 &self
298 .states
299 .iter()
300 .enumerate()
301 .filter_map(|(i, s)| {
302 #[allow(clippy::cast_possible_wrap, clippy::cast_possible_truncation)]
303 let var_id = i as i32;
304 match s {
305 VarState::Assigned(true) => Some(var_id),
306 VarState::Assigned(false) => Some(-var_id),
307 _ => None,
308 }
309 })
310 .collect_vec(),
311 )
312 }
313
314 fn all_assigned(&self) -> bool {
315 self.states.iter().all(|v| v.is_assigned())
316 }
317}
318
319#[derive(Debug, Clone, PartialEq, Eq, Default)]
326pub struct HashMapAssignment {
327 map: FxHashMap<Variable, VarState>,
329 num_vars: usize,
332}
333
334impl Index<usize> for HashMapAssignment {
335 type Output = VarState;
336
337 fn index(&self, index: usize) -> &Self::Output {
342 #[allow(clippy::cast_possible_truncation)]
343 self.map
344 .get(&(index as Variable))
345 .unwrap_or(&VarState::Unassigned)
346 }
347}
348
349impl IndexMut<usize> for HashMapAssignment {
350 fn index_mut(&mut self, index: usize) -> &mut Self::Output {
355 #[allow(clippy::cast_possible_truncation)]
356 self.map
357 .entry(index as Variable)
358 .or_insert(VarState::Unassigned)
359 }
360}
361
362impl Assignment for HashMapAssignment {
363 fn new(n_vars: usize) -> Self {
371 Self {
372 map: FxHashMap::default(),
373 num_vars: n_vars,
374 }
375 }
376
377 fn num_vars(&self) -> usize {
378 self.num_vars
379 }
380
381 fn set(&mut self, var: Variable, b: bool) {
382 self.map.insert(var, VarState::Assigned(b));
383 }
384
385 fn reset(&mut self) {
386 self.map.clear();
387 }
388
389 fn unassign(&mut self, var: Variable) {
392 self.map.insert(var, VarState::Unassigned);
393 }
394
395 fn get_solutions(&self) -> Solutions {
396 Solutions::new(
397 &self
398 .map
399 .iter()
400 .filter_map(|(&var, s)| {
401 #[allow(clippy::cast_possible_wrap)]
402 let var_id = var as i32;
403 match s {
404 VarState::Assigned(true) => Some(var_id),
405 VarState::Assigned(false) => Some(-var_id),
406 _ => None,
407 }
408 })
409 .collect_vec(),
410 )
411 }
412
413 fn all_assigned(&self) -> bool {
414 self.map.len() == self.num_vars && self.map.values().all(|v| v.is_assigned())
415 }
416}
417
418#[derive(Clone, Debug)]
421pub enum AssignmentImpls {
422 Vec(VecAssignment),
424
425 HashMap(HashMapAssignment),
427}
428
429impl Index<usize> for AssignmentImpls {
430 type Output = VarState;
431 fn index(&self, index: usize) -> &Self::Output {
432 match self {
433 Self::Vec(v) => v.index(index),
434 Self::HashMap(v) => v.index(index),
435 }
436 }
437}
438
439impl IndexMut<usize> for AssignmentImpls {
440 fn index_mut(&mut self, index: usize) -> &mut Self::Output {
441 match self {
442 Self::Vec(v) => v.index_mut(index),
443 Self::HashMap(v) => v.index_mut(index),
444 }
445 }
446}
447
448impl Assignment for AssignmentImpls {
449 fn new(n_vars: usize) -> Self {
450 Self::Vec(VecAssignment::new(n_vars))
451 }
452
453 fn num_vars(&self) -> usize {
454 match self {
455 Self::Vec(v) => v.num_vars(),
456 Self::HashMap(v) => v.num_vars(),
457 }
458 }
459
460 fn set(&mut self, var: Variable, b: bool) {
461 match self {
462 Self::Vec(v) => v.set(var, b),
463 Self::HashMap(v) => v.set(var, b),
464 }
465 }
466
467 fn reset(&mut self) {
468 match self {
469 Self::Vec(v) => v.reset(),
470 Self::HashMap(v) => v.reset(),
471 }
472 }
473 fn unassign(&mut self, var: Variable) {
474 match self {
475 Self::Vec(v) => v.unassign(var),
476 Self::HashMap(v) => v.unassign(var),
477 }
478 }
479
480 fn get_solutions(&self) -> Solutions {
481 match self {
482 Self::Vec(v) => v.get_solutions(),
483 Self::HashMap(v) => v.get_solutions(),
484 }
485 }
486 fn all_assigned(&self) -> bool {
487 match self {
488 Self::Vec(v) => v.all_assigned(),
489 Self::HashMap(v) => v.all_assigned(),
490 }
491 }
492}
493
494#[derive(Debug, Clone, PartialEq, Eq, Copy, Default, Hash, ValueEnum)]
496pub enum AssignmentType {
497 #[default]
499 Vec,
500 HashMap,
502}
503
504impl Display for AssignmentType {
505 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
506 match self {
507 Self::Vec => write!(f, "vec"),
508 Self::HashMap => write!(f, "hash-map"),
509 }
510 }
511}
512
513impl AssignmentType {
514 #[must_use]
524 pub fn to_impl(self, n_vars: usize) -> AssignmentImpls {
525 match self {
526 Self::Vec => AssignmentImpls::Vec(VecAssignment::new(n_vars)),
527 Self::HashMap => AssignmentImpls::HashMap(HashMapAssignment::new(n_vars)),
528 }
529 }
530}
531
532#[cfg(test)]
533mod tests {
534 use super::*;
535 use crate::sat::literal::PackedLiteral;
536
537 #[test]
538 fn test_var_state() {
539 assert!(VarState::Unassigned.is_unassigned());
540 assert!(!VarState::Unassigned.is_assigned());
541 assert!(!VarState::Unassigned.is_true());
542 assert!(!VarState::Unassigned.is_false());
543
544 assert!(!VarState::Assigned(true).is_unassigned());
545 assert!(VarState::Assigned(true).is_assigned());
546 assert!(VarState::Assigned(true).is_true());
547 assert!(!VarState::Assigned(true).is_false());
548
549 assert!(!VarState::Assigned(false).is_unassigned());
550 assert!(VarState::Assigned(false).is_assigned());
551 assert!(!VarState::Assigned(false).is_true());
552 assert!(VarState::Assigned(false).is_false());
553 }
554
555 #[allow(clippy::cognitive_complexity)]
556 fn test_assignment<A: Assignment>(a: &mut A) {
557 a.set(1, true);
558 a.set(2, false);
559 a.set(3, true);
560
561 assert!(a.is_assigned(1));
562 assert!(a.is_assigned(2));
563 assert!(a.is_assigned(3));
564 assert!(!a.is_assigned(0));
565
566 assert_eq!(a.var_value(1), Some(true));
567 assert_eq!(a.var_value(2), Some(false));
568 assert_eq!(a.var_value(3), Some(true));
569 assert_eq!(a.var_value(0), None);
570
571 assert_eq!(a.literal_value(PackedLiteral::new(1, false)), Some(false));
572 assert_eq!(a.literal_value(PackedLiteral::new(1, true)), Some(true));
573
574 assert_eq!(a.literal_value(PackedLiteral::new(2, false)), Some(true));
575 assert_eq!(a.literal_value(PackedLiteral::new(2, true)), Some(false));
576
577 assert_eq!(a.literal_value(PackedLiteral::new(3, false)), Some(false));
578 assert_eq!(a.literal_value(PackedLiteral::new(3, true)), Some(true));
579
580 a.unassign(1);
581 assert!(!a.is_assigned(1));
582 assert_eq!(a.var_value(1), None);
583 assert_eq!(a.literal_value(PackedLiteral::new(1, false)), None);
584
585 let s = a.get_solutions();
586 assert_eq!(s, Solutions::new(&[-2, 3]));
587
588 let unassigned_vars = a.unassigned().collect_vec();
589 assert_eq!(unassigned_vars, vec![0, 1]);
590
591 assert!(!a.all_assigned());
592 a.set(0, true);
593 a.set(1, true);
594 assert!(a.all_assigned());
595
596 a.reset();
597 assert!(!a.is_assigned(0));
598 assert!(!a.is_assigned(1));
599 assert!(!a.is_assigned(2));
600 assert!(!a.is_assigned(3));
601 assert!(!a.all_assigned());
602 }
603
604 #[test]
605 fn test_assignment_vec() {
606 let mut a: VecAssignment = Assignment::new(4);
607 test_assignment(&mut a);
608 }
609
610 #[test]
611 fn test_hashmap_assignment() {
612 let mut a = HashMapAssignment::new(4);
613 test_assignment(&mut a);
614 }
615
616 #[test]
617 fn test_assignment_unassigned_default_impl() {
618 let a = VecAssignment::new(4);
619 assert!(!a.is_assigned(0));
620 assert!(!a.is_assigned(1));
621 assert!(!a.is_assigned(2));
622 assert!(!a.is_assigned(3));
623 assert_eq!(a.unassigned().count(), 4);
624 assert!(!a.all_assigned());
625
626 let b = HashMapAssignment::new(4);
627 assert!(!b.is_assigned(0));
628 assert!(!b.is_assigned(1));
629 assert_eq!(b.unassigned().count(), 4);
630 assert!(!b.all_assigned());
631
632 let c = VecAssignment::new(0);
633 assert!(c.all_assigned());
634
635 let d = HashMapAssignment::new(0);
636 assert!(d.all_assigned());
637 }
638}