1#[cfg(feature = "ppl")]
7use fugue::{addr, ChoiceValue, Trace};
8use rand::seq::SliceRandom;
9use rand::Rng;
10use serde::{Deserialize, Serialize};
11
12use crate::error::GenomeError;
13use crate::genome::bounds::MultiBounds;
14use crate::genome::traits::{EvolutionaryGenome, PermutationGenome};
15
16#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
24pub struct Permutation {
25 perm: Vec<usize>,
27}
28
29impl Permutation {
30 pub fn new(perm: Vec<usize>) -> Self {
35 let result = Self { perm };
36 assert!(
37 result.is_valid_permutation(),
38 "Input must be a valid permutation of 0..n"
39 );
40 result
41 }
42
43 pub fn from_vec_unchecked(perm: Vec<usize>) -> Self {
60 let result = Self { perm };
61 debug_assert!(
62 result.is_valid_permutation(),
63 "from_vec_unchecked called with a vector that is not a valid permutation of 0..n"
64 );
65 result
66 }
67
68 pub fn try_new(perm: Vec<usize>) -> Result<Self, GenomeError> {
70 let result = Self { perm };
71 if result.is_valid_permutation() {
72 Ok(result)
73 } else {
74 Err(GenomeError::InvalidStructure(
75 "Input is not a valid permutation of 0..n".to_string(),
76 ))
77 }
78 }
79
80 pub fn identity(n: usize) -> Self {
82 Self {
83 perm: (0..n).collect(),
84 }
85 }
86
87 pub fn random<R: Rng>(n: usize, rng: &mut R) -> Self {
89 let mut perm: Vec<usize> = (0..n).collect();
90 perm.shuffle(rng);
91 Self { perm }
92 }
93
94 pub fn generate_with_len<R: Rng>(rng: &mut R, len: usize) -> Self {
101 Self::random(len, rng)
102 }
103
104 pub fn len(&self) -> usize {
106 self.perm.len()
107 }
108
109 pub fn is_empty(&self) -> bool {
111 self.perm.is_empty()
112 }
113
114 pub fn get(&self, i: usize) -> Option<usize> {
116 self.perm.get(i).copied()
117 }
118
119 pub fn inverse(&self) -> Self {
123 let n = self.perm.len();
124 let mut inv = vec![0; n];
125 for (i, &j) in self.perm.iter().enumerate() {
126 inv[j] = i;
127 }
128 Self { perm: inv }
129 }
130
131 pub fn compose(&self, other: &Self) -> Result<Self, GenomeError> {
135 if self.perm.len() != other.perm.len() {
136 return Err(GenomeError::DimensionMismatch {
137 expected: self.perm.len(),
138 actual: other.perm.len(),
139 });
140 }
141 let composed: Vec<usize> = self.perm.iter().map(|&i| other.perm[i]).collect();
142 Ok(Self { perm: composed })
143 }
144
145 pub fn swap(&mut self, i: usize, j: usize) {
147 self.perm.swap(i, j);
148 }
149
150 pub fn reverse_segment(&mut self, start: usize, end: usize) {
152 if start < end && end < self.perm.len() {
153 self.perm[start..=end].reverse();
154 }
155 }
156
157 pub fn insert(&mut self, from: usize, to: usize) {
159 if from == to || from >= self.perm.len() || to >= self.perm.len() {
160 return;
161 }
162 let elem = self.perm.remove(from);
163 self.perm.insert(to, elem);
164 }
165
166 pub fn inversions(&self) -> usize {
171 let n = self.perm.len();
172 let mut count = 0;
173 for i in 0..n {
174 for j in (i + 1)..n {
175 if self.perm[i] > self.perm[j] {
176 count += 1;
177 }
178 }
179 }
180 count
181 }
182
183 pub fn kendall_tau_distance(&self, other: &Self) -> Result<usize, GenomeError> {
188 if self.perm.len() != other.perm.len() {
189 return Err(GenomeError::DimensionMismatch {
190 expected: self.perm.len(),
191 actual: other.perm.len(),
192 });
193 }
194
195 let other_inv = other.inverse();
197 let composed = self.compose(&other_inv)?;
198
199 Ok(composed.inversions())
201 }
202
203 pub fn is_cyclic(&self) -> bool {
205 if self.perm.is_empty() {
206 return true;
207 }
208
209 let n = self.perm.len();
210 let mut visited = vec![false; n];
211 let mut current = 0;
212 let mut cycle_len = 0;
213
214 while !visited[current] {
215 visited[current] = true;
216 current = self.perm[current];
217 cycle_len += 1;
218 }
219
220 cycle_len == n && current == 0
221 }
222
223 pub fn into_inner(self) -> Vec<usize> {
225 self.perm
226 }
227
228 pub fn as_slice(&self) -> &[usize] {
230 &self.perm
231 }
232}
233
234impl EvolutionaryGenome for Permutation {
235 type Allele = usize;
236 type Phenotype = Vec<usize>;
237
238 fn decode(&self) -> Self::Phenotype {
239 self.perm.clone()
240 }
241
242 fn dimension(&self) -> usize {
243 self.perm.len()
244 }
245
246 fn generate<R: Rng>(rng: &mut R, bounds: &MultiBounds) -> Self {
252 Self::generate_with_len(rng, bounds.dimension())
253 }
254
255 fn distance(&self, other: &Self) -> f64 {
256 self.try_distance(other).unwrap_or_else(|e| {
257 panic!("Permutation::distance: {e}; use try_distance for a fallible comparison")
258 })
259 }
260
261 fn try_distance(&self, other: &Self) -> Result<f64, GenomeError> {
262 self.kendall_tau_distance(other).map(|d| d as f64)
265 }
266}
267
268#[cfg(feature = "ppl")]
269impl crate::genome::trace_genome::TraceGenome for Permutation {
270 fn to_trace(&self) -> Trace {
281 let n = self.perm.len();
282 let mut available: Vec<usize> = (0..n).collect();
283 let mut trace = Trace::default();
284 for (i, &val) in self.perm.iter().enumerate() {
285 let rank = available
286 .iter()
287 .position(|&v| v == val)
288 .expect("Permutation invariant guarantees the value is available");
289 available.remove(rank);
290 trace.insert_choice(addr!("perm", i), ChoiceValue::Usize(rank), 0.0);
291 }
292 trace
293 }
294
295 fn from_trace(trace: &Trace) -> Result<Self, GenomeError> {
304 let mut ranks = Vec::new();
306 let mut i = 0;
307 loop {
308 match trace.choices.get(&addr!("perm", i)) {
309 None => break,
310 Some(choice) => match choice.value.as_usize() {
311 Some(rank) => {
312 ranks.push(rank);
313 i += 1;
314 }
315 None => {
316 return Err(GenomeError::TypeMismatch {
317 address: format!("perm#{i}"),
318 expected: "usize".to_string(),
319 actual: choice.value.type_name().to_string(),
320 });
321 }
322 },
323 }
324 }
325 if ranks.is_empty() {
326 return Err(GenomeError::InvalidStructure(
327 "No permutation found in trace".to_string(),
328 ));
329 }
330 let n = ranks.len();
332 let mut available: Vec<usize> = (0..n).collect();
333 let mut perm = Vec::with_capacity(n);
334 for (i, &rank) in ranks.iter().enumerate() {
335 if rank >= available.len() {
336 return Err(GenomeError::InvalidStructure(format!(
337 "Lehmer rank {rank} at perm#{i} out of range 0..{}",
338 available.len()
339 )));
340 }
341 perm.push(available.remove(rank));
342 }
343 Self::try_new(perm)
344 }
345
346 fn trace_prefix() -> &'static str {
347 "perm"
348 }
349}
350
351impl PermutationGenome for Permutation {
352 fn permutation(&self) -> &[usize] {
353 &self.perm
354 }
355
356 fn permutation_mut(&mut self) -> &mut [usize] {
357 &mut self.perm
358 }
359
360 fn from_permutation(perm: Vec<usize>) -> Result<Self, GenomeError> {
361 Self::try_new(perm)
362 }
363}
364
365impl std::ops::Index<usize> for Permutation {
366 type Output = usize;
367
368 fn index(&self, index: usize) -> &Self::Output {
369 &self.perm[index]
370 }
371}
372
373impl From<Vec<usize>> for Permutation {
374 fn from(perm: Vec<usize>) -> Self {
375 Self::new(perm)
376 }
377}
378
379impl From<Permutation> for Vec<usize> {
380 fn from(p: Permutation) -> Self {
381 p.perm
382 }
383}
384
385impl IntoIterator for Permutation {
386 type Item = usize;
387 type IntoIter = std::vec::IntoIter<usize>;
388
389 fn into_iter(self) -> Self::IntoIter {
390 self.perm.into_iter()
391 }
392}
393
394impl<'a> IntoIterator for &'a Permutation {
395 type Item = &'a usize;
396 type IntoIter = std::slice::Iter<'a, usize>;
397
398 fn into_iter(self) -> Self::IntoIter {
399 self.perm.iter()
400 }
401}
402
403#[cfg(test)]
404mod tests {
405 use super::*;
406 use crate::genome::traits::PermutationGenome;
407
408 #[test]
409 fn test_permutation_new() {
410 let p = Permutation::new(vec![2, 0, 1, 3]);
411 assert_eq!(p.len(), 4);
412 assert_eq!(p[0], 2);
413 assert_eq!(p[1], 0);
414 }
415
416 #[test]
417 #[should_panic(expected = "valid permutation")]
418 fn test_permutation_new_invalid_duplicate() {
419 Permutation::new(vec![0, 1, 1, 3]);
420 }
421
422 #[test]
423 #[should_panic(expected = "valid permutation")]
424 fn test_permutation_new_invalid_out_of_range() {
425 Permutation::new(vec![0, 1, 5, 3]);
426 }
427
428 #[test]
429 fn test_permutation_try_new() {
430 assert!(Permutation::try_new(vec![2, 0, 1, 3]).is_ok());
431 assert!(Permutation::try_new(vec![0, 1, 1, 3]).is_err());
432 }
433
434 #[test]
435 fn test_permutation_identity() {
436 let p = Permutation::identity(5);
437 assert_eq!(p.as_slice(), &[0, 1, 2, 3, 4]);
438 }
439
440 #[test]
441 fn test_permutation_random() {
442 let mut rng = rand::thread_rng();
443 let p = Permutation::random(10, &mut rng);
444 assert!(p.is_valid_permutation());
445 assert_eq!(p.len(), 10);
446 }
447
448 #[test]
449 fn test_permutation_inverse() {
450 let p = Permutation::new(vec![2, 0, 3, 1]);
451 let inv = p.inverse();
452 assert_eq!(inv.as_slice(), &[1, 3, 0, 2]);
455
456 let composed = p.compose(&inv).unwrap();
458 assert_eq!(composed.as_slice(), &[0, 1, 2, 3]);
459 }
460
461 #[test]
462 fn test_permutation_compose() {
463 let p1 = Permutation::new(vec![1, 2, 0]);
464 let p2 = Permutation::new(vec![2, 0, 1]);
465 let composed = p1.compose(&p2).unwrap();
466 assert_eq!(composed.as_slice(), &[0, 1, 2]);
469 }
470
471 #[test]
472 fn test_permutation_swap() {
473 let mut p = Permutation::new(vec![0, 1, 2, 3]);
474 p.swap(0, 3);
475 assert_eq!(p.as_slice(), &[3, 1, 2, 0]);
476 }
477
478 #[test]
479 fn test_permutation_reverse_segment() {
480 let mut p = Permutation::new(vec![0, 1, 2, 3, 4]);
481 p.reverse_segment(1, 3);
482 assert_eq!(p.as_slice(), &[0, 3, 2, 1, 4]);
483 }
484
485 #[test]
486 fn test_permutation_insert() {
487 let mut p = Permutation::new(vec![0, 1, 2, 3, 4]);
488 p.insert(1, 4);
489 assert_eq!(p.as_slice(), &[0, 2, 3, 4, 1]);
490 }
491
492 #[test]
493 fn test_permutation_inversions() {
494 let p1 = Permutation::identity(5);
496 assert_eq!(p1.inversions(), 0);
497
498 let p2 = Permutation::new(vec![4, 3, 2, 1, 0]);
500 assert_eq!(p2.inversions(), 10); let p3 = Permutation::new(vec![1, 0, 2, 3, 4]);
504 assert_eq!(p3.inversions(), 1);
505 }
506
507 #[test]
508 fn test_permutation_kendall_tau() {
509 let p1 = Permutation::new(vec![0, 1, 2, 3]);
510 let p2 = Permutation::new(vec![0, 1, 2, 3]);
511 assert_eq!(p1.kendall_tau_distance(&p2).unwrap(), 0);
512
513 let p3 = Permutation::new(vec![0, 1, 3, 2]);
514 assert_eq!(p1.kendall_tau_distance(&p3).unwrap(), 1);
515
516 let p4 = Permutation::new(vec![3, 2, 1, 0]);
517 assert_eq!(p1.kendall_tau_distance(&p4).unwrap(), 6);
518 }
519
520 #[test]
521 fn test_permutation_is_cyclic() {
522 let cyclic = Permutation::new(vec![3, 2, 0, 1]);
524 assert!(cyclic.is_cyclic());
526
527 let identity = Permutation::identity(4);
529 assert!(!identity.is_cyclic()); let empty = Permutation::identity(0);
533 assert!(empty.is_cyclic());
534 }
535
536 #[test]
537 fn test_permutation_decode() {
538 let p = Permutation::new(vec![2, 0, 1]);
539 assert_eq!(p.decode(), vec![2, 0, 1]);
540 }
541
542 #[test]
543 fn test_permutation_dimension() {
544 let p = Permutation::new(vec![2, 0, 1, 3, 4]);
545 assert_eq!(p.dimension(), 5);
546 }
547
548 #[test]
549 fn test_permutation_generate() {
550 let mut rng = rand::thread_rng();
551 let bounds = MultiBounds::symmetric(1.0, 10);
552 let p = Permutation::generate(&mut rng, &bounds);
553 assert_eq!(p.dimension(), 10);
554 assert!(p.is_valid_permutation());
555 }
556
557 #[test]
558 fn test_permutation_distance() {
559 let p1 = Permutation::new(vec![0, 1, 2, 3]);
560 let p2 = Permutation::new(vec![3, 2, 1, 0]);
561 assert_eq!(p1.distance(&p2), 6.0);
562 }
563
564 #[test]
565 #[cfg(feature = "ppl")]
566 fn test_permutation_to_trace() {
567 use crate::genome::trace_genome::TraceGenome;
568 let p = Permutation::new(vec![2, 0, 1]);
569 let trace = p.to_trace();
570
571 assert_eq!(trace.get_usize(&addr!("perm", 0)), Some(2));
573 assert_eq!(trace.get_usize(&addr!("perm", 1)), Some(0));
574 assert_eq!(trace.get_usize(&addr!("perm", 2)), Some(0));
575 assert_eq!(trace.get_usize(&addr!("perm", 3)), None);
576 }
577
578 #[test]
579 #[cfg(feature = "ppl")]
580 fn test_permutation_from_trace() {
581 use crate::genome::trace_genome::TraceGenome;
582 let mut trace = Trace::default();
583 trace.insert_choice(addr!("perm", 0), ChoiceValue::Usize(1), 0.0);
585 trace.insert_choice(addr!("perm", 1), ChoiceValue::Usize(1), 0.0);
586 trace.insert_choice(addr!("perm", 2), ChoiceValue::Usize(0), 0.0);
587
588 let p = Permutation::from_trace(&trace).unwrap();
589 assert_eq!(p.as_slice(), &[1, 2, 0]);
590 }
591
592 #[test]
593 #[cfg(feature = "ppl")]
594 fn test_permutation_trace_roundtrip() {
595 use crate::genome::trace_genome::TraceGenome;
596 let original = Permutation::new(vec![4, 2, 0, 3, 1]);
597 let trace = original.to_trace();
598 let recovered = Permutation::from_trace(&trace).unwrap();
599 assert_eq!(original, recovered);
600 }
601
602 #[test]
603 #[cfg(feature = "ppl")]
604 fn test_permutation_from_trace_invalid() {
605 use crate::genome::trace_genome::TraceGenome;
606 let mut trace = Trace::default();
607 trace.insert_choice(addr!("perm", 0), ChoiceValue::Usize(0), 0.0);
608 trace.insert_choice(addr!("perm", 1), ChoiceValue::Usize(5), 0.0); let result = Permutation::from_trace(&trace);
611 assert!(result.is_err());
612 }
613
614 #[test]
615 #[cfg(feature = "ppl")]
616 fn test_permutation_from_trace_empty() {
617 use crate::genome::trace_genome::TraceGenome;
618 let trace = Trace::default();
619 let result = Permutation::from_trace(&trace);
620 assert!(result.is_err());
621 }
622
623 #[test]
624 fn test_permutation_serialization() {
625 let p = Permutation::new(vec![2, 0, 1, 3]);
626 let serialized = serde_json::to_string(&p).unwrap();
627 let deserialized: Permutation = serde_json::from_str(&serialized).unwrap();
628 assert_eq!(p, deserialized);
629 }
630
631 #[test]
632 fn test_permutation_iteration() {
633 let p = Permutation::new(vec![2, 0, 1]);
634 let collected: Vec<usize> = p.into_iter().collect();
635 assert_eq!(collected, vec![2, 0, 1]);
636 }
637
638 #[test]
639 fn test_permutation_ref_iteration() {
640 let p = Permutation::new(vec![2, 0, 1]);
641 let sum: usize = p.into_iter().sum();
642 assert_eq!(sum, 3);
643 }
644
645 #[test]
646 fn test_permutation_into_inner() {
647 let p = Permutation::new(vec![2, 0, 1]);
648 let v: Vec<usize> = p.into_inner();
649 assert_eq!(v, vec![2, 0, 1]);
650 }
651
652 #[test]
653 fn test_permutation_from_vec() {
654 let p: Permutation = vec![1, 0, 2].into();
655 assert_eq!(p.as_slice(), &[1, 0, 2]);
656 }
657
658 #[test]
659 fn test_permutation_try_distance_length_mismatch() {
660 let p1 = Permutation::identity(3);
663 let p2 = Permutation::identity(5);
664 assert!(matches!(
665 p1.try_distance(&p2),
666 Err(GenomeError::DimensionMismatch {
667 expected: 3,
668 actual: 5
669 })
670 ));
671 }
672
673 #[test]
674 #[should_panic(expected = "Dimension mismatch")]
675 fn test_permutation_distance_length_mismatch_panics() {
676 let p1 = Permutation::identity(3);
679 let p2 = Permutation::identity(5);
680 let _ = p1.distance(&p2);
681 }
682
683 #[test]
684 #[cfg(feature = "ppl")]
685 fn test_permutation_from_trace_type_mismatch() {
686 use crate::genome::trace_genome::TraceGenome;
690 let mut trace = Trace::default();
691 trace.insert_choice(addr!("perm", 0), ChoiceValue::Usize(2), 0.0);
692 trace.insert_choice(addr!("perm", 1), ChoiceValue::Bool(true), 0.0); trace.insert_choice(addr!("perm", 2), ChoiceValue::Usize(0), 0.0);
694
695 match Permutation::from_trace(&trace) {
696 Err(GenomeError::TypeMismatch {
697 address,
698 expected,
699 actual,
700 }) => {
701 assert_eq!(address, "perm#1");
702 assert_eq!(expected, "usize");
703 assert_eq!(actual, "bool");
704 }
705 other => panic!("expected TypeMismatch, got {other:?}"),
706 }
707 }
708
709 #[test]
710 fn test_permutation_from_vec_unchecked_debug_asserts() {
711 let p = Permutation::from_vec_unchecked(vec![2, 0, 1]);
714 assert!(p.is_valid_permutation());
715 }
716
717 #[test]
718 #[cfg(debug_assertions)]
719 #[should_panic(expected = "not a valid permutation")]
720 fn test_permutation_from_vec_unchecked_rejects_invalid_in_debug() {
721 let _ = Permutation::from_vec_unchecked(vec![0, 0, 2]);
723 }
724
725 #[test]
726 fn test_permutation_generate_with_len() {
727 let mut rng = rand::thread_rng();
729 let p = Permutation::generate_with_len(&mut rng, 8);
730 assert_eq!(p.len(), 8);
731 assert!(p.is_valid_permutation());
732 }
733}