-
Notifications
You must be signed in to change notification settings - Fork 330
Added array_permutations
(attempt 2)
#1014
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
Open
ronnodas
wants to merge
18
commits into
rust-itertools:master
Choose a base branch
from
ronnodas:array-permutations
base: master
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Changes from 1 commit
Commits
Show all changes
18 commits
Select commit
Hold shift + click to select a range
e27b3ee
Treat k==0 less special
phimuemue 8ae44e0
Treat k==0 less special (2)
phimuemue 9b3d6e2
Introduce MaybeConstSize
phimuemue 5003927
PoolIndex<T> -> PoolIndex
phimuemue 5826470
MaybeConstSize (2)
phimuemue aa90cbb
Express some things via PoolIndex/MaybeConstUsize
phimuemue 98b79de
Try to use PoolIndex for permutations
phimuemue 79f52b2
Move MaybeConstUsize, PoolIndex to lazy_buffer
ronnodas 85a84bd
Rename PoolIndex to ArrayOrVecHelper
ronnodas 6056b73
Rename ArrayOrVecHelper::from_fn to item_from_fn
ronnodas 99de003
Use Idx type directly in PermutationState
ronnodas d8de4b8
Use Box<[usize]> instead of Vec<usize> in Permutations
ronnodas 57fff6e
Use ArrayOrVecHelper::start in {Array,}Combinations
ronnodas 0b96072
Update ArrayOrVecHelper doc comments
ronnodas 406eac2
Avoid `use ... as _`
ronnodas 1348785
Specify generic in `ArrayCombinations::new`
ronnodas 3dd45f5
Add `debug_assert` in advancing `PermutationState::Buffered`
ronnodas 5a7c522
Use `last_mut()?` instead of indexing
ronnodas File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -33,13 +33,9 @@ enum PermutationState<Idx: ArrayOrVecHelper> { | |
/// No permutation generated yet. | ||
Start { k: Idx::Length }, | ||
/// Values from the iterator are not fully loaded yet so `n` is still unknown. | ||
Buffered { k: Idx::Length, min_n: usize }, | ||
Buffered { indices: Idx, min_n: usize }, | ||
/// All values from the iterator are known so `n` is known. | ||
Loaded { | ||
indices: Box<[usize]>, | ||
cycles: Box<[usize]>, // TODO Should be Idx::Item<usize> | ||
k: Idx::Length, // TODO Should be inferred from cycles | ||
}, | ||
Loaded { indices: Box<[usize]>, cycles: Idx }, | ||
/// No permutation left to generate. | ||
End, | ||
} | ||
|
@@ -80,47 +76,43 @@ where | |
return None; | ||
} | ||
*state = PermutationState::Buffered { | ||
k, | ||
indices: Idx::start(k), | ||
min_n: k.value(), | ||
}; | ||
} | ||
Some(Idx::item_from_fn(k, |i| vals[i].clone())) | ||
} | ||
PermutationState::Buffered { k, min_n } => { | ||
PermutationState::Buffered { indices, min_n } => { | ||
let k = indices.len(); | ||
if vals.get_next() { | ||
// TODO This is ugly. Maybe working on indices is better? | ||
let item = Idx::item_from_fn(*k, |i| { | ||
vals[if i == k.value() - 1 { *min_n } else { i }].clone() | ||
}); | ||
indices.borrow_mut()[k.value() - 1] += 1; | ||
ronnodas marked this conversation as resolved.
Show resolved
Hide resolved
|
||
*min_n += 1; | ||
Some(item) | ||
Some(indices.extract_item(vals)) | ||
} else { | ||
let n = *min_n; | ||
let prev_iteration_count = n - k.value() + 1; | ||
let mut indices: Box<[_]> = (0..n).collect(); | ||
let mut cycles: Box<[_]> = (n - k.value()..n).rev().collect(); | ||
let mut cycles = Idx::from_fn(k, |i| n - 1 - i); | ||
// Advance the state to the correct point. | ||
for _ in 0..prev_iteration_count { | ||
if advance(&mut indices, &mut cycles) { | ||
if advance(&mut indices, cycles.borrow_mut()) { | ||
*state = PermutationState::End; | ||
return None; | ||
} | ||
} | ||
let item = Idx::item_from_fn(*k, |i| vals[indices[i]].clone()); | ||
*state = PermutationState::Loaded { | ||
indices, | ||
cycles, | ||
k: *k, | ||
}; | ||
let item = Idx::item_from_fn(k, |i| vals[indices[i]].clone()); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Isn't this There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. No, for the same reason as in the |
||
*state = PermutationState::Loaded { indices, cycles }; | ||
Some(item) | ||
} | ||
} | ||
PermutationState::Loaded { indices, cycles, k } => { | ||
if advance(indices, cycles) { | ||
PermutationState::Loaded { indices, cycles } => { | ||
if advance(indices, cycles.borrow_mut()) { | ||
*state = PermutationState::End; | ||
return None; | ||
} | ||
Some(Idx::item_from_fn(*k, |i| vals[indices[i]].clone())) | ||
Some(Idx::item_from_fn(cycles.len(), |i| { | ||
vals[indices[i]].clone() | ||
})) | ||
} | ||
PermutationState::End => None, | ||
} | ||
|
@@ -173,22 +165,26 @@ impl<Idx: ArrayOrVecHelper> PermutationState<Idx> { | |
let total = (n - k.value() + 1..=n).try_fold(1usize, |acc, i| acc.checked_mul(i)); | ||
(total.unwrap_or(usize::MAX), total) | ||
}; | ||
match *self { | ||
match self { | ||
ronnodas marked this conversation as resolved.
Show resolved
Hide resolved
|
||
Self::Start { k } if n < k.value() => (0, Some(0)), | ||
Self::Start { k } => at_start(n, k), | ||
Self::Buffered { k, min_n } => { | ||
Self::Start { k } => at_start(n, *k), | ||
Self::Buffered { indices, min_n } => { | ||
let k = indices.len(); | ||
// Same as `Start` minus the previously generated items. | ||
size_hint::sub_scalar(at_start(n, k), min_n - k.value() + 1) | ||
} | ||
Self::Loaded { | ||
ref indices, | ||
ref cycles, | ||
k: _, | ||
} => { | ||
let count = cycles.iter().enumerate().try_fold(0usize, |acc, (i, &c)| { | ||
acc.checked_mul(indices.len() - i) | ||
.and_then(|count| count.checked_add(c)) | ||
}); | ||
let count = cycles | ||
.borrow() | ||
.iter() | ||
.enumerate() | ||
.try_fold(0usize, |acc, (i, &c)| { | ||
acc.checked_mul(indices.len() - i) | ||
.and_then(|count| count.checked_add(c)) | ||
}); | ||
(count.unwrap_or(usize::MAX), count) | ||
} | ||
Self::End => (0, Some(0)), | ||
|
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is
cycles
really anIdx
or should it actually beIdx::Item<usize>
? I know that these are the same types, but don't the semantics differ? I.e. isn'tIdx
always meant to index into a slice, whereasIdx::Item<usize>
is an array or aVec
containingusize
s?If we'd like to avoid answering this question, we could keep
Loaded::k: Idx::Length
.Uh oh!
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
cycles
is really neither anIdx
nor anIdx::Item<usize>
, sinceIdx::Item
should be what is obtained by indexing something of typeIdx
into the buffer, but I don't feel strongly about this. Maybe it makes sense to keepcycles
of typeBox<[usize]>
and switch back to the namePoolIndex
so that that trait has clearer semantics.