1#[cfg(feature = "ppl")]
7use fugue::{addr, ChoiceValue, Trace};
8use rand::Rng;
9use serde::{Deserialize, Serialize};
10
11use crate::error::GenomeError;
12use crate::genome::bounds::MultiBounds;
13use crate::genome::traits::{BinaryGenome, EvolutionaryGenome};
14
15#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
20pub struct BitString {
21 bits: Vec<bool>,
23}
24
25impl BitString {
26 pub fn new(bits: Vec<bool>) -> Self {
28 Self { bits }
29 }
30
31 pub fn zeros(length: usize) -> Self {
33 Self {
34 bits: vec![false; length],
35 }
36 }
37
38 pub fn ones(length: usize) -> Self {
40 Self {
41 bits: vec![true; length],
42 }
43 }
44
45 pub fn generate_with_len<R: Rng>(rng: &mut R, len: usize) -> Self {
52 Self {
53 bits: (0..len).map(|_| rng.gen()).collect(),
54 }
55 }
56
57 pub fn from_u64(value: u64, length: usize) -> Self {
59 assert!(length <= 64, "Length must be <= 64 for u64 conversion");
60 let bits = (0..length).map(|i| (value >> i) & 1 == 1).collect();
61 Self { bits }
62 }
63
64 pub fn to_u64(&self) -> Option<u64> {
66 if self.bits.len() > 64 {
67 return None;
68 }
69 let mut value = 0u64;
70 for (i, &bit) in self.bits.iter().enumerate() {
71 if bit {
72 value |= 1 << i;
73 }
74 }
75 Some(value)
76 }
77
78 pub fn len(&self) -> usize {
80 self.bits.len()
81 }
82
83 pub fn is_empty(&self) -> bool {
85 self.bits.is_empty()
86 }
87
88 pub fn get(&self, index: usize) -> Option<bool> {
90 self.bits.get(index).copied()
91 }
92
93 pub fn set(&mut self, index: usize, value: bool) {
95 if let Some(bit) = self.bits.get_mut(index) {
96 *bit = value;
97 }
98 }
99
100 pub fn flip(&mut self, index: usize) {
102 if let Some(bit) = self.bits.get_mut(index) {
103 *bit = !*bit;
104 }
105 }
106
107 pub fn flip_all(&mut self) {
109 for bit in &mut self.bits {
110 *bit = !*bit;
111 }
112 }
113
114 pub fn complement(&self) -> Self {
116 Self {
117 bits: self.bits.iter().map(|b| !b).collect(),
118 }
119 }
120
121 pub fn hamming_distance(&self, other: &Self) -> usize {
128 self.try_hamming_distance(other)
129 .unwrap_or_else(|e| panic!("BitString::hamming_distance: {e}"))
130 }
131
132 pub fn try_hamming_distance(&self, other: &Self) -> Result<usize, GenomeError> {
136 if self.bits.len() != other.bits.len() {
137 return Err(GenomeError::DimensionMismatch {
138 expected: self.bits.len(),
139 actual: other.bits.len(),
140 });
141 }
142 Ok(self
143 .bits
144 .iter()
145 .zip(other.bits.iter())
146 .filter(|(a, b)| a != b)
147 .count())
148 }
149
150 pub fn and(&self, other: &Self) -> Result<Self, GenomeError> {
152 if self.bits.len() != other.bits.len() {
153 return Err(GenomeError::DimensionMismatch {
154 expected: self.bits.len(),
155 actual: other.bits.len(),
156 });
157 }
158 Ok(Self {
159 bits: self
160 .bits
161 .iter()
162 .zip(other.bits.iter())
163 .map(|(a, b)| *a && *b)
164 .collect(),
165 })
166 }
167
168 pub fn or(&self, other: &Self) -> Result<Self, GenomeError> {
170 if self.bits.len() != other.bits.len() {
171 return Err(GenomeError::DimensionMismatch {
172 expected: self.bits.len(),
173 actual: other.bits.len(),
174 });
175 }
176 Ok(Self {
177 bits: self
178 .bits
179 .iter()
180 .zip(other.bits.iter())
181 .map(|(a, b)| *a || *b)
182 .collect(),
183 })
184 }
185
186 pub fn xor(&self, other: &Self) -> Result<Self, GenomeError> {
188 if self.bits.len() != other.bits.len() {
189 return Err(GenomeError::DimensionMismatch {
190 expected: self.bits.len(),
191 actual: other.bits.len(),
192 });
193 }
194 Ok(Self {
195 bits: self
196 .bits
197 .iter()
198 .zip(other.bits.iter())
199 .map(|(a, b)| *a ^ *b)
200 .collect(),
201 })
202 }
203}
204
205impl EvolutionaryGenome for BitString {
206 type Allele = bool;
207 type Phenotype = Vec<bool>;
208
209 fn decode(&self) -> Self::Phenotype {
210 self.bits.clone()
211 }
212
213 fn dimension(&self) -> usize {
214 self.bits.len()
215 }
216
217 fn generate<R: Rng>(rng: &mut R, bounds: &MultiBounds) -> Self {
223 Self::generate_with_len(rng, bounds.dimension())
224 }
225
226 fn as_slice(&self) -> Option<&[bool]> {
227 Some(&self.bits)
228 }
229
230 fn as_mut_slice(&mut self) -> Option<&mut [bool]> {
231 Some(&mut self.bits)
232 }
233
234 fn distance(&self, other: &Self) -> f64 {
235 self.try_distance(other).unwrap_or_else(|e| {
236 panic!("BitString::distance: {e}; use try_distance for a fallible comparison")
237 })
238 }
239
240 fn try_distance(&self, other: &Self) -> Result<f64, GenomeError> {
241 self.try_hamming_distance(other).map(|d| d as f64)
242 }
243}
244
245#[cfg(feature = "ppl")]
246impl crate::genome::trace_genome::TraceGenome for BitString {
247 fn to_trace(&self) -> Trace {
251 let mut trace = Trace::default();
252 for (i, &bit) in self.bits.iter().enumerate() {
253 trace.insert_choice(addr!("bit", i), ChoiceValue::Bool(bit), 0.0);
254 }
255 trace
256 }
257
258 fn from_trace(trace: &Trace) -> Result<Self, GenomeError> {
266 let mut bits = Vec::new();
267 let mut i = 0;
268 loop {
269 match trace.choices.get(&addr!("bit", i)) {
270 None => break,
271 Some(choice) => match choice.value.as_bool() {
272 Some(val) => {
273 bits.push(val);
274 i += 1;
275 }
276 None => {
277 return Err(GenomeError::TypeMismatch {
278 address: format!("bit#{i}"),
279 expected: "bool".to_string(),
280 actual: choice.value.type_name().to_string(),
281 });
282 }
283 },
284 }
285 }
286 if bits.is_empty() {
287 return Err(GenomeError::InvalidStructure(
288 "No bits found in trace".to_string(),
289 ));
290 }
291 Ok(Self { bits })
292 }
293
294 fn trace_prefix() -> &'static str {
295 "bit"
296 }
297}
298
299impl BinaryGenome for BitString {
300 fn bits(&self) -> &[bool] {
301 &self.bits
302 }
303
304 fn bits_mut(&mut self) -> &mut [bool] {
305 &mut self.bits
306 }
307
308 fn from_bits(bits: Vec<bool>) -> Result<Self, GenomeError> {
309 Ok(Self { bits })
310 }
311}
312
313impl std::ops::Index<usize> for BitString {
314 type Output = bool;
315
316 fn index(&self, index: usize) -> &Self::Output {
317 &self.bits[index]
318 }
319}
320
321impl From<Vec<bool>> for BitString {
322 fn from(bits: Vec<bool>) -> Self {
323 Self { bits }
324 }
325}
326
327impl From<BitString> for Vec<bool> {
328 fn from(genome: BitString) -> Self {
329 genome.bits
330 }
331}
332
333impl<const N: usize> From<[bool; N]> for BitString {
334 fn from(arr: [bool; N]) -> Self {
335 Self { bits: arr.to_vec() }
336 }
337}
338
339impl IntoIterator for BitString {
340 type Item = bool;
341 type IntoIter = std::vec::IntoIter<bool>;
342
343 fn into_iter(self) -> Self::IntoIter {
344 self.bits.into_iter()
345 }
346}
347
348impl<'a> IntoIterator for &'a BitString {
349 type Item = &'a bool;
350 type IntoIter = std::slice::Iter<'a, bool>;
351
352 fn into_iter(self) -> Self::IntoIter {
353 self.bits.iter()
354 }
355}
356
357impl std::fmt::Display for BitString {
358 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
359 for bit in &self.bits {
360 write!(f, "{}", if *bit { '1' } else { '0' })?;
361 }
362 Ok(())
363 }
364}
365
366#[cfg(test)]
367mod tests {
368 use super::*;
369 #[cfg(feature = "ppl")]
370 use fugue::addr;
371
372 #[test]
373 fn test_bit_string_new() {
374 let bs = BitString::new(vec![true, false, true]);
375 assert_eq!(bs.len(), 3);
376 assert_eq!(bs.bits(), &[true, false, true]);
377 }
378
379 #[test]
380 fn test_bit_string_zeros() {
381 let bs = BitString::zeros(5);
382 assert_eq!(bs.len(), 5);
383 assert!(bs.bits().iter().all(|&b| !b));
384 assert_eq!(bs.count_ones(), 0);
385 assert_eq!(bs.count_zeros(), 5);
386 }
387
388 #[test]
389 fn test_bit_string_ones() {
390 let bs = BitString::ones(5);
391 assert_eq!(bs.len(), 5);
392 assert!(bs.bits().iter().all(|&b| b));
393 assert_eq!(bs.count_ones(), 5);
394 assert_eq!(bs.count_zeros(), 0);
395 }
396
397 #[test]
398 fn test_bit_string_from_u64() {
399 let bs = BitString::from_u64(0b101, 4);
400 assert_eq!(bs.bits(), &[true, false, true, false]);
401 }
402
403 #[test]
404 fn test_bit_string_to_u64() {
405 let bs = BitString::new(vec![true, false, true, false]);
406 assert_eq!(bs.to_u64(), Some(0b0101));
407
408 let long_bs = BitString::zeros(100);
409 assert_eq!(long_bs.to_u64(), None);
410 }
411
412 #[test]
413 fn test_bit_string_get_set() {
414 let mut bs = BitString::zeros(3);
415 assert_eq!(bs.get(0), Some(false));
416 assert_eq!(bs.get(3), None);
417
418 bs.set(1, true);
419 assert_eq!(bs.get(1), Some(true));
420 }
421
422 #[test]
423 fn test_bit_string_flip() {
424 let mut bs = BitString::zeros(3);
425 bs.flip(1);
426 assert_eq!(bs.bits(), &[false, true, false]);
427 }
428
429 #[test]
430 fn test_bit_string_flip_all() {
431 let mut bs = BitString::new(vec![true, false, true]);
432 bs.flip_all();
433 assert_eq!(bs.bits(), &[false, true, false]);
434 }
435
436 #[test]
437 fn test_bit_string_complement() {
438 let bs = BitString::new(vec![true, false, true]);
439 let comp = bs.complement();
440 assert_eq!(comp.bits(), &[false, true, false]);
441 }
442
443 #[test]
444 fn test_bit_string_hamming_distance() {
445 let bs1 = BitString::new(vec![true, false, true, false]);
446 let bs2 = BitString::new(vec![true, true, false, false]);
447 assert_eq!(bs1.hamming_distance(&bs2), 2);
448 }
449
450 #[test]
451 fn test_bit_string_and() {
452 let bs1 = BitString::new(vec![true, true, false, false]);
453 let bs2 = BitString::new(vec![true, false, true, false]);
454 let result = bs1.and(&bs2).unwrap();
455 assert_eq!(result.bits(), &[true, false, false, false]);
456 }
457
458 #[test]
459 fn test_bit_string_or() {
460 let bs1 = BitString::new(vec![true, true, false, false]);
461 let bs2 = BitString::new(vec![true, false, true, false]);
462 let result = bs1.or(&bs2).unwrap();
463 assert_eq!(result.bits(), &[true, true, true, false]);
464 }
465
466 #[test]
467 fn test_bit_string_xor() {
468 let bs1 = BitString::new(vec![true, true, false, false]);
469 let bs2 = BitString::new(vec![true, false, true, false]);
470 let result = bs1.xor(&bs2).unwrap();
471 assert_eq!(result.bits(), &[false, true, true, false]);
472 }
473
474 #[test]
475 fn test_bit_string_dimension_mismatch() {
476 let bs1 = BitString::zeros(3);
477 let bs2 = BitString::zeros(4);
478 assert!(bs1.and(&bs2).is_err());
479 assert!(bs1.or(&bs2).is_err());
480 assert!(bs1.xor(&bs2).is_err());
481 }
482
483 #[test]
484 fn test_bit_string_generate() {
485 let mut rng = rand::thread_rng();
486 let bounds = MultiBounds::symmetric(1.0, 10);
487 let bs = BitString::generate(&mut rng, &bounds);
488 assert_eq!(bs.len(), 10);
489 }
490
491 #[test]
492 fn test_bit_string_distance() {
493 let bs1 = BitString::new(vec![true, false, true, false]);
494 let bs2 = BitString::new(vec![true, true, false, false]);
495 assert_eq!(bs1.distance(&bs2), 2.0);
496 }
497
498 #[test]
499 fn test_bit_string_display() {
500 let bs = BitString::new(vec![true, false, true, true]);
501 assert_eq!(format!("{}", bs), "1011");
502 }
503
504 #[test]
505 fn test_bit_string_indexing() {
506 let bs = BitString::new(vec![true, false, true]);
507 assert!(bs[0]);
508 assert!(!bs[1]);
509 assert!(bs[2]);
510 }
511
512 #[test]
513 fn test_bit_string_from_array() {
514 let bs: BitString = [true, false, true].into();
515 assert_eq!(bs.bits(), &[true, false, true]);
516 }
517
518 #[test]
519 fn test_bit_string_serialization() {
520 let bs = BitString::new(vec![true, false, true]);
521 let serialized = serde_json::to_string(&bs).unwrap();
522 let deserialized: BitString = serde_json::from_str(&serialized).unwrap();
523 assert_eq!(bs, deserialized);
524 }
525
526 #[test]
527 fn test_bit_string_decode() {
528 let bs = BitString::new(vec![true, false, true]);
529 let phenotype = bs.decode();
530 assert_eq!(phenotype, vec![true, false, true]);
531 }
532
533 #[test]
534 #[cfg(feature = "ppl")]
535 fn test_bit_string_to_trace() {
536 use crate::genome::trace_genome::TraceGenome;
537 let bs = BitString::new(vec![true, false, true, false]);
538 let trace = bs.to_trace();
539
540 assert_eq!(trace.get_bool(&addr!("bit", 0)), Some(true));
541 assert_eq!(trace.get_bool(&addr!("bit", 1)), Some(false));
542 assert_eq!(trace.get_bool(&addr!("bit", 2)), Some(true));
543 assert_eq!(trace.get_bool(&addr!("bit", 3)), Some(false));
544 assert_eq!(trace.get_bool(&addr!("bit", 4)), None);
545 }
546
547 #[test]
548 #[cfg(feature = "ppl")]
549 fn test_bit_string_from_trace() {
550 use crate::genome::trace_genome::TraceGenome;
551 let mut trace = Trace::default();
552 trace.insert_choice(addr!("bit", 0), ChoiceValue::Bool(true), 0.0);
553 trace.insert_choice(addr!("bit", 1), ChoiceValue::Bool(false), 0.0);
554 trace.insert_choice(addr!("bit", 2), ChoiceValue::Bool(true), 0.0);
555
556 let bs = BitString::from_trace(&trace).unwrap();
557 assert_eq!(bs.bits(), &[true, false, true]);
558 }
559
560 #[test]
561 #[cfg(feature = "ppl")]
562 fn test_bit_string_trace_roundtrip() {
563 use crate::genome::trace_genome::TraceGenome;
564 let original = BitString::new(vec![true, false, true, true, false]);
565 let trace = original.to_trace();
566 let recovered = BitString::from_trace(&trace).unwrap();
567 assert_eq!(original, recovered);
568 }
569
570 #[test]
571 #[cfg(feature = "ppl")]
572 fn test_bit_string_from_trace_empty() {
573 use crate::genome::trace_genome::TraceGenome;
574 let trace = Trace::default();
575 let result = BitString::from_trace(&trace);
576 assert!(result.is_err());
577 }
578
579 #[test]
580 fn test_bit_string_try_hamming_distance_mismatch() {
581 let bs1 = BitString::new(vec![true, true]);
584 let bs2 = BitString::new(vec![true, true, true, true, true, true]);
585 assert!(matches!(
586 bs1.try_hamming_distance(&bs2),
587 Err(GenomeError::DimensionMismatch {
588 expected: 2,
589 actual: 6
590 })
591 ));
592 assert!(bs1.try_distance(&bs2).is_err());
593 }
594
595 #[test]
596 #[should_panic(expected = "Dimension mismatch")]
597 fn test_bit_string_distance_mismatch_panics() {
598 let bs1 = BitString::new(vec![true, true]);
600 let bs2 = BitString::new(vec![true, true, true, true, true, true]);
601 let _ = bs1.distance(&bs2);
602 }
603
604 #[test]
605 #[cfg(feature = "ppl")]
606 fn test_bit_string_from_trace_type_mismatch() {
607 use crate::genome::trace_genome::TraceGenome;
610 let mut trace = Trace::default();
611 trace.insert_choice(addr!("bit", 0), ChoiceValue::Bool(true), 0.0);
612 trace.insert_choice(addr!("bit", 1), ChoiceValue::F64(1.0), 0.0); trace.insert_choice(addr!("bit", 2), ChoiceValue::Bool(false), 0.0);
614
615 match BitString::from_trace(&trace) {
616 Err(GenomeError::TypeMismatch {
617 address,
618 expected,
619 actual,
620 }) => {
621 assert_eq!(address, "bit#1");
622 assert_eq!(expected, "bool");
623 assert_eq!(actual, "f64");
624 }
625 other => panic!("expected TypeMismatch, got {other:?}"),
626 }
627 }
628
629 #[test]
630 fn test_bit_string_generate_with_len() {
631 let mut rng = rand::thread_rng();
633 let bs = BitString::generate_with_len(&mut rng, 7);
634 assert_eq!(bs.len(), 7);
635 }
636}