summaryrefslogtreecommitdiff
path: root/Master/texmf-dist/source/latex/randomwalk/randomwalk.dtx
blob: 1e38dd7d3bf33a04c0d99a5ff0da6f77a4e124f6 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
% \iffalse
%% File: randomwalk.dtx Copyright (C) 2011 Bruno Le Floch
%%
%% It may be distributed and/or modified under the conditions of the
%% LaTeX Project Public License (LPPL), either version 1.3c of this
%% license or (at your option) any later version.  The latest version
%% of this license is in the file
%%
%%    http://www.latex-project.org/lppl.txt
%%
%% -----------------------------------------------------------------------
%
%<*driver|package>
\RequirePackage{l3names}
%</driver|package>
%\fi
\GetIdInfo$Id: randomwalk.dtx 0.2 2011-09-09 10:15:31Z blefloch $
       {Customizable Random Walks using TikZ}%
%\iffalse
%<*driver>
%\fi
\ProvidesFile{\ExplFileName.dtx}
  [\ExplFileDate\space v\ExplFileVersion\space\ExplFileDescription]
%\iffalse
\documentclass[full]{l3doc}
\usepackage{randomwalk}
\usepackage{amsmath}
\begin{document}
  \DocInput{randomwalk.dtx}
\end{document}
%</driver>
% \fi
%
%
% \title{The \textsf{randomwalk} package: \\
%   customizable random walks using TikZ\thanks{This file has version
%     number \ExplFileVersion, last revised \ExplFileDate.}}
% \author{Bruno Le Floch}
% \date{\ExplFileDate}
%
% \maketitle
% \tableofcontents
%
% \begin{documentation}
%
% \begin{abstract}
%
% The |randomwalk| package draws random walks using TikZ. The following
% parameters can be customized:
% \begin{itemize}
% \item The number of steps, of course.
% \item The length of the steps, either a fixed length, or a length taken
%   at random from a given set.
% \item The angle of each step, either taken at random from a given set, or
%   uniformly distributed.
% \end{itemize}
%
% \end{abstract}
%
%
% \section{How to use it}
%
% The |randomwalk| package has exactly one user command: |\RandomWalk|,
% which takes a list of key-value pairs as its argument. A few examples:
% \begin{verbatim}
% \RandomWalk {number = 100, length = {4pt, 10pt}}
% \RandomWalk {number = 100, angles = {0,60,120,180,240,300}, degree}
% \RandomWalk {number = 100, length = 2em,
%   angles = {0,10,20,-10,-20}, degree, angles-relative}
% \end{verbatim}
% The simplest is to give a list of all the keys, and their meaning:
% \begin{itemize}
%
% \item |number|: the number of steps (default \(10\))
%
% \item |length|: the length of each step: either one dimension (e.g., |1em|),
%   or a comma-separated list of dimensions (e.g. |{2pt, 5pt}|), by
%   default |10pt|. The length of each step is a random element in this set
%   of possible dimensions.
%
% \item |angles|: the polar angle for each step: a comma-separated list of
%   angles, and each step takes a random angle among the list. If this is not specified, then the angle is uniformly distributed along the circle.
%
% \item |degree|(|s|): specifies that the angles are given in degrees.
%
% \item |angles-relative|: instead of being absolute, the angles are relative
%   to the direction of the previous step.
%
% \end{itemize}
%
% \begin{figure}
%   \begin{center}
%     \framebox{\RandomWalk {number = 400, length = {4pt, 10pt}}}
%     \caption{The result of \texttt{RandomWalk\{number\ =\
%         400,\ length\ =\ \{4pt,\ 10pt\}\}}: a \(400\) steps long walk,
%       where each step has one of two lengths.}
%   \end{center}
% \end{figure}
%
% \begin{figure}
%   \begin{center}
%     \framebox{\RandomWalk{number = 100,
%         angles = {0,60,120,180,240,300}, degrees}}
%     \caption{The result of \texttt{\string\RandomWalk\{number\ =\
%         100,\ angles\ =\ \{0,60,120,180,240,300\}, degrees\}}: angles
%       are constrained.}
%   \end{center}
% \end{figure}
%
% \begin{figure}
%   \begin{center}
%     \framebox{\RandomWalk {number = 40, length = 1em,
%         angles = {0,15,30,-15,-30}, degree, angles-relative}}
%     \caption{A last example: \texttt{\string\RandomWalk\ \{number\ =\ 100,\
%         length\ =\ 2em,\ angles\ =\ \{0,10,20,-10,-20\},\
%         degree,\ angles-relative\}}}
%   \end{center}
% \end{figure}
%
% \end{documentation}
%
% \begin{implementation}
%
% \section{\pkg{randomwalk} implementation}
%
% \subsection{Packages}
%
% The whole |expl3| bundle is loaded first, including Joseph Wright's
% very useful package |l3fp.sty| for floating point calculations.
%
%<*package>
%    \begin{macrocode}
\ProvidesExplPackage
  {\ExplFileName}{\ExplFileDate}{\ExplFileVersion}{\ExplFileDescription}
\RequirePackage{expl3}
\RequirePackage{xparse}
%    \end{macrocode}
%
% I use some LaTeX2e packages: TikZ, for figures, and lcg for
% random numbers.
%    \begin{macrocode}
\RequirePackage{tikz}
%    \end{macrocode}
%
% |lcg| needs to know the smallest and biggest random numbers that it
% should produce, |\c_rw_lcg_first| and |_last|. It will then store them in
% |\c@lcg@rand|: the |\c@| is there because of how \LaTeXe\ defines
% counters. To make it clear that |\c| has a very special meaning here,
% I do not follow \LaTeX3 naming conventions.
%
% The |lcg| package would support a range of \( 2^{31} - 1 \), but
% |l3fp| constrains us to \(9\) digit numbers, so we take the closest
% available power of \(2\), namely \( 536870911 = 2^{29} - 1 \).
%
%    \begin{macrocode}
\int_const:Nn \c_rw_lcg_first_int {0}
\int_const:Nn \c_rw_lcg_last_int  {536870911}
\int_const:Nn \c_rw_lcg_range_int
  { \c_rw_lcg_last_int - \c_rw_lcg_first_int }
\RequirePackage
  [
    first= \c_rw_lcg_first_int,
    last = \c_rw_lcg_last_int,
    counter = lcg@rand
  ]
  { lcg }
\rand % This \rand avoids some very odd bug.
%    \end{macrocode}
%
% We need this constant for fast conversion from degrees to radians later.
%    \begin{macrocode}
\fp_const:Nn \c_rw_one_degree_fp {+1.74532925e-2}
%    \end{macrocode}
%
%
% \subsection{How the key-value list is treated}
%
% \begin{macro}{\RandomWalk}
%   The only user command is |\RandomWalk|: it simply does the setup, and
%   calls the internal macro |\rw_walk:|.
%    \begin{macrocode}
\DeclareDocumentCommand \RandomWalk { m }
  {
    \rw_set_defaults:
    \keys_set:nn { randomwalk } { #1 }
    \rw_walk:
  }
%    \end{macrocode}
% \end{macro}
%
%
% \begin{macro}{\g_rw_Ado_tl}
% \begin{macro}{\g_rw_Ldo_tl}
% \begin{macro}{\rw_set_defaults:}
%   Currently, the package treats the length of steps, and the angle,
%   completely independently. The token list \cs{g_rw_Ldo_tl} contains
%   the action that should be done to decide the length of the next step,
%   while the token list \cs{g_rw_Ado_tl} pertains to the angle.
%
%   \cs{rw_set_defaults:} sets the default values before processing the user's
%   key-value input.
%    \begin{macrocode}
\tl_new:N \g_rw_Ado_tl
\tl_new:N \g_rw_Ldo_tl
\bool_new:N \l_rw_A_relative_bool
\bool_new:N \l_rw_revert_random_bool
\cs_new:Npn \rw_set_defaults:
  {
    \fp_set:Nn \l_rw_step_length_fp {10}
    \int_set:Nn \l_rw_step_number_int {10}
    \tl_gset:Nn \g_rw_Ado_tl { \rw_Ainterval:nn {-\c_pi_fp} {\c_pi_fp} }
    \tl_gset:Nn \g_rw_Ldo_tl { \rw_Lfixed:n \l_rw_step_length_fp } %^^A bug?
    \bool_set_false:N \l_rw_revert_random_bool
    \bool_set_false:N \l_rw_A_relative_bool
  }
%    \end{macrocode}
% \end{macro}
% \end{macro}
% \end{macro}
%
% \begin{macro}{\keys_define:nn}
%   We introduce the keys for the package.
%    \begin{macrocode}
\keys_define:nn { randomwalk }
  {
    number .value_required:,
    length .value_required:,
    angles .value_required:,
    number .code:n = {\int_set:Nn \l_rw_step_number_int {#1}},
    length .code:n =
      {
        \clist_set:Nn \l_rw_lengths_clist {#1}
        \rw_clist_fp_from_dim:N \l_rw_lengths_clist
        \int_compare:nNnTF { \clist_length:N \l_rw_lengths_clist } = {1}
          { \tl_gset:Nn \g_rw_Ldo_tl { \rw_Lfixed:n \l_rw_lengths_clist } }
          { \tl_gset:Nn \g_rw_Ldo_tl { \rw_Llist:N \l_rw_lengths_clist } }
      },
    angles .code:n  =
      {
        \clist_set:Nn \l_rw_angles_clist {#1}
        \tl_gset:Nn \g_rw_Ado_tl { \rw_Alist:N \l_rw_angles_clist }
      },
    degree .code:n  = { \rw_radians_from_degrees:N \l_rw_angles_clist },
    degrees .code:n = { \rw_radians_from_degrees:N \l_rw_angles_clist },
    angles-relative .code:n   = { \bool_set_true:N \l_rw_A_relative_bool },
    revert-random .bool_set:N = \l_rw_revert_random_bool,
  }
%    \end{macrocode}
% \end{macro}
%
%
% \subsection{Drawing}
%
% \begin{macro}{\rw_walk:}
%   We are ready to define |\rw_walk:|, which draws a TikZ picture of
%   a random walk with the parameters set up by the |keys|.
%   We reset all the coordinates to zero originally. Then we draw the relevant
%   TikZ picture by repeatedly calling |\rw_step_draw:|.
%    \begin{macrocode}
\cs_new:Npn \rw_walk:
  {
    \fp_zero:N \l_rw_old_x_fp
    \fp_zero:N \l_rw_old_y_fp
    \fp_zero:N \l_rw_new_x_fp
    \fp_zero:N \l_rw_new_y_fp
    \begin{tikzpicture}
      \prg_replicate:nn { \l_rw_step_number_int } { \rw_step_draw: }
      \bool_if:NF \l_rw_revert_random_bool
        { \int_gset_eq:NN \cr@nd \cr@nd }
    \end{tikzpicture}
  }
%    \end{macrocode}
%   \cs{cr@nd} is internal to the lcg package.
% \end{macro}
%
% \begin{macro}{\rw_step_draw:}
%   |\rw_step_draw:| passes its second argument \emph{with one level of
%     braces removed} to its first argument, responsible for making a random
%   step. Then, |\rw_step_draw:| draws the random step.
%    \begin{macrocode}
\cs_new:Npn \rw_step_draw:
  {
    \g_rw_Ldo_tl
    \g_rw_Ado_tl
    \rw_cartesian_from_polar:NNNN
      \l_rw_step_x_fp \l_rw_step_y_fp
      \l_rw_radius_fp \l_rw_angle_fp
    \fp_add:Nn \l_rw_new_x_fp { \l_rw_step_x_fp }
    \fp_add:Nn \l_rw_new_y_fp { \l_rw_step_y_fp }
    \draw ( \fp_to_dim:N \l_rw_old_x_fp, \fp_to_dim:N \l_rw_old_y_fp )
       -- ( \fp_to_dim:N \l_rw_new_x_fp, \fp_to_dim:N \l_rw_new_y_fp );
    \fp_set_eq:NN \l_rw_old_x_fp \l_rw_new_x_fp
    \fp_set_eq:NN \l_rw_old_y_fp \l_rw_new_y_fp
  }
%    \end{macrocode}
% \end{macro}
%
% The next couple of macros store a random floating point in
% |\l_rw_length_fp| or |\l_rw_angle_fp|.
%
% \begin{macro}{\rw_L..:.}
%   First for the length of steps.
%    \begin{macrocode}
\cs_new:Npn \rw_Lfixed:n #1
  { \fp_set:Nn \l_rw_radius_fp {#1} }
\cs_new:Npn \rw_Llist:N #1
  { \rw_set_to_random_clist_element:NN \l_rw_radius_fp #1 }
\cs_new:Npn \rw_Linterval:nn #1#2
  { \rw_set_to_random_fp:Nnn \l_rw_radius_fp {#1} {#2} }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{\rw_A..:.}
%   Then for angles.
%    \begin{macrocode}
\cs_new:Npn \rw_Ainterval:nn #1#2
  {
    \bool_if:NTF \l_rw_A_relative_bool
      { \rw_add_to_random_fp:Nnn }
      { \rw_set_to_random_fp:Nnn }
      \l_rw_angle_fp {#1} {#2}
  }
\cs_new:Npn \rw_Alist:N #1
  {
    \bool_if:NTF \l_rw_A_relative_bool
      { \rw_add_to_random_clist_element:NN }
      { \rw_set_to_random_clist_element:NN }
      \l_rw_angle_fp #1
  }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{\rw_cartesian_from_polar:NNNN}
%   The four arguments of |\rw_cartesian_from_polar:NNNN| are
%   \( (x, y, r, \theta) \): it sets \( (x, y) \) equal to the cartesian
%   coordinates corresponding to a radius \(r\) and an angle \( \theta \).
%   We also give a version with global assignments.
%    \begin{macrocode}
\cs_new_protected:Npn \rw_cartesian_from_polar:NNNN #1#2#3#4
  {
    \fp_cos:Nn #1 {\fp_use:N #4}
    \fp_sin:Nn #2 {\fp_use:N #4}
    \fp_mul:Nn #1 {\fp_use:N #3}
    \fp_mul:Nn #2 {\fp_use:N #3}
  }
\cs_new_protected:Npn \rw_gcartesian_from_polar:NNNN #1#2#3#4
  {
    \fp_gcos:Nn #1 {\fp_use:N #4}
    \fp_gsin:Nn #2 {\fp_use:N #4}
    \fp_gmul:Nn #1 {\fp_use:N #3}
    \fp_gmul:Nn #2 {\fp_use:N #3}
  }
%    \end{macrocode}
% \end{macro}
%
% We cannot yet do the conversion in the other direction: |l3fp.dtx| does
% not yet provide inverse trigonometric functions. But in fact, we do not
% need this conversion, so let's stop worrying.
%
% \subsection{On random numbers etc.}
%
% For random numbers, the interface of |lcg| is not quite enough, so we
% provide our own \LaTeX3y functions. Also, this will allow us to change
% quite easily our source of random numbers.
%
%    \begin{macrocode}
\cs_new:Npn \rw_set_to_random_int:Nnn #1#2#3
  {
    \rand
    \int_set:Nn #1 { \int_mod:nn {\c@lcg@rand} { #3 - (#2) } }
  }
%    \end{macrocode}
% We also need floating point random numbers.
%    \begin{macrocode}
\cs_new:Npn \rw_set_to_random_fp:Nnn #1#2#3
  {
    \fp_set:Nn \l_rw_tmpa_fp {#3}
    \fp_sub:Nn \l_rw_tmpa_fp {#2}
    \rand
    \fp_set:Nn \l_rw_tmpb_fp { \int_use:N \c@lcg@rand }
    \fp_div:Nn \l_rw_tmpb_fp { \int_use:N \c_rw_lcg_range_int }
    \fp_mul:Nn \l_rw_tmpa_fp { \l_rw_tmpb_fp }
    \fp_add:Nn \l_rw_tmpa_fp {#2}
    \fp_set:Nn #1 { \l_rw_tmpa_fp }
  }
\cs_new:Npn \rw_add_to_random_fp:Nnn #1#2#3
  {
    \fp_set:Nn \l_rw_tmpa_fp {#3}
    \fp_sub:Nn \l_rw_tmpa_fp {#2}
    \rand
    \fp_set:Nn \l_rw_tmpb_fp { \int_use:N \c@lcg@rand }
    \fp_div:Nn \l_rw_tmpb_fp { \int_use:N \c_rw_lcg_range_int }
    \fp_mul:Nn \l_rw_tmpa_fp { \l_rw_tmpb_fp }
    \fp_add:Nn \l_rw_tmpa_fp {#2}
    \fp_add:Nn #1 { \l_rw_tmpa_fp } %here: mod?
  }
%    \end{macrocode}
%
% We can now pick an element at random from a comma-separated list
%    \begin{macrocode}
\cs_new:Npn \rw_set_to_random_clist_element:NN #1#2
  {
    \rw_set_to_random_int:Nnn \l_rw_tmpb_int {0} { \clist_length:N #2 }
    \fp_set:Nn #1 { \clist_item:Nn #2 { \l_rw_tmpb_int } }
  }
\cs_new:Npn \rw_add_to_random_clist_element:NN #1#2
  {
    \rw_set_to_random_int:Nnn \l_rw_tmpb_int {0} { \clist_length:N #2 }
    \fp_add:Nn #1 { \clist_item:Nn #2 { \l_rw_tmpb_int } }
  }
%    \end{macrocode}
%
% \subsection{Other comma list operations}
% More stuff on |clist|s.
%    \begin{macrocode}
\cs_new:Npn \rw_radians_from_degrees:N #1
  {
    \clist_clear:N \l_rw_tmpa_clist
    \clist_map_inline:Nn #1
      {
        \fp_set:Nn \l_rw_tmpa_fp {##1}
        \fp_mul:Nn \l_rw_tmpa_fp { \c_rw_one_degree_fp }
        \clist_push:NV \l_rw_tmpa_clist \l_rw_tmpa_fp
      }
    \clist_set_eq:NN #1 \l_rw_tmpa_clist
  }
\cs_new:Npn \rw_clist_fp_from_dim:N #1
  {
    \clist_clear:N \l_rw_tmpa_clist
    \clist_map_inline:Nn #1
      {
        \fp_set_from_dim:Nn \l_rw_tmpa_fp {##1}
        \clist_push:NV \l_rw_tmpa_clist \l_rw_tmpa_fp
      }
    \clist_set_eq:NN #1 \l_rw_tmpa_clist
  }
%    \end{macrocode}
%
% \subsection{Variables}
%
% We need a bunch of floating point numbers: each step line goes from the
% |_old| point to the |_new| point. The coordinates |_add| are those of the
% vector from one to the next, so that |_new = _old + _add|.
%    \begin{macrocode}
\fp_new:N \l_rw_old_x_fp
\fp_new:N \l_rw_old_y_fp
\fp_new:N \l_rw_step_x_fp
\fp_new:N \l_rw_step_y_fp
\fp_new:N \l_rw_new_x_fp
\fp_new:N \l_rw_new_y_fp
\fp_new:N \l_rw_angle_fp
\int_new:N \l_rw_step_number_int
\clist_new:N \l_rw_angles_clist
\clist_new:N \l_rw_lengths_clist
\fp_new:N \l_rw_tmpa_fp
\fp_new:N \l_rw_tmpb_fp
\clist_new:N \l_rw_tmpa_clist
\int_new:N \l_rw_tmpb_int
%    \end{macrocode}
%</package>
%
% \end{implementation}
%
% \endinput