1
Fork 0

std::vec: Replace each_permutation with a new Permutations iterator

Introduce ElementSwaps and Permutations. ElementSwaps is an iterator
that for a given sequence length yields the element swaps needed
to visit each possible permutation of the sequence in turn.

We use an algorithm that generates a sequence such that each permutation
is only one swap apart.

    let mut v = [1, 2, 3];
    for perm in v.permutations_iter() {
        // yields 1 2 3 | 1 3 2 | 3 1 2 | 3 2 1 | 2 3 1 | 2 1 3
    }

The `.permutations_iter()` yields clones of the input vector for each
permutation.

If a copyless traversal is needed, it can be constructed with
`ElementSwaps`:

    for (a, b) in ElementSwaps::new(3) {
        // yields (2, 1), (1, 0), (2, 1) ...
        v.swap(a, b);
        // ..
    }
This commit is contained in:
blake2-ppc 2013-09-09 01:29:07 +02:00
parent 6212729315
commit de9546a3f8

View file

@ -408,56 +408,106 @@ pub fn unzip<T, U, V: Iterator<(T, U)>>(mut iter: V) -> (~[T], ~[U]) {
(ts, us)
}
/**
* Iterate over all permutations of vector `v`.
*
* Permutations are produced in lexicographic order with respect to the order
* of elements in `v` (so if `v` is sorted then the permutations are
* lexicographically sorted).
*
* The total number of permutations produced is `v.len()!`. If `v` contains
* repeated elements, then some permutations are repeated.
*
* See [Algorithms to generate
* permutations](http://en.wikipedia.org/wiki/Permutation).
*
* # Arguments
*
* * `values` - A vector of values from which the permutations are
* chosen
*
* * `fun` - The function to iterate over the combinations
*/
pub fn each_permutation<T:Clone>(values: &[T], fun: &fn(perm : &[T]) -> bool) -> bool {
let length = values.len();
let mut permutation = vec::from_fn(length, |i| values[i].clone());
if length <= 1 {
fun(permutation);
return true;
/// An Iterator that yields the element swaps needed to produce
/// a sequence of all possible permutations for an indexed sequence of
/// elements. Each permutation is only a single swap apart.
///
/// The SteinhausJohnsonTrotter algorithm is used.
///
/// Generates even and odd permutations alternatingly.
///
/// The last generated swap is always (0, 1), and it returns the
/// sequence to its initial order.
pub struct ElementSwaps {
priv sdir: ~[SizeDirection],
/// If true, emit the last swap that returns the sequence to initial state
priv emit_reset: bool,
}
impl ElementSwaps {
/// Create an `ElementSwaps` iterator for a sequence of `length` elements
pub fn new(length: uint) -> ElementSwaps {
// Initialize `sdir` with a direction that position should move in
// (all negative at the beginning) and the `size` of the
// element (equal to the original index).
ElementSwaps{
emit_reset: true,
sdir: range(0, length)
.map(|i| SizeDirection{ size: i, dir: Neg })
.to_owned_vec()
}
}
let mut indices = vec::from_fn(length, |i| i);
loop {
if !fun(permutation) { return true; }
// find largest k such that indices[k] < indices[k+1]
// if no such k exists, all permutations have been generated
let mut k = length - 2;
while k > 0 && indices[k] >= indices[k+1] {
k -= 1;
}
enum Direction { Pos, Neg }
/// An Index and Direction together
struct SizeDirection {
size: uint,
dir: Direction,
}
impl Iterator<(uint, uint)> for ElementSwaps {
#[inline]
fn next(&mut self) -> Option<(uint, uint)> {
fn new_pos(i: uint, s: Direction) -> uint {
i + match s { Pos => 1, Neg => -1 }
}
if k == 0 && indices[0] > indices[1] { return true; }
// find largest l such that indices[k] < indices[l]
// k+1 is guaranteed to be such
let mut l = length - 1;
while indices[k] >= indices[l] {
l -= 1;
// Find the index of the largest mobile element:
// The direction should point into the vector, and the
// swap should be with a smaller `size` element.
let max = self.sdir.iter().map(|&x| x).enumerate()
.filter(|&(i, sd)|
new_pos(i, sd.dir) < self.sdir.len() &&
self.sdir[new_pos(i, sd.dir)].size < sd.size)
.max_by(|&(_, sd)| sd.size);
match max {
Some((i, sd)) => {
let j = new_pos(i, sd.dir);
self.sdir.swap(i, j);
// Swap the direction of each larger SizeDirection
for x in self.sdir.mut_iter() {
if x.size > sd.size {
x.dir = match x.dir { Pos => Neg, Neg => Pos };
}
}
Some((i, j))
},
None => if self.emit_reset && self.sdir.len() > 1 {
self.emit_reset = false;
Some((0, 1))
} else {
None
}
}
// swap indices[k] and indices[l]; sort indices[k+1..]
// (they're just reversed)
indices.swap(k, l);
indices.mut_slice(k+1, length).reverse();
// fixup permutation based on indices
for i in range(k, length) {
permutation[i] = values[indices[i]].clone();
}
}
/// An Iterator that uses `ElementSwaps` to iterate through
/// all possible permutations of a vector.
///
/// The first iteration yields a clone of the vector as it is,
/// then each successive element is the vector with one
/// swap applied.
///
/// Generates even and odd permutations alternatingly.
pub struct Permutations<T> {
priv swaps: ElementSwaps,
priv v: ~[T],
}
impl<T: Clone> Iterator<~[T]> for Permutations<T> {
#[inline]
fn next(&mut self) -> Option<~[T]> {
match self.swaps.next() {
None => None,
Some((a, b)) => {
let elt = self.v.clone();
self.v.swap(a, b);
Some(elt)
}
}
}
}
@ -1141,6 +1191,7 @@ impl<'self, T: TotalOrd> ImmutableTotalOrdVector<T> for &'self [T] {
pub trait ImmutableCopyableVector<T> {
fn partitioned(&self, f: &fn(&T) -> bool) -> (~[T], ~[T]);
unsafe fn unsafe_get(&self, elem: uint) -> T;
fn permutations_iter(self) -> Permutations<T>;
}
/// Extension methods for vectors
@ -1170,6 +1221,16 @@ impl<'self,T:Clone> ImmutableCopyableVector<T> for &'self [T] {
unsafe fn unsafe_get(&self, index: uint) -> T {
(*self.unsafe_ref(index)).clone()
}
/// Create an iterator that yields every possible permutation of the
/// vector in succession.
fn permutations_iter(self) -> Permutations<T> {
Permutations{
swaps: ElementSwaps::new(self.len()),
v: self.to_owned(),
}
}
}
#[allow(missing_doc)]
@ -2847,28 +2908,6 @@ mod tests {
assert_eq!(v, ~[1, 3, 5]);
}
#[test]
fn test_each_permutation() {
let mut results: ~[~[int]];
results = ~[];
do each_permutation([]) |v| { results.push(v.to_owned()); true };
assert_eq!(results, ~[~[]]);
results = ~[];
do each_permutation([7]) |v| { results.push(v.to_owned()); true };
assert_eq!(results, ~[~[7]]);
results = ~[];
do each_permutation([1,1]) |v| { results.push(v.to_owned()); true };
assert_eq!(results, ~[~[1,1],~[1,1]]);
results = ~[];
do each_permutation([5,2,0]) |v| { results.push(v.to_owned()); true };
assert!(results ==
~[~[5,2,0],~[5,0,2],~[2,5,0],~[2,0,5],~[0,5,2],~[0,2,5]]);
}
#[test]
fn test_zip_unzip() {
let z1 = ~[(1, 4), (2, 5), (3, 6)];
@ -2880,6 +2919,58 @@ mod tests {
assert_eq!((3, 6), (left[2], right[2]));
}
#[test]
fn test_element_swaps() {
let mut v = [1, 2, 3];
for (i, (a, b)) in ElementSwaps::new(v.len()).enumerate() {
v.swap(a, b);
match i {
0 => assert_eq!(v, [1, 3, 2]),
1 => assert_eq!(v, [3, 1, 2]),
2 => assert_eq!(v, [3, 2, 1]),
3 => assert_eq!(v, [2, 3, 1]),
4 => assert_eq!(v, [2, 1, 3]),
5 => assert_eq!(v, [1, 2, 3]),
_ => fail!(),
}
}
}
#[test]
fn test_permutations() {
use hashmap;
{
let v: [int, ..0] = [];
let mut it = v.permutations_iter();
assert_eq!(it.next(), None);
}
{
let v = [~"Hello"];
let mut it = v.permutations_iter();
assert_eq!(it.next(), None);
}
{
let v = [1, 2, 3];
let mut it = v.permutations_iter();
assert_eq!(it.next(), Some(~[1,2,3]));
assert_eq!(it.next(), Some(~[1,3,2]));
assert_eq!(it.next(), Some(~[3,1,2]));
assert_eq!(it.next(), Some(~[3,2,1]));
assert_eq!(it.next(), Some(~[2,3,1]));
assert_eq!(it.next(), Some(~[2,1,3]));
assert_eq!(it.next(), None);
}
{
// check that we have N! unique permutations
let mut set = hashmap::HashSet::new();
let v = ['A', 'B', 'C', 'D', 'E', 'F'];
for perm in v.permutations_iter() {
set.insert(perm);
}
assert_eq!(set.len(), 2 * 3 * 4 * 5 * 6);
}
}
#[test]
fn test_position_elem() {
assert!([].position_elem(&1).is_none());
@ -3175,13 +3266,12 @@ mod tests {
fn test_permute_fail() {
let v = [(~0, @0), (~0, @0), (~0, @0), (~0, @0)];
let mut i = 0;
do each_permutation(v) |_elt| {
for _ in v.permutations_iter() {
if i == 2 {
fail!()
}
i += 1;
true
};
}
}
#[test]
@ -3493,50 +3583,6 @@ mod tests {
assert_eq!(values, [1,4,3,2,5]);
}
#[test]
fn test_permutations0() {
let values = [];
let mut v : ~[~[int]] = ~[];
do each_permutation(values) |p| {
v.push(p.to_owned());
true
};
assert_eq!(v, ~[~[]]);
}
#[test]
fn test_permutations1() {
let values = [1];
let mut v : ~[~[int]] = ~[];
do each_permutation(values) |p| {
v.push(p.to_owned());
true
};
assert_eq!(v, ~[~[1]]);
}
#[test]
fn test_permutations2() {
let values = [1,2];
let mut v : ~[~[int]] = ~[];
do each_permutation(values) |p| {
v.push(p.to_owned());
true
};
assert_eq!(v, ~[~[1,2],~[2,1]]);
}
#[test]
fn test_permutations3() {
let values = [1,2,3];
let mut v : ~[~[int]] = ~[];
do each_permutation(values) |p| {
v.push(p.to_owned());
true
};
assert_eq!(v, ~[~[1,2,3],~[1,3,2],~[2,1,3],~[2,3,1],~[3,1,2],~[3,2,1]]);
}
#[test]
fn test_vec_zero() {
use num::Zero;