derangement/derange.rs
1use std::ops::Index;
2use rand::Rng;
3use rand::seq::SliceRandom;
4use std::fmt::{Display, Formatter};
5use std::fmt;
6use serde::{Serialize, Deserialize};
7use std::convert::TryFrom;
8
9/// Enum encapsulating errors produced in the module.
10#[derive(Debug, Clone)]
11pub enum ErrorKind {
12 /// Error returned by the [`Derange::apply`] method.
13 /// Returned if the size of the `source`, `destination` and the derangement itself are not all equal.
14 /// Contains the source size, destination size and the derangement size.
15 SizeMismatch(usize, usize, usize),
16
17 /// Error returned by the [`Derange::try_from`] method.
18 /// Returned if the slice does not constitute a valid permutation.
19 /// Contains the offending value.
20 BadPermutation(usize),
21
22 /// Error returned by the [`Derange::try_from`] method.
23 /// Returned if the slice contains a fixed point.
24 /// Index of the fixed point.
25 FixedPoint(usize),
26}
27
28
29/// A special [`std::result::Result`] by the module.
30/// See [`ErrorKind`] for more information.
31///
32/// ['Result']: std::result::Result
33/// ['Derange::ErrorKind']: crate::derangement::derange::ErrorKind
34pub type Result<T> = std::result::Result<T, ErrorKind>;
35
36/// The struct representing the derangement.
37#[derive(Eq, PartialEq, Debug, Clone, Serialize, Deserialize)]
38pub struct Derange {
39 _map: Vec<usize>,
40}
41
42impl Derange {
43
44 /// Generate a random derangement with an order of `size`.
45 pub fn new<R: Rng + ?Sized>(rng: & mut R, size: usize) -> Self {
46
47 let mut permutation = Vec::with_capacity(size);
48 let mut derangement = Vec::with_capacity(size);
49
50 // Fill the permutation with 0..STATE_SIZE
51 for i in 0..size {
52 permutation.push(i);
53 derangement.push(0);
54 }
55
56 //Shuffle the permutation
57 permutation.shuffle( rng);
58
59 //Get a slice representing the remaining elements to partition
60 let mut remaining = &permutation[..];
61
62 // Randomly partition and convert from cyclic to permutation notation
63 while remaining.len() != 0 {
64
65 //If there are only 2 elements left, the partition size MUST be 2. Otherwise randomly get the partition size
66 let mut partition_size = if remaining.len() == 2
67 {
68 2
69 }
70 else {
71 rng.gen_range(2..=remaining.len()-1)
72 };
73
74 //Turn remaining.len()-1 into remaining.len() since remaining.len()-1 cannot be a partition size (it would introduce a fixed point)
75 if partition_size == remaining.len()-1 { //Special case
76 partition_size = remaining.len();
77 }
78
79 //Get a slice representing the partition
80 let partition = &remaining[..partition_size];
81
82 //Iterate over the partiton, treating it as a cycle and converting it into standard form
83 for (i, element) in partition.iter().enumerate() {
84 derangement[*element] = partition[(i+1) % partition_size];
85 }
86
87 //Move the slice forward
88 remaining = &remaining[partition_size..];
89 }
90
91 Derange {
92 _map: derangement,
93 }
94 }
95
96 ///Returns `Some` with the value that `i` maps to.
97 ///
98 /// Otherwise returns `None` if `i >= size`.
99 pub fn get(&self, i: usize) -> Option<&usize> {
100 self._map.get(i)
101 }
102
103 ///Get the inverse of this derangement as a new object.
104 pub fn inverse(&self) -> Derange {
105
106 let mut inverse = Vec::with_capacity(self._map.len());
107
108 for _ in 0..self._map.len() {
109 inverse.push(0);
110 }
111
112 for (i, val) in self._map.iter().enumerate() {
113 inverse[*val] = i;
114 }
115
116 Derange {
117 _map: inverse,
118 }
119 }
120
121 ///The underlying vector map as a slice. The map is represented by mapping `n` to the `n`th element.
122 ///
123 /// For example the derangement where 0 maps to 1, 1 maps to 2 and 2 maps to 0 would be represented with the array `[1, 2, 0]`
124 pub fn map(&self) -> &[usize] {
125 self._map.as_slice()
126 }
127
128 /// Apply the derangement to `source` and clone it into `destination`.
129 ///
130 /// If the apply succeeds, then a `Ok(())` is returned, and the permutation is applied to the destination slice. Otherwise an `Err(ErrorKind)` is returned and the destination slice is left alone.
131 pub fn apply<T: Clone>(&self, source: &[T], destination: & mut [T]) -> Result<()> {
132
133 if source.len() != destination.len() && source.len() != self._map.len() {
134 return Result::Err(ErrorKind::SizeMismatch(source.len(), destination.len(), self._map.len()));
135 }
136
137 for (index, obj) in self._map.iter().zip(destination.iter_mut()) {
138 *obj = source[*index].clone();
139 }
140
141 Ok(())
142
143 }
144
145
146}
147
148impl Index<usize> for Derange {
149 type Output = usize;
150
151 fn index(&self, index: usize) -> &Self::Output {
152 self.get(index).unwrap()
153 }
154}
155
156impl TryFrom<&[usize]> for Derange {
157 type Error = ErrorKind;
158
159 ///Attempts to convert a slice of indices into a derangement.
160 ///
161 /// The slice must represent a permutation with no fixed points, or the conversion will fail.
162 fn try_from(value: &[usize]) -> Result<Self> {
163
164 let mut clone = Vec::from(value);
165
166 clone.sort();
167
168 for (i, (original, cloned)) in value.iter().zip(clone.iter()).enumerate() {
169 if i != *cloned {
170 return Result::Err(ErrorKind::BadPermutation(*cloned));
171 }
172
173 if i == *original {
174 return Result::Err(ErrorKind::FixedPoint(i))
175 }
176
177
178 }
179
180 Ok(Derange {
181 _map: Vec::from(value)
182 })
183
184 }
185}
186
187impl Display for Derange {
188
189 ///Formats the derangement as a permutation in cyclic form.
190 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
191
192 let mut checklist: Vec<_> = (0..self._map.len()).map(|_| false ).collect();
193
194 loop {
195 match checklist.iter().position(|x| *x == false) {
196 Some(start) => {
197 let mut next = start;
198
199 f.write_str("(")?;
200
201 loop {
202 write!(f, "{}", next)?;
203
204 checklist[next] = true;
205
206 next = self._map[next];
207
208 if next == start {
209 f.write_str(")")?;
210 break;
211 }
212
213 f.write_str(" ")?;
214 }
215 }
216 None => {
217 break;
218 }
219 }
220 }
221
222 fmt::Result::Ok(())
223
224 }
225}