#[derive(Debug, Clone, PartialEq, Eq)]
pub struct BitVec2048 {
words: [u64; 32],
}
impl Default for BitVec2048 {
fn default() -> Self {
Self::new()
}
}
impl BitVec2048 {
pub fn new() -> Self {
Self { words: [0u64; 32] }
}
pub fn set(&mut self, bit: usize) {
assert!(
bit < 2048,
"bit index {bit} out of range for BitVec2048 (max 2047)"
);
self.words[bit / 64] |= 1u64 << (bit % 64);
}
pub fn get(&self, bit: usize) -> bool {
assert!(
bit < 2048,
"bit index {bit} out of range for BitVec2048 (max 2047)"
);
(self.words[bit / 64] >> (bit % 64)) & 1 == 1
}
pub fn popcount(&self) -> u32 {
self.words.iter().map(|w| w.count_ones()).sum()
}
pub fn and(&self, other: &Self) -> Self {
let mut result = Self::new();
for (out, (a, b)) in result
.words
.iter_mut()
.zip(self.words.iter().zip(other.words.iter()))
{
*out = a & b;
}
result
}
pub fn or(&self, other: &Self) -> Self {
let mut result = Self::new();
for (out, (a, b)) in result
.words
.iter_mut()
.zip(self.words.iter().zip(other.words.iter()))
{
*out = a | b;
}
result
}
pub fn tanimoto(&self, other: &Self) -> f64 {
let intersection = self.and(other).popcount() as f64;
let a = self.popcount() as f64;
let b = other.popcount() as f64;
let union = a + b - intersection;
if union == 0.0 {
1.0
} else {
intersection / union
}
}
pub fn dice(&self, other: &Self) -> f64 {
let intersection = self.and(other).popcount() as f64;
let a = self.popcount() as f64;
let b = other.popcount() as f64;
let denom = a + b;
if denom == 0.0 {
1.0
} else {
2.0 * intersection / denom
}
}
pub fn fold(&self, bits: usize) -> Self {
assert!(
matches!(bits, 256 | 512 | 1024),
"fold target must be 1024, 512, or 256; got {bits}"
);
let mut current = self.clone();
let mut current_bits = 2048usize;
while current_bits > bits {
let half_words = current_bits / 64 / 2; let mut folded = Self::new();
for i in 0..half_words {
folded.words[i] = current.words[i] ^ current.words[i + half_words];
}
current = folded;
current_bits /= 2;
}
current
}
pub fn to_bitvecn(&self) -> BitVecN {
BitVecN {
words: self.words.to_vec(),
bits: 2048,
}
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct BitVecN {
words: Vec<u64>,
bits: usize,
}
impl BitVecN {
pub fn new(bits: usize) -> Self {
assert!(bits > 0, "BitVecN must have at least 1 bit");
let num_words = (bits + 63) / 64;
Self {
words: vec![0u64; num_words],
bits,
}
}
pub fn bit_width(&self) -> usize {
self.bits
}
pub fn set(&mut self, bit: usize) {
assert!(
bit < self.bits,
"bit index {bit} out of range for BitVecN (max {})",
self.bits - 1
);
self.words[bit / 64] |= 1u64 << (bit % 64);
}
pub fn get(&self, bit: usize) -> bool {
assert!(
bit < self.bits,
"bit index {bit} out of range for BitVecN (max {})",
self.bits - 1
);
(self.words[bit / 64] >> (bit % 64)) & 1 == 1
}
pub fn popcount(&self) -> u32 {
self.words.iter().map(|w| w.count_ones()).sum()
}
pub fn tanimoto(&self, other: &Self) -> f64 {
assert_eq!(
self.bits, other.bits,
"BitVecN tanimoto requires same bit width"
);
let mut intersection = 0u32;
for (a, b) in self.words.iter().zip(other.words.iter()) {
intersection += (a & b).count_ones();
}
let intersection = intersection as f64;
let a = self.popcount() as f64;
let b = other.popcount() as f64;
let union = a + b - intersection;
if union == 0.0 {
1.0
} else {
intersection / union
}
}
pub fn from_bitvec2048(bv: &BitVec2048) -> Self {
BitVecN {
words: bv.words.to_vec(),
bits: 2048,
}
}
pub fn to_bitvec2048(&self) -> Option<BitVec2048> {
if self.bits != 2048 {
return None;
}
let mut arr = [0u64; 32];
for (i, &w) in self.words.iter().enumerate() {
arr[i] = w;
}
Some(BitVec2048 { words: arr })
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn new_bitvec_is_all_zero() {
let bv = BitVec2048::new();
assert_eq!(bv.popcount(), 0, "new bitvec must have popcount 0");
}
#[test]
fn set_and_get_boundary_bits() {
let mut bv = BitVec2048::new();
bv.set(0);
bv.set(2047);
assert_eq!(bv.popcount(), 2);
assert!(bv.get(0));
assert!(!bv.get(1));
assert!(bv.get(2047));
}
#[test]
fn tanimoto_identical_nonzero() {
let mut bv = BitVec2048::new();
bv.set(42);
bv.set(100);
assert_eq!(bv.tanimoto(&bv.clone()), 1.0);
}
#[test]
fn tanimoto_disjoint_is_zero() {
let mut a = BitVec2048::new();
a.set(10);
let mut b = BitVec2048::new();
b.set(20);
assert_eq!(a.tanimoto(&b), 0.0);
}
#[test]
fn dice_identical_nonzero() {
let mut bv = BitVec2048::new();
bv.set(7);
assert_eq!(bv.dice(&bv.clone()), 1.0);
}
#[test]
fn fold_1024_popcount_leq_original() {
let mut bv = BitVec2048::new();
for i in (0..2048).step_by(3) {
bv.set(i);
}
let folded = bv.fold(1024);
assert!(
folded.popcount() <= bv.popcount(),
"folded popcount ({}) must be <= original ({})",
folded.popcount(),
bv.popcount()
);
}
#[test]
fn and_or_basic_correctness() {
let mut a = BitVec2048::new();
a.set(5);
a.set(10);
let mut b = BitVec2048::new();
b.set(10);
b.set(15);
let and = a.and(&b);
assert!(and.get(10), "AND: shared bit 10 should be set");
assert!(!and.get(5), "AND: bit 5 only in A should be clear");
assert!(!and.get(15), "AND: bit 15 only in B should be clear");
let or = a.or(&b);
assert!(or.get(5), "OR: bit 5 should be set");
assert!(or.get(10), "OR: bit 10 should be set");
assert!(or.get(15), "OR: bit 15 should be set");
assert!(!or.get(0), "OR: bit 0 should be clear");
}
#[test]
fn bitvecn_new_creates_zero_vector() {
let bv = BitVecN::new(512);
assert_eq!(bv.bit_width(), 512);
assert_eq!(bv.popcount(), 0);
}
#[test]
fn bitvecn_set_get_basic() {
let mut bv = BitVecN::new(1024);
bv.set(0);
bv.set(512);
bv.set(1023);
assert!(bv.get(0));
assert!(bv.get(512));
assert!(bv.get(1023));
assert!(!bv.get(1));
assert_eq!(bv.popcount(), 3);
}
#[test]
fn bitvecn_tanimoto_identical() {
let mut bv = BitVecN::new(256);
bv.set(10);
bv.set(50);
assert_eq!(bv.tanimoto(&bv.clone()), 1.0);
}
#[test]
fn bitvecn_tanimoto_disjoint() {
let mut a = BitVecN::new(256);
a.set(5);
let mut b = BitVecN::new(256);
b.set(10);
assert_eq!(a.tanimoto(&b), 0.0);
}
#[test]
fn bitvecn_conversion_to_from_2048() {
let mut bv2048 = BitVec2048::new();
bv2048.set(42);
bv2048.set(100);
let bvn = BitVecN::from_bitvec2048(&bv2048);
assert_eq!(bvn.bit_width(), 2048);
assert!(bvn.get(42));
assert!(bvn.get(100));
assert_eq!(bvn.popcount(), 2);
let bv2048_back = bvn.to_bitvec2048();
assert_eq!(bv2048_back, Some(bv2048));
}
#[test]
fn bitvecn_arbitrary_sizes() {
for size in [128, 256, 512, 1024, 2048, 4096] {
let mut bv = BitVecN::new(size);
bv.set(0);
bv.set(size - 1);
assert_eq!(bv.popcount(), 2);
assert_eq!(bv.bit_width(), size);
}
}
}