Skip to content

Commit

Permalink
auto merge of #6523 : cmr/rust/faster_each_permutation, r=luqmana
Browse files Browse the repository at this point in the history
Closes #5127
  • Loading branch information
bors committed May 17, 2013
2 parents 09bf401 + af54d58 commit 77c98f0
Showing 1 changed file with 127 additions and 20 deletions.
147 changes: 127 additions & 20 deletions src/libcore/vec.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1445,6 +1445,46 @@ pub fn reverse<T>(v: &mut [T]) {
}
}

/**
* Reverse part of a vector in place.
*
* Reverse the elements in the vector between `start` and `end - 1`.
*
* If either start or end do not represent valid positions in the vector, the
* vector is returned unchanged.
*
* # Arguments
*
* * `v` - The mutable vector to be modified
*
* * `start` - Index of the first element of the slice
*
* * `end` - Index one past the final element to be reversed.
*
* # Example
*
* Assume a mutable vector `v` contains `[1,2,3,4,5]`. After the call:
*
* ~~~
*
* reverse_part(v, 1, 4);
*
* ~~~
*
* `v` now contains `[1,4,3,2,5]`.
*/
pub fn reverse_part<T>(v: &mut [T], start: uint, end : uint) {
let sz = v.len();
if start >= sz || end > sz { return; }
let mut i = start;
let mut j = end - 1;
while i < j {
vec::swap(v, i, j);
i += 1;
j -= 1;
}
}

/// Returns a vector with the order of elements reversed
pub fn reversed<T:Copy>(v: &const [T]) -> ~[T] {
let mut rs: ~[T] = ~[];
Expand Down Expand Up @@ -1739,29 +1779,49 @@ pub fn each2_mut<U, T>(v1: &mut [U], v2: &mut [T], f: &fn(u: &mut U, t: &mut T)
*
* The total number of permutations produced is `len(v)!`. 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
*/
#[cfg(not(stage0))]
pub fn each_permutation<T:Copy>(v: &[T], put: &fn(ts: &[T]) -> bool) -> bool {
let ln = len(v);
if ln <= 1 {
put(v);
} else {
// This does not seem like the most efficient implementation. You
// could make far fewer copies if you put your mind to it.
let mut i = 0u;
while i < ln {
let elt = v[i];
let mut rest = slice(v, 0u, i).to_vec();
rest.push_all(const_slice(v, i+1u, ln));
for each_permutation(rest) |permutation| {
if !put(append(~[elt], permutation)) {
return false;
}
}
i += 1u;
pub fn each_permutation<T:Copy>(values: &[T], fun: &fn(perm : &[T]) -> bool) -> bool {
let length = values.len();
let mut permutation = vec::from_fn(length, |i| values[i]);
if length <= 1 {
fun(permutation);
return true;
}
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;
}
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;
}
// swap indices[k] and indices[l]; sort indices[k+1..]
// (they're just reversed)
vec::swap(indices, k, l);
reverse_part(indices, k+1, length);
// fixup permutation based on indices
for uint::range(k, length) |i| {
permutation[i] = values[indices[i]];
}
}
return true;
}

/**
Expand Down Expand Up @@ -4730,6 +4790,53 @@ mod tests {
}
}

#[test]
fn test_reverse_part() {
let mut values = [1,2,3,4,5];
reverse_part(values,1,4);
assert_eq!(values, [1,4,3,2,5]);
}

#[test]
fn test_permutations0() {
let values = [];
let mut v : ~[~[int]] = ~[];
for each_permutation(values) |p| {
v.push(p.to_owned());
}
assert_eq!(v, ~[~[]]);
}

#[test]
fn test_permutations1() {
let values = [1];
let mut v : ~[~[int]] = ~[];
for each_permutation(values) |p| {
v.push(p.to_owned());
}
assert_eq!(v, ~[~[1]]);
}

#[test]
fn test_permutations2() {
let values = [1,2];
let mut v : ~[~[int]] = ~[];
for each_permutation(values) |p| {
v.push(p.to_owned());
}
assert_eq!(v, ~[~[1,2],~[2,1]]);
}

#[test]
fn test_permutations3() {
let values = [1,2,3];
let mut v : ~[~[int]] = ~[];
for each_permutation(values) |p| {
v.push(p.to_owned());
}
assert_eq!(v, ~[~[1,2,3],~[1,3,2],~[2,1,3],~[2,3,1],~[3,1,2],~[3,2,1]]);
}

#[test]
fn test_each_val() {
use old_iter::CopyableNonstrictIter;
Expand Down

0 comments on commit 77c98f0

Please sign in to comment.