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}