[latex3-commits] [git/LaTeX3-latex3-latex3] master: Shuffle using toks (see #456) (d4ebe94)
Bruno Le Floch
bruno at le-floch.fr
Sun Apr 29 22:37:39 CEST 2018
Repository : https://github.com/latex3/latex3
On branch : master
Link : https://github.com/latex3/latex3/commit/d4ebe946ba4600d1321f55e90d6a44ad62712ab2
>---------------------------------------------------------------
commit d4ebe946ba4600d1321f55e90d6a44ad62712ab2
Author: Bruno Le Floch <bruno at le-floch.fr>
Date: Sun Apr 29 16:04:57 2018 -0400
Shuffle using toks (see #456)
>---------------------------------------------------------------
d4ebe946ba4600d1321f55e90d6a44ad62712ab2
l3kernel/l3candidates.dtx | 188 ++++++++++-----------------------------------
1 file changed, 42 insertions(+), 146 deletions(-)
diff --git a/l3kernel/l3candidates.dtx b/l3kernel/l3candidates.dtx
index 00a8e04..ca3146b 100644
--- a/l3kernel/l3candidates.dtx
+++ b/l3kernel/l3candidates.dtx
@@ -2413,164 +2413,60 @@
% \end{macrocode}
% \end{macro}
%
-% \begin{macro}{\seq_shuffle:N, \seq_gshuffle:N, \@@_shuffle:NN,
-% \@@_shuffle:w, \@@_shuffle_one:w, \@@_shuffle_two:w,
-% \@@_shuffle_cycle:w, \@@_shuffle_end:, \@@_shuffle_few:,
-% \@@_shuffle_item_few:n, \@@_shuffle_item_a_few:n,
-% \@@_shuffle_item_b_few:n, \@@_shuffle_end_few:, \@@_shuffle_aux:w,
-% \@@_shuffle_many:, \@@_shuffle_item_many:n,
-% \@@_shuffle_item_a_many:n, \@@_shuffle_item_b_many:n,
-% \@@_shuffle_end_many:}
-% \begin{variable}{\c_@@_shuffle_int, \g_@@_internal_tl, \l_@@_a_tl,
-% \l_@@_b_tl, \l_@@_len_int, \l_@@_b_int, \l_@@_goal_a_int,
-% \l_@@_goal_b_int}
-% The auxiliary \cs{@@_shuffle:w} expects a number of items and a
-% sequence with that number of items (the \cs{s_@@} start marker
-% serves as a delimiter between the two arguments). It shuffles the
-% sequence and appends the resulting items to \cs{g_@@_internal_tl} as
-% they are determined.
-%
-% We use the primitive \cs{pdftex_uniformdeviate:D} for speed reasons.
-% Its non-uniformity is not too important for small arguments, and in
-% any case we cannot shuffle huge lists.
-%
-% The idea is to randomly split the input into two equal-sized parts
-% \cs{l_@@_a_tl} and \cs{l_@@_b_tl} then apply \cs{@@_shuffle:w} to
-% each part. To preserve uniformity, the probability for each item to
-% go on one side or the other is proportional to the remaining number
-% of slots on that side, which we keep track of as \cs{l_@@_len_int}
-% minus \cs{l_@@_b_int} and as \cs{l_@@_b_int}. When there are many
-% items to split (controlled by \cs{c_@@_shuffle_int}, whose value was
-% chosen somewhat arbitrarily and could easily be fine-tuned), the
-% token lists \cs{l_@@_a_tl} and \cs{l_@@_b_tl} are filled using the
-% \cs[no-index]{tl_build_\ldots{}} machinery.
+% \begin{macro}{\seq_shuffle:N, \seq_gshuffle:N, \@@_shuffle:NN, \@@_shuffle_item:n}
+% \begin{variable}{\g_@@_internal_seq, \l_@@_internal_a_int, \l_@@_internal_b_int}
+% We apply the Fisher–Yates shuffle, storing items in \tn{toks}
+% registers. We use the primitive \cs{pdftex_uniformdeviate:D} for
+% speed reasons. Its non-uniformity is of order its argument divided
+% by $2^{28}$, not too bad for small lists. For sequences with more
+% than $13$ elements there are more possible permutations than
+% possible seeds ($13!>2^{28}$) so the question of uniformity is
+% somewhat moot.
% \begin{macrocode}
\cs_if_exist:NTF \pdftex_uniformdeviate:D
{
- \int_const:Nn \c_@@_shuffle_int { 12 }
- \tl_new:N \g_@@_internal_tl
- \tl_new:N \l_@@_a_tl
- \tl_new:N \l_@@_b_tl
- \int_new:N \l_@@_len_int
- \int_new:N \l_@@_b_int
- \int_new:N \l_@@_goal_a_int
- \int_new:N \l_@@_goal_b_int
+ \int_new:N \l_@@_internal_a_int
+ \int_new:N \l_@@_internal_b_int
+ \seq_new:N \g_@@_internal_seq
\cs_new_protected:Npn \seq_shuffle:N { \@@_shuffle:NN \seq_set_eq:NN }
\cs_new_protected:Npn \seq_gshuffle:N { \@@_shuffle:NN \seq_gset_eq:NN }
\cs_new_protected:Npn \@@_shuffle:NN #1#2
{
- \group_begin:
- \tl_build_gbegin:N \g_@@_internal_tl
- \tl_build_gput_right:Nn \g_@@_internal_tl { \s_@@ }
- \cs_set_eq:NN \@@_item:n \@@_shuffle_item_few:n
- \exp_after:wN \@@_shuffle:w
- \int_value:w \seq_count:N #2 #2 \@@_shuffle_end:
- \tl_build_gend:N \g_@@_internal_tl
- \group_end:
- #1 #2 \g_@@_internal_tl
- }
- \cs_new_protected:Npn \@@_shuffle:w #1 \s_@@
- {
- \if_case:w #1 \exp_stop_f:
- \exp_after:wN \use_none:n
- \or: \exp_after:wN \@@_shuffle_one:w
- \or: \exp_after:wN \@@_shuffle_two:w
- \else:
- \int_set:Nn \l_@@_len_int {#1}
- \if_int_compare:w \l_@@_len_int < \c_@@_shuffle_int
- \@@_shuffle_few:
- \else:
- \@@_shuffle_many:
- \fi:
- \fi:
- }
- \cs_new_protected:Npn \@@_shuffle_one:w #1 \@@_shuffle_end:
- { \tl_build_gput_right:Nn \g_@@_internal_tl {#1} }
- \cs_new_protected:Npn \@@_shuffle_two:w
- {
- \if_int_odd:w \pdftex_uniformdeviate:D 2 \exp_stop_f:
- \exp_stop_f:
- \exp_after:wN \@@_shuffle_one:w
- \else:
- \exp_after:wN \@@_shuffle_cycle:w
- \fi:
- }
- \cs_new_protected:Npn \@@_shuffle_cycle:w #1#2#3 \@@_shuffle_end:
- { \tl_build_gput_right:Nn \g_@@_internal_tl { #3 #1 {#2} } }
- \cs_new_protected:Npn \@@_shuffle_few:
- {
- \int_set:Nn \l_@@_goal_a_int { \l_@@_len_int / 2 }
- \int_set:Nn \l_@@_goal_b_int { \l_@@_len_int - \l_@@_goal_a_int }
- \int_set_eq:NN \l_@@_b_int \l_@@_goal_b_int
- \tl_clear:N \l_@@_a_tl
- \tl_clear:N \l_@@_b_tl
- }
- \cs_new_protected:Npn \@@_shuffle_item_few:n
- {
- \int_decr:N \l_@@_len_int
- \if_int_compare:w
- \pdftex_uniformdeviate:D \l_@@_len_int < \l_@@_b_int
- \int_decr:N \l_@@_b_int
- \exp_after:wN \@@_shuffle_item_b_few:n
- \else:
- \exp_after:wN \@@_shuffle_item_a_few:n
- \fi:
- }
- \cs_new_protected:Npn \@@_shuffle_item_a_few:n #1
- { \tl_put_right:Nn \l_@@_a_tl { \@@_item:n {#1} } }
- \cs_new_protected:Npn \@@_shuffle_item_b_few:n #1
- { \tl_put_right:Nn \l_@@_b_tl { \@@_item:n {#1} } }
- \cs_new_protected:Npn \@@_shuffle_end_few:
- {
- \exp_after:wN \@@_shuffle_aux:w
- \int_value:w \int_use:N \l_@@_goal_b_int
- \exp_after:wN \s_@@ \l_@@_b_tl \@@_shuffle_end:
- }
- \cs_new_protected:Npn \@@_shuffle_aux:w
- {
- \exp_after:wN \@@_shuffle:w
- \int_value:w \int_use:N \l_@@_goal_a_int
- \exp_after:wN \s_@@ \l_@@_a_tl \@@_shuffle_end:
- \@@_shuffle:w
- }
- \cs_new_protected:Npn \@@_shuffle_many:
- {
- \int_set:Nn \l_@@_goal_a_int { \l_@@_len_int / 2 }
- \int_set:Nn \l_@@_goal_b_int
- { \l_@@_len_int - \l_@@_goal_a_int }
- \int_set_eq:NN \l_@@_b_int \l_@@_goal_b_int
- \tl_build_begin:N \l_@@_a_tl
- \tl_build_begin:N \l_@@_b_tl
- \cs_set_eq:NN \@@_item:n \@@_shuffle_item_many:n
- \cs_set_eq:NN \@@_shuffle_end: \@@_shuffle_end_many:
+ \int_compare:nNnTF { \seq_count:N #2 } > \c_max_register_int
+ {
+ \__kernel_msg_error:nnx { kernel } { shuffle-too-large }
+ { \token_to_str:N #2 }
+ }
+ {
+ \group_begin:
+ \cs_set_eq:NN \@@_item:n \@@_shuffle_item:n
+ \int_zero:N \l_@@_internal_a_int
+ #2
+ \seq_gset_from_inline_x:Nnn \g_@@_internal_seq
+ { \int_step_function:nN { \l_@@_internal_a_int } }
+ { \tex_the:D \tex_toks:D ##1 }
+ \group_end:
+ #1 #2 \g_@@_internal_seq
+ \seq_gclear:N \g_@@_internal_seq
+ }
}
- \cs_new_protected:Npn \@@_shuffle_item_many:n
+ \cs_new_protected:Npn \@@_shuffle_item:n
{
- \if_int_compare:w
- \pdftex_uniformdeviate:D \l_@@_len_int < \l_@@_b_int
- \int_decr:N \l_@@_len_int
- \int_decr:N \l_@@_b_int
- \exp_after:wN \@@_shuffle_item_b_many:n
- \else:
- \int_decr:N \l_@@_len_int
- \exp_after:wN \@@_shuffle_item_a_many:n
- \fi:
+ \int_incr:N \l_@@_internal_a_int
+ \int_set:Nn \l_@@_internal_b_int
+ { 1 + \pdftex_uniformdeviate:D \l_@@_internal_a_int }
+ \tex_toks:D \l_@@_internal_a_int
+ = \tex_toks:D \l_@@_internal_b_int
+ \tex_toks:D \l_@@_internal_b_int
}
- \cs_new_protected:Npn \@@_shuffle_item_a_many:n #1
- { \tl_build_put_right:Nn \l_@@_a_tl { \@@_item:n {#1} } }
- \cs_new_protected:Npn \@@_shuffle_item_b_many:n #1
- { \tl_build_put_right:Nn \l_@@_b_tl { \@@_item:n {#1} } }
- \cs_new_protected:Npn \@@_shuffle_end_many:
+ \__kernel_msg_new:nnnn { kernel } { shuffle-too-large }
+ { The~sequence~#1~is~too~long~to~be~shuffled~by~TeX. }
{
- \cs_set_eq:NN \@@_shuffle_end: \@@_shuffle_end_few:
- \cs_set_eq:NN \@@_item:n \@@_shuffle_item_few:n
- \tl_build_end:N \l_@@_b_tl
- \tl_build_end:N \l_@@_a_tl
- \exp_after:wN \@@_shuffle_aux:w
- \int_value:w \int_use:N \l_@@_goal_b_int
- \exp_after:wN \s_@@ \l_@@_b_tl \@@_shuffle_end:
+ TeX~has~ \int_eval:n { \c_max_register_int + 1 } ~
+ toks~registers:~this~only~allows~to~shuffle~up~to~
+ \int_use:N \c_max_register_int \ items.~
+ The~list~will~not~be~shuffled.
}
- \cs_new_eq:NN \@@_shuffle_end: \@@_shuffle_end_few:
}
{
\cs_new_protected:Npn \seq_shuffle:N #1
More information about the latex3-commits
mailing list