summaryrefslogtreecommitdiff
path: root/macros
diff options
context:
space:
mode:
authorNorbert Preining <norbert@preining.info>2023-05-31 03:00:51 +0000
committerNorbert Preining <norbert@preining.info>2023-05-31 03:00:51 +0000
commit63f5147c70933ab652aa5c700beabb6685d1139a (patch)
tree0c25a1485a60eb8d64426d4492cfa9fb74faccec /macros
parentf827efba635562d077a72b37051b2d219388a93b (diff)
CTAN sync 202305310300
Diffstat (limited to 'macros')
-rw-r--r--macros/latex/contrib/counterz/README.txt (renamed from macros/latex/contrib/counterz/README)2
-rw-r--r--macros/latex/contrib/counterz/counterz.dtx960
-rw-r--r--macros/latex/contrib/counterz/counterz.ins4
-rw-r--r--macros/latex/contrib/counterz/counterz.pdfbin300058 -> 315915 bytes
-rw-r--r--macros/luatex/latex/luacas/doc/appendix/luacas.dat4
-rw-r--r--macros/luatex/latex/luacas/doc/appendix/versionhistory.tex9
-rw-r--r--macros/luatex/latex/luacas/doc/luacas.pdfbin760471 -> 761064 bytes
-rw-r--r--macros/luatex/latex/luacas/doc/luacas.tex2
-rw-r--r--macros/luatex/latex/luacas/tex/algebra/luacas-absexpression.lua2
-rw-r--r--macros/luatex/latex/luacas/tex/algebra/luacas-algebra_init.lua24
-rw-r--r--macros/luatex/latex/luacas/tex/algebra/luacas-equation.lua2
-rw-r--r--macros/luatex/latex/luacas/tex/algebra/luacas-euclideandomain.lua2
-rw-r--r--macros/luatex/latex/luacas/tex/algebra/luacas-factorialexpression.lua2
-rw-r--r--macros/luatex/latex/luacas/tex/algebra/luacas-field.lua2
-rw-r--r--macros/luatex/latex/luacas/tex/algebra/luacas-integer.lua17
-rw-r--r--macros/luatex/latex/luacas/tex/algebra/luacas-integerquotientring.lua11
-rw-r--r--macros/luatex/latex/luacas/tex/algebra/luacas-logarithm.lua2
-rw-r--r--macros/luatex/latex/luacas/tex/algebra/luacas-polynomialring.lua21
-rw-r--r--macros/luatex/latex/luacas/tex/algebra/luacas-rational.lua22
-rw-r--r--macros/luatex/latex/luacas/tex/algebra/luacas-ring.lua2
-rw-r--r--macros/luatex/latex/luacas/tex/algebra/luacas-rootexpression.lua2
-rw-r--r--macros/luatex/latex/luacas/tex/algebra/luacas-sqrtexpression.lua2
-rw-r--r--macros/luatex/latex/luacas/tex/algebra/luacas-trigexpression.lua2
-rw-r--r--macros/luatex/latex/luacas/tex/calculus/luacas-calculus_init.lua6
-rw-r--r--macros/luatex/latex/luacas/tex/calculus/luacas-derivativeexpression.lua2
-rw-r--r--macros/luatex/latex/luacas/tex/calculus/luacas-diffexpression.lua2
-rw-r--r--macros/luatex/latex/luacas/tex/calculus/luacas-integralexpression.lua2
-rw-r--r--macros/luatex/latex/luacas/tex/core/luacas-atomicexpression.lua2
-rw-r--r--macros/luatex/latex/luacas/tex/core/luacas-binaryoperation.lua4
-rw-r--r--macros/luatex/latex/luacas/tex/core/luacas-compoundexpression.lua2
-rw-r--r--macros/luatex/latex/luacas/tex/core/luacas-constantexpression.lua2
-rw-r--r--macros/luatex/latex/luacas/tex/core/luacas-core_init.lua16
-rw-r--r--macros/luatex/latex/luacas/tex/core/luacas-functionexpression.lua2
-rw-r--r--macros/luatex/latex/luacas/tex/core/luacas-symbolexpression.lua2
-rw-r--r--macros/luatex/latex/luacas/tex/luacas.sty2
-rw-r--r--macros/luatex/latex/luacas/tex/luacas_init.lua304
-rw-r--r--macros/luatex/latex/luacas/tex/test/luacas-main.lua17
-rw-r--r--macros/luatex/latex/luacas/tex/test/luacas-parser.lua24
-rw-r--r--macros/luatex/latex/luacas/tex/test/rings/luacas-conversion.lua20
39 files changed, 1120 insertions, 385 deletions
diff --git a/macros/latex/contrib/counterz/README b/macros/latex/contrib/counterz/README.txt
index b7376e3a0b..00daf51728 100644
--- a/macros/latex/contrib/counterz/README
+++ b/macros/latex/contrib/counterz/README.txt
@@ -1,7 +1,7 @@
----------------------------------------------------------------------
-`counterz' --- 2023/05/19 Version 1.0.0
+`counterz' --- 2023/05/30 Version 1.1.0
Copyright (C) 2023 by Christopher McClain
E-mail: christopher.mcclain@mail.wvu.edu
diff --git a/macros/latex/contrib/counterz/counterz.dtx b/macros/latex/contrib/counterz/counterz.dtx
index 82857faf4c..2efbfa056d 100644
--- a/macros/latex/contrib/counterz/counterz.dtx
+++ b/macros/latex/contrib/counterz/counterz.dtx
@@ -7,7 +7,7 @@
%<*readme>
----------------------------------------------------------------------
-`counterz' --- 2023/05/19 Version 1.0.0
+`counterz' --- 2023/05/30 Version 1.1.0
Copyright (C) 2023 by Christopher McClain
E-mail: christopher.mcclain@mail.wvu.edu
@@ -38,7 +38,7 @@ random counters and save such counter values for future typesetting.
\preamble
----------------------------------------------------------------------
-`counterz' --- 2023/05/19 Version 1.0.0 Additional tools for counters
+`counterz' --- 2023/05/30 Version 1.1.0 Additional tools for counters
E-mail: christopher.mcclain@mail.wvu.edu
Released under the LaTeX Project Public License v1.3c or later
See https://www.latex-project.org/lppl.txt
@@ -110,11 +110,12 @@ and the derived files counterz.ins,
\newcounter,\newbool,\newwrite,\numexpr,\openout,\pdfuniformdeviate,
\providecounter,\ProvidesPackage,\relax,\renewcommand,
\RequirePackage,\Roman,\roman,\setcounter,\the,\unexpanded,\value,
- \whileboolexpr,\write}
+ \whileboolexpr,\write,\@ifnextchar,\ifltxcounter,\InputIfFileExists,
+ \m@k@gobbleendoptarg,\MessageBreak,\PackageError,\protect,\space,
+ \typein,\@typein}
\CodelineIndex
\RecordChanges
\begin{document}
- \newenvironment{codeoutput}{\newline\newline}{\newline\newline}
\DocInput{\jobname.dtx}
\end{document}
%</driver>
@@ -136,6 +137,7 @@ and the derived files counterz.ins,
%\maketitle
%
%\changes{v1.0.0}{2023/05/19}{First public release}
+%\changes{v1.1.0}{2023/05/30}{New and revised commands and error reports}
%
%
%\begin{abstract}
@@ -188,11 +190,12 @@ and the derived files counterz.ins,
%
%\subsection{Installation}
%
-% This package may be installed by copying the file \textsf{counterz.sty} to
-% your local texmf directory. The code and documentation may also be generated
-% from \textsf{\jobname.dtx}. Typesetting the documentation requires
-% the package \textsf{hypdoc} which is included in \TeX\ distributions and at
-% \href{http://www.ctan.org}{The Comprehensive TeX Archive Network}.
+% Run (pdf)\TeX{} on counterz.dtx to generate the file counterz.sty, and copy it
+% to your local texmf directory. To generate both the package file counterz.sty
+% and the documentation counterz.pdf, run (pdf)\LaTeX{} on counterz.dtx.
+% Typesetting the documentation requires the package \textsf{hypdoc} which is
+% included in \TeX\ distributions and at \href{http://www.ctan.org}
+% {The Comprehensive TeX Archive Network}.
%
%\section{User Guide}
%
@@ -202,57 +205,69 @@ and the derived files counterz.ins,
%\begin{verbatim}
%\usepackage{counterz}
%\end{verbatim}
+%
+% \noindent
% The package \textsf{counterz} loads the packages \textsf{etoolbox} and
% \textsf{makecmds}, both of which are included in \TeX\ distributions
% and at \href{http://www.ctan.org}{The Comprehensive TeX Archive Network}.
%
%\subsection{Counter Prefixes}
%
-%\DescribeMacro{\setcounterprefix}
-%\DescribeMacro{\clearcounterprefix}
% Counter prefixes are stored in an internal macro whose default value is an
-% empty string. The command \cs{setcounterprefix}\marg{prefix} is used to change
-% this value. For example, to change the prefix to \textit{PurpleMonkey}, use
+% empty string.
+%\DescribeMacro{\setcounterprefix}
+% The command \cs{setcounterprefix}\marg{prefix} is used to change this value.
+% For example, to change the prefix to \textit{PurpleMonkey}, use
+%
%\begin{verbatim}
%\setcounterprefix{PurpleMonkey}
%\end{verbatim}
+%
+% \noindent
% and to change it from \textit{PurpleMonkey} to \textit{Dishwasher}, use
+%
%\begin{verbatim}
%\setcounterprefix{Dishwasher}
%\end{verbatim}
-% The command \cs{clearcounterprefix} returns the prefix to its empty default:
-%\begin{verbatim}
-%\clearcounterprefix
-%\end{verbatim}
+%
+% \noindent
+%\DescribeMacro{\clearcounterprefix}
+% The command \cs{clearcounterprefix} returns the prefix to its empty default.
%
%\subsection{Manipulating Counters}
%
%\DescribeMacro{\xnewcounter}
-%\DescribeMacro{\xprovidecounter}
-%\DescribeMacro{\xsetcounter}
-%\DescribeMacro{\xaddtocounter}
-%\DescribeMacro{\xvalue}
% The command \cs{xnewcounter}\marg{countername} creates a counter with a
-% prefixed name. The command \cs{xsetcounter}\marg{countername}\marg{integer}
-% assigns the specified value to the counter with the prefixed name. For
-% example, suppose that the file \textsf{BoringFile1.tex} contains the
-% following:
+% prefixed name.
+%\DescribeMacro{\xsetcounter}
+% The command \cs{xsetcounter}\marg{countername}\marg{integer} assigns the
+% specified value to the counter with the prefixed name. For example, suppose
+% that the file \textsf{BoringFile1.tex} contains the following:
+%
%\begin{verbatim}
%\xnewcounter{bestcounterever}
%\xsetcounter{bestcounterever}{100}
%\end{verbatim}
+%
+% \noindent
% and suppose that the file \textsf{BoringFile2.tex} contains the following:
+%
%\begin{verbatim}
%\xnewcounter{bestcounterever}
%\xsetcounter{bestcounterever}{-29}
%\end{verbatim}
+%
+% \noindent
% and, finally, suppose that the file Main.tex contains (in part) the following:
+%
%\begin{verbatim}
%\setcounterprefix{PurpleMonkey}
%\input{BoringFile1}
%\setcounterprefix{Dishwasher}
%\input{BoringFile2}
%\end{verbatim}
+%
+% \noindent
% Then typesetting \textsf{Main.tex} will create a counter
% \textit{PurpleMonkeybestcounterever} with the value 100 and a counter
% \textit{Dishwasherbestcounterever} with the value $-29$. By using commands
@@ -263,9 +278,12 @@ and the derived files counterz.ins,
% in the file \textsf{Main.tex}. By changing prefixes, \textsf{Main.tex} can
% even input the same file multiple times without conflict.
%
+%\DescribeMacro{\xprovidecounter}
% The commands \cs{xprovidecounter}, \cs{xaddtocounter}, and \cs{xvalue} are
% likewise prefix versions of commands \cs{providecounter}, \cs{addtocounter},
+%\DescribeMacro{\xaddtocounter}
% and \cs{value}, respectively. When the prefix is empty, the commands expand
+%\DescribeMacro{\xvalue}
% like their standard counterparts. (Note: \cs{providecounter} defines a counter
% if it has not already been defined. See the documentation for the package
% \textsf{makecmds} for details.)
@@ -273,15 +291,17 @@ and the derived files counterz.ins,
%\subsection{Conditional Statements}
%
%\DescribeMacro{\ifctrequal}
-%\DescribeMacro{\ifctrless}
-%\DescribeMacro{\ifctrmore}
% The command \cs{ifctrequal}\marg{counter1}\marg{counter2}\marg{foo}\marg{bar}
% uses the command \cs{xvalue} to compare the values of the (prefixed) counters
% and then executes \meta{foo} if the values are equal and otherwise executes
-% \meta{bar}. The commands \cs{ifctrless} and \cs{ifctrmore} work analogously,
-% based on whether the value of prefixed \meta{counter1} is less than that of
-% of prefixed \meta{counter2} or more than that of prefixed \meta{counter2},
-% respectively. Consider the example code
+% \meta{bar}. The commands
+%\DescribeMacro{\ifctrless}
+% \cs{ifctrless} and \cs{ifctrmore} work analogously, based on whether the value
+% of prefixed \meta{counter1} is less than that of of prefixed \meta{counter2}
+%\DescribeMacro{\ifctrmore}
+% or more than that of prefixed \meta{counter2}, respectively. Consider the
+% example code
+%
%\begin{verbatim}
%\setcounterprefix{TigerTiger}
%\xnewcounter{Small}
@@ -292,8 +312,11 @@ and the derived files counterz.ins,
%\ifctrless{Small}{Large}{March}{April}
%\ifctrmore{Small}{Large}{May}{June}
%\end{verbatim}
+%
+% \noindent
% which produces the output
-% \begin{codeoutput}
+%
+% \bigskip
%\setcounterprefix{TigerTiger}
%\xnewcounter{Small}
%\xsetcounter{Small}{7}
@@ -302,18 +325,21 @@ and the derived files counterz.ins,
%\ifctrequal{Small}{Large}{January}{February}
%\ifctrless{Small}{Large}{March}{April}
%\ifctrmore{Small}{Large}{May}{June}
-% \end{codeoutput}
+%
+% \bigskip
+% \noindent
% because the value of the counter \textit{TigerTigerSmall} is 7 which is less
% than 11, the value of the counter \textit{TigerTigerLarge}.
%
%\DescribeMacro{\ifctrzero}
-%\DescribeMacro{\ifctrneg}
-%\DescribeMacro{\ifctrpos}
% The command \cs{ifctrzero}\marg{counter}\marg{foo}\marg{bar} executes
% \meta{foo} if the value of the (prefixed) counter is zero and otherwise
-% executes \meta{bar}. The commands \cs{ifctrneg} and \cs{ifctrpos} work
-% analogously based on whether the value is negative or positive, respectively.
-% The example code
+% executes \meta{bar}. The commands
+%\DescribeMacro{\ifctrneg}
+% \cs{ifctrneg} and \cs{ifctrpos} work analogously based on whether the value
+%\DescribeMacro{\ifctrpos}
+% is negative or positive, respectively. The example code
+%
%\begin{verbatim}
%\setcounterprefix{TigerTiger}
%\xprovidecounter{Small}
@@ -322,54 +348,72 @@ and the derived files counterz.ins,
%\ifctrneg{Small}{March}{April}
%\ifctrpos{Small}{May}{June}
%\end{verbatim}
+%
+% \noindent
% produces the output
-% \begin{codeoutput}
+%
+% \bigskip
%\setcounterprefix{TigerTiger}
%\xprovidecounter{Small}
%\xsetcounter{Small}{7}
%\ifctrzero{Small}{January}{February}
%\ifctrneg{Small}{March}{April}
%\ifctrpos{Small}{May}{June}
-% \end{codeoutput}
+%
+% \bigskip
+% \noindent
% because the value of the counter \textit{TigerTigerSmall} is 7 which is
% positive (and thus nonzero, as well).
%
%\subsection{Displaying Counters}
%
%\DescribeMacro{\xarabic}
+% The command \cs{xarabic}\marg{counter} is simply a prefix version of the
+% standard display command \cs{arabic}.
%\DescribeMacro{\xroman}
+% The commands \cs{xroman}, \cs{xRoman}, \cs{xalph}, \cs{xAlph}, and
%\DescribeMacro{\xRoman}
+% \cs{xfnsymbol} are likewise prefix versions of the standard display commands
%\DescribeMacro{\xalph}
+% \cs{roman}, \cs{Roman}, \cs{alph}, \cs{Alph}, and \cs{fnsymbol}, inheriting
+% the restrictions of their
%\DescribeMacro{\xAlph}
+% parent commands.
+%
%\DescribeMacro{\xfnsymbol}
-% The command \cs{xarabic}\marg{counter} is simply a prefix version of the
-% standard display command \cs{arabic}. The commands \cs{xroman}, \cs{xRoman},
-% \cs{xalph}, \cs{xAlph}, and \cs{xfnsymbol} are likewise prefix versions of
-% the standard display commands \cs{roman}, \cs{Roman}, \cs{alph}, \cs{Alph},
-% and \cs{fnsymbol}, inheriting the restrictions of their parent commands.
% Note that the code
+%
%\begin{verbatim}
%\setcounterprefix{Sneaky}
%\xprovidecounter{Pete}
%\xsetcounter{Pete}{42}
%\arabic{Pete}
%\end{verbatim}
+%
+% \noindent
% produces an error because the counter \textit{Pete} is not defined, but the
% code
+%
%\begin{verbatim}
%\setcounterprefix{Sneaky}
%\xprovidecounter{Pete}
%\xsetcounter{Pete}{42}
%\xarabic{Pete}
%\end{verbatim}
+%
+% \noindent
% produces the output
-% \begin{codeoutput}
+%
+% \bigskip
%\setcounterprefix{Sneaky}
%\xprovidecounter{Pete}
%\xsetcounter{Pete}{42}
%\xarabic{Pete}
-% \end{codeoutput}
+%
+% \bigskip
+% \noindent
% which is the value of the counter \textit{SneakyPete}. The code
+%
%\begin{verbatim}
%\setcounterprefix{Sneaky}
%\xprovidecounter{Pete}
@@ -377,6 +421,8 @@ and the derived files counterz.ins,
%\clearcounterprefix
%\xarabic{Pete}
%\end{verbatim}
+%
+% \noindent
% also generates error because the final line is trying to use the
% undefined counter \textit{Pete} after the prefix was returned to its
% default value.
@@ -385,6 +431,7 @@ and the derived files counterz.ins,
% \textsf{counterz} defines some variants of \cs{xarabic} that are useful in
% the display of mathematical expressions. For example, consider the following
% code:
+%
%\begin{verbatim}
%\xprovidecounter{a}
%\xsetcounter{a}{5}
@@ -394,8 +441,11 @@ and the derived files counterz.ins,
%\xsetcounter{c}{-7}
%$\xarabic{a}+\xarabic{b}+\xarabic{c}$
%\end{verbatim}
+%
+% \noindent
% which produces
-% \begin{codeoutput}
+%
+% \bigskip
%\xprovidecounter{a}
%\xsetcounter{a}{5}
%\xprovidecounter{b}
@@ -403,81 +453,109 @@ and the derived files counterz.ins,
%\xprovidecounter{c}
%\xsetcounter{c}{-7}
%$\xarabic{a}+\xarabic{b}+\xarabic{c}$
-% \end{codeoutput}
-% Using \cs{arabicx} causes the expression to
-% contain the consecutive pair $+-$. The command
+%
+% \bigskip
+% \noindent
+% Using \cs{arabicx} causes the expression to contain the consecutive pair $+-$.
+% The command \cs{xsigned}\marg{counter} is like \cs{xarabic} except that
%\DescribeMacro{\xsigned}
-% \cs{xsigned}\marg{counter} is like \cs{xarabic} except that nonnegative values
-% are preceded by a plus sign ``+''. The code
+% nonnegative values are preceded by a plus sign ``+''. The code
+%
%\begin{verbatim}
%$\xarabic{a}\xsigned{b}\xsigned{c}$
%\end{verbatim}
+%
+% \noindent
% produces
-% \begin{codeoutput}
+%
+% \bigskip
%$\xarabic{a}\xsigned{b}\xsigned{c}$
-% \end{codeoutput}
+%
+% \bigskip
+% \noindent
% If we wish to suppress the $0$, we can instead use the command
%\DescribeMacro{\xsignednz}
-%\DescribeMacro{\xarabicnz}
% \cs{xsignednz}\marg{counter} which is a nonzero version of \cs{xsigned} and,
% if desired or necessary, the command \cs{xarabicnz}\marg{counter} which is a
-% nonzero version of \cs{xarabic}.
-% The code
+%\DescribeMacro{\xarabicnz}
+% nonzero version of \cs{xarabic}. The code
+%
%\begin{verbatim}
%$\xarabicnz{a}\xsignednz{b}\xsignednz{c}$
%\end{verbatim}
+%
+% \noindent
% produces
-% \begin{codeoutput}
+%
+% \bigskip
%$\xarabicnz{a}\xsignednz{b}\xsignednz{c}$
-% \end{codeoutput}
+%
+% \bigskip
+% \noindent
%\DescribeMacro{\xnegof}
+% The command \cs{xnegof}\marg{counter} displays the negative of \meta{counter}.
+% The command \cs{xnegofnz} does the same except that it suppresses the number
%\DescribeMacro{\xnegofnz}
+% zero. The command \cs{xnegsigned} includes the appropriate signs of plus ``+''
%\DescribeMacro{\xnegsigned}
+% and minus ``-'' (assigning a minus to zero in this case).
%\DescribeMacro{\xnegsignednz}
-% The package also contains variants of these commands for displaying the
-% negatives of counters, as demonstrated by the following code:
+% Finally, the command \cs{xnegsignednz} does the same except that it suppresses
+% the number zero., as demonstrated by the following code:
+%
%\begin{verbatim}
%\xprovidecounter{d}
%\xsetcounter{d}{-2}
-%$\xarabic{a}\xsigned{b}\xsigned{c}=\xarabic{d}$\\
-%$\xnegof{d}=\xnegof{a}\xnegsigned{b}\xnegsigned{c}$\\
+%
+%$\xarabic{a}\xsigned{b}\xsigned{c}=\xarabic{d}$
+%
+%$\xnegof{d}=\xnegof{a}\xnegsigned{b}\xnegsigned{c}$
+%
%$\xnegofnz{d}=\xnegofnz{a}\xnegsignednz{b}\xnegsignednz{c}$
%\end{verbatim}
+%
+% \noindent
% which produces
-%\begin{codeoutput}
+%
+% \bigskip
%\xprovidecounter{d}
%\xsetcounter{d}{-2}
-%$\xarabic{a}\xsigned{b}\xsigned{c}=\xarabic{d}$\\
-%$\xnegof{d}=\xnegof{a}\xnegsigned{b}\xnegsigned{c}$\\
+%
+%$\xarabic{a}\xsigned{b}\xsigned{c}=\xarabic{d}$
+%
+%$\xnegof{d}=\xnegof{a}\xnegsigned{b}\xnegsigned{c}$
+%
%$\xnegofnz{d}=\xnegofnz{a}\xnegsignednz{b}\xnegsignednz{c}$
-%\end{codeoutput}
+%
+% \bigskip
% The preceding commands for displaying values related to counters were created
% by using some other commands that we make available in case they prove useful.
%\DescribeMacro{\xabsof}
-%\DescribeMacro{\xsignof}
-%\DescribeMacro{\xnegsignof}
% The command \cs{xabsof}\marg{counter} prints the absolute value of
% \meta{counter}. The command \cs{xsignof}\marg{counter} prints a minus sign
+%\DescribeMacro{\xsignof}
% ``-'' if \meta{counter} is negative and otherwise prints a plus sign ``+''.
% (Note that the latter case includes the value zero.) The command
+%\DescribeMacro{\xnegsignof}
% \cs{xnegsignof}\marg{counter} prints a plus sign ``+'' if \meta{counter} is
-% negative and otherwise prints a minus sign ``-''. (Note that the former case
+% negative and otherwise prints a minus sign ``-''. (Note that the latter case
% includes the value zero.)
%
% Additional variants of these commands suppress certain output, as is
% conventional when using integers as coefficients in algebraic expressions.
-%\DescribeMacro{\xabsofcoef}
-%\DescribeMacro{\xsignofcoef}
-%\DescribeMacro{\xnegsignofcoef}
% The command \cs{xabsofcoef}\marg{counter} prints the absolute value of
+%\DescribeMacro{\xabsofcoef}
% \meta{counter} except that it suppresses the values of 1 and 0. The command
+%\DescribeMacro{\xsignofcoef}
% \cs{xsignofcoef}\marg{counter} prints the sign of \meta{counter} if the value
% of \meta{counter} is nonzero. The command \cs{xnegsignofcoef}\marg{counter}
+%\DescribeMacro{\xnegsignofcoef}
% prints the opposite sign of \meta{counter} if the value of \meta{counter} is
% nonzero. These commands are used to build versions of \cs{xarabic} and
% \cs{xsigned} specific to typesetting coefficients, as we now illustrate.
%
% Consider the following code
+%
%\begin{verbatim}
%\xprovidecounter{a0}
%\xsetcounter{a0}{-10}
@@ -492,10 +570,13 @@ and the derived files counterz.ins,
%\xprovidecounter{a5}
%\xsetcounter{a5}{11}
%$\xarabic{a5}x^5 + \xarabic{a4}x^4 + \xarabic{a3}x^3 + \xarabic{a2}x^2
-% + \xarabic{a1}x + \xarabic{a0} = 42$
+% + \xarabic{a1}x + \xarabic{a0} = 42$
%\end{verbatim}
+%
+% \noindent
% and its output
-%\begin{codeoutput}
+%
+% \bigskip
%\xprovidecounter{a0}
%\xsetcounter{a0}{-10}
%\xprovidecounter{a1}
@@ -509,57 +590,95 @@ and the derived files counterz.ins,
%\xprovidecounter{a5}
%\xsetcounter{a5}{11}
%$\xarabic{a5}x^5 + \xarabic{a4}x^4 + \xarabic{a3}x^3 + \xarabic{a2}x^2
-% + \xarabic{a1}x + \xarabic{a0} = 42$
-%\end{codeoutput}
-% We seek a better way to handle the coefficients, especially $1$ and $-1$.
+% + \xarabic{a1}x + \xarabic{a0} = 42$
+%
+% \bigskip
+% \noindent
+% We seek a better way to handle the coefficients, especially $1$ and $-1$. The
+% command \cs{xcoef}\marg{counter} prints the value of \meta{counter} except
%\DescribeMacro{\xcoef}
-%\DescribeMacro{\xsignedcoef}
-% The command \cs{xcoef}\marg{counter} prints the value of \meta{counter} except
% that it suppresses the values of 1, 0, and -1, printing a minus sign ``-'' in
% the latter case. The command \cs{xsignedcoef}\marg{counter} is like \cs{xcoef}
+%\DescribeMacro{\xsignedcoef}
% except that positive values are preceded by a plus sign ``+''. We use these to
% write the code
+%
%\begin{verbatim}
%$\xarabic{a5}x^5 + \xarabic{a4}x^4 + \xarabic{a3}x^3 + \xarabic{a2}x^2
-% + \xarabic{a1}x + \xarabic{a0} = 42$\\
-%$\xcoef{a5}\ifctrzero{a5}{}{x^5} \xsignedcoef{a4}\ifctrzero{a4}{}{x^4}
-% \xsignedcoef{a3}\ifctrzero{a3}{}{x^3} \xsignedcoef{a2}\ifctrzero{a2}{}{x^2}
-% \xsignedcoef{a1}\ifctrzero{a1}{}{x} \xsignednz{a0} = 42$
+% + \xarabic{a1}x + \xarabic{a0} = 42$
+%
+%$\xcoef{a5}\ifctrzero{a5}{}{x^5}
+% \xsignedcoef{a4}\ifctrzero{a4}{}{x^4}
+% \xsignedcoef{a3}\ifctrzero{a3}{}{x^3}
+% \xsignedcoef{a2}\ifctrzero{a2}{}{x^2}
+% \xsignedcoef{a1}\ifctrzero{a1}{}{x}
+% \xsignednz{a0}
+% = 42$
%\end{verbatim}
+%
+% \noindent
% whose output is
-%\begin{codeoutput}
+%
+% \bigskip
%$\xarabic{a5}x^5 + \xarabic{a4}x^4 + \xarabic{a3}x^3 + \xarabic{a2}x^2
-% + \xarabic{a1}x + \xarabic{a0} = 42$\\
-%$\xcoef{a5}\ifctrzero{a5}{}{x^5} \xsignedcoef{a4}\ifctrzero{a4}{}{x^4}
-% \xsignedcoef{a3}\ifctrzero{a3}{}{x^3} \xsignedcoef{a2}\ifctrzero{a2}{}{x^2}
-% \xsignedcoef{a1}\ifctrzero{a1}{}{x} \xsignednz{a0} = 42$
-%\end{codeoutput}
+% + \xarabic{a1}x + \xarabic{a0} = 42$
+%
+%$\xcoef{a5}\ifctrzero{a5}{}{x^5}
+% \xsignedcoef{a4}\ifctrzero{a4}{}{x^4}
+% \xsignedcoef{a3}\ifctrzero{a3}{}{x^3}
+% \xsignedcoef{a2}\ifctrzero{a2}{}{x^2}
+% \xsignedcoef{a1}\ifctrzero{a1}{}{x}
+% \xsignednz{a0}
+% = 42$
+%
+% \bigskip
%\DescribeMacro{\xnegcoef}
-%\DescribeMacro{\xnegsignedcoef}
% The command \cs{xnegcoef}\marg{counter} prints the negative of the value of
% \meta{counter} except that it suppresses the values of 1, 0, and -1, printing
% a ``-'' in the latter case. The command \cs{xnegsignedcoef}\marg{counter} is
+%\DescribeMacro{\xnegsignedcoef}
% like \cs{xnegcoef} except that positive values are preceded by a plus sign
% ``+''. We use these to write the code
+%
%\begin{verbatim}
-%$\xcoef{a5}\ifctrzero{a5}{}{x^5} \xsignedcoef{a4}\ifctrzero{a4}{}{x^4}
-% \xsignedcoef{a3}\ifctrzero{a3}{}{x^3} \xsignedcoef{a2}\ifctrzero{a2}{}{x^2}
-% \xsignedcoef{a1}\ifctrzero{a1}{}{x} \xsignednz{a0} = 42$\\
-%$\xcoef{a5}\ifctrzero{a5}{}{x^5} \xsignedcoef{a4}\ifctrzero{a4}{}{x^4}
-% \xsignedcoef{a2}\ifctrzero{a2}{}{x^2} \xsignednz{a0}
-% = \xnegcoef{a3}\ifctrzero{a3}{}{x^3} \xnegsignedcoef{a1}\ifctrzero{a1}{}{x}
+%$\xcoef{a5}\ifctrzero{a5}{}{x^5}
+% \xsignedcoef{a4}\ifctrzero{a4}{}{x^4}
+% \xsignedcoef{a3}\ifctrzero{a3}{}{x^3}
+% \xsignedcoef{a2}\ifctrzero{a2}{}{x^2}
+% \xsignedcoef{a1}\ifctrzero{a1}{}{x}
+% \xsignednz{a0}
+% = 42$
+%
+%$\xcoef{a5}\ifctrzero{a5}{}{x^5}
+% \xsignedcoef{a4}\ifctrzero{a4}{}{x^4}
+% \xsignedcoef{a2}\ifctrzero{a2}{}{x^2}
+% \xsignednz{a0}
+% = \xnegcoef{a3}\ifctrzero{a3}{}{x^3}
+% \xnegsignedcoef{a1}\ifctrzero{a1}{}{x}
% +42$
%\end{verbatim}
+%
+% \noindent
% whose output is
-%\begin{codeoutput}
-%$\xcoef{a5}\ifctrzero{a5}{}{x^5} \xsignedcoef{a4}\ifctrzero{a4}{}{x^4}
-% \xsignedcoef{a3}\ifctrzero{a3}{}{x^3} \xsignedcoef{a2}\ifctrzero{a2}{}{x^2}
-% \xsignedcoef{a1}\ifctrzero{a1}{}{x} \xsignednz{a0} = 42$\\
-%$\xcoef{a5}\ifctrzero{a5}{}{x^5} \xsignedcoef{a4}\ifctrzero{a4}{}{x^4}
-% \xsignedcoef{a2}\ifctrzero{a2}{}{x^2} \xsignednz{a0}
-% = \xnegcoef{a3}\ifctrzero{a3}{}{x^3} \xnegsignedcoef{a1}\ifctrzero{a1}{}{x}
+%
+% \bigskip
+%$\xcoef{a5}\ifctrzero{a5}{}{x^5}
+% \xsignedcoef{a4}\ifctrzero{a4}{}{x^4}
+% \xsignedcoef{a3}\ifctrzero{a3}{}{x^3}
+% \xsignedcoef{a2}\ifctrzero{a2}{}{x^2}
+% \xsignedcoef{a1}\ifctrzero{a1}{}{x}
+% \xsignednz{a0}
+% = 42$
+%
+%$\xcoef{a5}\ifctrzero{a5}{}{x^5}
+% \xsignedcoef{a4}\ifctrzero{a4}{}{x^4}
+% \xsignedcoef{a2}\ifctrzero{a2}{}{x^2}
+% \xsignednz{a0}
+% = \xnegcoef{a3}\ifctrzero{a3}{}{x^3}
+% \xnegsignedcoef{a1}\ifctrzero{a1}{}{x}
% +42$
-%\end{codeoutput}
+%
+% \bigskip
% As the reader has probably already observed in the code above, these display
% commands appear to be less efficient than a manual adjustment of signs and
% numbers. For fixed, known values of counters, this assessment is correct. The
@@ -568,16 +687,21 @@ and the derived files counterz.ins,
%
%\subsection{Random Counters}
%
+% We first define random versions of \cs{setcounter} and \cs{addtocounter}.
+% The command \cs{randsetcounter}\marg{counter}\marg{min}\marg{max} assigns
+%\DescribeMacro{\randsetcounter}
+% to \meta{counter} a random integer value between \meta{min} and \meta{max}.
%\DescribeMacro{\xrandsetcounter}
+% The command \cs{xrandsetcounter} is a prefix version of \cs{randsetcounter}.
+% Analogously, we define the command
+%\DescribeMacro{\randaddtocounter}
+% \cs{randaddtocounter}\marg{counter}\marg{min}\marg{max} which adds to
+% \meta{counter} a random integer value between \meta{min} and \meta{max}.
%\DescribeMacro{\xrandaddtocounter}
-% We first define random versions of \cs{xsetcounter} and \cs{xaddtocounter}.
-% The command \cs{xrandsetcounter}\marg{counter}\marg{min}\marg{max} assigns
-% to the prefixed \meta{counter} a random integer value between \meta{min} and
-% \meta{max}. Analogously, the command
-% \cs{xrandaddtocounter}\marg{counter}\marg{min}\marg{max} adds to the prefixed
-% \meta{counter} a random integer value between \meta{min} and \meta{max}. The
-% following code may be used to produce an expression in the form $ax+b$, where
-% $a$ and $b$ are random integers between $-10$ and $10$:
+% \cs{xrandaddtocounter} is a prefix version of \cs{randaddtocounter}.
+% The following code may be used to produce an expression in the form
+% $ax+b$, where $a$ and $b$ are random integers between $-10$ and $10$:
+%
%\begin{verbatim}
%\xprovidecounter{a}
%\xprovidecounter{b}
@@ -585,9 +709,13 @@ and the derived files counterz.ins,
%\xrandsetcounter{b}{-10}{10}
%$\xcoef{a}\ifctrzero{a}{\xarabic{b}}{x \xsignednz{b}}$
%\end{verbatim}
+%
+% \noindent
% Organized in the following table are sixty instances of output that are
% randomly generated by the typesetting of this document:
-%\begin{codeoutput}
+%
+% \bigskip
+%\noindent
%\xprovidecounter{a}
%\xprovidecounter{b}
%\begin{tabular}{rrrrrr}
@@ -772,57 +900,130 @@ and the derived files counterz.ins,
%\xrandsetcounter{b}{-10}{10}
%$\xcoef{a}\ifctrzero{a}{\xarabic{b}}{x \xsignednz{b}}$ \\
%\end{tabular}
-%\end{codeoutput}
+%
+% \bigskip
+% In order to effectively manage the options of randomizing counter values or
+%\DescribeMacro{\randomizectr}
+% reusing counter values, the commands \cs{randomizectr} and \cs{norandomizectr}
+% are used to toggle an internal boolean variable. The internal boolean
+%\DescribeMacro{\norandomizectr}
+% is initialized as TRUE when the \textsf{counterz} package is loaded. A
+% conditional command \cs{ifrandomizectr}\marg{foo}\marg{bar} executes
+%\DescribeMacro{\ifrandomizectr}
+% \meta{foo} when the boolean is true and otherwise executes \meta{bar}.
%
% If our document contains randomly generated counters, but we wish to typeset
% the document again without changing those values, then we need a way to save
-% those values. The \textsf{counterz} package offers the following solution: a
-% file \textsf{\meta{jobname}.counters.tex} may be created during the
-% typesetting process to store the necessary information. For example, if the
-% document is named \textsf{Yellowdog.tex}, then the previously generated
-% counters and their assigned values will be stored the file
-% \textsf{Yellowdog.counters.tex}.
%\DescribeMacro{\opencountersfile}
-% The command \cs{opencountersfile} creates and opens the write stream to this
-% file. The author only has to include this command once, prior to any commands
-% used to save the counter values.
-%
+% them. The command \cs{opencountersfile} creates and opens the write stream to
+% the file \textsf{\meta{jobname}.counters.tex} to store the necessary
+% information. For example, if the document is
+% named \textsf{Yellowdog.tex}, then the previously generated counters and their
+% assigned values will be stored the file \textsf{Yellowdog.counters.tex}.
+% The author only has to include this command once, prior to any commands used
+% to save the counter values. Additional instances of \cs{opencountersfile} will
+% report an error, as will trying to use the command when the document is set to
+% not randomize (e.g. \cs{norandomizectr}). These error reports are designed to
+% prevent the accidental overwriting of \textsf{\meta{jobname}.counters.tex}.
+%
+% After opening the write stream to \textsf{\meta{jobname}.counters.tex}, the
+% command \cs{savecounter}\marg{counter} may be used to ``save'' the value of
+%\DescribeMacro{\savecounter}
+% \textit{counter} by writing to the file the relevant \cs{providecounter} and
+% \cs{setcounter} commands. The command \cs{xsavecounter} is a prefix version of
%\DescribeMacro{\xsavecounter}
-% The command \cs{xsavecounter}\marg{counter} ``saves'' the value of
-% \textit{counter} by writing to the file \textsf{\meta{jobname}.counters.tex}
-% the relevant \cs{providecounter} and \cs{setcounter} commands. The commands
-% written to the file explicitly include the necessary counter prefixes, and
-% consequently an author can, if necessary, manually find in the file the
-% specific assignment for any counter. The counters file may then be inputted
-% near the beginning of a subsequent typesetting to preassign all of the
-% values.
+% \cs{savecounter}. When using \cs{xsavecounter}, the commands that are written
+% to the file include the necessary counter prefixes. Consequently, an author
+% can, if necessary or desired, manually search the file for the value assigned
+% to any randomly generated counter.
+%
+% Once we have generated a file for storing counters, we need a way to recover
+% those values during a subsequent typesetting. The command
+%\DescribeMacro{\inputcountersfile}
+% \cs{inputcountersfile} will input the necessary file, if it exists, and report
+% an error if it does not. Keep in mind that inputting the file will override
+% any previous assignments of those counters, so it is probably best to invoke
+% this command near the beginning of a document. For example, after including an
+% instance of either \cs{randomizectr} or \cs{norandomizectr}, a document named
+% \textsf{Yellowdog.tex} might include the code
%
-%\DescribeMacro{\randomizectr}
-%\DescribeMacro{\norandomizectr}
-%\DescribeMacro{\ifrandomizectr}
-% In order to effectively manage the options of randomizing counter values or
-% reusing counter values, the \textsf{counterz} package offers the commands
-% \cs{randomizectr} and \cs{norandomizectr} that toggle an internal boolean
-% variable, and a conditional \cs{ifrandomizectr}\marg{foo}\marg{bar} that
-% executes \meta{foo} when the boolean is true and otherwise executes
-% \meta{bar}. For example, a document named \textsf{Yellowdog.tex} might
-% include the code
%\begin{verbatim}
-%\ifrandomizectr{}{input{Yellowdog.counters}}
+%\ifrandomizectr{\opencountersfile}{\inputcountersfile}
%\end{verbatim}
-% to determine whether to preload previously stored counter values.
%
-%\DescribeMacro{\xrandprovidecounter}
-%\DescribeMacro{\xrandprovidecounternz}
-% The command \cs{xrandprovidecounter}\marg{counter}\marg{min}\marg{max}
-% combines the four commands \cs{xprovidecounter}, \cs{ifrandomizectr},
-% \cs{xrandsetcounter}, and \cs{xsavecounter} to define a command that creates
-% \meta{counter} if it has not already been defined and, if the document is
+% \noindent
+% to determine whether to preload previously stored counter values or open the
+% write stream in anticipation of randomly generating new counter values.
+%
+%\DescribeMacro{\promptrandomizectr}
+% The command \cs{promptrandomizectr}\oarg{macro}\marg{message}\marg{string}
+% offers an alternative to manually switching between the commands
+% \cs{randomizectr} and \cs{norandomizectr} for different typesettings. The
+% contents of \meta{message} are displayed in the terminal, awaiting a response
+% from the user at the prompt \meta{macro}. If the optional argument is not used
+% then the default prompt is \cs{@typein}. If the optional argument is given, it
+% must be a macro name that includes the backslash. The user's response is
+% stored as a string in \meta{macro} and compared to \meta{string}. If they are
+% equal, then the command \cs{randomizectr} is executed. If they are not equal
+% then \cs{norandomizectr} is executed.
+%
+% Consider the following example code:
+%
+%\begin{verbatim}
+%\promptrandomizectr[\EnterResponse]{%
+% ^^J Enter 1 to randomize.
+% ^^J Enter 2 to not randomize.
+%}{%
+% 1%
+%}%
+%\ifrandomizectr{%
+% \opencountersfile
+%}{%
+% \inputcountersfile
+%}%
+%\end{verbatim}
+%
+% \noindent
+% which displays the following in the terminal:
+%
+%\begin{verbatim}
+% Enter 1 to randomize.
+% Enter 2 to not randomize.
+%
+%\EnterResponse=
+%\end{verbatim}
+%
+% \noindent
+% Notice that the first (optional) argument \cs{EnterResponse} begins with a
+% backslash and is displayed with an equals sign ``='' at the prompt. Also note
+% that the second argument contains two instances of the text \texttt{\^{}\^{}J}
+% which is used to produce a line break in the terminal output. Next, note that
+% the third argument \texttt{1} is immediately followed by a percent symbol
+% \texttt{\%} to prevent extra space being included in the string. (If the
+% \texttt{1} was immediately followed by a closing brace instead of a line break
+% in the code, the percent symbol would not be used.) Finally, note that if the
+% user types a \texttt{1} in the terminal and presses Enter, then the commands
+% \cs{randomizectr} and \cs{opencountersfile} will be executed. If the user
+% enters \textit{any other text} or simply presses Enter with no text, then the
+% commands \cs{norandomizectr} and \cs{inputcountersfile} will be executed,
+% despite the instructions to enter a \texttt{2} to achieve this outcome.
+%
+%\DescribeMacro{\randprovidecounter}
+% The command \cs{randprovidecounter}\marg{counter}\marg{min}\marg{max}
+% combines the four commands \cs{providecounter}, \cs{ifrandomizectr},
+% \cs{randsetcounter}, and \cs{savecounter}. The command creates \meta{counter}
+% if it has not already been defined and, if the document is
% randomized, assigns to \meta{counter} a random integer value between
% \meta{min} and \meta{max} and saves this value to the counters file. The
-% command \cs{xrandprovidecounternz} is like \cs{xrandprovidecounter} except
-% that the generated value is nonzero. Suppose that \textsf{Neverending.tex}
+%\DescribeMacro{\randprovidecounternz}
+% command \cs{randprovidecounternz} is like \cs{randprovidecounter} except
+%\DescribeMacro{\xrandprovidecounter}
+% that the generated value is nonzero. The commands \cs{xrandprovidecounter} and
+%\DescribeMacro{\xrandprovidecounternz}
+% \cs{xrandprovidecounternz} are prefix versions of \cs{randprovidecounter} and
+% \cs{randprovidecounternz}, respectively. Suppose that \textsf{Neverending.tex}
% contains the code
+%
%\begin{verbatim}
%\randomizectr
%\ifrandomizectr{\opencountersfile}{}
@@ -830,21 +1031,27 @@ and the derived files counterz.ins,
%\xrandprovidecounternz{Oracle}{-10}{10}
%\xcoef{Oracle}x+42
%\end{verbatim}
+%
+% \noindent
% After typesetting once, the resulting document might display an expression
% such as $-9x+42$ and print to \textsf{Neverending.counters.tex} the line
+%
%\begin{verbatim}
%\providecounter {SouthernOracle} \setcounter {SouthernOracle}{-9}
%\end{verbatim}
+%
+% \noindent
% After typesetting a second time, the resulting document might display $4x+42$
% and print to \textsf{Neverending.counters.tex} the line
+%
%\begin{verbatim}
%\providecounter {SouthernOracle} \setcounter {SouthernOracle}{4}
%\end{verbatim}
+%
+% \noindent
% If, however, the command \cs{randomizectr} is replaced by \cs{norandomizectr},
% then a third typesetting will leave both the displayed text and the counters
-% file unchanged. (Tip: Users who are concerned about accidental randomization
-% might create a terminal prompt with the commands \cs{typeout} and \cs{typein}
-% to input the randomization preference, as an added layer of security.)
+% file unchanged.
%
%\StopEventually{^^A
% \PrintChanges
@@ -859,7 +1066,9 @@ and the derived files counterz.ins,
%
% \begin{macrocode}
%<*package>
-\ProvidesPackage{counterz}[2023/05/19 v1.0.0 Additional tools for counters]
+\ProvidesPackage{counterz}[%
+ 2023/05/30 v1.1.0 Additional tools for counters
+]%
\RequirePackage{etoolbox,makecmds}
% \end{macrocode}
%
@@ -874,8 +1083,12 @@ and the derived files counterz.ins,
%
% \begin{macrocode}
\newcommand{\@counterz@counterprefix}{}
-\newcommand{\setcounterprefix}[1]{\renewcommand{\@counterz@counterprefix}{#1}}
-\newcommand{\clearcounterprefix}{\setcounterprefix{}}
+\newcommand{\setcounterprefix}[1]{%
+ \renewcommand{\@counterz@counterprefix}{#1}
+}%
+\newcommand{\clearcounterprefix}{%
+ \setcounterprefix{}
+}%
% \end{macrocode}
%
%\end{macro}
@@ -898,11 +1111,21 @@ and the derived files counterz.ins,
% counterparts.
%
% \begin{macrocode}
-\newcommand{\xnewcounter}[1]{\newcounter{\@counterz@counterprefix #1}}
-\newcommand{\xprovidecounter}[1]{\providecounter{\@counterz@counterprefix #1}}
-\newcommand{\xsetcounter}[2]{\setcounter{\@counterz@counterprefix #1}{#2}}
-\newcommand{\xaddtocounter}[2]{\addtocounter{\@counterz@counterprefix #1}{#2}}
-\newcommand{\xvalue}[1]{\value{\@counterz@counterprefix #1}}
+\newcommand{\xnewcounter}[1]{%
+ \newcounter{\@counterz@counterprefix #1}
+}%
+\newcommand{\xprovidecounter}[1]{%
+ \providecounter{\@counterz@counterprefix #1}
+}%
+\newcommand{\xsetcounter}[2]{%
+ \setcounter{\@counterz@counterprefix #1}{#2}
+}%
+\newcommand{\xaddtocounter}[2]{%
+ \addtocounter{\@counterz@counterprefix #1}{#2}
+}%
+\newcommand{\xvalue}[1]{%
+ \value{\@counterz@counterprefix #1}
+}%
% \end{macrocode}
%
%\end{macro}
@@ -926,7 +1149,9 @@ and the derived files counterz.ins,
% \meta{counter2} and otherwise executes \meta{bar}.
%
% \begin{macrocode}
-\newcommand{\ifctrequal}[4]{\ifnumequal{\xvalue{#1}}{\xvalue{#2}}{#3}{#4}}
+\newcommand{\ifctrequal}[4]{%
+ \ifnumequal{\xvalue{#1}}{\xvalue{#2}}{#3}{#4}
+}%
% \end{macrocode}
%
%\end{macro}
@@ -938,7 +1163,9 @@ and the derived files counterz.ins,
% \meta{counter2} and otherwise executes \meta{bar}.
%
% \begin{macrocode}
-\newcommand{\ifctrless}[4]{\ifnumless{\xvalue{#1}}{\xvalue{#2}}{#3}{#4}}
+\newcommand{\ifctrless}[4]{%
+ \ifnumless{\xvalue{#1}}{\xvalue{#2}}{#3}{#4}
+}%
% \end{macrocode}
%
%\end{macro}
@@ -950,7 +1177,9 @@ and the derived files counterz.ins,
% \meta{counter2} and otherwise executes \meta{bar}.
%
% \begin{macrocode}
-\newcommand{\ifctrmore}[4]{\ifnumless{\xvalue{#2}}{\xvalue{#1}}{#3}{#4}}
+\newcommand{\ifctrmore}[4]{%
+ \ifnumless{\xvalue{#2}}{\xvalue{#1}}{#3}{#4}
+}%
% \end{macrocode}
%
%\end{macro}
@@ -961,7 +1190,9 @@ and the derived files counterz.ins,
% the value of \meta{counter} is zero and otherwise executes \meta{bar}.
%
% \begin{macrocode}
-\newcommand{\ifctrzero}[3]{\ifnumequal{\xvalue{#1}}{0}{#2}{#3}}
+\newcommand{\ifctrzero}[3]{%
+ \ifnumequal{\xvalue{#1}}{0}{#2}{#3}
+}%
% \end{macrocode}
%
%\end{macro}
@@ -972,7 +1203,9 @@ and the derived files counterz.ins,
% value of \meta{counter} is negative and otherwise executes \meta{bar}.
%
% \begin{macrocode}
-\newcommand{\ifctrneg}[3]{\ifnumless{\xvalue{#1}}{0}{#2}{#3}}
+\newcommand{\ifctrneg}[3]{%
+ \ifnumless{\xvalue{#1}}{0}{#2}{#3}
+}%
% \end{macrocode}
%
%\end{macro}
@@ -983,7 +1216,9 @@ and the derived files counterz.ins,
% value of \meta{counter} is positive and otherwise executes \meta{bar}.
%
% \begin{macrocode}
-\newcommand{\ifctrpos}[3]{\ifnumless{\xvalue{#1}}{1}{#3}{#2}}
+\newcommand{\ifctrpos}[3]{%
+ \ifnumless{\xvalue{#1}}{1}{#3}{#2}
+}%
% \end{macrocode}
%
%\end{macro}
@@ -1042,7 +1277,9 @@ and the derived files counterz.ins,
% includes the value zero.
%
% \begin{macrocode}
-\newcommand{\xsignof}[1]{\ifctrneg{#1}{-}{+}}
+\newcommand{\xsignof}[1]{%
+ \ifctrneg{#1}{-}{+}
+}%
% \end{macrocode}
%
%\end{macro}
@@ -1054,7 +1291,9 @@ and the derived files counterz.ins,
% includes the value zero.
%
% \begin{macrocode}
-\newcommand{\xnegsignof}[1]{\ifctrneg{#1}{+}{-}}
+\newcommand{\xnegsignof}[1]{%
+ \ifctrneg{#1}{+}{-}
+}%
% \end{macrocode}
%
%\end{macro}
@@ -1066,7 +1305,9 @@ and the derived files counterz.ins,
% \cs{xsignof}.
%
% \begin{macrocode}
-\newcommand{\xsigned}[1]{\xsignof{#1} \xabsof{#1}}
+\newcommand{\xsigned}[1]{%
+ \xsignof{#1} \xabsof{#1}
+}%
% \end{macrocode}
%
%\end{macro}
@@ -1077,7 +1318,9 @@ and the derived files counterz.ins,
% zero.
%
% \begin{macrocode}
-\newcommand{\xsignednz}[1]{\ifctrzero{#1}{}{\xsigned{#1}}}
+\newcommand{\xsignednz}[1]{%
+ \ifctrzero{#1}{}{\xsigned{#1}}
+}%
% \end{macrocode}
%
%\end{macro}
@@ -1088,7 +1331,9 @@ and the derived files counterz.ins,
% zero.
%
% \begin{macrocode}
-\newcommand{\xarabicnz}[1]{\ifctrzero{#1}{}{\xarabic{#1}}}
+\newcommand{\xarabicnz}[1]{%
+ \ifctrzero{#1}{}{\xarabic{#1}}
+}%
% \end{macrocode}
%
%\end{macro}
@@ -1100,7 +1345,9 @@ and the derived files counterz.ins,
% \cs{xnegsignof}.
%
% \begin{macrocode}
-\newcommand{\xnegsigned}[1]{\xnegsignof{#1} \xabsof{#1}}
+\newcommand{\xnegsigned}[1]{%
+ \xnegsignof{#1} \xabsof{#1}
+}%
% \end{macrocode}
%
%\end{macro}
@@ -1111,7 +1358,9 @@ and the derived files counterz.ins,
% number zero.
%
% \begin{macrocode}
-\newcommand{\xnegsignednz}[1]{\ifctrzero{#1}{}{\xnegsigned{#1}}}
+\newcommand{\xnegsignednz}[1]{%
+ \ifctrzero{#1}{}{\xnegsigned{#1}}
+}%
% \end{macrocode}
%
%\end{macro}
@@ -1121,7 +1370,9 @@ and the derived files counterz.ins,
% \cs{xnegof}\marg{counter} prints the negative of the value of \meta{counter}.
%
% \begin{macrocode}
-\newcommand{\xnegof}[1]{\ifctrpos{#1}{-}{}\xabsof{#1}}
+\newcommand{\xnegof}[1]{%
+ \ifctrpos{#1}{-}{}\xabsof{#1}
+}%
% \end{macrocode}
%
%\end{macro}
@@ -1132,7 +1383,9 @@ and the derived files counterz.ins,
% zero.
%
% \begin{macrocode}
-\newcommand{\xnegofnz}[1]{\ifctrzero{#1}{}{\xnegof{#1}}}
+\newcommand{\xnegofnz}[1]{%
+ \ifctrzero{#1}{}{\xnegof{#1}}
+}%
% \end{macrocode}
%
%\end{macro}
@@ -1144,13 +1397,15 @@ and the derived files counterz.ins,
%
% \begin{macrocode}
\newcommand{\xcoef}[1]{%
- \ifboolexpr{test {\ifnumless{\xvalue{#1}}{-1}}%
- or test {\ifnumgreater{\xvalue{#1}}{1}}}{%
- \xarabic{#1}%
+ \ifboolexpr{%
+ test {\ifnumless{\xvalue{#1}}{-1}}
+ or test {\ifnumgreater{\xvalue{#1}}{1}}
+ }{%
+ \xarabic{#1}
}{%
}%
- \ifnumequal{\xvalue{#1}}{-1}{-}{}%
-}
+ \ifnumequal{\xvalue{#1}}{-1}{-}{}
+}%
% \end{macrocode}
%
%\end{macro}
@@ -1162,13 +1417,15 @@ and the derived files counterz.ins,
%
% \begin{macrocode}
\newcommand{\xnegcoef}[1]{%
- \ifboolexpr{test {\ifnumless{\xvalue{#1}}{-1}}%
- or test {\ifnumgreater{\xvalue{#1}}{1}}}{%
- \xnegof{#1}%
+ \ifboolexpr{%
+ test {\ifnumless{\xvalue{#1}}{-1}}
+ or test {\ifnumgreater{\xvalue{#1}}{1}}
+ }{%
+ \xnegof{#1}
}{%
}%
- \ifnumequal{\xvalue{#1}}{1}{-}{}%
-}
+ \ifnumequal{\xvalue{#1}}{1}{-}{}
+}%
% \end{macrocode}
%
%\end{macro}
@@ -1180,12 +1437,14 @@ and the derived files counterz.ins,
%
% \begin{macrocode}
\newcommand{\xabsofcoef}[1]{%
- \ifboolexpr{test {\ifnumless{\xvalue{#1}}{-1}}%
- or test {\ifnumgreater{\xvalue{#1}}{1}}}{%
- \xabsof{#1}%
+ \ifboolexpr{%
+ test {\ifnumless{\xvalue{#1}}{-1}}
+ or test {\ifnumgreater{\xvalue{#1}}{1}}
}{%
- }
-}
+ \xabsof{#1}
+ }{%
+ }%
+}%
% \end{macrocode}
%
%\end{macro}
@@ -1196,7 +1455,9 @@ and the derived files counterz.ins,
% \meta{counter} is nonzero.
%
% \begin{macrocode}
-\newcommand{\xsignofcoef}[1]{\ifctrzero{#1}{}{\xsignof{#1}}}
+\newcommand{\xsignofcoef}[1]{%
+ \ifctrzero{#1}{}{\xsignof{#1}}
+}%
% \end{macrocode}
%
%\end{macro}
@@ -1207,7 +1468,9 @@ and the derived files counterz.ins,
% if \meta{counter} is nonzero.
%
% \begin{macrocode}
-\newcommand{\xnegsignofcoef}[1]{\ifctrzero{#1}{}{\xnegsignof{#1}}}
+\newcommand{\xnegsignofcoef}[1]{%
+ \ifctrzero{#1}{}{\xnegsignof{#1}}
+}%
% \end{macrocode}
%
%\end{macro}
@@ -1218,7 +1481,9 @@ and the derived files counterz.ins,
% are preceded by a plus sign ``+''.
%
% \begin{macrocode}
-\newcommand{\xsignedcoef}[1]{\xsignofcoef{#1} \xabsofcoef{#1}}
+\newcommand{\xsignedcoef}[1]{%
+ \xsignofcoef{#1} \xabsofcoef{#1}
+}%
% \end{macrocode}
%
%\end{macro}
@@ -1229,68 +1494,190 @@ and the derived files counterz.ins,
% opposite sign.
%
% \begin{macrocode}
-\newcommand{\xnegsignedcoef}[1]{\xnegsignofcoef{#1} \xabsofcoef{#1}}
+\newcommand{\xnegsignedcoef}[1]{%
+ \xnegsignofcoef{#1} \xabsofcoef{#1}
+}%
% \end{macrocode}
%
%\end{macro}
%
%\subsection{Random Counters}
%
-% The commands \cs{xrandsetcounter} and \cs{xrandaddtocounter} use the pdf\TeX\
+% The commands \cs{randsetcounter} and \cs{randaddtocounter} use the pdf\TeX\
% primitive \cs{pdfuniformdeviate} to provide random versions of
-% \cs{xsetcounter} and \cs{xaddtocounter}.
+% \cs{setcounter} and \cs{addtocounter}. The commands \cs{xrandsetcounter} and
+% \cs{xrandaddtocounter} are prefix versions of \cs{randsetcounter} and
+% \cs{randaddtocounter}, respectively.
%
+%\begin{macro}{\randsetcounter}
+%\changes{v1.1.0}{2023/05/30}{new}
%\begin{macro}{\xrandsetcounter}
+%\changes{v1.1.0}{2023/05/30}{now based on a new \cs{randsetcounter}}
%
-% \cs{xrandsetcounter}\marg{counter}\marg{min}\marg{max} assigns to (the
-% prefixed) \meta{counter} a random integer value between \meta{min} and
-% \meta{max}.
+% \cs{randsetcounter}\marg{counter}\marg{min}\marg{max} assigns to
+% \meta{counter} a random integer value between \meta{min} and \meta{max}.
%
% \begin{macrocode}
-\newcommand{\xrandsetcounter}[3]{%
- \xsetcounter{#1}{%
+\newcommand{\randsetcounter}[3]{%
+ \setcounter{#1}{%
\the \numexpr #2+\pdfuniformdeviate \numexpr #3-#2+1 \relax
- }
-}
+ }%
+}%
+\newcommand{\xrandsetcounter}[3]{%
+ \randsetcounter{\@counterz@counterprefix#1}{#2}{#3}
+}%
% \end{macrocode}
%
%\end{macro}
+%\end{macro}
%
+%\begin{macro}{\randaddtocounter}
+%\changes{v1.1.0}{2023/05/30}{new}
%\begin{macro}{\xrandaddtocounter}
+%\changes{v1.1.0}{2023/05/30}{now based on a new \cs{randaddtocounter}}
%
-% \cs{xrandaddtocounter}\marg{counter}\marg{min}\marg{max} adds to (the
-% prefixed) \meta{counter} a random integer value between \meta{min} and
-% \meta{max}.
+% \cs{randaddtocounter}\marg{counter}\marg{min}\marg{max} adds to \meta{counter}
+% a random integer value between \meta{min} and \meta{max}.
%
% \begin{macrocode}
-\newcommand{\xrandaddtocounter}[3]{%
- \xaddtocounter{#1}{%
+\newcommand{\randaddtocounter}[3]{%
+ \addtocounter{#1}{%
\the \numexpr #2+\pdfuniformdeviate \numexpr #3-#2+1 \relax
- }
-}
+ }%
+}%
+\newcommand{\xrandaddtocounter}[3]{%
+ \randaddtocounter{\@counterz@counterprefix#1}{#2}{#3}
+}%
% \end{macrocode}
%
%\end{macro}
+%\end{macro}
% The following commands are designed to provide a means by which authors can
% generate random values for counters but also preserve those values for future
% typesettings. This is accomplished by storing counters and their values in an
% external file and then inputting the file before a subsequent typesetting.
%
+%\begin{macro}{\randomizectr}
+%\begin{macro}{\norandomizectr}
+%
+% In order to assign a random value to a counter during one typesetting and
+% avoid overwriting this value with a random assignment during another
+% typesetting, the boolean \textit{@counterz@random} is used to distinguish
+% between the two typesetting options. The value of \textit{@counterz@random} may
+% be changed by the commands \cs{randomizectr} and \cs{norandomizectr}.
+%
+% \begin{macrocode}
+\newbool{@counterz@random}
+\booltrue{@counterz@random}
+\newcommand{\randomizectr}{\booltrue{@counterz@random}}
+\newcommand{\norandomizectr}{\boolfalse{@counterz@random}}
+% \end{macrocode}
+%
+%\end{macro}
+%\end{macro}
+%
+%\begin{macro}{\ifrandomizectr}
+%
+% \cs{ifrandomizectr}\marg{foo}\marg{bar} executes \meta{foo} if the boolean
+% \textit{@counterz@random} is true and otherwise executes \meta{bar}.
+%
+% \begin{macrocode}
+\newcommand{\ifrandomizectr}[2]{%
+ \ifbool{@counterz@random}{#1}{#2}
+}%
+% \end{macrocode}
+%
+%\end{macro}
+%
+%\begin{macro}{\promptrandomizectr}
+%\changes{v1.1.0}{2023/05/30}{new}
+%
+% \cs{promptrandomizectr}\oarg{command}\marg{message}\marg{string} writes
+% \meta{message} to the terminal and awaits a response from the user at the
+% prompt. The user's response is stored in \meta{command} and compared to the
+% text of \meta{string}. If they are equal, then \cs{randomizectr} is executed.
+% If they are not equal, then \cs{norandomizectr} is executed.
+%
+% \begin{macrocode}
+\newcommand{\promptrandomizectr}[3][\@typein]{%
+ \typein[#1]{#2}
+ \ifdefstring{#1}{#3}{%
+ \randomizectr
+ }{%
+ \norandomizectr
+ }%
+}%
+% \end{macrocode}
+%
+%\end{macro}
+%
%\begin{macro}{\opencountersfile}
+%\changes{v1.1.0}{2023/05/30}{new error reports}
%
% The command \cs{opencountersfile} creates and opens the write stream to the
% file \textsf{\meta{jobname}.counters.tex}, referenced by the macro
-% \cs{countersfile}.
+% \cs{countersfile}. If the file already exists, it is overwritten. For this
+% reason,
%
% \begin{macrocode}
+\newbool{@counterz@fileISopen}
+\boolfalse{@counterz@fileISopen}
\newcommand{\opencountersfile}{%
- \newwrite\countersfile
- \immediate\openout\countersfile=\jobname.counters.tex
+ \ifbool{@counterz@fileISopen}{%
+ \PackageError{counterz}{%
+ The write stream is already open!
+ \MessageBreak Process interrupted to prevent overwriting
+ \MessageBreak \jobname.counters.tex
+ }{%
+ Be sure to include only one instance of
+ \protect\opencountersfile.
+ }%
+ }{%
+ \ifrandomizectr{%
+ \newwrite\countersfile
+ \immediate\openout\countersfile=\jobname.counters.tex
+ \booltrue{@counterz@fileISopen}
+ }{%
+ \PackageError{counterz}{%
+ \protect\opencountersfile\space requires
+ \protect\randomizectr
+ \MessageBreak Process interrupted to prevent overwriting
+ \MessageBreak \jobname.counters.tex
+ }{%
+ \protect\opencountersfile\space is designed to open a file
+ for saving newly randomized counters. See the Random
+ Counters section of the counterz package documentation for
+ details.
+ }%
+ }%
+ }%
}
% \end{macrocode}
%
%\end{macro}
%
+%\begin{macro}{\inputcountersfile}
+%\changes{v1.1.0}{2023/05/30}{new}
+%
+% The command \cs{inputcountersfile} inputs \textsf{\meta{jobname}.counters.tex}
+% if the file exists and reports a package error if the file does not exist.
+%
+% \begin{macrocode}
+\newcommand{\inputcountersfile}{%
+ \InputIfFileExists{\jobname.counters}{%
+ }{%
+ \PackageError{counterz}{%
+ The file \jobname.counters.tex does not exist.
+ }{%
+ See the Random Counters section of the counterz package
+ documentation.
+ }%
+ }%
+}%
+% \end{macrocode}
+%
+%\end{macro}
+%
%\begin{macro}{\@counterz@openbrace}
%\begin{macro}{\@counterz@closebrace}
%
@@ -1309,59 +1696,79 @@ and the derived files counterz.ins,
%\end{macro}
%\end{macro}
%
+%\begin{macro}{\savecounter}
+%\changes{v1.1.0}{2023/05/30}{new}
%\begin{macro}{\xsavecounter}
+%\changes{v1.1.0}{2023/05/30}{now based on a new \cs{savecounter}}
%
-% \cs{xsavecounter}\marg{counter} writes \cs{providecounter} and \cs{setcounter}
+% \cs{savecounter}\marg{counter} writes \cs{providecounter} and \cs{setcounter}
% commands to the file \textsf{\meta{jobname}.counters.tex} so that they may be
-% inputted as part of a future typesetting.
+% inputted as part of a future typesetting. The command reports a package error
+% if the write stream to \textsf{\meta{jobname}.counters.tex} is not open. The
+% command \cs{xsavecounter} is a prefix version of \cs{savecounter}.
+%
%
% \begin{macrocode}
-\newcommand{\xsavecounter}[1]{%
- \immediate\write\countersfile{%
- \unexpanded{\providecounter}\@counterz@openbrace%
- \@counterz@counterprefix #1\@counterz@closebrace%
- \unexpanded{ \setcounter}\@counterz@openbrace%
- \@counterz@counterprefix #1\@counterz@closebrace%
- \@counterz@openbrace%
- \arabic{\@counterz@counterprefix #1}\@counterz@closebrace%
+\newcommand{\savecounter}[1]{%
+ \ifbool{@counterz@fileISopen}{%
+ \immediate\write\countersfile{%
+ \unexpanded{\providecounter}
+ \@counterz@openbrace#1\@counterz@closebrace
+ \unexpanded{\setcounter}
+ \@counterz@openbrace#1\@counterz@closebrace
+ \@counterz@openbrace\arabic{#1}\@counterz@closebrace
+ }%
+ }{%
+ \PackageError{counterz}{%
+ The write stream to the file \jobname.counters.tex must be
+ opened before \protect\savecounter\space can be executed.
+ }{%
+ See \protect\opencountersfile\space and
+ \protect\savecounter\space in the counterz package
+ documentation.
+ }%
}%
}%
-% \end{macrocode}
-%
-%\end{macro}
-%
-%\begin{macro}{\randomizectr}
-%\begin{macro}{\norandomizectr}
-%
-% In order to assign a random value to a counter during one typesetting and
-% avoid overwriting this value with a random assignment during another
-% typesetting, the boolean \textit{@counterz@random} is used to distinguish
-% between the two typesettings. The value of \textit{@counterz@random} may
-% be changed by the commands \cs{randomizectr} and \cs{norandomizectr}.
-%
-% \begin{macrocode}
-\newbool{@counterz@random}
-\newcommand{\randomizectr}{\booltrue{@counterz@random}}
-\newcommand{\norandomizectr}{\boolfalse{@counterz@random}}
+
+\newcommand{\xsavecounter}[1]{%
+ \savecounter{\@counterz@counterprefix#1}%
+}%
% \end{macrocode}
%
%\end{macro}
%\end{macro}
%
-%\begin{macro}{\ifrandomizectr}
+%\begin{macro}{\randprovidecounter}
+%\changes{v1.1.0}{2023/05/30}{new}
%
-% \cs{ifrandomizectr}\marg{foo}\marg{bar} executes \meta{foo} if the boolean
-% \textit{@counterz@random} is true and otherwise executes \meta{bar}.
+% \cs{randprovidecounter}\marg{counter}\marg{min}\marg{max} creates
+% \meta{counter} if it does not already exist, and if the boolean
+% \textit{@counterz@random} is true then \meta{counter} is assigned a
+% random integer value between \meta{min} and \meta{max} and then saved.
%
% \begin{macrocode}
-\newcommand{\ifrandomizectr}[2]{%
- \ifbool{@counterz@random}{#1}{#2}
+\newcommand{\randprovidecounter}[3]{%
+ \ifltxcounter{#1}{%
+ \@ifnextchar]{%
+ \m@k@gobbleendoptarg
+ }{%
+ }%
+ }{%
+ \newcounter{#1}
+ \ifrandomizectr{%
+ \randsetcounter{#1}{#2}{#3}
+ \savecounter{#1}
+ }{%
+ }%
+ }%
}%
% \end{macrocode}
%
%\end{macro}
%
%\begin{macro}{\xrandprovidecounter}
+%\changes{v1.1.0}{2023/05/30}{no longer randomizes if already defined;
+%now based on a new \cs{randprovidecounter}}
%
% \cs{xrandprovidecounter}\marg{counter}\marg{min}\marg{max} creates
% \meta{counter} if it does not already exist, and if the boolean
@@ -1370,18 +1777,45 @@ and the derived files counterz.ins,
%
% \begin{macrocode}
\newcommand{\xrandprovidecounter}[3]{%
- \xprovidecounter{#1}
- \ifrandomizectr{%
- \xrandsetcounter{#1}{#2}{#3}
- \xsavecounter{#1}
- }{%
- }
-}
+ \randprovidecounter{\@counterz@counterprefix#1}{#2}{#3}
+}%
% \end{macrocode}
%
%\end{macro}
%
+%\begin{macro}{\randprovidecounternz}
+%\changes{v1.1.0}{2023/05/30}{new}
+%
+% \cs{randprovidecounternz}\marg{counter}\marg{min}\marg{max} does the same
+% job as the command \cs{xrandprovidecounter} except that the value of
+% \meta{counter} is randomized until it is nonzero.
+%
+% \begin{macrocode}
+\newcommand{\randprovidecounternz}[3]{%
+ \ifltxcounter{#1}{%
+ \@ifnextchar]{%
+ \m@k@gobbleendoptarg
+ }{%
+ }%
+ }{%
+ \newcounter{#1}
+ \ifrandomizectr{%
+ \setcounter{#1}{0}
+ \whileboolexpr{test {\ifnumequal{\value{#1}}{0}}}{%
+ \randsetcounter{#1}{#2}{#3}
+ }%
+ \savecounter{#1}
+ }{%
+ }%
+ }%
+}%
+% \end{macrocode}
+%
+%\end{macro}%
+%
%\begin{macro}{\xrandprovidecounternz}
+%\changes{v1.1.0}{2023/05/30}{no longer randomizes if already defined;
+%now based on a new \cs{randprovidecounternz}}
%
% \cs{xrandprovidecounternz}\marg{counter}\marg{min}\marg{max} does the same
% job as the command \cs{xrandprovidecounter} except that the value of
@@ -1389,16 +1823,8 @@ and the derived files counterz.ins,
%
% \begin{macrocode}
\newcommand{\xrandprovidecounternz}[3]{%
- \xprovidecounter{#1}
- \ifrandomizectr{%
- \xsetcounter{#1}{0}
- \whileboolexpr{ test {\ifnumequal{\xvalue{#1}}{0}}}{%
- \xrandsetcounter{#1}{#2}{#3}
- }
- \xsavecounter{#1}
- }{%
- }
-}
+ \randprovidecounternz{\@counterz@counterprefix#1}{#2}{#3}
+}%
% \end{macrocode}
%
%\end{macro}%
diff --git a/macros/latex/contrib/counterz/counterz.ins b/macros/latex/contrib/counterz/counterz.ins
index 7de3d88187..73c612db3d 100644
--- a/macros/latex/contrib/counterz/counterz.ins
+++ b/macros/latex/contrib/counterz/counterz.ins
@@ -6,7 +6,7 @@
%%
%% counterz.dtx (with options: `install')
%% ----------------------------------------------------------------------
-%% `counterz' --- 2023/05/19 Version 1.0.0 Additional tools for counters
+%% `counterz' --- 2023/05/30 Version 1.1.0 Additional tools for counters
%% E-mail: christopher.mcclain@mail.wvu.edu
%% Released under the LaTeX Project Public License v1.3c or later
%% See https://www.latex-project.org/lppl.txt
@@ -22,7 +22,7 @@
\preamble
----------------------------------------------------------------------
-`counterz' --- 2023/05/19 Version 1.0.0 Additional tools for counters
+`counterz' --- 2023/05/30 Version 1.1.0 Additional tools for counters
E-mail: christopher.mcclain@mail.wvu.edu
Released under the LaTeX Project Public License v1.3c or later
See https://www.latex-project.org/lppl.txt
diff --git a/macros/latex/contrib/counterz/counterz.pdf b/macros/latex/contrib/counterz/counterz.pdf
index 4b358cbb48..66820f93e8 100644
--- a/macros/latex/contrib/counterz/counterz.pdf
+++ b/macros/latex/contrib/counterz/counterz.pdf
Binary files differ
diff --git a/macros/luatex/latex/luacas/doc/appendix/luacas.dat b/macros/luatex/latex/luacas/doc/appendix/luacas.dat
index 7f2efd0a10..c0011e71b2 100644
--- a/macros/luatex/latex/luacas/doc/appendix/luacas.dat
+++ b/macros/luatex/latex/luacas/doc/appendix/luacas.dat
@@ -1,4 +1,4 @@
-% Copyright (c) ???
+% Copyright (c)
%
% Permission is granted to copy, distribute and/or modify this
% software under the terms of the LaTeX Project Public License
@@ -11,7 +11,7 @@
\NeedsTeXFormat{LaTeX2e}
\ProvidesPackage{luacas}
- [2022/11/15 v1.0.1 CAS written in Lua for LaTeX]
+ [2023/05/26 v1.0.2 CAS written in Lua for LaTeX]
\RequirePackage{iftex}
\ifluatex
diff --git a/macros/luatex/latex/luacas/doc/appendix/versionhistory.tex b/macros/luatex/latex/luacas/doc/appendix/versionhistory.tex
index 26754b3c7d..ad7e4f53fe 100644
--- a/macros/luatex/latex/luacas/doc/appendix/versionhistory.tex
+++ b/macros/luatex/latex/luacas/doc/appendix/versionhistory.tex
@@ -7,6 +7,15 @@
\section{Version History}
+\subsection*{v1.0.2}
+
+\begin{itemize}
+ \item Fix Polynomial Rings displaying redundant ones in \LaTeX{}
+ \item Fix rational forced non-simplification not working
+ \item Added ability to load LuaCAS modules as local variables
+ \item Fix arithmetic with decimal expressions
+\end{itemize}
+
\subsection*{v1.0.1}
\begin{itemize}
diff --git a/macros/luatex/latex/luacas/doc/luacas.pdf b/macros/luatex/latex/luacas/doc/luacas.pdf
index 667791efb6..13f358c5e8 100644
--- a/macros/luatex/latex/luacas/doc/luacas.pdf
+++ b/macros/luatex/latex/luacas/doc/luacas.pdf
Binary files differ
diff --git a/macros/luatex/latex/luacas/doc/luacas.tex b/macros/luatex/latex/luacas/doc/luacas.tex
index 3d0c51a343..7c49b9eef5 100644
--- a/macros/luatex/latex/luacas/doc/luacas.tex
+++ b/macros/luatex/latex/luacas/doc/luacas.tex
@@ -160,7 +160,7 @@ style=numeric,
\begin{document}
\title{The {\ttfamily luacas} package}
\author{Evan Cochrane\thanks{\href{mailto:cochraef@rose-hulman.edu}{\ttfamily cochraef@rose-hulman.edu}} , Timothy All\thanks{\href{mailto:timothy.all@rose-hulman.edu}{\ttfamily timothy.all@rose-hulman.edu}}}
-\date{v1.0.1 \\ \today}
+\date{v1.0.2\\ \today}
\maketitle
diff --git a/macros/luatex/latex/luacas/tex/algebra/luacas-absexpression.lua b/macros/luatex/latex/luacas/tex/algebra/luacas-absexpression.lua
index 2bf0b6a7ef..264730cbbe 100644
--- a/macros/luatex/latex/luacas/tex/algebra/luacas-absexpression.lua
+++ b/macros/luatex/latex/luacas/tex/algebra/luacas-absexpression.lua
@@ -2,7 +2,7 @@
--- The absolute value of an expression.
--- @field expression Expression
AbsExpression = {}
-__AbsExpression = {}
+local __AbsExpression = {}
----------------------------
-- Instance functionality --
diff --git a/macros/luatex/latex/luacas/tex/algebra/luacas-algebra_init.lua b/macros/luatex/latex/luacas/tex/algebra/luacas-algebra_init.lua
deleted file mode 100644
index ac37c56a5b..0000000000
--- a/macros/luatex/latex/luacas/tex/algebra/luacas-algebra_init.lua
+++ /dev/null
@@ -1,24 +0,0 @@
--- Loads algebra files in the correct order.
-require("_lib.luacas-table")
-
-require("core.luacas-core_init")
-
-require("algebra.luacas-ring")
-require("algebra.luacas-euclideandomain")
-require("algebra.luacas-field")
-require("algebra.luacas-polynomialring")
-require("algebra.luacas-integer")
-require("algebra.luacas-rational")
-require("algebra.luacas-integerquotientring")
-require("algebra.luacas-sqrtexpression")
-
-require("algebra.luacas-absexpression")
-require("algebra.luacas-equation")
-require("algebra.luacas-factorialexpression")
-require("algebra.luacas-logarithm")
-require("algebra.luacas-rootexpression")
-require("algebra.luacas-trigexpression")
-
-require("algebra.polynomialring.luacas-berlekampfactoring")
-require("algebra.polynomialring.luacas-zassenhausfactoring")
-require("algebra.polynomialring.luacas-decomposition") \ No newline at end of file
diff --git a/macros/luatex/latex/luacas/tex/algebra/luacas-equation.lua b/macros/luatex/latex/luacas/tex/algebra/luacas-equation.lua
index 4e81d5ca95..18d6a9c091 100644
--- a/macros/luatex/latex/luacas/tex/algebra/luacas-equation.lua
+++ b/macros/luatex/latex/luacas/tex/algebra/luacas-equation.lua
@@ -3,7 +3,7 @@
--- @field lhs Expression
--- @field rhs Expression
Equation = {}
-__Equation = {}
+local __Equation = {}
--------------------------
-- Static functionality --
diff --git a/macros/luatex/latex/luacas/tex/algebra/luacas-euclideandomain.lua b/macros/luatex/latex/luacas/tex/algebra/luacas-euclideandomain.lua
index fab2c5c7c2..fec52d5d81 100644
--- a/macros/luatex/latex/luacas/tex/algebra/luacas-euclideandomain.lua
+++ b/macros/luatex/latex/luacas/tex/algebra/luacas-euclideandomain.lua
@@ -1,7 +1,7 @@
--- @class EuclideanDomain
--- Interface for an element of a euclidean domain.
EuclideanDomain = {}
-__EuclideanDomain = {}
+local __EuclideanDomain = {}
----------------------
-- Required methods --
diff --git a/macros/luatex/latex/luacas/tex/algebra/luacas-factorialexpression.lua b/macros/luatex/latex/luacas/tex/algebra/luacas-factorialexpression.lua
index 1c5b824ff7..5920d22733 100644
--- a/macros/luatex/latex/luacas/tex/algebra/luacas-factorialexpression.lua
+++ b/macros/luatex/latex/luacas/tex/algebra/luacas-factorialexpression.lua
@@ -2,7 +2,7 @@
--- The factorial of an expression.
--- @field expression Expression
FactorialExpression = {}
-__FactorialExpression = {}
+local __FactorialExpression = {}
----------------------------
-- Instance functionality --
diff --git a/macros/luatex/latex/luacas/tex/algebra/luacas-field.lua b/macros/luatex/latex/luacas/tex/algebra/luacas-field.lua
index c845e94c55..0846a90ec9 100644
--- a/macros/luatex/latex/luacas/tex/algebra/luacas-field.lua
+++ b/macros/luatex/latex/luacas/tex/algebra/luacas-field.lua
@@ -1,7 +1,7 @@
--- @class Field
--- Interface for an element of a field.
Field = {}
-__Field = {}
+local __Field = {}
----------------------
-- Required methods --
diff --git a/macros/luatex/latex/luacas/tex/algebra/luacas-integer.lua b/macros/luatex/latex/luacas/tex/algebra/luacas-integer.lua
index a3c54f498c..6a81be295b 100644
--- a/macros/luatex/latex/luacas/tex/algebra/luacas-integer.lua
+++ b/macros/luatex/latex/luacas/tex/algebra/luacas-integer.lua
@@ -3,7 +3,7 @@
--- @field self table<number, number>
--- @field sign number
Integer = {}
-__Integer = {}
+local __Integer = {}
--------------------------
-- Static functionality --
@@ -90,6 +90,9 @@ end
--- @return Integer
function Integer.ceillog(a, base)
base = base or Integer(10)
+ if a == Integer.one() then
+ return Integer.one()
+ end
local k = Integer.zero()
while (base ^ k) < a do
@@ -138,9 +141,9 @@ end
----------------------------
-- So we don't have to copy the Euclidean operations each time we create an integer.
-local __o = Copy(__EuclideanOperations)
-__o.__index = Integer
-__o.__tostring = function(a) -- Only works if the digit size is a power of 10
+__IntegerOperations = Copy(__EuclideanOperations)
+__IntegerOperations.__index = Integer
+__IntegerOperations.__tostring = function(a) -- Only works if the digit size is a power of 10
local out = ""
for i, digit in ipairs(a) do
local pre = tostring(math.floor(digit))
@@ -156,7 +159,7 @@ __o.__tostring = function(a) -- Only works if the digit size is a power of 10
end
return out
end
-__o.__div = function(a, b) -- Constructor for a rational number disguised as division
+__IntegerOperations.__div = function(a, b) -- Constructor for a rational number disguised as division
if not b.getring then
return BinaryOperation.DIVEXP({a, b})
end
@@ -165,7 +168,7 @@ __o.__div = function(a, b) -- Constructor for a rational number disguised as d
end
return __FieldOperations.__div(a, b)
end
-__o.__concat = function(a, b) -- Like a decimal, but fancier. Used mainly for the parser with decimal numbers.
+__IntegerOperations.__concat = function(a, b) -- Like a decimal, but fancier. Used mainly for the parser with decimal numbers.
return a + b / (Integer(10) ^ Integer.ceillog(b))
end
@@ -174,7 +177,7 @@ end
--- @return Integer
function Integer:new(n)
local o = {}
- o = setmetatable(o, __o)
+ o = setmetatable(o, __IntegerOperations)
if not n then
o[1] = 0
diff --git a/macros/luatex/latex/luacas/tex/algebra/luacas-integerquotientring.lua b/macros/luatex/latex/luacas/tex/algebra/luacas-integerquotientring.lua
index 4c2188c9e5..6fe0ce1cdf 100644
--- a/macros/luatex/latex/luacas/tex/algebra/luacas-integerquotientring.lua
+++ b/macros/luatex/latex/luacas/tex/algebra/luacas-integerquotientring.lua
@@ -4,7 +4,7 @@
--- @field modulus Integer
IntegerModN = {}
-__IntegerModN = {}
+local __IntegerModN = {}
-- Metatable for ring objects.
local __obj = {__index = IntegerModN, __eq = function(a, b)
@@ -37,11 +37,10 @@ end
----------------------------
-- So we don't have to copy the field operations each time
-local __o
-__o = Copy(__FieldOperations)
+__IntegerModNOperations = Copy(__FieldOperations)
-__o.__index = IntegerModN
-__o.__tostring = function(a)
+__IntegerModNOperations.__index = IntegerModN
+__IntegerModNOperations.__tostring = function(a)
return tostring(a.element)
end
@@ -56,7 +55,7 @@ function IntegerModN:new(i, n)
error("Argument error: modulus must be an integer greater than 0.")
end
- o = setmetatable(o, __o)
+ o = setmetatable(o, __IntegerModNOperations)
if i < Integer.zero() or i >= n then
i = i % n
diff --git a/macros/luatex/latex/luacas/tex/algebra/luacas-logarithm.lua b/macros/luatex/latex/luacas/tex/algebra/luacas-logarithm.lua
index 07a9db84d1..135a74f326 100644
--- a/macros/luatex/latex/luacas/tex/algebra/luacas-logarithm.lua
+++ b/macros/luatex/latex/luacas/tex/algebra/luacas-logarithm.lua
@@ -4,7 +4,7 @@
--- @field base Expression
--- @field expression Expression
Logarithm = {}
-__Logarithm = {}
+local __Logarithm = {}
----------------------------
-- Instance functionality --
diff --git a/macros/luatex/latex/luacas/tex/algebra/luacas-polynomialring.lua b/macros/luatex/latex/luacas/tex/algebra/luacas-polynomialring.lua
index 568c21c921..2a76bda265 100644
--- a/macros/luatex/latex/luacas/tex/algebra/luacas-polynomialring.lua
+++ b/macros/luatex/latex/luacas/tex/algebra/luacas-polynomialring.lua
@@ -4,7 +4,7 @@
--- @field symbol SymbolExpression
--- @field ring RingIdentifier
PolynomialRing = {}
-__PolynomialRing = {}
+local __PolynomialRing = {}
-- Metatable for ring objects.
local __obj = {__index = PolynomialRing, __eq = function(a, b)
@@ -214,9 +214,9 @@ end
----------------------------
-- So we don't have to copy the Euclidean operations each time
-local __o = Copy(__EuclideanOperations)
-__o.__index = PolynomialRing
-__o.__tostring = function(a)
+__PolynomialOperations = Copy(__EuclideanOperations)
+__PolynomialOperations.__index = PolynomialRing
+__PolynomialOperations.__tostring = function(a)
local out = ""
local loc = a.degree:asnumber()
while loc >= 0 do
@@ -229,7 +229,7 @@ __o.__tostring = function(a)
end
return string.sub(out, 1, string.len(out) - 1)
end
-__o.__div = function(a, b)
+__PolynomialOperations.__div = function(a, b)
if not b.getring then
return BinaryOperation.DIVEXP({a, b})
end
@@ -258,13 +258,20 @@ function PolynomialRing:tolatex()
end
if self.ring == Rational.getring() or self.ring == Integer.getring() or self.ring == IntegerModN.getring() then
if self.coefficients[loc] ~= Integer.one() then
- out = out .. self.coefficients[loc]:tolatex() .. self.symbol
+ if self.coefficients[loc] == Integer(-1) then
+ out = out .. "-" .. self.symbol
+ elseif self.coefficients[loc] == Integer.zero() then
+ goto lead
+ else
+ out = out .. self.coefficients[loc]:tolatex() .. self.symbol
+ end
else
out = out .. self.symbol
end
if loc ~=1 then
out = out .. "^{" .. loc .. "}"
end
+ ::lead::
loc = loc -1
while loc >=0 do
local coeff = self.coefficients[loc]
@@ -330,7 +337,7 @@ end
-- Creates a new polynomial ring given an array of coefficients and a symbol
function PolynomialRing:new(coefficients, symbol, degree)
local o = {}
- o = setmetatable(o, __o)
+ o = setmetatable(o, __PolynomialOperations)
if type(coefficients) ~= "table" then
error("Sent parameter of wrong type: Coefficients must be in an array")
diff --git a/macros/luatex/latex/luacas/tex/algebra/luacas-rational.lua b/macros/luatex/latex/luacas/tex/algebra/luacas-rational.lua
index 811909a948..0802eb5172 100644
--- a/macros/luatex/latex/luacas/tex/algebra/luacas-rational.lua
+++ b/macros/luatex/latex/luacas/tex/algebra/luacas-rational.lua
@@ -4,7 +4,7 @@
--- @field denominator Ring
--- @field ring RingIdentifier
Rational = {}
-__Rational = {}
+local __Rational = {}
--------------------------
@@ -54,9 +54,9 @@ end
----------------------------
-- So we don't have to copy the field operations each time.
-local __o = Copy(__FieldOperations)
-__o.__index = Rational
-__o.__tostring = function(a)
+__RationalOperations = Copy(__FieldOperations)
+__RationalOperations.__index = Rational
+__RationalOperations.__tostring = function(a)
if a.ring.symbol then
return "(" .. tostring(a.numerator)..")/("..tostring(a.denominator) .. ")"
end
@@ -70,7 +70,7 @@ end
--- @param keep boolean
function Rational:new(n, d, keep)
local o = {}
- o = setmetatable(o, __o)
+ o = setmetatable(o, __RationalOperations)
if n:getring() == PolynomialRing.getring() then
o.symbol = n.symbol
@@ -88,7 +88,15 @@ function Rational:new(n, d, keep)
d = d or Integer.one()
o.numerator = n
o.denominator = d
- o:reduce()
+ if not keep then
+ o:reduce()
+ end
+
+ if o.numerator:getring() == Integer.getring() then
+ o.ring = Integer.getring()
+ elseif o.numerator:getring() == PolynomialRing.getring() then
+ o.ring = Ring.resultantring(o.numerator:getring(), o.denominator:getring())
+ end
if (not keep) and o.denominator == Integer.one() or (not keep) and o.numerator == Integer.zero() then
return o.numerator
@@ -107,7 +115,6 @@ function Rational:reduce()
local gcd = Integer.gcd(self.numerator, self.denominator)
self.numerator = self.numerator//gcd
self.denominator = self.denominator//gcd
- self.ring = Integer.getring()
elseif self.numerator:getring() == PolynomialRing.getring() then
local lc = self.denominator:lc()
self.denominator = self.denominator/lc
@@ -115,7 +122,6 @@ function Rational:reduce()
local gcd = PolynomialRing.gcd(self.numerator, self.denominator)
self.numerator = self.numerator//gcd
self.denominator = self.denominator//gcd
- self.ring = Ring.resultantring(self.numerator:getring(), self.denominator:getring())
end
end
diff --git a/macros/luatex/latex/luacas/tex/algebra/luacas-ring.lua b/macros/luatex/latex/luacas/tex/algebra/luacas-ring.lua
index 4903b9c912..81df15d18c 100644
--- a/macros/luatex/latex/luacas/tex/algebra/luacas-ring.lua
+++ b/macros/luatex/latex/luacas/tex/algebra/luacas-ring.lua
@@ -1,7 +1,7 @@
--- @class Ring
--- Interface for an element of a ring with unity.
Ring = {}
-__Ring = {}
+local __Ring = {}
--------------------------
-- Static functionality --
diff --git a/macros/luatex/latex/luacas/tex/algebra/luacas-rootexpression.lua b/macros/luatex/latex/luacas/tex/algebra/luacas-rootexpression.lua
index a66182579a..6f9a492591 100644
--- a/macros/luatex/latex/luacas/tex/algebra/luacas-rootexpression.lua
+++ b/macros/luatex/latex/luacas/tex/algebra/luacas-rootexpression.lua
@@ -2,7 +2,7 @@
--- An expression that represents the solutions to expression = 0.
--- @field expression Expression
RootExpression = {}
-__RootExpression = {}
+local __RootExpression = {}
----------------------------
-- Instance functionality --
diff --git a/macros/luatex/latex/luacas/tex/algebra/luacas-sqrtexpression.lua b/macros/luatex/latex/luacas/tex/algebra/luacas-sqrtexpression.lua
index bc96f4e1d8..641198fd65 100644
--- a/macros/luatex/latex/luacas/tex/algebra/luacas-sqrtexpression.lua
+++ b/macros/luatex/latex/luacas/tex/algebra/luacas-sqrtexpression.lua
@@ -2,7 +2,7 @@
--- An expression that represents the positive real solution to x^n = a where n is a positive integer and a is constant.
--- @field expression Expression
SqrtExpression = {}
-__SqrtExpression = {}
+local __SqrtExpression = {}
----------------------------
-- Instance functionality --
diff --git a/macros/luatex/latex/luacas/tex/algebra/luacas-trigexpression.lua b/macros/luatex/latex/luacas/tex/algebra/luacas-trigexpression.lua
index 307bfe1737..6f09e39f57 100644
--- a/macros/luatex/latex/luacas/tex/algebra/luacas-trigexpression.lua
+++ b/macros/luatex/latex/luacas/tex/algebra/luacas-trigexpression.lua
@@ -3,7 +3,7 @@
--- @field name string
--- @field expression Expression
TrigExpression = {}
-__TrigExpression = {}
+local __TrigExpression = {}
----------------------------
-- Instance functionality --
diff --git a/macros/luatex/latex/luacas/tex/calculus/luacas-calculus_init.lua b/macros/luatex/latex/luacas/tex/calculus/luacas-calculus_init.lua
deleted file mode 100644
index 89b38b650e..0000000000
--- a/macros/luatex/latex/luacas/tex/calculus/luacas-calculus_init.lua
+++ /dev/null
@@ -1,6 +0,0 @@
--- Loads calculus files in the correct order.
-require("algebra.luacas-algebra_init")
-
-require("calculus.luacas-derivativeexpression")
-require("calculus.luacas-integralexpression")
-require("calculus.luacas-diffexpression")
diff --git a/macros/luatex/latex/luacas/tex/calculus/luacas-derivativeexpression.lua b/macros/luatex/latex/luacas/tex/calculus/luacas-derivativeexpression.lua
index b757759c4c..2ef4c43125 100644
--- a/macros/luatex/latex/luacas/tex/calculus/luacas-derivativeexpression.lua
+++ b/macros/luatex/latex/luacas/tex/calculus/luacas-derivativeexpression.lua
@@ -3,7 +3,7 @@
--- @field symbol SymbolExpression
--- @field expression Expression
DerivativeExpression = {}
-__DerivativeExpression = {}
+local __DerivativeExpression = {}
----------------------------
-- Instance functionality --
diff --git a/macros/luatex/latex/luacas/tex/calculus/luacas-diffexpression.lua b/macros/luatex/latex/luacas/tex/calculus/luacas-diffexpression.lua
index df1dc90f33..bf15c56b6f 100644
--- a/macros/luatex/latex/luacas/tex/calculus/luacas-diffexpression.lua
+++ b/macros/luatex/latex/luacas/tex/calculus/luacas-diffexpression.lua
@@ -4,7 +4,7 @@
--- @field expression Expression
DiffExpression = {}
-__DiffExpression = {}
+local __DiffExpression = {}
----------------------------
-- Instance functionality --
diff --git a/macros/luatex/latex/luacas/tex/calculus/luacas-integralexpression.lua b/macros/luatex/latex/luacas/tex/calculus/luacas-integralexpression.lua
index 5267127264..bddc179fa4 100644
--- a/macros/luatex/latex/luacas/tex/calculus/luacas-integralexpression.lua
+++ b/macros/luatex/latex/luacas/tex/calculus/luacas-integralexpression.lua
@@ -10,7 +10,7 @@
--- @field recursive boolean
IntegralExpression = {}
-__IntegralExpression = {}
+local __IntegralExpression = {}
--------------------------
diff --git a/macros/luatex/latex/luacas/tex/core/luacas-atomicexpression.lua b/macros/luatex/latex/luacas/tex/core/luacas-atomicexpression.lua
index 6cc6e4f58e..4eed1592f4 100644
--- a/macros/luatex/latex/luacas/tex/core/luacas-atomicexpression.lua
+++ b/macros/luatex/latex/luacas/tex/core/luacas-atomicexpression.lua
@@ -1,7 +1,7 @@
--- @class AtomicExpression
--- Interface for an atomic mathematical expression that has no sub-expressions.
AtomicExpression = {}
-__AtomicExpression = {}
+local __AtomicExpression = {}
----------------------
diff --git a/macros/luatex/latex/luacas/tex/core/luacas-binaryoperation.lua b/macros/luatex/latex/luacas/tex/core/luacas-binaryoperation.lua
index 708a6c1540..f2998436eb 100644
--- a/macros/luatex/latex/luacas/tex/core/luacas-binaryoperation.lua
+++ b/macros/luatex/latex/luacas/tex/core/luacas-binaryoperation.lua
@@ -5,7 +5,7 @@
--- @field operation function
--- @field expressions table<number, Expression>
BinaryOperation = {}
-__BinaryOperation = {}
+local __BinaryOperation = {}
----------------------------
-- Instance functionality --
@@ -621,6 +621,8 @@ function BinaryOperation:tolatex()
for index, expression in ipairs(self.expressions) do
if index == 1 then
out = out .. expression:tolatex()
+ elseif expression:isconstant() and expression < Integer.zero() then
+ out = out .. "\\cdot (" .. expression:tolatex() .. ")"
else
out = out .. "\\cdot " .. expression:tolatex()
end
diff --git a/macros/luatex/latex/luacas/tex/core/luacas-compoundexpression.lua b/macros/luatex/latex/luacas/tex/core/luacas-compoundexpression.lua
index 792c36cfc2..cae82719ac 100644
--- a/macros/luatex/latex/luacas/tex/core/luacas-compoundexpression.lua
+++ b/macros/luatex/latex/luacas/tex/core/luacas-compoundexpression.lua
@@ -1,7 +1,7 @@
--- @class CompoundExpression
--- Interface for an expression consisting of one or more subexpressions.
CompoundExpression = {}
-__CompoundExpression = {}
+local __CompoundExpression = {}
----------------------
-- Instance methods --
diff --git a/macros/luatex/latex/luacas/tex/core/luacas-constantexpression.lua b/macros/luatex/latex/luacas/tex/core/luacas-constantexpression.lua
index 0f91a037a9..6d9f8e96d2 100644
--- a/macros/luatex/latex/luacas/tex/core/luacas-constantexpression.lua
+++ b/macros/luatex/latex/luacas/tex/core/luacas-constantexpression.lua
@@ -3,7 +3,7 @@
--- Interface for a mathematical expression without any symbols.
--- ConstantExpressions are AtomicExpressions by default, but individual classes may overwrite that inheritance.
ConstantExpression = {}
-__ConstantExpression = {}
+local __ConstantExpression = {}
----------------------
-- Instance methods --
diff --git a/macros/luatex/latex/luacas/tex/core/luacas-core_init.lua b/macros/luatex/latex/luacas/tex/core/luacas-core_init.lua
deleted file mode 100644
index c9c3b89126..0000000000
--- a/macros/luatex/latex/luacas/tex/core/luacas-core_init.lua
+++ /dev/null
@@ -1,16 +0,0 @@
--- Loads core files in the correct order.
-
-require("core.luacas-expression")
-require("core.luacas-atomicexpression")
-require("core.luacas-compoundexpression")
-require("core.luacas-constantexpression")
-require("core.luacas-symbolexpression")
-require("core.luacas-binaryoperation")
-require("core.luacas-functionexpression")
-
-
-require("core.binaryoperation.luacas-power")
-require("core.binaryoperation.luacas-product")
-require("core.binaryoperation.luacas-sum")
-require("core.binaryoperation.luacas-quotient")
-require("core.binaryoperation.luacas-difference") \ No newline at end of file
diff --git a/macros/luatex/latex/luacas/tex/core/luacas-functionexpression.lua b/macros/luatex/latex/luacas/tex/core/luacas-functionexpression.lua
index dc94790b81..f6f3a99720 100644
--- a/macros/luatex/latex/luacas/tex/core/luacas-functionexpression.lua
+++ b/macros/luatex/latex/luacas/tex/core/luacas-functionexpression.lua
@@ -6,7 +6,7 @@
--- @field variables table<number,SymbolExpression>
--- @alias Function FunctionExpression
FunctionExpression = {}
-__FunctionExpression = {}
+local __FunctionExpression = {}
----------------------------
-- Instance functionality --
diff --git a/macros/luatex/latex/luacas/tex/core/luacas-symbolexpression.lua b/macros/luatex/latex/luacas/tex/core/luacas-symbolexpression.lua
index 0d9192c084..068ab71dcc 100644
--- a/macros/luatex/latex/luacas/tex/core/luacas-symbolexpression.lua
+++ b/macros/luatex/latex/luacas/tex/core/luacas-symbolexpression.lua
@@ -3,7 +3,7 @@
--- @field symbol string
--- @alias Symbol SymbolExpression
SymbolExpression = {}
-__SymbolExpression = {}
+local __SymbolExpression = {}
----------------------
-- Instance methods --
diff --git a/macros/luatex/latex/luacas/tex/luacas.sty b/macros/luatex/latex/luacas/tex/luacas.sty
index d46ee847fc..939bd9d392 100644
--- a/macros/luatex/latex/luacas/tex/luacas.sty
+++ b/macros/luatex/latex/luacas/tex/luacas.sty
@@ -9,7 +9,7 @@
\NeedsTeXFormat{LaTeX2e}
\ProvidesPackage{luacas}
- [2022/11/15 v1.0.1 CAS written in Lua for LaTeX]
+ [2023/05/26 v1.0.2 CAS written in Lua for LaTeX]
\RequirePackage{iftex}
\ifluatex
diff --git a/macros/luatex/latex/luacas/tex/luacas_init.lua b/macros/luatex/latex/luacas/tex/luacas_init.lua
new file mode 100644
index 0000000000..8d58e259e7
--- /dev/null
+++ b/macros/luatex/latex/luacas/tex/luacas_init.lua
@@ -0,0 +1,304 @@
+--- @class LuaCAS
+--- @class Module
+--- A table that initalizes and stores luacas modules.
+--- @field moduleinfo table<string, table>
+--- @field core Module
+--- @field algebra Module
+--- @field calculus Module
+local luacas = {}
+
+
+-- a table containing a list of module names, descriptions, class names, variables, required files, and dependent modules
+luacas.moduleinfo = {
+ ["core"]=
+ {
+ "Classes needed for creating basic expressions such as symbols, binary operations, and functions.",
+ {
+ "Expression",
+ "AtomicExpression",
+ "CompoundExpression",
+ "ConstantExpression",
+ "SymbolExpression",
+ "BinaryOperation",
+ "FunctionExpression",
+
+ "__ExpressionOperations"
+ },
+ {"E", "I", "PI"},
+ {
+ "_lib.luacas-table",
+ "core.luacas-expression",
+ "core.luacas-atomicexpression",
+ "core.luacas-compoundexpression",
+ "core.luacas-constantexpression",
+ "core.luacas-symbolexpression",
+ "core.luacas-binaryoperation",
+ "core.luacas-functionexpression",
+ "core.binaryoperation.luacas-power",
+ "core.binaryoperation.luacas-product",
+ "core.binaryoperation.luacas-sum",
+ "core.binaryoperation.luacas-quotient",
+ "core.binaryoperation.luacas-difference",
+ },
+ {}
+ },
+
+ ["algebra"]=
+ {
+ "Classes for elements of rings (integers, rationals, polynomials, etc., and operations on those elements (polynomial factoring). Also includes some elementary functions like logs and trig functions.",
+ {
+ "Ring",
+ "EuclideanDomain",
+ "Field",
+ "PolynomialRing",
+ "Integer",
+ "Rational",
+ "IntegerModN",
+ "SqrtExpression",
+ "AbsExpression",
+ "Equation",
+ "FactorialExpression",
+ "Logarithm",
+ "RootExpression",
+ "TrigExpression",
+
+ "__RingOperations", -- Not classes, but we need to set the environment for this
+ "__EuclideanOperations",
+ "__FieldOperations",
+ "__PolynomialOperations",
+ "__IntegerOperations",
+ "__IntegerModNOperations",
+ "__RationalOperations"
+ },
+ {"ABS", "ARCCOS", "ARCCOT", "ARCCSC", "ARCSEC", "ARCSIN", "ARCTAN", "COS", "COT", "CSC", "FACT", "LN", "LOG", "SEC", "SIN", "TAN"},
+ {
+ "algebra.luacas-ring",
+ "algebra.luacas-euclideandomain",
+ "algebra.luacas-field",
+ "algebra.luacas-polynomialring",
+ "algebra.luacas-integer",
+ "algebra.luacas-rational",
+ "algebra.luacas-integerquotientring",
+ "algebra.luacas-sqrtexpression",
+ "algebra.luacas-absexpression",
+ "algebra.luacas-equation",
+ "algebra.luacas-factorialexpression",
+ "algebra.luacas-logarithm",
+ "algebra.luacas-rootexpression",
+ "algebra.luacas-trigexpression",
+ "algebra.polynomialring.luacas-berlekampfactoring",
+ "algebra.polynomialring.luacas-zassenhausfactoring",
+ "algebra.polynomialring.luacas-decomposition"
+ },
+ {"core"}
+ },
+
+ ["calculus"]=
+ {
+ "Classes for symbolic differentation and integration.",
+ {
+ "DerivativeExpression",
+ "IntegralExpression",
+ "DiffExpression"
+ },
+ {"DD", "INT"},
+ {
+ "calculus.luacas-derivativeexpression",
+ "calculus.luacas-integralexpression",
+ "calculus.luacas-diffexpression"
+ },
+ {"algebra"}
+ }
+}
+
+--- Retrieves a short description for a module.
+--- @param mod string
+--- @return string
+function luacas:moduledesc(mod)
+ if self.moduleinfo[mod] then
+ return self.moduleinfo[mod][1]
+ end
+ return "Module not found."
+end
+
+--- Retrieves a list of class names included in a module.
+--- @param mod string
+--- @return table<number,string>
+function luacas:moduleclasses(mod)
+ if self.moduleinfo[mod] then
+ return self.moduleinfo[mod][2]
+ end
+ return {}
+end
+
+--- Retrieves a list of fields included in a module.
+--- @param mod string
+--- @return table<number,string>
+function luacas:modulefields(mod)
+ if self.moduleinfo[mod] then
+ return self.moduleinfo[mod][3]
+ end
+ return {}
+end
+
+--- Retrieves a list of files included in a module.
+--- @param mod string
+--- @return table<number,string>
+function luacas:modulefiles(mod)
+ if self.moduleinfo[mod] then
+ return self.moduleinfo[mod][4]
+ end
+ return {}
+end
+
+--- Retrieves a list of a module's immediate dependencies.
+--- @param mod string
+--- @return table<number,string>
+function luacas:moduledependencies(mod)
+ if self.moduleinfo[mod] then
+ return self.moduleinfo[mod][5]
+ end
+ return {}
+end
+
+--- Initalizes a LuaCAS module and returns it.
+--- Since this creates temporary global variables, it should be treated as atomic to avoid collisions.
+--- @param mod string
+--- @return Module|nil
+function luacas:initmodule(mod)
+ if not self.moduleinfo[mod] then
+ return nil
+ end
+
+ -- TODO: This is a special case, since the algebra module is dependent on the core module and vice versa,
+ -- but our initialization scheme does not allow for circular dependencies.
+ if mod == "core" then
+ self:initmodule("algebra")
+ end
+
+ -- Since other modules require globals from their dependencies, we only remove global variables after all modules have been initalized
+ local G = self:saveglobalstate()
+ self:_initmodulerec(mod)
+ self:restoreglobalstate(G)
+
+ return self[mod]
+end
+
+--- Recursive part of initalizing modules.
+--- @param mod string
+function luacas:_initmodulerec(mod)
+
+ for _, dep in ipairs(self:moduledependencies(mod)) do
+ self:_initmodulerec(dep)
+ end
+
+ if self[mod] then
+ -- Since globals from a dependency might be needed to initialize a module, we create globals even if a module has already been initalized.
+ for class, _ in self[mod] do
+ _G[class] = self[mod][class]
+ end
+ else
+ -- Creates globals needed for modules dependent on this one.
+ self:initglobalmodule(mod)
+
+ -- Adds classes to module table.
+ self[mod] = {}
+ for _, class in ipairs(self:moduleclasses(mod)) do
+ self[mod][class] = _G[class]
+ end
+
+ -- Sets the environment for each method of each class to include all dependent classes of this class.
+ self:setmoduleenvironment(mod)
+ -- TODO: This is a special case, since the algebra module is dependent on the core module and vice versa,
+ -- but our initialization scheme does not allow for circular dependencies.
+ if mod == "algebra" then
+ self:setmoduleenvironment("core")
+ end
+
+ -- Adds fields to module tables
+ for _, class in ipairs(self:modulefields(mod)) do
+ self[mod][class] = _G[class]
+ end
+ end
+end
+
+--- Sets the environment for each method of each class in a module to the current global environment, so it can keep using global variables when reset.
+--- @param mod string
+function luacas:setmoduleenvironment(mod)
+ local realenv = self:saveglobalstate()
+ for _, class in pairs(self[mod]) do
+ -- print(_)
+ for _, func in pairs(class) do
+ -- print(" ", _)
+ if type(func) == "function" then
+ --- Functions only have an _ENV upvalue if they have a global variable, so this should work
+ local _envloc = debug.findupvalue(func, "_ENV")
+ if _envloc then
+ debug.upvaluejoin(func, debug.findupvalue(func, "_ENV"), function () return realenv end, 1)
+ end
+ end
+ end
+
+ -- local meta = getmetatable(class)
+ -- if meta then
+ -- for _, func in pairs(meta) do
+ -- print(" ", _)
+ -- if type(func) == "function" then
+ -- --- Functions only have an _ENV upvalue if they have a global variable, so this should work
+ -- local _envloc = debug.findupvalue(func, "_ENV")
+ -- if _envloc then
+ -- debug.upvaluejoin(func, debug.findupvalue(func, "_ENV"), function () return realenv end, 1)
+ -- end
+ -- end
+ -- end
+ -- end
+ end
+end
+
+--- Saves the current global state as a table and returns it.
+--- @return table
+function luacas:saveglobalstate()
+ local G = {}
+ for key, value in pairs(_G) do
+ G[key] = value
+ end
+ return G
+end
+
+--- Saves the current global state as a table and returns it.
+--- @param G table
+function luacas:restoreglobalstate(G)
+ for key, _ in pairs(_G) do
+ if key ~= "_G" and key ~= "pairs" then
+ _G[key] = nil
+ end
+ end
+ for key, value in pairs(G) do
+ _G[key] = value
+ end
+end
+
+--- Initalizes a LuaCAS module and creates global variables for all classes in that module.
+--- DOES NOT HANDLE DEPENDENCIES, so dependent modules must be globally initalized first.
+--- @param mod string
+--- @return Module|nil
+function luacas:initglobalmodule(mod)
+ for _, filename in ipairs(self:modulefiles(mod)) do
+ require(filename)
+ end
+end
+
+--- Why is Lua like this?
+function debug.findupvalue(fn, search_name)
+ local i = 1
+ while true do
+ local name, val = debug.getupvalue(fn, i)
+ if not name then break end
+ if name == search_name then
+ return i, val
+ end
+ i = i + 1
+ end
+end
+
+return luacas \ No newline at end of file
diff --git a/macros/luatex/latex/luacas/tex/test/luacas-main.lua b/macros/luatex/latex/luacas/tex/test/luacas-main.lua
index 95f77885e4..78b25aa587 100644
--- a/macros/luatex/latex/luacas/tex/test/luacas-main.lua
+++ b/macros/luatex/latex/luacas/tex/test/luacas-main.lua
@@ -1,8 +1,23 @@
---@diagnostic disable: lowercase-global
-- Runs test code from test files.
-require("calculus.luacas-calculus_init")
require("_lib.luacas-pepperfish")
+require("_lib.luacas-table")
+
+local luacas = require("luacas_init")
+luacas:initmodule("calculus")
+
+for name, class in pairs(luacas.core) do
+ _G[name] = class
+end
+
+for name, class in pairs(luacas.algebra) do
+ _G[name] = class
+end
+
+for name, class in pairs(luacas.calculus) do
+ _G[name] = class
+end
-- Stuff required for the basic parser.
local constants = {e="E", pi = "PI", ln = "LN", log = "LOG", Integer = "Integer", DD = "DD", int = "INT", abs = "ABS", fact="FACT"}
diff --git a/macros/luatex/latex/luacas/tex/test/luacas-parser.lua b/macros/luatex/latex/luacas/tex/test/luacas-parser.lua
index 3380549620..47f0640c3f 100644
--- a/macros/luatex/latex/luacas/tex/test/luacas-parser.lua
+++ b/macros/luatex/latex/luacas/tex/test/luacas-parser.lua
@@ -1,8 +1,10 @@
-- Rudimentary parser for making the CAS easier to use. Essentially just wraps SymbolExpression() around symbols and Integer() around integers.
-
-require("calculus.luacas-calculus_init")
+local luacas = require("luacas_init")
+luacas:initglobalmodule("core")
+luacas:initglobalmodule("algebra")
+luacas:initglobalmodule("calculus")
-- Splits a string on a seperator.
function split(str, sep)
@@ -284,8 +286,16 @@ end
--- @param input string
function CASparse(input)
- -- First, we replace any occurance of a number with an integer or rational version of itself.
- local str = string.gsub(input, ".?[0-9]+", function (s)
+ -- First, we replace any occurrence of a decimal with the appropriate fraction.
+
+ local str = string.gsub(input,"%d+%.%d+", function(s)
+ local ints = split(s,"%.")
+ return "("..ints[1]..ints[2].." / 10^" .. tostring(string.len(ints[2])) .. ")"
+ end)
+
+ -- Next, we replace any occurance of a number with an integer or rational version of itself.
+
+ str = string.gsub(str, ".?[0-9]+", function (s)
-- Here, we are part of an identifier, so we don't replace anything
if string.match(string.sub(s, 1, 1), "[A-Z]") or string.match(string.sub(s, 1, 1), "[a-z]") or string.match(string.sub(s, 1, 1), "_") then
return
@@ -301,11 +311,11 @@ function CASparse(input)
--------------------------
-- HERE COMES THE JANK. --
--------------------------
-
+ -- The JANK may not actually be doing anything now. But for the sake of posterity...
-- Replaces each instance of a decimal with .., so we can use integer metatables to convert it into a rational properly.
str = string.gsub(str, "Integer%('[0-9]+'%)%.Integer%('[0-9]+'%)", function (s)
local ints = split(s, "%.")
- return ints[1] .. ".." .. ints[2]
+ return "("..ints[1] .. ".." .. ints[2] .. ")"
end)
str = string.gsub(str, ".?%.Integer%('[0-9]+'%)", function (s)
if string.sub(s, 1, 2) == ".." then
@@ -320,4 +330,4 @@ function CASparse(input)
else
print(err)
end
-end \ No newline at end of file
+end
diff --git a/macros/luatex/latex/luacas/tex/test/rings/luacas-conversion.lua b/macros/luatex/latex/luacas/tex/test/rings/luacas-conversion.lua
index b9eb523c7a..6a53dacd17 100644
--- a/macros/luatex/latex/luacas/tex/test/rings/luacas-conversion.lua
+++ b/macros/luatex/latex/luacas/tex/test/rings/luacas-conversion.lua
@@ -120,9 +120,9 @@ testringconvert(a, fring, "12/1x^0", "QQ[x]")
testringconvert(a, gring, "((12x^0)y^0)z^0", "ZZ[x][y][z]")
testringconvert(a, hring, "((12/1z^0)y^0)x^0", "QQ[z][y][x]")
testringconvert(a, iring, "(12x^0)/(1x^0)", "ZZ(x)")
-testringconvert(a, jring, "(12x^0)/(1x^0)", "ZZ(x)")
+testringconvert(a, jring, "(12/1x^0)/(1/1x^0)", "QQ(x)")
testringconvert(a, kring, "2x^0", "Z/Z5[x]")
-testringconvert(a, lring, "((12x^0)/(1x^0))y^0", "ZZ(x)[y]")
+testringconvert(a, lring, "((12/1x^0)/(1/1x^0))y^0", "QQ(x)[y]")
-- testringconvert(b, aring, "3/2", "ZZ")
testringconvert(b, bring, "3/2", "QQ")
@@ -133,9 +133,9 @@ testringconvert(b, fring, "3/2x^0", "QQ[x]")
-- testringconvert(b, gring, "3/2", "ZZ[x][y][z]")
testringconvert(b, hring, "((3/2z^0)y^0)x^0", "QQ[z][y][x]")
-- testringconvert(b, iring, "3/2", "ZZ(x)")
-testringconvert(b, jring, "(3/2x^0)/(1x^0)", "QQ(x)")
+testringconvert(b, jring, "(3/2x^0)/(1/1x^0)", "QQ(x)")
-- testringconvert(b, kring, "3/2", "Z/Z5[x]")
-testringconvert(b, lring, "((3/2x^0)/(1x^0))y^0", "QQ(x)[y]")
+testringconvert(b, lring, "((3/2x^0)/(1/1x^0))y^0", "QQ(x)[y]")
testringconvert(c, aring, "4", "ZZ")
-- testringconvert(c, bring, "4", "QQ")
@@ -172,9 +172,9 @@ testringconvert(e, fring, "3/1x^2+0/1x^1+6/1x^0", "QQ[x]")
testringconvert(e, gring, "((3x^2+0x^1+6x^0)y^0)z^0", "ZZ[x][y][z]")
testringconvert(e, hring, "((3/1z^0)y^0)x^2+((0/1z^0)y^0)x^1+((6/1z^0)y^0)x^0", "QQ[z][y][x]")
testringconvert(e, iring, "(3x^2+0x^1+6x^0)/(1x^0)", "ZZ(x)")
-testringconvert(e, jring, "(3x^2+0x^1+6x^0)/(1x^0)", "ZZ(x)")
+testringconvert(e, jring, "(3/1x^2+0/1x^1+6/1x^0)/(1/1x^0)", "QQ(x)")
testringconvert(e, kring, "3x^2+0x^1+1x^0", "Z/Z5[x]")
-testringconvert(e, lring, "((3x^2+0x^1+6x^0)/(1x^0))y^0", "ZZ(x)[y]")
+testringconvert(e, lring, "((3/1x^2+0/1x^1+6/1x^0)/(1/1x^0))y^0", "QQ(x)[y]")
-- testringconvert(f, aring, "12x^1+4/5x^0", "ZZ")
-- testringconvert(f, bring, "12x^1+4/5x^0", "QQ")
@@ -185,9 +185,9 @@ testringconvert(f, fring, "12x^1+4/5x^0", "QQ[x]")
-- testringconvert(f, gring, "12x^1+4/5x^0", "ZZ[x][y][z]")
testringconvert(f, hring, "((12/1z^0)y^0)x^1+((4/5z^0)y^0)x^0", "QQ[z][y][x]")
-- testringconvert(f, iring, "12x^1+4/5x^0", "ZZ(x)")
-testringconvert(f, jring, "(12x^1+4/5x^0)/(1x^0)", "QQ(x)")
+testringconvert(f, jring, "(12x^1+4/5x^0)/(1/1x^0)", "QQ(x)")
-- testringconvert(f, kring, "12x^1+4/5x^0", "Z/Z5[x]")
-testringconvert(f, lring, "((12x^1+4/5x^0)/(1x^0))y^0", "QQ(x)[y]")
+testringconvert(f, lring, "((12x^1+4/5x^0)/(1/1x^0))y^0", "QQ(x)[y]")
-- testringconvert(g, aring, "", "ZZ")
-- testringconvert(g, bring, "", "QQ")
@@ -224,9 +224,9 @@ testringconvert(h, hring, "((1z^0)y^0)x^3+((1z^0)y^3+(1/9z^1+-16z^0)y^2+(1z^2+8z
-- testringconvert(i, gring, "", "ZZ[x][y][z]")
-- testringconvert(i, hring, "", "QQ[z][y][x]")
testringconvert(i, iring, "(1x^1+-2x^0)/(1x^2+3x^1+3x^0)", "ZZ(x)")
-testringconvert(i, jring, "(1x^1+-2x^0)/(1x^2+3x^1+3x^0)", "ZZ(x)")
+testringconvert(i, jring, "(1/1x^1+-2/1x^0)/(1/1x^2+3/1x^1+3/1x^0)", "QQ(x)")
-- testringconvert(i, kring, "", "Z/Z5[x]")
-testringconvert(i, lring, "((1x^1+-2x^0)/(1x^2+3x^1+3x^0))y^0", "ZZ(x)[y]")
+testringconvert(i, lring, "((1/1x^1+-2/1x^0)/(1/1x^2+3/1x^1+3/1x^0))y^0", "QQ(x)[y]")
-- testringconvert(j, aring, "", "ZZ")
-- testringconvert(j, bring, "", "QQ")