Re: [PATCH 2/2] add permutation iterator
[Thread Prev] | [Thread Next]
- Subject: Re: [PATCH 2/2] add permutation iterator
- From: Ori Bernstein <ori@xxxxxxxxxxxxxx>
- Reply-to: myrddin-dev@xxxxxxxxxxxxxx
- Date: Mon, 1 Jan 2018 23:16:29 -0800
- To: myrddin-dev@xxxxxxxxxxxxxx
- Cc: "S. Gilles" <sgilles@xxxxxxxxxxxx>
Sorry for taking a while to review this. Overall, it looks pretty good,
just a few minor nits. I've already made them on my local branch, so
as long as they look good to you, I can push.
On Sun, 31 Dec 2017 02:49:07 -0500, "S. Gilles" <sgilles@xxxxxxxxxxxx> wrote:
> A good exposition of this algorithm is at
> https://www.nayuki.io/page/next-lexicographical-permutation-algorithm
<snip>
> +generic byperm = {a, cmp
> + /* start off by backwards-sorting a */
> + std.sort(a, cmp)
Hm. Since we need random access, it looks like this might need to have a
slice, even after the new syntax lands. That's unfortunate, I suppose,
but unavoidable.
> +impl iterable permiter(@a) -> @a[:] =
> + __iternext__ = {itp, valp
> + var j : std.size = seq.len - 1
> + var i : std.size = seq.len - 1
> + var seq : @a[:] = itp.seq
> +
> + /* We're permuting seq in place */
Moved this comment up.
> + valp# = itp.seq
> +
> + if itp.first
> + itp.first = false
> + -> true
> + ;;
> +
> + /* Find the longest decreasing sequence at end */
Yes, but why? Proposing this replacement:
/*
To generate the next permutation, we need
to increase the sequence by as little as
possible. That means that we start by finding
the longest monotonically decreasing trailing
sequence.
*/
> + j = seq.len - 1
> + while true
> + if j == 0
> + -> false
> + ;;
> + match itp.cmp(seq[j - 1], seq[j])
> + | `std.After: j--
> + | _: break
> + ;;
> + ;;
> + j--
> +
> + /* Now seq[j+1:] is all decreasing */
This comment also doesn't add much; if the previous code worked,
we already know this. I'd like to propose another comment that
explains why we're doing it:
/*
Find highest i s.t. seq[j] < seq[i]. This
is the index that will maintain the order of
the suffix, while increasing the value of the
element in the 'pivot'.
*/
> +
> + /* Find highest i s.t. seq[j] < seq[i] */
> + i = seq.len - 1
> + while true
Indentation seemed a bit screwed up. Fixed it.
> + if i <= j
> + -> false
> + ;;
> + match itp.cmp(seq[j], seq[i])
> + | `std.Before: break
> + | _: i--
> + ;;
> + ;;
> +
> + /* First, swap seq[i] and seq[j] */
And, another comment change:
/*
Then, swap seq[i] and seq[j] and reverse the
sequence. Because the suffix was in decreasing
order, reversing it means that our sequence is
now in increasing order: ie, our most significant
place has the smallest value.
*/
> + std.swap(&seq[i], &seq[j])
> +
> + /* Now reverse seq[j+1:] */
> + i = 1
> + while j + i < seq.len - i
> + std.swap(&seq[j + i], &seq[seq.len - i])
> + i++
> + ;;
> +
> + -> true
> + }
> +
> + __iterfin__ = {itp, valp
> + }
> +;;
> diff --git a/lib/iter/test/perm.myr b/lib/iter/test/perm.myr
> new file mode 100644
> index 00000000..cfebb036
> --- /dev/null
> +++ b/lib/iter/test/perm.myr
> @@ -0,0 +1,54 @@
> +use std
> +use testr
> +
> +use iter
> +
> +const main = {
> + testr.run([
> + [.name = "byperm-01", .fn = byperm01],
> + [.name = "byperm-02", .fn = byperm02],
> + [.name = "byperm-03", .fn = byperm03],
> + ][:])
> +}
> +
> +const byperm01 = {c
> + var v : int[:] = [ 0, 2, 1 ][:]
> + var sb : std.strbuf# = std.mksb()
> + std.sbfmt(sb, " ")
> +
> + for w : iter.byperm(v, std.numcmp)
> + std.sbfmt(sb, "{} ", w)
> + ;;
> +
> + var expected : byte[:] = " [0, 1, 2] [0, 2, 1] [1, 0, 2] [1, 2, 0] [2, 0, 1] [2, 1, 0] "
> + var actual : byte[:] = std.sbfin(sb)
> + testr.check(c, std.eq(expected, actual), "expected “{}”, got “{}”", expected, actual)
> +}
> +
> +const byperm02 = {c
> + var v : int[:] = [ 1, 1 ][:]
> + var sb : std.strbuf# = std.mksb()
> + std.sbfmt(sb, " ")
> +
> + for w : iter.byperm(v, std.numcmp)
> + std.sbfmt(sb, "{} ", w)
> + ;;
> +
> + var expected : byte[:] = " [1, 1] "
> + var actual : byte[:] = std.sbfin(sb)
> + testr.check(c, std.eq(expected, actual), "expected “{}”, got “{}”", expected, actual)
> +}
> +
> +const byperm03 = {c
> + var v : int[:] = [ 3, 1, 1 ][:]
> + var sb : std.strbuf# = std.mksb()
> + std.sbfmt(sb, " ")
> +
> + for w : iter.byperm(v, std.numcmp)
> + std.sbfmt(sb, "{} ", w)
> + ;;
> +
> + var expected : byte[:] = " [1, 1, 3] [1, 3, 1] [3, 1, 1] "
> + var actual : byte[:] = std.sbfin(sb)
> + testr.check(c, std.eq(expected, actual), "expected “{}”, got “{}”", expected, actual)
> +}
> --
> 2.15.1
>
>
--
Ori Bernstein
| Re: [PATCH 2/2] add permutation iterator | "S. Gilles" <sgilles@xxxxxxxxxxxx> |
- Prev by Date: New Trait Syntax Coming.
- Next by Date: Re: [PATCH 2/2] add permutation iterator
- Previous by thread: Re: New Trait Syntax Coming.
- Next by thread: Re: [PATCH 2/2] add permutation iterator
- Index(es):