From e0c6872cf40896c7be36b11dcc744620f10adf1d Mon Sep 17 00:00:00 2001 From: Norbert Preining Date: Mon, 2 Sep 2019 13:46:59 +0900 Subject: Initial commit --- macros/latex/contrib/randomwalk/README.md | 32 ++ macros/latex/contrib/randomwalk/randomwalk.dtx | 486 +++++++++++++++++++++++++ macros/latex/contrib/randomwalk/randomwalk.ins | 22 ++ macros/latex/contrib/randomwalk/randomwalk.pdf | Bin 0 -> 478962 bytes 4 files changed, 540 insertions(+) create mode 100644 macros/latex/contrib/randomwalk/README.md create mode 100644 macros/latex/contrib/randomwalk/randomwalk.dtx create mode 100644 macros/latex/contrib/randomwalk/randomwalk.ins create mode 100644 macros/latex/contrib/randomwalk/randomwalk.pdf (limited to 'macros/latex/contrib/randomwalk') diff --git a/macros/latex/contrib/randomwalk/README.md b/macros/latex/contrib/randomwalk/README.md new file mode 100644 index 0000000000..5c5ffc3264 --- /dev/null +++ b/macros/latex/contrib/randomwalk/README.md @@ -0,0 +1,32 @@ +Random Walks for LaTeX +================================= +* E-mail: blflatex+randomwalk@gmail.com +* Released under the LaTeX Project Public License v1.3c or later + See http://www.latex-project.org/lppl.txt + +The randomwalk package provides a user command, `\RandomWalk`, to draw +random walks with a given number of steps. Lengths and angles of the +steps can be customized in various ways. + +This package uses `pgf`. It also uses the `l3kernel` and `l3packages` +bundles. + + +All suggestions/comments/bug reports are welcome! +See https://github.com/blefloch/latex-randomwalk + + +The package is extracted by running + + pdflatex randomwalk.ins + +The documentation is produced by running + + pdflatex randomwalk.dtx + makeindex -s gglo.ist -o randomwalk.gls randomwalk.glo + makeindex -s gind.ist -o randomwalk.ind randomwalk.idx + pdflatex randomwalk.dtx + pdflatex randomwalk.dtx + + + diff --git a/macros/latex/contrib/randomwalk/randomwalk.dtx b/macros/latex/contrib/randomwalk/randomwalk.dtx new file mode 100644 index 0000000000..58cc492858 --- /dev/null +++ b/macros/latex/contrib/randomwalk/randomwalk.dtx @@ -0,0 +1,486 @@ +% \iffalse +%% File: randomwalk.dtx Copyright (C) 2011-2018 Bruno Le Floch +%% +%% This work may be distributed and/or modified under the +%% conditions of the LaTeX Project Public License, either version 1.3c +%% of this license or (at your option) any later version. +%% The latest version of this license is in +%% http://www.latex-project.org/lppl.txt +%% +%% This work has the LPPL maintenance status 'maintained' +%% and the current maintainer is Bruno Le Floch. +%% +%% This work consists of the files randomwalk.dtx and randomwalk.ins and +%% derived files randomwalk.sty and randomwalk.pdf. +%% ----------------------------------------------------------------------- +% +%<*driver|package> +% +%<*driver> +\RequirePackage{expl3} +\documentclass[full]{l3doc} +\usepackage{randomwalk} +\AtBeginDocument{\chgrand[seed = 411500]\rand} +\usepackage{amsmath} +\begin{document} + \DocInput{randomwalk.dtx} +\end{document} +% +% \fi +% +%^^A The date here also is in \ProvidesExplPackage, and in the copyright. +% \def\fileversion{v0.6} +% \def\filedate{2018/12/28} +% +% \title{The \pkg{randomwalk} package: \\ +% customizable random walks\thanks{This file describes version +% \fileversion, last revised \filedate.}} +% \author{Bruno Le Floch\thanks{E-mail blflatex+randomwalk@gmail.com}} +% \date{Released on \filedate} +% +% \maketitle +% \tableofcontents +% +% \begin{documentation} +% +% \begin{abstract} +% +% The \pkg{randomwalk} package draws random walks. 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 uniformly at random from a given list. +% \item The angle of each step, either taken uniformly at random +% from a given list, or uniformly distributed between $0$~and +% $360$ degrees. +% \end{itemize} +% +% \end{abstract} +% +% +% \section{How to use \pkg{randomwalk}} +% +% \newcommand{\examplei} +% {\RandomWalk {number = 200, length = {4pt, 10pt}}} +% \newcommand{\exampleii} +% {\RandomWalk {number = 100, angles = {0,60,120,180,240,300}, degree}} +% \newcommand{\exampleiii} +% {\RandomWalk {number = 50, length = 1ex, angles = {0,24,48,-24,-48}, degree, angles-relative}} +% \begin{function}{\RandomWalk} +% The \pkg{randomwalk} package has a single user command: +% \cs{RandomWalk}, which takes a list of key-value pairs as its +% argument. A few examples are given in Figures~\ref{examplei}, \ref{exampleii}, and~\ref{exampleiii}: +% \begin{quote}\ttfamily +% \detokenize\expandafter{\examplei}\\ +% \detokenize\expandafter{\exampleii}\\ +% \detokenize\expandafter{\exampleiii} +% \end{quote} +% Here is a list of all the keys, and their meaning: +% \begin{itemize} +% \item \texttt{number}: the number of steps (default \(10\)) +% \item \texttt{length}: the length of each step: either one dimension +% (\emph{e.g.}, |1ex|), or a comma-separated list of dimensions +% (\emph{e.g.}, |{2pt, 5pt}|), by default |10pt|. The length of each +% step is a (uniformly distributed) random element in this set of +% possible dimensions. +% \item \texttt{angles}: the polar angle for each step: a +% comma-separated list of angles, and each step takes a random angle +% in the list. If this is not specified, then the angle is +% uniformly distributed along the circle. +% \item \texttt{degree} or \texttt{degrees}: specify that the angles +% are given in degrees (by default, they are in radians). +% \item \texttt{angles-relative}: instead of being absolute, the +% angles are relative to the direction of the previous step. +% \item \texttt{revert-random} (boolean, false by default): revert the +% seed of the random number generator to its original value after +% the random walk. +% \end{itemize} +% \end{function} +% +% \begin{figure} +% \begin{center} +% \framebox{\examplei} +% \caption{\label{examplei}A \(200\) steps long +% walk, where each step has one of two lengths: +% \texttt{\detokenize\expandafter{\examplei}}} +% \end{center} +% \end{figure} +% +% \begin{figure} +% \begin{center} +% \framebox{\exampleii} +% \caption{\label{exampleii}A walk with constrained angles: +% \texttt{\detokenize\expandafter{\exampleii}}} +% \end{center} +% \end{figure} +% +% \begin{figure} +% \begin{center} +% \framebox{\exampleiii} +% \caption{\label{exampleiii}A last example, with small relative +% angles: \texttt{\detokenize\expandafter{\exampleiii}}} +% \end{center} +% \end{figure} +% +% \end{documentation} +% +% \begin{implementation} +% +% \section{\pkg{randomwalk} implementation} +% +% \subsection{Packages} +% +% The \pkg{expl3} bundle is loaded first. +% +%<*package> +% \begin{macrocode} +%<@@=randomwalk> +% \end{macrocode} +% +% \begin{macrocode} +\RequirePackage{expl3}[2017/11/14] +\ProvidesExplPackage + {randomwalk} {2018/12/28} {0.6} {Customizable random walks} +\RequirePackage{xparse}[2017/11/14] +% \end{macrocode} +% +% Load \pkg{pgfcore} for figures. +% \begin{macrocode} +\RequirePackage{pgfcore} +% \end{macrocode} +% +% Load \pkg{lcg} for random numbers. +% It needs to know the smallest and biggest random numbers that +% should be produced, which we take to be $0$ and $\cs{c_@@_lcg_last_int} +% = 2^{31}-2$. It will then store them in \cs{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. Also of note is that I use \cs{cr@nd} in \cs{@@_walk:}. +% +% It seems that the \pkg{lcg} package has to be loaded after the +% document class, hence we do it \cs{AtBeginDocument}. Also worth noting +% is the call to \cs{rand}, which avoids some very odd bug. +% \begin{macrocode} +\int_const:Nn \c_@@_lcg_last_int { \c_max_int - 1 } +\AtBeginDocument + { + \RequirePackage + [ + first= 0 , + last = \c_@@_lcg_last_int , + counter = lcg@rand + ] + { lcg } + \rand + } +% \end{macrocode} +% +% \subsection{Variables} +% +% \begin{variable}{\l_@@_internal_tl, \l_@@_internal_int} +% Used for scratch assignments. +% \begin{macrocode} +\tl_new:N \l_@@_internal_tl +\int_new:N \l_@@_internal_int +% \end{macrocode} +% \end{variable} +% +% \begin{variable}{\l_@@_step_number_int} +% The number of steps requested by the caller. +% \begin{macrocode} +\int_new:N \l_@@_step_number_int +% \end{macrocode} +% \end{variable} +% +% \begin{variable}{\l_@@_relative_angles_bool, \l_@@_degrees_bool} +% Booleans for whether angles are relative (keyval option), +% and whether they are in degrees. +% \begin{macrocode} +\bool_new:N \l_@@_relative_angles_bool +\bool_new:N \l_@@_degrees_bool +% \end{macrocode} +% \end{variable} +% +% \begin{variable}{\l_@@_revert_random_bool} +% Booleans for whether to revert the random seed to its original value +% or keep the last value reached at the end of a random path. +% \begin{macrocode} +\bool_new:N \l_@@_revert_random_bool +% \end{macrocode} +% \end{variable} +% +% \begin{macro}{\@@_next_angle:, \@@_next_length:} +% Set the \cs{l_@@_angle_fp} and \cs{l_@@_length_fp} of the next step, +% most often randomly. +% \begin{macrocode} +\cs_new_protected:Npn \@@_next_angle: { } +\cs_new_protected:Npn \@@_next_length: { } +% \end{macrocode} +% \end{macro} +% +% \begin{variable}{\l_@@_angle_fp, \l_@@_length_fp} +% Angle and length of the next step. +% \begin{macrocode} +\fp_new:N \l_@@_angle_fp +\fp_new:N \l_@@_length_fp +% \end{macrocode} +% \end{variable} +% +% \begin{variable}{\l_@@_x_dim, \l_@@_y_dim} +% Current coordinates: each \cs{pgfpathlineto} statement +% goes from the previous value of these to the next. See +% \cs{@@_walk_step:}. +% \begin{macrocode} +\dim_new:N \l_@@_x_dim +\dim_new:N \l_@@_y_dim +% \end{macrocode} +% \end{variable} +% +% \begin{variable}{\l_@@_angles_seq, \l_@@_lengths_seq} +% Sequences containing all allowed angles and lengths, as +% floating point numbers. +% \begin{macrocode} +\seq_new:N \l_@@_angles_seq +\seq_new:N \l_@@_lengths_seq +% \end{macrocode} +% \end{variable} +% +% \subsection{User command and key-value list} +% +% \begin{macro}{\RandomWalk, \randomwalk:n} +% The user command \cs{RandomWalk} is based on the code-level +% command \cs{randomwalk:n}, which simply does the setup and calls +% the internal macro \cs{@@_walk:}. +% \begin{macrocode} +\DeclareDocumentCommand \RandomWalk { m } + { \randomwalk:n {#1} } +\cs_new_protected:Npn \randomwalk:n #1 + { + \@@_setup_defaults: + \keys_set:nn { randomwalk } {#1} + \@@_walk: + } +% \end{macrocode} +% \end{macro} +% +% We introduce the keys for the package. +% \begin{macrocode} +\keys_define:nn { randomwalk } + { + number .value_required:n = true , + length .value_required:n = true , + angles .value_required:n = true , + number .int_set:N = \l_@@_step_number_int , + length .code:n = { \@@_setup_length:n {#1} } , + angles .code:n = { \@@_setup_angles:n {#1} } , + degree .bool_set:N = \l_@@_degrees_bool , + degrees .bool_set:N = \l_@@_degrees_bool , + angles-relative .bool_set:N = \l_@@_relative_angles_bool , + revert-random .bool_set:N = \l_@@_revert_random_bool , + } +% \end{macrocode} +% +% \subsection{Setup} +% +% \begin{macro}{\@@_setup_defaults:} +% The package treats the length of steps, and the angle, +% completely independently. The function \cs{@@_next_length:} +% contains the action that decides the length of the next step, while +% the function \cs{@@_next_angle:} pertains to the angle. +% +% \cs{@@_setup_defaults:} sets the default values before processing the +% user's key-value input. This also sets initial values of variables +% that currently cannot be altered through keys, because it might be +% good to provide keys for their initial values too later on. +% \begin{macrocode} +\cs_new_protected:Npn \@@_setup_defaults: + { + \int_set:Nn \l_@@_step_number_int {10} + \cs_gset_protected:Npn \@@_next_angle: + { \@@_fp_set_rand:Nnn \l_@@_angle_fp { 0 } { 360 } } + \cs_gset_protected:Npn \@@_next_length: + { \fp_set:Nn \l_@@_length_fp {10} } + \bool_set_false:N \l_@@_revert_random_bool + \bool_set_false:N \l_@@_relative_angles_bool + \fp_zero:N \l_@@_angle_fp + \fp_zero:N \l_@@_length_fp + \dim_zero:N \l_@@_x_dim + \dim_zero:N \l_@@_y_dim + } +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\@@_setup_length:n} +% Convert each item in the comma list into a floating point, then +% define \cs{@@_next_length:} to set \cs{l_@@_length_fp} to a random +% floating point in the list. +% \begin{macrocode} +\cs_new_protected:Npn \@@_setup_length:n #1 + { + \seq_set_split:Nnn \l_@@_lengths_seq { , } {#1} + \seq_set_map:NNn \l_@@_lengths_seq + \l_@@_lengths_seq { \dim_to_fp:n {##1} } + \cs_gset_protected:Npn \@@_next_length: + { + \@@_get_rand_seq_item:NN + \l_@@_lengths_seq \l_@@_internal_tl + \fp_set:Nn \l_@@_length_fp { \l_@@_internal_tl } + } + } +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\@@_setup_angles:n} +% Two complications compared to \cs{@@_setup_length:n}. First, the +% angle can be given in radians rather than degrees: then add |rad| +% after the randomly chosen value (in principle it would be better to +% convert angles once and for all at the beginning, but that +% interacts in a complicated way with the fact that keys can be given +% in any order). Second, angles can be relative, in which case we +% use \cs{fp_add:Nn} to take the last angle into account. +% \begin{macrocode} +\cs_new_protected:Npn \@@_setup_angles:n #1 + { + \seq_set_split:Nnn \l_@@_angles_seq { , } {#1} + \seq_set_map:NNn \l_@@_angles_seq + \l_@@_angles_seq { \fp_to_tl:n {##1} } + \cs_gset_protected:Npn \@@_next_angle: + { + \@@_get_rand_seq_item:NN + \l_@@_angles_seq \l_@@_internal_tl + \bool_if:NF \l_@@_degrees_bool + { \tl_put_right:Nn \l_@@_internal_tl { rad } } + \bool_if:NTF \l_@@_relative_angles_bool + { \fp_add:Nn } { \fp_set:Nn } + \l_@@_angle_fp { \l_@@_internal_tl } + } + } +% \end{macrocode} +% \end{macro} +% +% \subsection{Drawing} +% +% \begin{macro}{\@@_walk:} +% We are ready to define \cs{@@_walk:}, which draws a \pkg{pgf} +% picture of a random walk with the parameters set up by the +% \texttt{keys}. We reset coordinates to zero originally. +% Then draw the relevant \pkg{pgf} picture by repeatedly calling +% \cs{@@_walk_step:}. +% \begin{macrocode} +\cs_new_protected:Npn \@@_walk: + { + \@@_walk_start: + \prg_replicate:nn { \l_@@_step_number_int } + { \@@_walk_step: } + \bool_if:NF \l_@@_revert_random_bool + { \int_gset_eq:NN \cr@nd \cr@nd } + \@@_walk_stop: + } +% \end{macrocode} +% \cs{cr@nd} is internal to the lcg package. +% \end{macro} +% +% \begin{macro}{\@@_walk_start:, \@@_walk_line:, \@@_walk_stop:} +% These functions encapsulate all of the \pkg{pgf}-related code. The +% \texttt{start} function begins the pgfpicture environment and +% starts a path at position (x,y). The \texttt{line} function adds +% to the path a line from the previous position to the new (x,y). +% The \texttt{stop} function draws the path constructed by +% \cs{@@_walk_step:} and ends the pgfpicture environment. +% \begin{macrocode} +\cs_new_protected:Npn \@@_walk_start: + { + \begin{pgfpicture} + \pgfpathmoveto + { \pgfpoint { \l_@@_x_dim } { \l_@@_y_dim } } + } +\cs_new_protected:Npn \@@_walk_line: + { + \pgfpathlineto + { \pgfpoint { \l_@@_x_dim } { \l_@@_y_dim } } + } +\cs_new_protected:Npn \@@_walk_stop: + { + \pgfusepath { stroke } + \end{pgfpicture} + } +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\@@_walk_step:} +% \cs{@@_walk_step:} calls \cs{@@_next_length:} and +% \cs{@@_next_angle:} to determine the length and angle of the new +% step. This is then converted to cartesian coordinates and added to +% the previous end-point. Finally, we call \pkg{pgf}'s \cs{pgfpathlineto} to +% produce a line to the new point. +% \begin{macrocode} +\cs_new_protected:Npn \@@_walk_step: + { + \@@_next_length: + \@@_next_angle: + \dim_add:Nn \l_@@_x_dim + { + \fp_to_dim:n + { \l_@@_length_fp * cosd ( \l_@@_angle_fp ) } + } + \dim_add:Nn \l_@@_y_dim + { + \fp_to_dim:n + { \l_@@_length_fp * sind ( \l_@@_angle_fp ) } + } + \@@_walk_line: + } +% \end{macrocode} +% \end{macro} +% +% \subsection{On random numbers and items} +% +% For random numbers, the interface of \pkg{lcg} is not quite enough, so +% we provide our own \LaTeX3-y functions. Also, this will allow us to +% change quite easily our source of random numbers. +% +% \begin{macro}{\@@_fp_set_rand:Nnn} +% We also need floating point random numbers, assigned +% to the variable |#1|. +% \begin{macrocode} +\cs_new_protected:Npn \@@_fp_set_rand:Nnn #1#2#3 + { + \rand + \fp_set:Nn #1 + { #2 + (#3 - (#2)) * \c@lcg@rand / \c_@@_lcg_last_int } + } +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\@@_get_rand_seq_item:NN} +% We can now pick an element at random from a sequence. If the +% sequence has a single element, no need for randomness. +% \begin{macrocode} +\cs_new_protected:Npn \@@_get_rand_seq_item:NN #1#2 + { + \int_set:Nn \l_@@_internal_int { \seq_count:N #1 } + \int_compare:nTF { \l_@@_internal_int = 1 } + { \tl_set:Nx #2 { \seq_item:Nn #1 { 1 } } } + { + \rand + \tl_set:Nx #2 + { + \seq_item:Nn #1 + { + 1 + + \int_mod:nn { \c@lcg@rand } { \l_@@_internal_int } + } + } + } + } +% \end{macrocode} +% \end{macro} +% +% \begin{macrocode} +% +% \end{macrocode} +% +% \end{implementation} +% +% \endinput diff --git a/macros/latex/contrib/randomwalk/randomwalk.ins b/macros/latex/contrib/randomwalk/randomwalk.ins new file mode 100644 index 0000000000..4e21b32a93 --- /dev/null +++ b/macros/latex/contrib/randomwalk/randomwalk.ins @@ -0,0 +1,22 @@ +\input l3docstrip.tex +\askforoverwritefalse + +\preamble + +Do not distribute a modified version of this file. + +Communicate any suggestions for changing this package +to Bruno Le Floch (see the latex-randomwalk repository +on GitHub). + +\endpreamble +% stop docstrip adding \endinput +\postamble +\endpostamble + +\keepsilent + +% the package +\generate{\file{randomwalk.sty}{\from{randomwalk.dtx}{package}}} + +\endbatchfile diff --git a/macros/latex/contrib/randomwalk/randomwalk.pdf b/macros/latex/contrib/randomwalk/randomwalk.pdf new file mode 100644 index 0000000000..e137bc4134 Binary files /dev/null and b/macros/latex/contrib/randomwalk/randomwalk.pdf differ -- cgit v1.2.3