Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Faster each permutation #5127

Closed
wants to merge 2 commits into from
Closed
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
214 changes: 194 additions & 20 deletions src/libcore/vec.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1291,6 +1291,46 @@ pub fn reverse<T>(v: &[mut T]) {
while i < ln / 2 { v[i] <-> v[ln - i - 1]; i += 1; }
}

/**
* 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 {
v[i] <-> v[j];
i += 1;
j -= 1;
}
}

/// Returns a vector with the order of elements reversed
pub pure fn reversed<T: Copy>(v: &[const T]) -> ~[T] {
let mut rs: ~[T] = ~[];
Expand Down Expand Up @@ -1457,31 +1497,74 @@ pub fn each2<U, T>(v1: &[U], v2: &[T], f: fn(u: &U, t: &T) -> bool) {
*
* 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
*/
pure fn each_permutation<T: Copy>(v: &[T], put: fn(ts: &[T]) -> 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);
unsafe {
rest.push_all(const_view(v, i+1u, ln));
for each_permutation(rest) |permutation| {
if !put(append(~[elt], permutation)) {
return;
}
}
}
i += 1u;
pub pure fn each_permutation<T : Copy>(values : &[T],
fun : &fn(perm : &[T]) -> bool) {
let length = values.len();
let mut permutation = vec::from_fn(length, |i| values[i]);
if length <= 1 {
fun(permutation);
return;
}
let mut indices = vec::from_fn(length, |i| i);
loop {
if !fun(permutation) { return; }
// 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; }
// 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)
indices[k] <-> indices[l];
unsafe {
reverse_part(indices, k+1, length);
}
// fixup permutation based on indices
for uint::range(k, length) |i| {
permutation[i] = values[indices[i]];
}
}
}

/**
* Iterate over all permutations of vector `values`.
*
* This is an alternative to each_permutation that uses references to
* avoid copying the elements of the values vector.
*
* To avoid copying, the iterator will be passed a reference to a vector
* containing references to the elements in the original `values` vector.
*
* # Arguments
*
* * `values` - A vector of values from which the permutations are chosen
*
* * `fun` - The function to iterate over the permutations
*/
pub pure fn each_permutation_ref<T>(values : &v/[T],
fun : &fn(perm : &[&v/T]) -> bool) {
each_permutation(vec::from_fn(values.len(), |i| &values[i]), fun);
}

pub pure fn windowed<TT: Copy>(nn: uint, xx: &[TT]) -> ~[~[TT]] {
let mut ww = ~[];
assert 1u <= nn;
Expand Down Expand Up @@ -3995,6 +4078,97 @@ mod tests {
}
}

fn dup<T:Copy>(values : &[&T]) -> ~[T] {
from_fn(values.len(), |i| *values[i])
}

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

#[test]
fn test_permutations0() {
let values = [];
let mut v : ~[~[int]] = ~[];
for each_permutation(values) |p| {
v.push(vec::from_slice(p));
}
assert v == ~[~[]];
}

#[test]
fn test_permutations0_ref() {
let values = [];
let mut v : ~[~[int]] = ~[];
for each_permutation_ref(values) |p| {
v.push(dup(p));
}
assert v == ~[~[]];
}

#[test]
fn test_permutations1() {
let values = [1];
let mut v : ~[~[int]] = ~[];
for each_permutation(values) |p| {
v.push(vec::from_slice(p));
}
assert v == ~[~[1]];
}

#[test]
fn test_permutations1_ref() {
let values = [1];
let mut v : ~[~[int]] = ~[];
for each_permutation_ref(values) |p| {
v.push(dup(p));
}
assert v == ~[~[1]];
}

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

#[test]
fn test_permutations2_ref() {
let values = [1,2];
let mut v : ~[~[int]] = ~[];
for each_permutation_ref(values) |p| {
v.push(dup(p));
}
assert 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(vec::from_slice(p));
}
assert v == ~[~[1,2,3],~[1,3,2],~[2,1,3],~[2,3,1],~[3,1,2],~[3,2,1]];
}

#[test]
fn test_permutations3_ref() {
let values = [1,2,3];
let mut v : ~[~[int]] = ~[];
for each_permutation_ref(values) |p| {
v.push(dup(p));
}
assert v == ~[~[1,2,3],~[1,3,2],~[2,1,3],~[2,3,1],~[3,1,2],~[3,2,1]];
}

}

// Local Variables:
Expand Down