-
Couldn't load subscription status.
- Fork 335
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
base: master
Are you sure you want to change the base?
Changes from 1 commit
e27b3ee
8ae44e0
9b3d6e2
5003927
5826470
aa90cbb
98b79de
79f52b2
85a84bd
6056b73
99de003
d8de4b8
57fff6e
0b96072
406eac2
1348785
3dd45f5
5a7c522
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| 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.
Outdated
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)), | ||
|
|
||
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
cyclesreally anIdxor should it actually beIdx::Item<usize>? I know that these are the same types, but don't the semantics differ? I.e. isn'tIdxalways meant to index into a slice, whereasIdx::Item<usize>is an array or aVeccontainingusizes?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.
cyclesis really neither anIdxnor anIdx::Item<usize>, sinceIdx::Itemshould be what is obtained by indexing something of typeIdxinto the buffer, but I don't feel strongly about this. Maybe it makes sense to keepcyclesof typeBox<[usize]>and switch back to the namePoolIndexso that that trait has clearer semantics.