1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
//! Bitvectors are simply sequences of boolean values. However, since they are used quite often
//! and in some very specific applications, we provide a unified optimized interface for them.
//!
//! Note that there is a ton of rust libraries which implement bitvectors (and indeed, we are
//! deferring to some of them for larger bit vectors). However, we wanted to avoid relying on
//! a specific library for this in order to provide a more unified API.
//!
//! AFAIK, `BitVector` is not used in any truly performance critical code, but there
//! are some concerns for overall memory consumption and efficiency.
//!
//! ```rust
//! use biodivine_lib_param_bn::biodivine_std::bitvector::{BitVector58, BitVector};
//! // Create a BitVector of length 4 initialized to false.
//! let mut bv = BitVector58::empty(4);
//! assert_eq!(4, bv.len());
//! bv.flip(1); // Invert value at given index.
//! bv.set(2, true); // Set value at index to a constant.
//! assert!(bv.get(1));
//! assert!(!bv.get(3));
//! // Should print BV(4)[1 2] using default `Display` implementation.
//! println!("{}", bv);
//! ```
//!
//! ### `BitVector` conversions
//!
//! Mostly for utility purposes (as this is not very efficient), every `BitVector` provides
//! conversion to and from `Vec<bool>` (exact representation of the values in the `BitVector`)
//! and `Vec<usize>` (indices of `true` item in the `BitVector`).
//!
//! ```rust
//! // Convert bool vector to BitVector.
//! use biodivine_lib_param_bn::biodivine_std::bitvector::{BitVector58, BitVector};
//! let bv = BitVector58::from(vec![false, true, true, false]);
//! // And back to bool vector.
//! assert_eq!(vec![false, true, true, false], bv.values());
//! // Convert index vector to BitVector.
//! assert_eq!(bv, BitVector58::from_ones(4, vec![1,2]));
//! // And also back to an index vector.
//! assert_eq!(vec![1,2], bv.ones());
//! // Inverted index vector is also available.
//! assert_eq!(vec![0,3], bv.zeros());
//! ```
//!
//! We recommend that users of bit vectors wrap these conversion utilities in more appropriate
//! methods aimed at the specific use case (e.g. substituting `usize` for domain specific
//! values).

use std::fmt::{Display, Formatter};

mod _impl_array_bit_vector;
mod _impl_bit_vector_58;

/// `BitVector` is a collection of boolean values of a fixed length.
///
/// When implementing `Display` and `From<Vec<bool>>`, please consult `BitVector::display` and
/// `BitVector::from_bool_vector`.
pub trait BitVector: Clone + Eq + Display + From<Vec<bool>> {
    /// If a `BitVector` implementation cannot handle arbitrary vector lengths, it can use this
    /// method to declare the largest bitvector it can handle.
    fn max_length() -> usize {
        usize::MAX
    }

    /// Create a new `BitVector` with the given length. Can panic if this implementation
    /// does not support the specified length. Once created, the length cannot be changed.
    fn empty(len: usize) -> Self;

    /// Create a new `BitVector` which contains `items` specified in the given vector.
    fn from_ones(len: usize, items: Vec<usize>) -> Self {
        let mut bits = Self::empty(len);
        for i in items {
            bits.set(i, true);
        }
        bits
    }

    /// The number of elements stored in this `BitVector`.
    fn len(&self) -> usize;

    /// Get the boolean value at the given `index`.
    fn get(&self, index: usize) -> bool;

    /// Set the boolean `value` at the given `index`.
    fn set(&mut self, index: usize, value: bool);

    /// Invert the value at the given `index`.
    fn flip(&mut self, index: usize);

    /// Return a vector of the values in this `BitVector`.
    fn values(&self) -> Vec<bool> {
        (0..self.len()).map(|i| self.get(i)).collect()
    }

    /// A vector of the indices of this `BitVector` which are set.
    fn ones(&self) -> Vec<usize> {
        (0..self.len()).filter(|i| self.get(*i)).collect()
    }

    /// A vector of the indices of this `BitVector` which are *not* set.
    fn zeros(&self) -> Vec<usize> {
        (0..self.len()).filter(|i| !self.get(*i)).collect()
    }

    /// A helper method for `Display` trait implementations for all variants of `BitVector`. Please
    /// use this method (or an equivalent display format) for all `Display` implementations of
    /// `BitVector`s.
    ///
    /// If you wish to provide a custom display format, wrap the `BitVector` into some
    /// domain-specific struct and implement a different `Display` for this struct. By
    /// providing this default implementation, we are ensuring that all `BitVector`
    /// implementations are "visually indistinguishable" to the user.
    ///
    /// You are still free to provide your own domain-specific `Debug` display method though!
    fn display(&self, f: &mut Formatter<'_>) -> Result<(), std::fmt::Error> {
        write!(f, "BV({})[", self.len())?;
        let mut first = true;
        for i in 0..self.len() {
            if self.get(i) {
                if !first {
                    write!(f, " ")?;
                }
                write!(f, "{}", i)?;
                first = false;
            }
        }
        write!(f, "]")?;
        Ok(())
    }

    /// A helper method for converting a vector of Booleans into a `BitVector`. Useful when
    /// implementing `From<Vec<bool>>`.
    fn from_bool_vector(items: Vec<bool>) -> Self {
        let mut bits = Self::empty(items.len());
        for (i, val) in items.iter().enumerate() {
            if *val {
                bits.set(i, true);
            }
        }
        bits
    }

    fn is_empty(&self) -> bool {
        self.len() == 0
    }
}

/// A `BitVector` implementation that uses the explicit implementation from the `bitvector` crate.
#[derive(Clone, PartialEq)]
pub struct ArrayBitVector {
    len: usize,
    values: bitvector::BitVector,
}

/// A `BitVector` implementation that uses `u64` as the underlying representation and
/// can therefore hold only up-to 58 values (remaining 6 bits store the vector length).
/// Should be pretty fast though.
///
/// `BitVector58` is also `Copy`, because it is small enough to pass by value.
#[derive(Clone, Copy, PartialEq, Eq, Hash)]
pub struct BitVector58(u64);