rulinalg/matrix/
permutation_matrix.rs

1use std;
2
3use matrix::{Matrix, BaseMatrix, BaseMatrixMut};
4use vector::Vector;
5use error::{Error, ErrorKind};
6
7use libnum::Num;
8
9/// An efficient implementation of a permutation matrix.
10///
11/// # Examples
12/// ```
13/// # #[macro_use] extern crate rulinalg; fn main() {
14/// use rulinalg::matrix::PermutationMatrix;
15///
16/// let ref x = matrix![1, 2, 3;
17///                     4, 5, 6;
18///                     7, 8, 9];
19///
20/// // Swap the two first rows of x by left-multiplying a permutation matrix
21/// let expected = matrix![4, 5, 6;
22///                        1, 2, 3;
23///                        7, 8, 9];
24/// let mut p = PermutationMatrix::identity(3);
25/// p.swap_rows(0, 1);
26/// assert_eq!(expected, p * x);
27///
28/// // Swap the two last columns of x by right-multiplying a permutation matrix
29/// let expected = matrix![1, 3, 2;
30///                        4, 6, 5;
31///                        7, 9, 8];
32/// let mut p = PermutationMatrix::identity(3);
33/// p.swap_rows(1, 2);
34/// assert_eq!(expected, x * p);
35///
36/// // One can also construct the same permutation matrix directly
37/// // from an array representation.
38/// let ref p = PermutationMatrix::from_array(vec![0, 2, 1]).unwrap();
39/// assert_eq!(expected, x * p);
40///
41/// // One may also obtain a full matrix representation of the permutation
42/// assert_eq!(p.as_matrix(), matrix![1, 0, 0;
43///                                   0, 0, 1;
44///                                   0, 1, 0]);
45///
46/// // The inverse of a permutation matrix can efficiently be obtained
47/// let p_inv = p.inverse();
48///
49/// // And permutations can be composed through multiplication
50/// assert_eq!(p * p_inv, PermutationMatrix::identity(3));
51/// # }
52/// ```
53///
54/// # Rationale and complexity
55///
56/// A [permutation matrix](https://en.wikipedia.org/wiki/Permutation_matrix)
57/// is a very special kind of matrix. It is essentially a matrix representation
58/// of the more general concept of a permutation. That is, an `n` x `n` permutation
59/// matrix corresponds to a permutation of ordered sets whose cardinality is `n`.
60/// In particular, given an `m` x `n` matrix `A` and an `m` x `m` permutation
61/// matrix `P`, the action of left-multiplying `A` by `P`, `PA`, corresponds
62/// to permuting the rows of `A` by the given permutation represented by `P`.
63/// Conversely, right-multiplication corresponds to column permutation.
64/// More precisely, given another permutation matrix `Q` of size `n` x `n`,
65/// then `AQ` is the corresponding permutation of the columns of `A`.
66///
67/// Due to their unique structure, permutation matrices can be much more
68/// efficiently represented and applied than general matrices. Recall that
69/// for general matrices `X` and `Y` of size `m` x `m` and `n` x `n` respectively,
70/// the storage of `X` requires O(`m`<sup>2</sup>) memory and the storage of
71/// `Y` requires O(`n`<sup>2</sup>) memory. Ignoring for the moment the existence
72/// of Strassen's matrix multiplication algorithm and more theoretical alternatives,
73/// the multiplication `XA` requires O(`m`<sup>2</sup>`n`) operations, and
74/// the multiplication `AY` requires O(`m``n`<sup>2</sup>) operations.
75///
76/// By contrast, the storage of `P` requires only O(`m`) memory, and
77/// the storage of `K` requires O(`n`) memory. Moreover, the products
78/// `PA` and `AK` both require merely O(`mn`) operations.
79///
80/// # Representation
81/// A permutation of an ordered set of cardinality *n* is a map of the form
82///
83/// ```text
84/// p: { 1, ..., n } -> { 1, ..., n }.
85/// ```
86///
87/// That is, for any index `i`, the permutation `p` sends `i` to some
88/// index `j = p(i)`, and hence the map may be represented as an array of integers
89/// of length *n*.
90///
91/// By convention, an instance of `PermutationMatrix` represents row permutations.
92/// That is, the indices referred to above correspond to *row indices*,
93/// and the internal representation of a `PermutationMatrix` is an array
94/// describing how the permutation sends a row index `i` to a new row index
95/// `j` in the permuted matrix. Because of this internal representation, one can only
96/// efficiently swap *rows* of a `PermutationMatrix`.
97/// However, keep in mind that while this API only lets one swap individual rows
98/// of the permutation matrix itself, the right-multiplication of a general
99/// matrix with a permutation matrix will permute the columns of the general matrix,
100/// and so in practice this restriction is insignificant.
101///
102#[derive(Debug, PartialEq, Eq, Clone)]
103pub struct PermutationMatrix<T> {
104    // A permutation matrix of dimensions NxN is represented as a permutation of the rows
105    // of an NxM matrix for any M.
106    perm: Vec<usize>,
107
108    // Currently, we need to let PermutationMatrix be generic over T,
109    // because BaseMatrixMut is.
110    marker: std::marker::PhantomData<T>
111}
112
113/// Parity is the fact of being even or odd.
114#[derive(Debug, Copy, Clone, PartialEq, Eq)]
115pub enum Parity {
116    /// Even parity.
117    Even,
118    /// Odd parity.
119    Odd
120}
121
122impl<T> PermutationMatrix<T> {
123    /// The identity permutation.
124    pub fn identity(n: usize) -> Self {
125        PermutationMatrix {
126            perm: (0 .. n).collect(),
127            marker: std::marker::PhantomData
128        }
129    }
130
131    /// Swaps rows i and j in the permutation matrix.
132    pub fn swap_rows(&mut self, i: usize, j: usize) {
133        self.perm.swap(i, j);
134    }
135
136    /// The inverse of the permutation matrix.
137    pub fn inverse(&self) -> PermutationMatrix<T> {
138        let mut inv: Vec<usize> = vec![0; self.size()];
139
140        for (source, target) in self.perm.iter().cloned().enumerate() {
141            inv[target] = source;
142        }
143
144        PermutationMatrix {
145            perm: inv,
146            marker: std::marker::PhantomData
147        }
148    }
149
150    /// The size of the permutation matrix.
151    ///
152    /// A permutation matrix is a square matrix, so `size()` is equal
153    /// to both the number of rows, as well as the number of columns.
154    pub fn size(&self) -> usize {
155        self.perm.len()
156    }
157
158    /// Constructs a `PermutationMatrix` from an array.
159    ///
160    /// # Errors
161    /// The supplied N-length array must satisfy the following:
162    ///
163    /// - Each element must be in the half-open range [0, N).
164    /// - Each element must be unique.
165    pub fn from_array<A: Into<Vec<usize>>>(array: A) -> Result<PermutationMatrix<T>, Error> {
166        let p = PermutationMatrix {
167            perm: array.into(),
168            marker: std::marker::PhantomData
169        };
170        validate_permutation(&p.perm).map(|_| p)
171    }
172
173    /// Constructs a `PermutationMatrix` from an array, without checking the validity of
174    /// the supplied permutation.
175    ///
176    /// # Safety
177    /// The supplied N-length array must satisfy the following:
178    ///
179    /// - Each element must be in the half-open range [0, N).
180    /// - Each element must be unique.
181    ///
182    /// Note that while this function *itself* is technically safe
183    /// regardless of the input array, passing an incorrect permutation matrix
184    /// may cause undefined behavior in other methods of `PermutationMatrix`.
185    /// As such, it may be difficult to debug. The user is strongly
186    /// encouraged to use the safe function `from_array`, which for
187    /// most real world applications only incurs a minor
188    /// or even insignificant performance hit as a result of the
189    /// extra validation.
190    pub unsafe fn from_array_unchecked<A: Into<Vec<usize>>>(array: A) -> PermutationMatrix<T> {
191        let p = PermutationMatrix {
192            perm: array.into(),
193            marker: std::marker::PhantomData
194        };
195        p
196    }
197
198    /// Maps the given row index into the resulting row index in the permuted matrix.
199    ///
200    /// More specifically, if the permutation sends row `i` to `j`, then
201    /// `map_row(i)` returns `j`.
202    ///
203    /// # Examples
204    ///
205    /// ```rust
206    /// use rulinalg::matrix::PermutationMatrix;
207    /// let mut p = PermutationMatrix::<u32>::identity(3);
208    /// p.swap_rows(1, 2);
209    /// assert_eq!(p.map_row(1), 2);
210    /// ```
211    pub fn map_row(&self, row_index: usize) -> usize {
212        self.perm[row_index]
213    }
214
215    /// Computes the parity of the permutation (even- or oddness).
216    pub fn parity(mut self) -> Parity {
217        // As it happens, permute_by_swap effectively decomposes
218        // each disjoint cycle in the permutation into a series
219        // of transpositions. The result is that the whole permutation
220        // is effectively decomposed into a series of
221        // transpositions.
222        // Hence, if we start out by assuming that the permutation
223        // is even and simply flip this variable every time a swap
224        // (transposition) is performed, we'll have the result by
225        // the end of the procedure.
226        let mut is_even = true;
227        permute_by_swap(&mut self.perm, |_, _| is_even = !is_even);
228
229        if is_even {
230            Parity::Even
231        } else {
232            Parity::Odd
233        }
234    }
235}
236
237impl<T: Num> PermutationMatrix<T> {
238    /// The permutation matrix in an equivalent full matrix representation.
239    pub fn as_matrix(&self) -> Matrix<T> {
240        Matrix::from_fn(self.size(), self.size(), |i, j|
241            if self.perm[i] == j {
242                T::one()
243            } else {
244                T::zero()
245            }
246        )
247    }
248
249    /// Computes the determinant of the permutation matrix.
250    ///
251    /// The determinant of a permutation matrix is always
252    /// +1 (if the permutation is even) or
253    /// -1 (if the permutation is odd).
254    pub fn det(self) -> T {
255        let parity = self.parity();
256        match parity {
257            Parity::Even => T::one(),
258            Parity::Odd  => T::zero() - T::one()
259        }
260    }
261}
262
263impl<T> PermutationMatrix<T> {
264    /// Permutes the rows of the given matrix in-place.
265    ///
266    /// # Panics
267    ///
268    /// - The number of rows in the matrix is not equal to
269    ///   the size of the permutation matrix.
270    pub fn permute_rows_in_place<M>(mut self, matrix: &mut M) where M: BaseMatrixMut<T> {
271        validate_permutation_left_mul_dimensions(&self, matrix);
272        permute_by_swap(&mut self.perm, |i, j| matrix.swap_rows(i, j));
273    }
274
275    /// Permutes the columns of the given matrix in-place.
276    ///
277    /// # Panics
278    ///
279    /// - The number of columns in the matrix is not equal to
280    ///   the size of the permutation matrix.
281    pub fn permute_cols_in_place<M>(mut self, matrix: &mut M) where M: BaseMatrixMut<T> {
282        validate_permutation_right_mul_dimensions(matrix, &self);
283        // Note: it _may_ be possible to increase cache efficiency
284        // of this routine by swapping elements in each row individually
285        // (since matrices are row major), but this would mean augmenting
286        // permute_by_swap in such a way that the original permutation can
287        // be recovered, which includes a little bit of additional work.
288        // Moreover, it would mean having to work with signed indices
289        // instead of unsigned (although temporarily casting would be sufficient),
290        // which may or may not complicate matters.
291        // For now, it was deemed significantly simpler and probably good enough
292        // to just swap whole columns instead.
293        permute_by_swap(&mut self.perm, |i, j| matrix.swap_cols(i, j));
294    }
295
296    /// Permutes the elements of the given vector in-place.
297    ///
298    /// # Panics
299    ///
300    /// - The size of the vector is not equal to the size of
301    ///   the permutation matrix.
302    pub fn permute_vector_in_place(mut self, vector: &mut Vector<T>) {
303        validate_permutation_vector_dimensions(&self, vector);
304        permute_by_swap(&mut self.perm, |i, j| vector.mut_data().swap(i, j));
305    }
306}
307
308impl<T: Clone> PermutationMatrix<T> {
309    /// Permutes the rows of the given `source_matrix` and stores the
310    /// result in `buffer`.
311    ///
312    /// # Panics
313    ///
314    /// - The number of rows in the source matrix is not equal to
315    ///   the size of the permutation matrix.
316    /// - The dimensions of the source matrix and the buffer
317    ///   are not identical.
318    pub fn permute_rows_into_buffer<X, Y>(&self, source_matrix: &X, buffer: &mut Y)
319        where X: BaseMatrix<T>, Y: BaseMatrixMut<T> {
320        assert!(source_matrix.rows() == buffer.rows()
321                && source_matrix.cols() == buffer.cols(),
322                "Source and target matrix must have equal dimensions.");
323        validate_permutation_left_mul_dimensions(self, source_matrix);
324        for (source_row, target_row_index) in source_matrix.row_iter()
325                                                           .zip(self.perm.iter()
326                                                                         .cloned()) {
327            buffer.row_mut(target_row_index)
328                  .raw_slice_mut()
329                  .clone_from_slice(source_row.raw_slice());
330        }
331    }
332
333    /// Permutes the columns of the given `source_matrix` and stores the
334    /// result in `buffer`.
335    ///
336    /// # Panics
337    ///
338    /// - The number of columns in the source matrix is not equal to
339    ///   the size of the permutation matrix.
340    /// - The dimensions of the source matrix and the buffer
341    ///   are not identical.
342    pub fn permute_cols_into_buffer<X, Y>(&self, source_matrix: &X, target_matrix: &mut Y)
343        where X: BaseMatrix<T>, Y: BaseMatrixMut<T> {
344        assert!(source_matrix.rows() == target_matrix.rows()
345                && source_matrix.cols() == target_matrix.cols(),
346                "Source and target matrix must have equal dimensions.");
347        validate_permutation_right_mul_dimensions(source_matrix, self);
348
349        // Permute columns in one row at a time for (presumably) better cache performance
350        for (row_index, source_row) in source_matrix.row_iter()
351                                                           .map(|r| r.raw_slice())
352                                                           .enumerate() {
353            let target_row = target_matrix.row_mut(row_index).raw_slice_mut();
354            for (source_element, target_col) in source_row.iter().zip(self.perm.iter().cloned()) {
355                target_row[target_col] = source_element.clone();
356            }
357        }
358    }
359
360    /// Permutes the elements of the given `source_vector` and stores the
361    /// result in `buffer`.
362    ///
363    /// # Panics
364    ///
365    /// - The size of the source vector is not equal to the
366    ///   size of the permutation matrix.
367    /// - The dimensions of the source vector and the buffer
368    ///   are not identical.
369    pub fn permute_vector_into_buffer(
370        &self,
371        source_vector: &Vector<T>,
372        buffer: &mut Vector<T>
373    ) {
374        assert!(source_vector.size() == buffer.size(),
375               "Source and target vector must have equal dimensions.");
376        validate_permutation_vector_dimensions(self, buffer);
377        for (source_element, target_index) in source_vector.data()
378                                                           .iter()
379                                                           .zip(self.perm.iter().cloned()) {
380            buffer[target_index] = source_element.clone();
381        }
382    }
383
384    /// Computes the composition of `self` with the given `source_perm`
385    /// and stores the result in `buffer`.
386    ///
387    /// # Panics
388    ///
389    /// - The size of the permutation matrix (self) is not equal to the
390    ///   size of the source permutation matrix.
391    pub fn compose_into_buffer(
392        &self,
393        source_perm: &PermutationMatrix<T>,
394        buffer: &mut PermutationMatrix<T>
395    ) {
396        assert!(source_perm.size() == buffer.size(),
397            "Source and target permutation matrix must have equal dimensions.");
398        let left = self;
399        let right = source_perm;
400        for i in 0 .. self.perm.len() {
401            buffer.perm[i] = left.perm[right.perm[i]];
402        }
403    }
404}
405
406impl<T> From<PermutationMatrix<T>> for Vec<usize> {
407    fn from(p: PermutationMatrix<T>) -> Vec<usize> {
408        p.perm
409    }
410}
411
412impl<'a, T> Into<&'a [usize]> for &'a PermutationMatrix<T> {
413    fn into(self) -> &'a [usize] {
414        &self.perm
415    }
416}
417
418fn validate_permutation_vector_dimensions<T>(p: &PermutationMatrix<T>, v: &Vector<T>) {
419    assert!(p.size() == v.size(),
420            "Permutation matrix and Vector dimensions are not compatible.");
421}
422
423
424fn validate_permutation_left_mul_dimensions<T, M>(p: &PermutationMatrix<T>, rhs: &M)
425    where M: BaseMatrix<T> {
426     assert!(p.size() == rhs.rows(),
427            "Permutation matrix and right-hand side matrix dimensions
428             are not compatible.");
429}
430
431fn validate_permutation_right_mul_dimensions<T, M>(lhs: &M, p: &PermutationMatrix<T>)
432    where M: BaseMatrix<T> {
433     assert!(lhs.cols() == p.size(),
434            "Left-hand side matrix and permutation matrix dimensions
435             are not compatible.");
436}
437
438fn validate_permutation(perm: &[usize]) -> Result<(), Error> {
439    // Recall that a permutation array of size n is valid if:
440    // 1. All elements are in the range [0, n)
441    // 2. All elements are unique
442
443    let n = perm.len();
444
445    // Here we use a vector of boolean. If memory usage or performance
446    // is ever an issue, we could replace the vector with a bit vector
447    // (from e.g. the bit-vec crate), which would cut memory usage
448    // to 1/8, and likely improve performance due to more data
449    // fitting in cache.
450    let mut visited = vec![false; n];
451    for p in perm.iter().cloned() {
452        if p < n {
453            visited[p] = true;
454        }
455        else {
456            return Err(Error::new(ErrorKind::InvalidPermutation,
457                "Supplied permutation array contains elements out of bounds."));
458        }
459    }
460    let all_unique = visited.iter().all(|x| x.clone());
461    if all_unique {
462        Ok(())
463    } else {
464        Err(Error::new(ErrorKind::InvalidPermutation,
465            "Supplied permutation array contains duplicate elements."))
466    }
467}
468
469/// Applies the permutation by swapping elements in an abstract
470/// container.
471///
472/// The permutation is applied by calls to `swap(i, j)` for indices
473/// `i` and `j`.
474///
475/// # Complexity
476///
477/// - O(1) memory usage.
478/// - O(n) worst case number of calls to `swap`.
479fn permute_by_swap<S>(perm: &mut [usize], mut swap: S) where S: FnMut(usize, usize) -> () {
480    // Please see https://en.wikipedia.org/wiki/Cyclic_permutation
481    // for some explanation to the terminology used here.
482    // Some useful resources I found on the internet:
483    //
484    // https://blog.merovius.de/2014/08/12/applying-permutation-in-constant.html
485    // http://stackoverflow.com/questions/16501424/algorithm-to-apply-permutation-in-constant-memory-space
486    //
487    // A fundamental property of permutations on finite sets is that
488    // any such permutation can be decomposed into a collection of
489    // cycles on disjoint orbits.
490    //
491    // An observation is thus that given a permutation P,
492    // we can trace out the cycle that includes index i
493    // by starting at i and moving to P[i] recursively.
494    for i in 0 .. perm.len() {
495        let mut target = perm[i];
496        while i != target {
497            // When resolving a cycle, we resolve each index in the cycle
498            // by repeatedly moving the current item into the target position,
499            // and item in the target position into the current position.
500            // By repeating this until we hit the start index,
501            // we effectively resolve the entire cycle.
502            let new_target = perm[target];
503            swap(i, target);
504            perm[target] = target;
505            target = new_target;
506        }
507        perm[i] = i;
508    }
509}
510
511#[cfg(test)]
512mod tests {
513    use matrix::Matrix;
514    use vector::Vector;
515    use super::{PermutationMatrix, Parity};
516    use super::{permute_by_swap, validate_permutation};
517
518    use itertools::Itertools;
519
520    #[test]
521    fn swap_rows() {
522        let mut p = PermutationMatrix::<u64>::identity(4);
523        p.swap_rows(0, 3);
524        p.swap_rows(1, 3);
525
526        let expected_permutation = PermutationMatrix::from_array(vec![3, 0, 2, 1]).unwrap();
527        assert_eq!(p, expected_permutation);
528    }
529
530    #[test]
531    fn as_matrix() {
532        let p = PermutationMatrix::from_array(vec![2, 1, 0, 3]).unwrap();
533        let expected_matrix: Matrix<u32> = matrix![0, 0, 1, 0;
534                                                   0, 1, 0, 0;
535                                                   1, 0, 0, 0;
536                                                   0, 0, 0, 1];
537
538        assert_matrix_eq!(expected_matrix, p.as_matrix());
539    }
540
541    #[test]
542    fn from_array() {
543        let array = vec![1, 0, 3, 2];
544        let p = PermutationMatrix::<u32>::from_array(array.clone()).unwrap();
545        let p_as_array: Vec<usize> = p.into();
546        assert_eq!(p_as_array, array);
547    }
548
549    #[test]
550    fn from_array_unchecked() {
551        let array = vec![1, 0, 3, 2];
552        let p = unsafe { PermutationMatrix::<u32>::from_array_unchecked(array.clone()) };
553        let p_as_array: Vec<usize> = p.into();
554        assert_eq!(p_as_array, array);
555    }
556
557    #[test]
558    fn from_array_invalid() {
559        assert!(PermutationMatrix::<u32>::from_array(vec![0, 1, 3]).is_err());
560        assert!(PermutationMatrix::<u32>::from_array(vec![0, 0]).is_err());
561        assert!(PermutationMatrix::<u32>::from_array(vec![3, 0, 1]).is_err());
562    }
563
564    #[test]
565    fn vec_from_permutation() {
566        let source_vec = vec![0, 2, 1];
567        let p = PermutationMatrix::<u32>::from_array(source_vec.clone()).unwrap();
568        let vec = Vec::from(p);
569        assert_eq!(&source_vec, &vec);
570    }
571
572    #[test]
573    fn into_slice_ref() {
574        let source_vec = vec![0, 2, 1];
575        let ref p = PermutationMatrix::<u32>::from_array(source_vec.clone()).unwrap();
576        let p_as_slice_ref: &[usize] = p.into();
577        assert_eq!(source_vec.as_slice(), p_as_slice_ref);
578    }
579
580    #[test]
581    fn map_row() {
582        let p = PermutationMatrix::<u32>::from_array(vec![0, 2, 1]).unwrap();
583        assert_eq!(p.map_row(0), 0);
584        assert_eq!(p.map_row(1), 2);
585        assert_eq!(p.map_row(2), 1);
586    }
587
588    #[test]
589    fn inverse() {
590        let p = PermutationMatrix::<u32>::from_array(vec![1, 2, 0]).unwrap();
591        let expected_inverse = PermutationMatrix::<u32>::from_array(vec![2, 0, 1]).unwrap();
592        assert_eq!(p.inverse(), expected_inverse);
593    }
594
595    #[test]
596    fn parity() {
597        {
598            let p = PermutationMatrix::<u32>::from_array(vec![1, 0, 3, 2]).unwrap();
599            assert_eq!(p.parity(), Parity::Even);
600        }
601
602        {
603            let p = PermutationMatrix::<u32>::from_array(vec![4, 2, 3, 1, 0, 5]).unwrap();
604            assert_eq!(p.parity(), Parity::Odd);
605        }
606    }
607
608    #[test]
609    fn det() {
610        {
611            let p = PermutationMatrix::<i32>::from_array(vec![1, 0, 3, 2]).unwrap();
612            assert_eq!(p.det(), 1);
613        }
614
615        {
616            let p = PermutationMatrix::<i32>::from_array(vec![4, 2, 3, 1, 0, 5]).unwrap();
617            assert_eq!(p.det(), -1);
618        }
619    }
620
621    #[test]
622    fn permute_by_swap_on_empty_array() {
623        let mut x = Vec::<char>::new();
624        let mut permutation_array = Vec::new();
625        permute_by_swap(&mut permutation_array, |i, j| x.swap(i, j));
626    }
627
628    #[test]
629    fn permute_by_swap_on_arbitrary_array() {
630        let mut x = vec!['a', 'b', 'c', 'd'];
631        let mut permutation_array = vec![0, 2, 3, 1];
632
633        permute_by_swap(&mut permutation_array, |i, j| x.swap(i, j));
634        assert_eq!(x, vec!['a', 'd', 'b', 'c']);
635    }
636
637    #[test]
638    fn permute_by_swap_identity_on_arbitrary_array() {
639        let mut x = vec!['a', 'b', 'c', 'd'];
640        let mut permutation_array = vec![0, 1, 2, 3];
641        permute_by_swap(&mut permutation_array, |i, j| x.swap(i, j));
642        assert_eq!(x, vec!['a', 'b', 'c', 'd']);
643    }
644
645    #[test]
646    fn compose_into_buffer() {
647        let p = PermutationMatrix::<u32>::from_array(vec![2, 1, 0]).unwrap();
648        let q = PermutationMatrix::<u32>::from_array(vec![1, 0, 2]).unwrap();
649        let pq_expected = PermutationMatrix::<u32>::from_array(vec![1, 2, 0]).unwrap();
650        let qp_expected = PermutationMatrix::<u32>::from_array(vec![2, 0, 1]).unwrap();
651
652        {
653            let mut pq = PermutationMatrix::identity(3);
654            p.compose_into_buffer(&q, &mut pq);
655            assert_eq!(pq, pq_expected);
656        }
657
658        {
659            let mut qp = PermutationMatrix::identity(3);
660            q.compose_into_buffer(&p, &mut qp);
661            assert_eq!(qp, qp_expected);
662        }
663    }
664
665    #[test]
666    fn compose_regression() {
667        // At some point during development, this example failed to
668        // give the expected results
669        let p = PermutationMatrix::<u32>::from_array(vec![1, 2, 0]).unwrap();
670        let q = PermutationMatrix::<u32>::from_array(vec![2, 0, 1]).unwrap();
671        let pq_expected = PermutationMatrix::<u32>::from_array(vec![0, 1, 2]).unwrap();
672
673        let mut pq = PermutationMatrix::identity(3);
674        p.compose_into_buffer(&q, &mut pq);
675        assert_eq!(pq, pq_expected);
676    }
677
678    #[test]
679    fn permute_rows_into_buffer() {
680        let x = matrix![ 0;
681                         1;
682                         2;
683                         3];
684        let p = PermutationMatrix::from_array(vec![2, 1, 3, 0]).unwrap();
685        let mut output = Matrix::zeros(4, 1);
686        p.permute_rows_into_buffer(&x, &mut output);
687        assert_matrix_eq!(output, matrix![ 3; 1; 0; 2]);
688    }
689
690    #[test]
691    fn permute_rows_in_place() {
692        let mut x = matrix![ 0;
693                         1;
694                         2;
695                         3];
696        let p = PermutationMatrix::from_array(vec![2, 1, 3, 0]).unwrap();
697        p.permute_rows_in_place(&mut x);
698        assert_matrix_eq!(x, matrix![ 3; 1; 0; 2]);
699    }
700
701    #[test]
702    fn permute_cols_into_buffer() {
703        let x = matrix![ 0, 1, 2, 3];
704        let p = PermutationMatrix::from_array(vec![2, 1, 3, 0]).unwrap();
705        let mut output = Matrix::zeros(1, 4);
706        p.permute_cols_into_buffer(&x, &mut output);
707        assert_matrix_eq!(output, matrix![ 3, 1, 0, 2]);
708    }
709
710    #[test]
711    fn permute_cols_in_place() {
712        let mut x = matrix![ 0, 1, 2, 3];
713        let p = PermutationMatrix::from_array(vec![2, 1, 3, 0]).unwrap();
714        p.permute_cols_in_place(&mut x);
715        assert_matrix_eq!(x, matrix![ 3, 1, 0, 2]);
716    }
717
718    #[test]
719    fn permute_vector_into_buffer() {
720        let x = vector![ 0, 1, 2, 3];
721        let p = PermutationMatrix::from_array(vec![2, 1, 3, 0]).unwrap();
722        let mut output = Vector::zeros(4);
723        p.permute_vector_into_buffer(&x, &mut output);
724        assert_vector_eq!(output, vector![ 3, 1, 0, 2]);
725    }
726
727    #[test]
728    fn permute_vector_in_place() {
729        let mut x = vector![ 0, 1, 2, 3];
730        let p = PermutationMatrix::from_array(vec![2, 1, 3, 0]).unwrap();
731        p.permute_vector_in_place(&mut x);
732        assert_vector_eq!(x, vector![ 3, 1, 0, 2]);
733    }
734
735    use quickcheck::{Arbitrary, Gen};
736
737    // In order to write property tests for the validation of a permutation,
738    // we need to be able to generate arbitrary (valid) permutations.
739    #[derive(Debug, Clone, PartialEq, Eq)]
740    struct ValidPermutationArray(pub Vec<usize>);
741
742    impl Arbitrary for ValidPermutationArray {
743        fn arbitrary<G: Gen>(g: &mut G) -> Self {
744            let upper_bound = g.size();
745            let mut array = (0 .. upper_bound).collect::<Vec<usize>>();
746            g.shuffle(&mut array);
747            ValidPermutationArray(array)
748        }
749    }
750
751    // We also want to be able to generate invalid permutations for
752    // the same reasons
753    #[derive(Debug, Clone, PartialEq, Eq)]
754    struct InvalidPermutationArray(pub Vec<usize>);
755
756    impl Arbitrary for InvalidPermutationArray {
757        fn arbitrary<G: Gen>(g: &mut G) -> Self {
758            // Take an arbitrary valid permutation and mutate it so that
759            // it is invalid
760            let mut permutation_array = ValidPermutationArray::arbitrary(g).0;
761            let n = permutation_array.len();
762
763            // There are two essential sources of invalidity:
764            // 1. Duplicate elements
765            // 2. Indices out of bounds
766            // We want to have either or both
767
768            let should_have_duplicates = g.gen::<bool>();
769            let should_have_out_of_bounds = !should_have_duplicates || g.gen::<bool>();
770            assert!(should_have_duplicates || should_have_out_of_bounds);
771
772            if should_have_out_of_bounds {
773                let num_out_of_bounds_rounds = g.gen_range::<usize>(1, n);
774                for _ in 0 .. num_out_of_bounds_rounds {
775                    let interior_index = g.gen_range::<usize>(0, n);
776                    let exterior_index = n + g.gen::<usize>();
777                    permutation_array[interior_index] = exterior_index;
778                }
779            }
780
781            if should_have_duplicates {
782                let num_duplicates = g.gen_range::<usize>(1, n);
783                for _ in 0 .. num_duplicates {
784                    let interior_index = g.gen_range::<usize>(0, n);
785                    let duplicate_value = permutation_array[interior_index];
786                    permutation_array.push(duplicate_value);
787                }
788            }
789
790            // The duplicates are placed at the end, so we perform
791            // an additional shuffle to end up with a more or less
792            // arbitrary invalid permutation
793            g.shuffle(&mut permutation_array);
794            InvalidPermutationArray(permutation_array)
795        }
796    }
797
798    impl<T: Send + Clone + 'static> Arbitrary for PermutationMatrix<T> {
799        fn arbitrary<G: Gen>(g: &mut G) -> Self {
800            let ValidPermutationArray(array) = ValidPermutationArray::arbitrary(g);
801            PermutationMatrix::from_array(array)
802                .expect("The generated permutation array should always be valid.")
803        }
804    }
805
806    quickcheck! {
807        fn property_validate_permutation_is_ok_for_valid_input(array: ValidPermutationArray) -> bool {
808            validate_permutation(&array.0).is_ok()
809        }
810    }
811
812    quickcheck! {
813        fn property_validate_permutation_is_err_for_invalid_input(array: InvalidPermutationArray) -> bool {
814            validate_permutation(&array.0).is_err()
815        }
816    }
817
818    quickcheck! {
819        fn property_identity_has_identity_array(size: usize) -> bool {
820            let p = PermutationMatrix::<u64>::identity(size);
821            let p_as_array: Vec<usize> = p.into();
822            let expected = (0 .. size).collect::<Vec<usize>>();
823            p_as_array == expected
824        }
825    }
826
827    quickcheck! {
828        fn property_dim_is_equal_to_array_dimensions(array: ValidPermutationArray) -> bool {
829            let ValidPermutationArray(array) = array;
830            let n = array.len();
831            let p = PermutationMatrix::<u32>::from_array(array).unwrap();
832            p.size() == n
833        }
834    }
835
836    quickcheck! {
837        fn property_inverse_of_inverse_is_original(p: PermutationMatrix<u32>) -> bool {
838            p == p.inverse().inverse()
839        }
840    }
841
842    quickcheck! {
843        fn property_inverse_composes_to_identity(p: PermutationMatrix<u32>) -> bool {
844            // Recall that P * P_inv = I and P_inv * P = I
845            let n = p.size();
846            let pinv = p.inverse();
847            let mut p_pinv_composition = PermutationMatrix::identity(n);
848            let mut pinv_p_composition = PermutationMatrix::identity(n);
849            p.compose_into_buffer(&pinv, &mut p_pinv_composition);
850            pinv.compose_into_buffer(&p, &mut pinv_p_composition);
851            assert_eq!(p_pinv_composition, PermutationMatrix::identity(n));
852            assert_eq!(pinv_p_composition, PermutationMatrix::identity(n));
853            true
854        }
855    }
856
857    quickcheck! {
858        fn property_identity_parity_is_even(n: usize) -> bool {
859            let p = PermutationMatrix::<u32>::identity(n);
860            p.parity() ==  Parity::Even
861        }
862    }
863
864    quickcheck! {
865        fn property_parity_agrees_with_parity_of_inversions(p: PermutationMatrix<u32>) -> bool {
866            let array: &[usize] = (&p).into();
867            let num_inversions = array.iter().cloned().enumerate()
868                                      .cartesian_product(array.iter().cloned().enumerate())
869                                      .filter(|&((i, permuted_i), (j, permuted_j))|
870                                        // This is simply the definition of an inversion
871                                        i < j && permuted_i > permuted_j
872                                      )
873                                      .count();
874            // Recall that the parity of the number of inversions in the
875            // permutation is equal to the parity of the permutation
876            let parity = if num_inversions % 2 == 0 {
877                Parity::Even
878            } else {
879                Parity::Odd
880            };
881
882            parity == p.clone().parity()
883        }
884    }
885}