|
2 | 2 | //! and related operators. |
3 | 3 | use std::{ |
4 | 4 | fmt::{Debug, Display}, |
5 | | - ops::{BitAnd, BitOr, Not}, |
| 5 | + ops::{BitAnd, BitOr, BitXor, Not}, |
6 | 6 | }; |
7 | 7 |
|
8 | 8 | /// Characteristic sequence of an LTL formula on a trace. |
9 | 9 | #[derive(Clone, Copy, PartialEq, Eq, Hash)] |
10 | 10 | pub struct CharSeq { |
11 | | - values: u64, |
| 11 | + pub(crate) values: u64, |
12 | 12 | length: usize, |
13 | 13 | } |
14 | 14 |
|
@@ -74,6 +74,41 @@ impl CharSeq { |
74 | 74 | (self.values & 1) == 1 |
75 | 75 | } |
76 | 76 |
|
| 77 | + /// Boolean implication operator (->) |
| 78 | + #[inline] |
| 79 | + pub(crate) fn implies(self, rhs: Self) -> Self { |
| 80 | + let CharSeq { values: x, length } = self; |
| 81 | + let CharSeq { |
| 82 | + values: y, |
| 83 | + length: _l2, |
| 84 | + } = rhs; |
| 85 | + // x -> y <=> !x or y |
| 86 | + let values = x.not().bitor(y); |
| 87 | + let values = if self.length < 64 { |
| 88 | + values & ((1u64 << self.length) - 1) |
| 89 | + } else { |
| 90 | + values |
| 91 | + }; |
| 92 | + CharSeq { values, length } |
| 93 | + } |
| 94 | + |
| 95 | + /// Boolean equivalence operator (<->) |
| 96 | + #[inline] |
| 97 | + pub(crate) fn equiv(self, rhs: Self) -> Self { |
| 98 | + let CharSeq { values: x, length } = self; |
| 99 | + let CharSeq { |
| 100 | + values: y, |
| 101 | + length: _l2, |
| 102 | + } = rhs; |
| 103 | + let values = (x.bitxor(y)).not(); |
| 104 | + let values = if self.length < 64 { |
| 105 | + values & ((1u64 << self.length) - 1) |
| 106 | + } else { |
| 107 | + values |
| 108 | + }; |
| 109 | + CharSeq { values, length } |
| 110 | + } |
| 111 | + |
77 | 112 | /// LTL Next operator (X) |
78 | 113 | #[inline] |
79 | 114 | pub(crate) fn next(mut self) -> Self { |
@@ -167,7 +202,7 @@ impl FromIterator<bool> for CharSeq { |
167 | 202 |
|
168 | 203 | #[cfg(test)] |
169 | 204 | mod tests { |
170 | | - use rand::{rng, Rng}; |
| 205 | + use rand::{Rng, rng}; |
171 | 206 |
|
172 | 207 | use super::*; |
173 | 208 |
|
@@ -320,4 +355,44 @@ mod tests { |
320 | 355 | assert_eq!(U(x, y), y | (x & X(U(x, y)))); |
321 | 356 | } |
322 | 357 | } |
| 358 | + |
| 359 | + #[test] |
| 360 | + fn x_implies_x() { |
| 361 | + for _ in 0..100 { |
| 362 | + let x = random_seq(); |
| 363 | + assert_eq!(x.implies(x).values, (1 << x.length) - 1); |
| 364 | + } |
| 365 | + } |
| 366 | + |
| 367 | + #[test] |
| 368 | + fn implies_def() { |
| 369 | + for _ in 0..100 { |
| 370 | + let (x, y) = random_pair(); |
| 371 | + assert_eq!(x.implies(y), x.not() | y); |
| 372 | + } |
| 373 | + } |
| 374 | + |
| 375 | + #[test] |
| 376 | + fn x_equiv_x() { |
| 377 | + for _ in 0..100 { |
| 378 | + let x = random_seq(); |
| 379 | + assert_eq!(x.equiv(x).values, (1 << x.length) - 1); |
| 380 | + } |
| 381 | + } |
| 382 | + |
| 383 | + #[test] |
| 384 | + fn equiv_iff_double_implies() { |
| 385 | + for _ in 0..100 { |
| 386 | + let (x, y) = random_pair(); |
| 387 | + assert_eq!(x.equiv(y), x.implies(y) & y.implies(x)); |
| 388 | + } |
| 389 | + } |
| 390 | + |
| 391 | + #[test] |
| 392 | + fn equiv_def() { |
| 393 | + for _ in 0..100 { |
| 394 | + let (x, y) = random_pair(); |
| 395 | + assert_eq!(x.equiv(y), (x & y) | (x.not() & y.not())); |
| 396 | + } |
| 397 | + } |
323 | 398 | } |
0 commit comments