[latex3-commits] [git/LaTeX3-latex3-latex3] master: Implement \seq_shuffle:N using \tl_build machinery (5e5dd9a)

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/5e5dd9a623f4680f196928476989186f1fa3de6e

>---------------------------------------------------------------

commit 5e5dd9a623f4680f196928476989186f1fa3de6e
Author: Bruno Le Floch <bruno at le-floch.fr>
Date:   Sun Apr 29 15:42:18 2018 -0400

    Implement \seq_shuffle:N using \tl_build machinery
    
    I am only committing this implementation for the record, and not updating
    test files, because I will commit a much faster implementation using
    \toks soon.


>---------------------------------------------------------------

5e5dd9a623f4680f196928476989186f1fa3de6e
 l3kernel/l3candidates.dtx |  168 +++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 168 insertions(+)

diff --git a/l3kernel/l3candidates.dtx b/l3kernel/l3candidates.dtx
index eef403a..00a8e04 100644
--- a/l3kernel/l3candidates.dtx
+++ b/l3kernel/l3candidates.dtx
@@ -2413,6 +2413,174 @@
 %    \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{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
+    \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:
+      }
+    \cs_new_protected:Npn \@@_shuffle_item_many: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:
+      }
+    \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:
+      {
+        \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:
+      }
+    \cs_new_eq:NN \@@_shuffle_end: \@@_shuffle_end_few:
+  }
+  {
+    \cs_new_protected:Npn \seq_shuffle:N #1
+      { \__kernel_msg_error:nn { kernel } { fp-no-random } }
+    \cs_new_eq:NN \seq_gshuffle:N \seq_shuffle:N
+  }
+%    \end{macrocode}
+% \end{variable}
+% \end{macro}
+%
 % \subsection{Additions to \pkg{l3skip}}
 %
 %    \begin{macrocode}





More information about the latex3-commits mailing list