Skip to main content

bit_matrix/
matrix.rs

1//! Matrix of bits.
2
3use core::cmp;
4use core::ops::{Index, IndexMut, RangeBounds};
5
6use crate::local_prelude::*;
7use crate::util::round_up_to_next;
8
9/// A matrix of bits.
10#[derive(Clone, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
11#[cfg_attr(
12    feature = "miniserde",
13    derive(miniserde::Serialize, miniserde::Deserialize)
14)]
15#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
16pub struct BitMatrix<B: BitBlock = u32> {
17    bit_vec: BitVec<B>,
18    row_bits: usize,
19}
20
21// Matrix
22
23impl<B: BitBlock> BitMatrix<B> {
24    /// Create a new BitMatrix with specific numbers of bits in columns and rows.
25    pub fn new(rows: usize, row_bits: usize) -> Self {
26        BitMatrix {
27            bit_vec: BitVec::from_elem_general(round_up_to_next(row_bits, B::bits()) * rows, false),
28            row_bits,
29        }
30    }
31
32    /// Returns the number of rows.
33    #[inline]
34    fn num_rows(&self) -> usize {
35        if self.row_bits == 0 {
36            0
37        } else {
38            let row_blocks = round_up_to_next(self.row_bits, B::bits()) / B::bits();
39            self.bit_vec.storage().len() / row_blocks
40        }
41    }
42
43    /// Returns the number of columns.
44    #[inline]
45    pub fn num_cols(&self) -> usize {
46        self.row_bits
47    }
48
49    /// Returns the matrix's size as `(rows, columns)`.
50    pub fn size(&self) -> (usize, usize) {
51        (self.num_rows(), self.row_bits)
52    }
53
54    /// Sets the value of a bit.
55    ///
56    /// # Panics
57    ///
58    /// Panics if `(row, col)` is out of bounds.
59    #[inline]
60    pub fn set(&mut self, row: usize, col: usize, enabled: bool) {
61        let row_size_in_bits = round_up_to_next(self.row_bits, B::bits());
62        self.bit_vec.set(row * row_size_in_bits + col, enabled);
63    }
64
65    /// Sets the value of all bits.
66    #[inline]
67    pub fn fill(&mut self, enabled: bool) {
68        self.bit_vec.fill(enabled);
69    }
70
71    /// Grows the matrix in-place, adding `num_rows` rows filled with `value`.
72    pub fn grow(&mut self, num_rows: usize, value: bool) {
73        self.bit_vec
74            .grow(round_up_to_next(self.row_bits, B::bits()) * num_rows, value);
75    }
76
77    /// Truncates the matrix.
78    pub fn truncate(&mut self, num_rows: usize) {
79        self.bit_vec
80            .truncate(round_up_to_next(self.row_bits, B::bits()) * num_rows);
81    }
82
83    /// Returns a slice of the matrix's rows.
84    #[inline]
85    pub fn sub_matrix<R: RangeBounds<usize>>(&self, range: R) -> BitSubMatrix<'_, B> {
86        let row_size = round_up_to_next(self.row_bits, B::bits()) / B::bits();
87        BitSubMatrix {
88            slice: &self.bit_vec.storage()[(
89                range.start_bound().map(|&s| s * row_size),
90                range.end_bound().map(|&e| e * row_size),
91            )],
92            row_bits: self.row_bits,
93        }
94    }
95
96    /// Returns a slice of the matrix's rows.
97    #[inline]
98    pub fn sub_matrix_mut<R: RangeBounds<usize>>(&mut self, range: R) -> BitSubMatrixMut<'_, B> {
99        let row_size = self.row_size();
100        // Safety:
101        //
102        unsafe {
103            BitSubMatrixMut {
104                slice: &mut self.bit_vec.storage_mut()[(
105                    range.start_bound().map(|&s| s * row_size),
106                    range.end_bound().map(|&e| e * row_size),
107                )],
108                row_bits: self.row_bits,
109            }
110        }
111    }
112
113    fn row_size(&self) -> usize {
114        round_up_to_next(self.row_bits, B::bits()) / B::bits()
115    }
116
117    /// Given a row's index, returns a slice of all rows above that row, a reference to said row,
118    /// and a slice of all rows below.
119    ///
120    /// Functionally equivalent to `(self.sub_matrix(0..row), &self[row],
121    /// self.sub_matrix(row..self.num_rows()))`.
122    #[inline]
123    pub fn split_at(&self, row: usize) -> (BitSubMatrix<'_, B>, BitSubMatrix<'_, B>) {
124        (
125            self.sub_matrix(0..row),
126            self.sub_matrix(row..self.num_rows()),
127        )
128    }
129
130    /// Given a row's index, returns a slice of all rows above that row, a reference to said row,
131    /// and a slice of all rows below.
132    #[inline]
133    pub fn split_at_mut(&mut self, row: usize) -> (BitSubMatrixMut<'_, B>, BitSubMatrixMut<'_, B>) {
134        let row_size = round_up_to_next(self.row_bits, B::bits()) / B::bits();
135        let (first, second) = unsafe { self.bit_vec.storage_mut().split_at_mut(row * row_size) };
136        (
137            BitSubMatrixMut::new(first, self.row_bits),
138            BitSubMatrixMut::new(second, self.row_bits),
139        )
140    }
141
142    /// Iterate over bits in the specified row.
143    pub fn iter_row(&self, row: usize) -> impl Iterator<Item = bool> + '_ {
144        BitSlice::new(&self[row].slice).iter_bits(self.row_bits)
145    }
146
147    /// Computes the transitive closure of the binary relation
148    /// represented by this square bit matrix.
149    ///
150    /// Modifies this matrix in place using Warshall's algorithm.
151    ///
152    /// After this operation, the matrix will describe a transitive
153    /// relation. This means that, for any indices `a`, `b`, `c`,
154    /// if `M[(a, b)]` and `M[(b, c)]`, then `M[(a, c)]`.
155    ///
156    /// # Complexity
157    ///
158    /// The time complexity is **O(n^3)**, where `n` is the number
159    /// of columns and rows.
160    ///
161    /// # Panics
162    ///
163    /// The matrix must be square for this operation to succeed.
164    pub fn transitive_closure(&mut self) {
165        Into::<BitSubMatrixMut<B>>::into(self).transitive_closure();
166    }
167
168    /// Determines whether the number of rows equals the number of columns.
169    ///
170    /// This means the matrix is square.
171    pub fn is_square(&self) -> bool {
172        self.num_rows() == self.row_bits
173    }
174
175    /// Determines whether the matrix is empty.
176    pub fn is_empty(&self) -> bool {
177        self.size() == (0, 0)
178    }
179
180    /// Computes the reflexive closure of the binary relation represented by
181    /// this bit matrix. The matrix can be rectangular.
182    ///
183    /// The reflexive closure means that for every `x`` that will be within bounds,
184    /// `M[(x, x)]` is true.
185    ///
186    /// In other words, modifies this matrix in-place by making all
187    /// bits on the diagonal set.
188    pub fn reflexive_closure(&mut self) {
189        for i in 0..cmp::min(self.row_bits, self.num_rows()) {
190            self.set(i, i, true);
191        }
192    }
193}
194
195/// Gains immutable access to the matrix's row in the form of a `BitSlice`.
196impl<B: BitBlock> Index<usize> for BitMatrix<B> {
197    type Output = BitSlice<B>;
198
199    #[inline]
200    fn index(&self, row: usize) -> &Self::Output {
201        let row_size = round_up_to_next(self.row_bits, B::bits()) / B::bits();
202        BitSlice::new(&self.bit_vec.storage()[row * row_size..(row + 1) * row_size])
203    }
204}
205
206/// Gains mutable access to the matrix's row in the form of a `BitSlice`.
207impl<B: BitBlock> IndexMut<usize> for BitMatrix<B> {
208    #[inline]
209    fn index_mut(&mut self, row: usize) -> &mut Self::Output {
210        let row_size = round_up_to_next(self.row_bits, B::bits()) / B::bits();
211        // Safety:
212        // This does not introduce any memory unsafety despite the `unsafe` keyword.
213        unsafe {
214            BitSlice::new_mut(&mut self.bit_vec.storage_mut()[row * row_size..(row + 1) * row_size])
215        }
216    }
217}
218
219/// Returns `true` if a bit is enabled in the matrix, or `false` otherwise.
220///
221/// The first index in the tuple is row number, and the second is column
222/// number.
223impl<B: BitBlock> Index<(usize, usize)> for BitMatrix<B> {
224    type Output = bool;
225
226    #[inline]
227    fn index(&self, (row, col): (usize, usize)) -> &bool {
228        let row_size_in_bits = round_up_to_next(self.row_bits, B::bits());
229        if self.bit_vec.get(row * row_size_in_bits + col).unwrap() {
230            &TRUE
231        } else {
232            &FALSE
233        }
234    }
235}
236
237impl<'a, B: BitBlock> From<&'a mut BitMatrix<B>> for BitSubMatrixMut<'a, B> {
238    fn from(value: &'a mut BitMatrix<B>) -> Self {
239        unsafe { BitSubMatrixMut::new(value.bit_vec.storage_mut(), value.row_bits) }
240    }
241}
242
243// Tests
244
245#[test]
246fn test_empty() {
247    let mut matrix = <BitMatrix>::new(0, 0);
248    for _ in 0..3 {
249        assert_eq!(matrix.num_rows(), 0);
250        assert_eq!(matrix.size(), (0, 0));
251        assert!(matrix.is_square());
252        assert!(matrix.is_empty());
253        matrix.transitive_closure();
254    }
255}