From dba7f6defe07041064f8b39e3b16f967c66ca3c0 Mon Sep 17 00:00:00 2001 From: "Tommy M. McGuire" Date: Wed, 13 Feb 2013 17:52:58 -0600 Subject: [PATCH 1/2] Add reverse_part, replace each_permutation, add tests --- src/libcore/vec.rs | 214 ++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 194 insertions(+), 20 deletions(-) diff --git a/src/libcore/vec.rs b/src/libcore/vec.rs index 9ad5d9f32da36..d15a5585d3be8 100644 --- a/src/libcore/vec.rs +++ b/src/libcore/vec.rs @@ -1291,6 +1291,46 @@ pub fn reverse(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`. + * + * # 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]`. + * + * # Safety note + * + * Behavior is undefined if `start` or `end` do not represent valid + * positions in `v`. + */ +pub fn reverse_part(v : &[mut T], start : uint, end : uint) { + 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(v: &[const T]) -> ~[T] { let mut rs: ~[T] = ~[]; @@ -1457,31 +1497,74 @@ pub fn each2(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(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(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(values : &v/[T], + fun : &fn(perm : &[&v/T]) -> bool) { + each_permutation(vec::from_fn(values.len(), |i| &values[i]), fun); +} + pub pure fn windowed(nn: uint, xx: &[TT]) -> ~[~[TT]] { let mut ww = ~[]; assert 1u <= nn; @@ -3995,6 +4078,97 @@ mod tests { } } + fn dup(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: From e0ff2b79ae53dc2c8d69685467c44cb9f401ba81 Mon Sep 17 00:00:00 2001 From: "Tommy M. McGuire" Date: Fri, 1 Mar 2013 17:06:37 -0600 Subject: [PATCH 2/2] Ensure reverse_part does not access outside given vector --- src/libcore/vec.rs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/libcore/vec.rs b/src/libcore/vec.rs index d15a5585d3be8..48a8da9e3d6b4 100644 --- a/src/libcore/vec.rs +++ b/src/libcore/vec.rs @@ -1296,6 +1296,9 @@ pub fn reverse(v: &[mut T]) { * * 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 @@ -1315,13 +1318,10 @@ pub fn reverse(v: &[mut T]) { * ~~~ * * `v` now contains `[1,4,3,2,5]`. - * - * # Safety note - * - * Behavior is undefined if `start` or `end` do not represent valid - * positions in `v`. */ pub fn reverse_part(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 {