From d50bfeb7feb32d585a89393c364ef5f9e1b915d0 Mon Sep 17 00:00:00 2001 From: Norbert Preining Date: Mon, 10 Jan 2022 03:02:56 +0000 Subject: CTAN sync 202201100302 --- macros/generic/polexpr/README.md | 13 +- macros/generic/polexpr/polexpr-examples.pdf | Bin 0 -> 58706 bytes macros/generic/polexpr/polexpr-examples.tex | 881 +++++++++++++++++++ macros/generic/polexpr/polexpr.html | 1263 +++++++++------------------ macros/generic/polexpr/polexpr.sty | 8 +- macros/generic/polexpr/polexprcore.tex | 10 +- macros/generic/polexpr/polexprexpr.tex | 6 +- macros/generic/polexpr/polexprsturm.tex | 211 ++--- 8 files changed, 1440 insertions(+), 952 deletions(-) create mode 100644 macros/generic/polexpr/polexpr-examples.pdf create mode 100644 macros/generic/polexpr/polexpr-examples.tex (limited to 'macros/generic/polexpr') diff --git a/macros/generic/polexpr/README.md b/macros/generic/polexpr/README.md index c52baa8b75..4a74900100 100644 --- a/macros/generic/polexpr/README.md +++ b/macros/generic/polexpr/README.md @@ -95,12 +95,14 @@ Releases - 0.8.5 (2021/11/30) Bugfix: `intfrom()` was documented at `0.8` but not declared to parser. Track (belatedly) `xintexpr` 1.4g changes +- 0.8.6 (2022/01/09) + Separate `polexpr-examples.{tex,pdf}` from the `polexpr.html` reference -Files of 0.8.5 release: - +Files of the 0.8.6 release: - polexpr.sty, polexprcore.tex, polexprexpr.tex, polexprsturm.tex, - README.md, -- polexpr.html (documentation) +- polexpr.html (reference documentation), +- polexpr-examples.pdf, polexpr-examples.tex (pdf doc and its source). Acknowledgments --------------- @@ -113,7 +115,7 @@ Jürgen Gilg and Thomas Söll for testing it on some concrete problems. License ------- -Copyright (C) 2018-2021 Jean-François Burnol +Copyright (C) 2018-2022 Jean-François Burnol See documentation of package [xintexpr](http://www.ctan.org/pkg/xint) for contact information. @@ -132,4 +134,5 @@ This Work has the LPPL maintenance status author-maintained. The Author of this Work is Jean-François Burnol. This Work consists of the package files polexpr.sty, polexprcore.tex, -polexprexpr.tex, polexprsturm.tex, this README.md and polexpr.html. +polexprexpr.tex, polexprsturm.tex, this README.md and documentation +polexpr.html, polexpr-examples.tex, polexpr-examples.pdf diff --git a/macros/generic/polexpr/polexpr-examples.pdf b/macros/generic/polexpr/polexpr-examples.pdf new file mode 100644 index 0000000000..1c67b4e533 Binary files /dev/null and b/macros/generic/polexpr/polexpr-examples.pdf differ diff --git a/macros/generic/polexpr/polexpr-examples.tex b/macros/generic/polexpr/polexpr-examples.tex new file mode 100644 index 0000000000..fa2f330513 --- /dev/null +++ b/macros/generic/polexpr/polexpr-examples.tex @@ -0,0 +1,881 @@ +% -*- sentence-end-double-space: t -*- +\documentclass[a4paper,svgnames,dvipsnames,dvipdfmx]{article} +\usepackage{geometry} +\usepackage{shortvrb} +\usepackage{xcolor} +\usepackage{graphicx} +\usepackage{polexpr} +\usepackage{hyperref} +\usepackage{bookmark} +% \usepackage{amsmath} +\usepackage{framed} +\usepackage{newtxtext,newtxmath} +\title{\pkg{polexpr} root localization examples} +\author{Jean-François Burnol} +\date{To access the reference documentation:\\ +% faut-il vraiment le ./ ? + \texttt{texdoc} \href{run:./polexpr.html}{polexpr.html}} +%\usepackage{parskip} +\MakeShortVerb{\|} + +% Note 25 juin 2021 et 8 janvier 2022 pour polexpr-examples.tex +% +% Ceci est extrait quasi verbatim de xint.dtx +% +% Le code est pour LaTeX, pas pour Plain TeX. +% Prévu pour latex+dvipdfmx, et j'ai supprimé ajouts spécifiques pour +% pdflatex/xetex/lualatex en ce qui concerne les couleurs et polices. +% +% Regarding latex+dvipdfmx, a document with many more usage +% of everbatim* could run into color stack overflow problems +% Refer to xint.dtx for how this problem is avoided there +% via direct usage of \special rather than \color in the +% \everbatimxprehook + +% verbatim macros and environments +% ================================ +% +% June 2013, then October 2014. +% ----------------------------- +% +\makeatletter +\catcode`_ 11 +% some of my verbatim environments do not make the space active (\lverb e.g.). Then +% \do@noligs must be modified, \char`#1 must be followed by a space token, else, +% the `#1 expansion will swallow one space. +\def\do@noligs #1{% + \catcode`#1\active + \begingroup + \lccode`~`#1\relax + \lowercase{% + \endgroup\def~{\leavevmode\kern\z@\char`#1 }}% +} +% \lowast +% Pas forcément adapté à toutes les polices +\def\lowast{\raisebox{-.25\height}{*}} +\catcode`* 13 +\def\makestarlowast {\let*\lowast\catcode`\*\active}% +\catcode`* 12 + + +%--- straight quotes, added (finally...) Nov 2, 2014 +%--- obsolete with use of newtxtt 1.05, late 2014 +\begingroup\makeatletter + \catcode`\'\active + \catcode`\`\active +\@firstofone {\endgroup + \def\makequotesstraight{% assumes textcomp package +% à propos textcomp est automatique avec pdflatex depuis Février 2020 + \let`\textasciigrave + \let'\textquotesingle + \catcode39\active + \catcode96\active }% +} + +% \verb +% ===== +% Initially, June 2013, then Sep 9, 2014, and Oct 9-12 2014 +% +% pour les short verb |...| + +\def\MicroFont{\ttfamily\makestarlowast\makequotesstraight}% default +\def\verb +{% + \relax \ifmmode\else\leavevmode\null\fi + \bgroup + \let\do\@makeother \dospecials + \@ifstar{\@sverb}% unused + {\MicroFont + \catcode 32 10 \endlinechar 32 % allows to fetch across line breaks + \frenchspacing + \@@jfverb}% +}% +% Note (Oct 12, 2014): in the improbable situation a newlinechar is +% found in the ##1, \scantokens will convert this to an end of line in +% its "write" phase, which will be then ignored in its "read" phase due +% to \endlinechar-1. This also avoids possible creation of \par which +% would defeat \@@jfverb@@. Thus it is good. +\def\@@jfverb #1{% + \ifcat\noexpand#1\noexpand~\catcode`#1\active\fi +% No problem with the EOL for the line where the short verb delimiter stands. + \def\next ##1#1{% + \@vobeyspaces\everyeof{\relax}\endlinechar\m@ne + \expandafter\@@jfverb_a\scantokens\expandafter{##1}}% +% hack with \@empty to prevent brace stripping if catcodes have been +% frozen earlier, like in footnotes. + \next \@empty +} +% We don't want a \discretionary at the very start. +% But then an empty argument is forbidden! +\def\@@jfverb_a #1{#1\@@jfverb_b } + +\def\@@jfverb_b #1{\ifx\relax #1% + \egroup + \else +% \penalty\z@, or rather (Oct 11, 2014) but I then adjust the textwidth +% precisely: + \discretionary{\copy\SoftWrapIcon}{}{}% + #1\expandafter\@@jfverb_b\fi +} +% \SoftWrapIcon box for line-breaking using discretionaries +% ========================================================= +\DeclareFontFamily{U}{MdSymbolC}{} +\DeclareFontShape {U}{MdSymbolC}{m}{n}{<-> MdSymbolC-Regular}{} +\newbox\SoftWrapIcon +% Emacs/AUCTeX uses very strange comment-like highlighting for \usefont{U}... +\def\SetSoftWrapIcon{% + \global\setbox\SoftWrapIcon\hb@xt@\z@ + {\hb@xt@\fontdimen2\font + {\hss{\color{verbsoftwrapiconcolor}% + \usefont{U}{MdSymbolC}{m}{n}\char"97}\hss}% + \hss}% + } +\AtBeginDocument {{\ttfamily\SetSoftWrapIcon}}% + +\catcode`_ 8 +\makeatother + +% everbatim environment +% ===================== + +% October 13-14, 2014 +% Verbatim with an \everypar hook, mainly to have background color, followed by +% execution of the contents (not limited by a group-scope) + +\makeatletter +\catcode`_ 11 + +\def\everbatimtop {\MacroFont\small}% default +\let\everbatimbottom\empty +\let\everbatimhook\empty + +\def\everbatim {\s@everbatim\@everbatim } +\@namedef{everbatim*}{\s@everbatim\expandafter\@everbatimx\expandafter + {\the\newlinechar}} +\let\everbatimbgcolorcmd\empty +\def\everbatimeverypar{\strut + {\everbatimbgcolorcmd\vrule\@width\linewidth }% + \kern-\linewidth + \kern\everbatimindent } +\def\everbatimindent {\z@} +% voir plus loin atbegindocument + +\def\endeverbatim {\if@newlist \leavevmode\fi\endtrivlist } + +\@namedef{endeverbatim*}{\endeverbatim\aftergroup\everbatimundoparskip} +\def\everbatimundoparskip{\vbox{}\kern-\baselineskip\kern-\parskip} +% Note 25 juin 2021 +% On ne peut pas emboîter un everbatim à l'intérieur d'un everbatim +% ou un everbatim* à l'intérieur d'un everbatim*... +\def\s@everbatim {% +% \ineverbtrue + \everbatimtop % put there size changes + \topsep \z@skip + \partopsep \z@skip + \itemsep \z@skip + \parsep \z@skip + \parskip \z@skip + \lineskip \z@skip + \let\do\@makeother \dospecials + \let\do\do@noligs \verbatim@nolig@list + \makestarlowast + \makequotesstraight + \everbatimhook + \trivlist + \@topsepadd \z@skip + \item\relax + \leftskip \@totalleftmargin + \rightskip \z@skip + \parindent \z@ + \parfillskip\@flushglue + \parskip \z@skip + \@@par + \def\par{\leavevmode\null\@@par\pagebreak[1]}% + \everypar\expandafter{\the\everypar \unpenalty + \everbatimeverypar + \everypar \expandafter{\the\everypar\everbatimeverypar}% + }% + \obeylines \@vobeyspaces +} + +\begingroup +\lccode`X 13 +\catcode`X \active +\lccode`Y `* % this is because of \makestarlowast. +% I have to think whether this is useful: obviously if I were to provide +% everbatim and everbatim* in a package I wouldn't do that. +\catcode`Y \active +\catcode`| 0 \catcode`[ 1 \catcode`] 2 \catcode`* 12 +\catcode`{ 12 \catcode`} 12 |catcode`\\ 12 +|lowercase[|endgroup% both freezes catcodes and converts X to active ^^M +|def|@everbatim #1X#2\end{everbatim}% + [#2|end[everbatim]|everbatimbottom ] +|def|@everbatimx #1#2X#3\end{everbatimY}]% + {#3\end{everbatim*}% + \everbatimbottom + \newlinechar 13 +% execution as LaTeX code of contents + \everbatimxprehook + \scantokens {#3}% + \newlinechar #1\relax + \everbatimxposthook +}% + +% L'espace venant du endofline final mis par \scantokens sera inhibé si #3 se +% termine par un % ou un \x, etc... + +\let\everbatimxfgcolorcmd\empty +\def\everbatimxprehook {\colorlet{everbsavedcolor}{.}% + \everbatimxfgcolorcmd + \smallskip % pour polexpr-examples.tex + % à cause de problèmes avec les + % output en "display" + }% + +\def\everbatimxposthook {\color{everbsavedcolor}} + + +\catcode`_ 8 +\makeatother + +\newcommand\pkg[2][]{\if\relax\detokenize{#1}\relax + \href{https://www.ctan.org/pkg/#2}{#2}% + \else + \href{https://www.ctan.org/pkg/#1}{#2}% + \fi + } + +% Colors for \verb and everbatim +% \MacroFont and \MicroFont +% font size in verbatim blocks + +% \verb +%\colorlet{verbcolor}{DarkCyan} +\colorlet{verbcolor}{black} +\colorlet{verbsoftwrapiconcolor}{DarkBlue} +\def\MicroFont{\ttfamily%\color{verbcolor} + \makestarlowast\makequotesstraight}% + +% everbatim/everbatim* +\def\everbatimtop{\MacroFont\small} +% the \small is not in \MacroFont in case of a document with macrocode (doc.sty) +% and some customization is desired +%\colorlet{everbatimfgcolor}{Olive} +\colorlet{everbatimfgcolor}{DarkBlue} +\def\MacroFont{\ttfamily\color{everbatimfgcolor}} + +%\colorlet{everbatimbgcolor}{WhiteSmoke} +\colorlet{everbatimbgcolor}{Ivory} +\def\everbatimbgcolorcmd{\color{everbatimbgcolor}} + +%\colorlet{everbatimxfgcolor}{MidnightBlue} +\colorlet{everbatimxfgcolor}{OliveDrab} +\def\everbatimxfgcolorcmd{\color{everbatimxfgcolor}} + +% Notice that \macrocode uses \macro@font which stores the \MacroFont meaning +% in force at \begin{document}. But doc.sty's verbatim uses current \MacroFont +% not the meaning at \begin{document}. Comprenne qui pourra... + +\begin{document} +\maketitle + + +The package provides a parser |\poldef| of algebraic polynomial +expressions. + +Once defined, a polynomial is usable by its name either as a numerical +function in |\xintexpr/\xinteval|, or for additional polynomial +definitions, or as argument to the package macros. + +% The localization of +% real roots to arbitrary precision as well as the determination of all +% rational roots is implemented via such macros. + +% Since release |0.8|, polexpr extends the \pkg{xintexpr} +% syntax to recognize +% polynomials as a new variable type (and not only as functions). +% Functionality which previously was implemented via macros such as the +% computation of a greatest common divisor is now available directly in +% |\xintexpr|, |\xinteval| or |\poldef| via infix or functional +% syntax. + +This document illustrates root localization via usage of macros such as +|\PolToSturm| and |\PolSturmIsolateZeros| which implement the +\href{https://en.wikipedia.org/wiki/Sturm%27s_theorem}{Sturm theorem}: +\begin{itemize} +\item Root localization based on + \href{https://en.wikipedia.org/wiki/Sturm%27s_theorem}{Sturm theorem} was + added at release |0.4| (2018/02/16). +\item Ability to find all rational roots was added at release |0.7.2| + (2018/12/09). +\end{itemize} +As of |0.8| (2021/03/29), \pkg{polexpr} is usable with Plain \TeX\ and not +only with \LaTeX. The examples here use most of the time a syntax which works +with both. + +Copying-pasting from |pdf| the example source may lose formatting. +Formerly, they were included verbatim in the |html| documentation. Here +they are both rendered verbatim and got executed during the \LaTeX\ run +which created this |pdf| file, with the output shown after the source code. + +% Perhaps future releases will implement other approaches, which are known +% to be generically computationally more efficient, at least in high +% degrees, than the \href{https://en.wikipedia.org/wiki/Sturm%27s_theorem}{Sturm theorem} based approach. This is not +% immediate priority though (perhaps support of multivariate polynomials +% would be more important feature; or localization of complex roots). + +Regarding how polynomial coefficients are printed on the typeset page by +|\PolTypeset|: +\begin{itemize}\def\everbatimtop {\MacroFont}% sans le \small +\item The default for |\PolTypesetOne| is to use |\xintTeXsignedFrac| with + \LaTeX, |\xintTeXsignedOver| with Plain. See the \pkg{xintexpr} + documentation for a description of what these macros do. A sensible + definition is: +\begin{everbatim} + \def\PolTypesetOne#1{\PolDecToString{\xintREZ{#1}}}% +\end{everbatim} +% le \smallskip est ennuyeux ici + It means to use decimal notation, with perhaps a trailing denominator if the + argument is a fraction, and will suppress trailing zeros after the decimal + mark. + +\item + As these are expandable macros, they are usable to redefine + |\PolToExprCmd| as well: +\begin{everbatim} + \def\PolToExprCmd#1{\PolDecToString{\xintREZ{#1}}}% +\end{everbatim} +% le \smallskip est ennuyeux ici + This will customize the output of |\PolToExpr| (which a priori is + destined for writes to external files but may also be used on the typeset + page). +\end{itemize} + +With |\xintverbosetrue| in the \TeX\ source extra information relative +to the internal data manipulated by the macros will be written to the |.log| +file. + +\begin{framed} + Package macros related to root localization create (user-level) new + polynomials, or numeric variables, via a naming scheme using the given + || as prefix. It is thus advisable to keep this + || name-space separate from the one used to name polynomial or + scalar variables. +\end{framed} + +\begin{framed} + Regrettably all examples here use the condemnable |\PolToSturm{f}{f}| + practice which means that internally defined polynomials will use as prefix + the original polynomial name. This merge of namespaces may cause + overwriting previously defined data and may lead to hard-to-debug problems. +\end{framed} + + +\section{A first example} + + +In this example the polynomial is square-free. +\begin{everbatim*} + \poldef f(x) := x^7 - x^6 - 2x + 1; + + \PolToSturm{f}{f} + \PolSturmIsolateZeros{f} + The \PolTypeset{f} polynomial has \PolSturmNbOfIsolatedZeros{f} distinct real + roots which are located in the following intervals: + \PolPrintIntervals{f} +\end{everbatim*} + +\begin{everbatim*} + Here is the second root with ten more decimal digits: + \PolRefineInterval[10]{f}{2} + $$\PolSturmIsolatedZeroLeft{f}{2}}| which would find exactly +the roots. The steps here retain their interest when one is interested +in finding isolating intervals for example to prepare some demonstration +of dichotomy method. + + +\begin{everbatim*} + \PolDef{Q}{(x-1.050001)(x-1.105001)(x-1.110501)(x-1.111051)} + \PolTypeset{Q} + \PolToSturm{Q}{Q} % it is allowed to use same prefix for Sturm chain + \PolSturmIsolateZeros{Q} + \PolPrintIntervals{Q} +\end{everbatim*} + +\begin{everbatim*} + \PolRefineInterval*{Q}{1} + \PolRefineInterval*{Q}{2} + \PolRefineInterval*{Q}{3} + \PolRefineInterval*{Q}{4} + \PolPrintIntervals{Q} +\end{everbatim*} + +\begin{everbatim*} + \PolEnsureIntervalLengths{Q}{-6} + \PolPrintIntervals{Q} + % finds here all roots exactly +\end{everbatim*} + +\section{The degree nine polynomial with 0.99, 0.999, 0.9999 as triple roots} + +Define a user command (\pkg[xint]{xinttools} is loaded automatically by +\pkg{polexpr}): + +\begin{everbatim*} + \def\showmultiplicities#1{% #1 = "sturmname" + \xintFor* ##1 in {\xintSeq{1}{\PolSturmNbOfIsolatedZeros{#1}}}\do{% + The multiplicity is \PolSturmIsolatedZeroMultiplicity{#1}{##1} + \PolSturmIfZeroExactlyKnown{#1}{##1}% + {at the root $x=\PolSturmIsolatedZeroLeft{#1}{##1}$} + {for the root such that + $\PolSturmIsolatedZeroLeft{#1}{##1}\PolPrintIntervalsTheVar_{\PolPrintIntervalsTheIndex}>% + \PolPrintIntervalsPrintLeftEndPoint}% + {\impossibleA}}% + {\xintifSgn{\PolPrintIntervalsTheRightEndPoint} + {\impossibleB}% + {\impossibleC}% + {0<\PolPrintIntervalsTheVar_{\PolPrintIntervalsTheIndex}<% + \PolPrintIntervalsPrintRightEndPoint}}% + {\xintifSgn{\PolPrintIntervalsTheRightEndPoint} + {\impossibleD}% + {\impossibleE}% + {\PolPrintIntervalsTheVar_{\PolPrintIntervalsTheIndex}=% + \PolPrintIntervalsPrintLeftEndPoint\dots}}% + $ +}% +\PolPrintIntervals{T_15} +\end{everbatim*} +\end{document} + diff --git a/macros/generic/polexpr/polexpr.html b/macros/generic/polexpr/polexpr.html index 9b6f99138d..5f695deb4b 100644 --- a/macros/generic/polexpr/polexpr.html +++ b/macros/generic/polexpr/polexpr.html @@ -3,7 +3,7 @@ -Package polexpr documentation +polexpr reference documentation -
-

Package polexpr documentation

-

0.8.5 (2021/11/30)

- +
+

polexpr reference documentation

+

0.8.6 (2022/01/09)

+ +
+

Introduction

+

This is a TeX and LaTeX macro package.

+

To use it with Plain or formats other than LaTeX:

+
\input polexpr.sty
+

To use it with LaTeX:

+
\usepackage{polexpr}
+

The capabilities of the package are implemented via:

+
    +
  • a parser \poldef allowing to define polynomials via the usual +algebraic notations,

  • +
  • many functions available for use directly in the powerful \poldef or +\xintexpr/\xinteval expandable functional syntax,

  • +
  • and macros acting on named polynomials which may serve either as +alternative to the functional interface or to provide further +capabilities, such as root localization to arbitrary precision.

  • +
+
+
+

Examples of root localization

+

This legacy section has been moved to the +polexpr-examples.pdf document. +To access it (if previous link does not work):

+
texdoc polexpr-examples
+
+
+

Usage via xintsession

+

The simplest manner to get a feeling for the package abilities regarding +root localization is to use it on the command line via the xintsession +interface. Here is an example:

+
$ rlwrap etex xintsession
+[...xintsession welcome message...]
+Starting in exact mode (floating point evaluations use 16 digits)
+>>> &pol
+pol mode (i.e. function definitions use \poldef)
+>>> f(x) := x^7 - x^6 - 2x + 1;
+f = x^7-x^6-2*x+1
+    --> &GenFloat(f) lets f become usable as function in fp mode
+    --> &ROOTS(f) (resp. &ROOTS(f,N)) finds all rational roots exactly and
+        all irrational roots with at least 10 (resp. N) fractional digits
+>>> &ROOTS(f)
+Solving for real roots of f and assigning them (please wait...)
+(mult. 1) Rootf_1 = -1.0719678841...
+(mult. 1) Rootf_2 = 0.4962386948...
+(mult. 1) Rootf_3 = 1.3151140860...
+Square-free irrational part: x^7-x^6-2*x+1
+    --> &REFINEROOTS(f,N) to extend real irr. roots to N fractional digits
+>>> &REFINEROOTS(f,40)
+Refining real roots of f to 40 digits (please wait...)
+(mult. 1) Rootf_1 = -1.0719678841080266034109100331975342338141...
+(mult. 1) Rootf_2 = 0.4962386948771497344730618510143671567979...
+(mult. 1) Rootf_3 = 1.3151140860165192656960005018679846354234...
+

The xintsession interface allows to define polynomial variables via its +&pol mode. It also exposes all polynomial functions added to the +xintexpr syntax by polexpr. Further, as seen in the +example above it also covers some of the polexpr capabilities +currently implemented via user macros. This is to be considered a work +in progress, the above &ROOTS and &REFINEROOTS may be renamed +into something else, and may have been so already since this +documentation was written.

+

Any input on the command line at the xintsession >>> prompt which +starts with a backslash is executed as TeX macros, so all macros of +polexpr are in fact already available, including those typesetting +material in background of the interactive session on command line. The +&ROOTS and &REFINEROOTS direct their outputs to the +terminal rather than to the TeX page as would the typesetting macros +defined by polexpr itself.

Contents

- -
  • Expandable macros

    +
  • \PolPrintIntervalsPrintMultiplicity

  • + + +
  • \PolSetToSturmChainSignChangesAt{\foo}{<sturmname>}{<value>}

  • +
  • \PolSetToNbOfZerosWithin{\foo}{<sturmname>}{<value_left>}{<value_right>}

  • + + +
  • \PolLet{<polname_2>}={<polname_1>}

  • +
  • \PolGlobalLet{<polname_2>}={<polname_1>}

  • +
  • \PolAssign{<polname>}\toarray\macro

  • +
  • \PolGet{<polname>}\fromarray\macro

  • +
  • \PolFromCSV{<polname>}{<csv>}

  • +
  • \PolMapCoeffs{\macro}{<polname>}

  • +
  • \PolReduceCoeffs{<polname>}

  • +
  • \PolReduceCoeffs*{<polname>}

  • +
  • \PolMakeMonic{<polname>}

  • +
  • \PolMakePrimitive{<polname>}

  • +
  • \PolDiff{<polname_1>}{<polname_2>}

  • +
  • \PolDiff[N]{<polname_1>}{<polname_2>}

  • +
  • \PolAntiDiff{<polname_1>}{<polname_2>}

  • +
  • \PolAntiDiff[N]{<polname_1>}{<polname_2>}

  • +
  • \PolDivide{<polname_1>}{<polname_2>}{<polname_Q>}{<polname_R>}

  • +
  • \PolQuo{<polname_1>}{<polname_2>}{<polname_Q>}

  • +
  • \PolRem{<polname_1>}{<polname_2>}{<polname_R>}

  • +
  • \PolGCD{<polname_1>}{<polname_2>}{<polname_GCD>}

  • + + +
  • Expandable macros

    +
  • +
  • \PolToFloatExpr{<pol. expr.>}

    -
  • -
  • \PolToExpr*{<pol. expr.>}

  • -
  • \PolToFloatExpr*{<pol. expr.>}

  • -
  • \PolNthCoeff{<polname>}{<index>}

  • -
  • \PolLeadingCoeff{<polname>}

  • -
  • \PolDegree{<polname>}

  • -
  • \PolIContent{<polname>}

  • -
  • \PolToList{<polname>}

  • -
  • \PolToCSV{<polname>}

  • -
  • \PolEval{<polname>}\AtExpr{<num. expr.>}

  • -
  • \PolEval{<polname>}\At{<value>}

  • -
  • \PolEvalReduced{<polname>}\AtExpr{<num. expr.>}

  • -
  • \PolEvalReduced{<polname>}\At{<value>}

  • -
  • \PolFloatEval{<polname>}\AtExpr{<num. expr.>}

  • -
  • \PolFloatEval{<polname>}\At{<value>}

  • -
  • Expandable macros related to the root localization routines

    +
  • \PolToFloatExprOneTerm{<raw_coeff>}{<exponent>}

  • +
  • \PolToFloatExprCmd{<raw_coeff>}

  • + + +
  • \PolToExpr*{<pol. expr.>}

  • +
  • \PolToFloatExpr*{<pol. expr.>}

  • +
  • \PolNthCoeff{<polname>}{<index>}

  • +
  • \PolLeadingCoeff{<polname>}

  • +
  • \PolDegree{<polname>}

  • +
  • \PolIContent{<polname>}

  • +
  • \PolToList{<polname>}

  • +
  • \PolToCSV{<polname>}

  • +
  • \PolEval{<polname>}\AtExpr{<num. expr.>}

  • +
  • \PolEval{<polname>}\At{<value>}

  • +
  • \PolEvalReduced{<polname>}\AtExpr{<num. expr.>}

  • +
  • \PolEvalReduced{<polname>}\At{<value>}

  • +
  • \PolFloatEval{<polname>}\AtExpr{<num. expr.>}

  • +
  • \PolFloatEval{<polname>}\At{<value>}

  • +
  • Expandable macros related to the root localization routines

    -
  • - - -
  • Booleans (with default setting as indicated)

    +
  • \PolSturmChainLength{<sturmname>}

  • +
  • \PolSturmIfZeroExactlyKnown{<sturmname>}{<index>}{T}{F}

  • +
  • \PolSturmIsolatedZeroLeft{<sturmname>}{<index>}

  • +
  • \PolSturmIsolatedZeroRight{<sturmname>}{<index>}

  • +
  • \PolSturmIsolatedZeroMultiplicity{<sturmname>}{<index>}

  • +
  • \PolSturmNbOfIsolatedZeros{<sturmname>}

  • +
  • \PolSturmNbOfRootsOf{<sturmname>}\LessThanOrEqualTo{<value>}

  • +
  • \PolSturmNbOfRootsOf{<sturmname>}\LessThanOrEqualToExpr{<num. expr.>}

  • +
  • \PolSturmNbWithMultOfRootsOf{<sturmname>}\LessThanOrEqualTo{<value>}

  • +
  • \PolSturmNbWithMultOfRootsOf{<sturmname>}\LessThanOrEqualToExpr{<num. expr.>}

  • +
  • \PolSturmNbOfRationalRoots{<sturmname>}

  • +
  • \PolSturmNbOfRationalRootsWithMultiplicities{<sturmname>}

  • +
  • \PolSturmRationalRoot{<sturmname>}{<k>}

  • +
  • \PolSturmRationalRootIndex{<sturmname>}{<k>}

  • +
  • \PolSturmRationalRootMultiplicity{<sturmname>}{<k>}

  • +
  • \PolIntervalWidth{<sturmname>}{<index>}

  • +
  • Expandable macros for use within execution of \PolPrintIntervals

  • +
  • \PolPrintIntervalsTheVar

  • +
  • \PolPrintIntervalsTheIndex

  • +
  • \PolPrintIntervalsTheSturmName

  • +
  • \PolPrintIntervalsTheLeftEndPoint

  • +
  • \PolPrintIntervalsTheRightEndPoint

  • +
  • \PolPrintIntervalsTheMultiplicity

  • + + + + +
  • Booleans (with default setting as indicated)

  • -
  • Utilies

    +
  • Utilies

  • -
  • Technicalities

  • -
  • CHANGE LOG

  • -
  • Acknowledgments

  • +
  • Technicalities

  • +
  • CHANGE LOG

  • +
  • Acknowledgments

  • -
    -

    Usage

    -

    The package can be used with TeX based formats incorporating the e-TeX -primitives. The \expanded primitive available generally since -TeXLive 2019 is required.

    -
    \input polexpr.sty
    -

    with Plain or other non-LaTeX macro formats, or:

    -
    \usepackage{polexpr}
    -

    with the LaTeX macro format.

    -

    The package requires xintexpr 1.4d or later.

    -
    -

    Note

    -

    Until 0.8 the package only had a LaTeX interface. As a result, -parts of this documentation may still give examples using LaTeX syntax such -as \newcommand. Please convert to the syntax appropriate to the -TeX macro format used if needed.

    -
    -
    -
    -

    Abstract

    -

    The package provides a parser \poldef of algebraic polynomial -expressions. As it is based on xintexpr -the coefficients are allowed to be arbitrary rational numbers.

    -

    Once defined, a polynomial is usable by its name either as a numerical -function in \xintexpr/\xinteval, or for additional polynomial -definitions, or as argument to the package macros. The localization of -real roots to arbitrary precision as well as the determination of all -rational roots is implemented via such macros.

    -

    Since release 0.8, polexpr extends the xintexpr -syntax to recognize -polynomials as a new variable type (and not only as functions). -Functionality which previously was implemented via macros such as the -computation of a greatest common divisor is now available directly in -\xintexpr, \xinteval or \poldef via infix or functional -syntax.

    -
    -
    -

    Prerequisites

    -
      -
    • The user must have some understanding of TeX as a macro-expansion -based programming interface, and in particular of how \edef -differs from \def: functionalities of the package as described in -the Expandable macros section are suitable for usage in \edef, -\write or \xinteval context. At 0.8 some of these -macros have an even more convenient functional interface inside -\xinteval, as is described in a dedicated section.

      -

      Despite its name \poldef is more to be seen as an \edef -although it does not define a TeX macro (at user level); and of course -\edef would do usually nothing on the typical input parsed by -\poldef which generally has no backslash in it: but if this input -does contain macros, they will then be expanded fully and are supposed to -produce recognizable syntax elements in this expansion only context.

      -

      Note that the def in \poldef reminds us that the macro does -some assignments hence is not usable in expandable only context. Its -whole point is rather to define entities which, them, can then be used -in the expandable only \xinteval (or \poldef) context.

      -
    • -
    • The user must have some familiarity with xintexpr and in -particular must know what \xintexpr, \xinttheexpr, -\xinteval and \xintfloatexpr, \xintthefloatexpr, -\xintfloateval mean and what are the good practices with them.

    • -
    • The user will become quickly aware that exact computations with -fractions easily lead to very big ones in very few steps; see -\PolReduceCoeffs{<polname>} in this context.

    • -
    • Finally, it is mandatory to read the entire documentation before -starting to use the package.

    • -

    Quick syntax overview

    The syntax to define a new polynomial is:

    \poldef polname(x):= expression in variable x;

    The package is focused on exact computations, so this expression will be -parsed by the services of xintexpr and accept arbitrarily big integers +parsed by the services of xintexpr and accept arbitrarily big integers or fractions.

    If you are interested into numerical evaluations, for example for plotting, it is advisable to use the \xintfloatexpr/\xintfloateval context, as exact evaluations will quickly lead to manipulating numbers with dozens of digits (when the number of digits exceeds five hundreds, -computation with xintexpr will become noticeably too slow, if many +computation with xintexpr will become noticeably too slow, if many evaluations need to be done). For the polynomial to be usable as a function in floating point context, an extra step beyond \poldef is required: see \PolGenFloatVariant.

    @@ -910,7 +898,7 @@ function, are only available in the \PolGenFloatVariant must be used each time the polynomial gets modified or a new polynomial created out of it, if continuing computations in \xintfloatexpr are to follow. But (see -xintexpr documentation) one can always use a sub-expression such as +xintexpr documentation) one can always use a sub-expression such as \xintexpr deg(P)\relax as sub-component inside a \xintfloatexpr/\xintfloateval.

    Conversely if perhaps the coefficients of your polynomial have become @@ -950,10 +938,10 @@ naturally no problem either if \poldef is text of some other macro which is defined at a time the ; has its standard catcode, as is the case in LaTeX in the document preamble, even with babel+french loaded.

    -

    The semi-colon intervenes in certain xintexpr syntax elements, within +

    The semi-colon intervenes in certain xintexpr syntax elements, within parentheses. This (except if the inner semi-colons are hidden within braces: {;}) will break \poldef which, contrarily to -xintexpr's \xintdefvar, does not balance parentheses when +xintexpr's \xintdefvar, does not balance parentheses when fetching the semi-colon delimited polynomial expression.

    @@ -1000,7 +988,7 @@ But then it gives zero!

    (1/2)*x^2 for disambiguation: x - 1/2*x^2 + 1/3*x^3.... It is simpler to move the denominator to the right: x - x^2/2 + x^3/3 - ....

    It is worth noting that 1/2(x-1)(x-2) suffers the same issue: -xintexpr's tacit multiplication always "ties more", hence this +xintexpr's tacit multiplication always "ties more", hence this gets interpreted as 1/(2*(x-1)*(x-2)) which gives zero by polynomial division. Thus, use in such cases one of (1/2)(x-1)(x-2), 1/2*(x-1)(x-2) or (x-1)(x-2)/2.

    @@ -1042,10 +1030,10 @@ polynomials.

    as a function, but only as a variable of polynomial type. Even worse:

    (P)(3)%  <--- attention!
    -

    will compute P*3, because one can not in current xintexpr syntax +

    will compute P*3, because one can not in current xintexpr syntax enclose a function name in parentheses: consequently it is the variable which is used here. There is a meager possibility that in future -some internal changes to xintexpr would let (P)(3) actually +some internal changes to xintexpr would let (P)(3) actually compute P(3) and (P+Q)(3) compute P(3) + Q(3), but note that (P)(P) will then do P(P) and not P*P, the latter, current interpretation, looking more @@ -1248,10 +1236,10 @@ about behaviour with pol2 a scalar.

    Comparison operators <, >, <=, >=, ==, !=

    NOT YET IMPLEMENTED

    -

    As the internal representation by xintfrac and xintexpr of +

    As the internal representation by xintfrac and xintexpr of fractions does not currently require them to be in reduced terms, such operations would be a bit costly as they could not benefit from -the \pdfstrcmp engine primitive. In fact xintexpr does not use +the \pdfstrcmp engine primitive. In fact xintexpr does not use it yet anywhere, even for normalized pure integers, although it could speed up signifcantly certain aspects of core arithmetic.

    Equality of polynomials can currently be tested by computing the @@ -1348,7 +1336,7 @@ required:

    If the first argument is an already declared polynomial P, use rather the functional form P() (which can accept a numerical as well as polynomial argument) as it is more efficient.

    -

    One can also use subs() syntax 2 (see xintexpr documentation):

    +

    One can also use subs() syntax 2 (see xintexpr documentation):

    \poldef K(x):= subs(-3y^3-5y+1, y = -27x^4+5x-2);

    but the evalp() will use a Horner evaluation scheme which is usually more efficient.

    @@ -1356,7 +1344,7 @@ usually more efficient.

    2

    by the way Maple uses the opposite, hence wrong, order subs(x=..., P) but was written before computer science -reached the xintexpr heights. However it makes validating +reached the xintexpr heights. However it makes validating Maple results by polexpr sometimes cumbersome, but perhaps they will update it at some point.

    @@ -1395,7 +1383,7 @@ polynomial...).

    name unstable

    I am considering in particular using polcoeffs() to avoid having to overload coeffs() in future when matrix type -will be added to xintexpr.

    +will be added to xintexpr.

    @@ -1416,7 +1404,7 @@ higher than the degree.

    name, syntax and output unstable

    I am hesitating with coeff(n,pol) syntax and also perhaps using polcoeff() in order to avoid having to overload coeff() -when matrix type will be added to xintexpr.

    +when matrix type will be added to xintexpr.

    The current behaviour is at odds with legacy \PolNthCoeff{<polname>}{<index>} regarding negative indices. Accessing leading or sub-leading coefficients can be done with @@ -1431,7 +1419,7 @@ negative indices do vanish, so I am for time being maintaining this.

    The leading coefficient. The same result can be obtained from coeffs(pol)[-1], which shows also how to generalize to access -sub-leading coefficients. See the xintexpr documentation for +sub-leading coefficients. See the xintexpr documentation for Python-like indexing syntax.

    @@ -1443,7 +1431,7 @@ Python-like indexing syntax.

    unstable

    Currently the coefficients are reduced to lowest terms (contrarily to legacy behaviour of \PolMakeMonic), and -additionally the xintfrac \xintREZ macro is applied which +additionally the xintfrac \xintREZ macro is applied which extracts powers of ten from numerator or denominator and stores them internally separately. This is generally beneficial to efficiency of multiplication.

    @@ -1538,7 +1526,7 @@ coefficients polynomials.

    subs(last(x)/first(x),x=prem(P,Q)) syntax as it avoids computing prem(P,Q) twice. This does the trick both in \poldef or in \xintdefvar.

    -

    However, as is explained in the xintexpr documentation, using +

    However, as is explained in the xintexpr documentation, using such syntax in an \xintdeffunc is (a.t.t.o.w) illusory, due to technicalities of how subs() gets converted into nested expandable macros. One needs an auxiliary function like this:

    @@ -1593,7 +1581,7 @@ inputs vanish.

    alternatively, only one argument which then must be a bracketed list or some expression or variable evaluating to such a "nutple" whose items are polynomials (see the documentation of the scalar gcd() -in xintexpr).

    +in xintexpr).

    The two variable case could (and was, during development) have been defined at user level like this:

    @@ -1656,7 +1644,7 @@ experimental status is as follows:

    This is currently implemented at high level via \xintdeffunc and recursive definitions, which were copied over from a scalar example -in the xintexpr manual:

    +in the xintexpr manual:

    \xintdeffunc polpowmod_(P, m, Q) :=
            isone(m)?
                % m=1: return P modulo Q
    @@ -1759,10 +1747,13 @@ maintaining this feature whose interest appears dubious.

    integral(<pol. expr. P>, [<pol. expr. a>, <pol. expr. b>])

    \int_a^b P(t)dt.

    +
    +

    Warning

    The brackets here are not denoting an optional argument but a mandatory nutple argument [a, b] with two items.

    -

    a and b are not restricted to be scalars, they can be -polynomials.

    +
    +

    a and b are not restricted to be scalars, they are allowed to +be themselves polynomial variables or even polynomial expressions.

    To compute \int_{x-1}^x P(t)dt it is more efficient to use intfrom(x-1).

    @@ -1774,431 +1765,16 @@ overhead to the pure scalar case ?

    -
    -

    Examples of localization of roots

    -
    -

    Note

    -

    As of 0.8, polexpr is usable with Plain TeX and not only with -LaTeX, the examples of this section have been converted to use a -syntax which (at least at time of writing, March 2021) works in both.

    -

    This is done in order for the examples to be easy to copy-paste to -documents using either macro format.

    -
    -

    This (slightly over-extended) section gives various examples of usage of -the package macros such as \PolToSturm, \PolSturmIsolateZeros -and \PolPrintIntervals for root localization, which exist since -release 0.4 (2018/02/16). The capacity to find all rational roots -exactly was added at 0.7.2 (2018/12/09).

    -

    The examples demonstrate that the package can find all real roots to -arbitrary precision, find the multiplicities of real roots, and find -exactly all rational roots.

    -

    Perhaps future releases will implement other approaches, which are known -to be generically computationally more efficient, at least in high -degrees, than the Sturm theorem based approach. This is not -immediate priority though (perhaps support of multivariate polynomials -would be more important feature; or localization of complex roots).

    -
      -
    • To make printed decimal numbers more enjoyable than via -\xintTeXsignedFrac (or \xintTeXsignedOver with Plain):

      -
      \def\PolTypesetOne#1{\PolDecToString{\xintREZ{#1}}}%
      -

      \PolDecToString will use decimal notation to incorporate the power -of ten part; and the \xintREZ will have the effect to suppress -trailing zeros if present in raw numerator (if those digits end up -after decimal mark.) Notice that the above are expandable macros and -that one can also do:

      -
      \def\PolToExprCmd#1{\PolDecToString{\xintREZ{#1}}}%
      -

      to modify output of \PolToExpr{<pol. expr.>}.

      -
    • -
    • For extra info in log file use \xintverbosetrue.

    • -
    -
    -

    Warning

    -

    Package macros related to root localization create (user-level) new -polynomials, or numeric variables, via a naming scheme which -postfixes a root name <sturmname> in various ways (see -\PolToSturm{<polname>}{<sturmname>} and -\PolSturmIsolateZeros{<sturmname>}). It is thus advisable to -keep the <sturmname> name-space separate from the one used to -name polynomial or scalar variables.

    -

    Regrettably all examples here use the condemnable -\PolToSturm{f}{f} practice which fuses the name-spaces. This can -lead to problems if one is not aware of the consequances.

    -
    -
    -

    A typical example

    -

    In this example the polynomial is square-free.

    -
    \poldef f(x) := x^7 - x^6 - 2x + 1;
    -
    -\PolToSturm{f}{f}
    -\PolSturmIsolateZeros{f}
    -The \PolTypeset{f} polynomial has \PolSturmNbOfIsolatedZeros{f} distinct real
    -roots which are located in the following intervals:
    -\PolPrintIntervals{f}
    -Here is the second root with ten more decimal digits:
    -\PolRefineInterval[10]{f}{2}
    -$$\PolSturmIsolatedZeroLeft{f}{2}<Z_2<\PolSturmIsolatedZeroRight{f}{2}$$
    -And here is the first root with twenty digits after decimal mark:
    -\PolEnsureIntervalLength{f}{1}{-20}
    -$$\PolSturmIsolatedZeroLeft{f}{1}<Z_1<\PolSturmIsolatedZeroRight{f}{1}$$
    -The first element of the Sturm chain has degree $\PolDegree{f_0}$. As
    -this is the original degreee $\PolDegree{f}$ we know that $f$ is square free.
    -Its derivative is up to a constant \PolTypeset{f_1} (in this example
    -it is identical with it).
    -\PolToSturm{f_1}{f_1}\PolSturmIsolateZeros{f_1}%
    -The derivative has \PolSturmNbOfIsolatedZeros{f_1} distinct real
    -roots:
    -\PolPrintIntervals[W]{f_1}
    -\PolEnsureIntervalLengths{f_1}{-10}%
    -Here they are with ten digits after decimal mark:
    -\PolPrintIntervals[W]{f_1}
    -\PolDiff{f_1}{f''}
    -\PolToSturm{f''}{f''}
    -\PolSturmIsolateZeros{f''}
    -The second derivative is \PolTypeset{f''}.
    -It has \PolSturmNbOfIsolatedZeros{f''} distinct real
    -roots:
    -\PolPrintIntervals[X]{f''}
    -Here is the positive one with 20 digits after decimal mark:
    -\PolEnsureIntervalLength{f''}{2}{-20}%
    -$$X_2 = \PolSturmIsolatedZeroLeft{f''}{2}\dots$$
    -The more mathematically advanced among our dear readers will be able
    -to give the exact value for $X_2$!
    -
    -
    -

    A degree four polynomial with nearby roots

    -

    Notice that this example is a bit outdated as 0.7 release has -added \PolSturmIsolateZeros**{<sturmname>} which would find exactly -the roots. The steps here retain their interest when one is interested -in finding isolating intervals for example to prepare some demonstration -of dichotomy method.

    -
    \PolDef{Q}{(x-1.050001)(x-1.105001)(x-1.110501)(x-1.111051)}
    -\PolTypeset{Q}
    -\PolToSturm{Q}{Q} % it is allowed to use same prefix for Sturm chain
    -\PolSturmIsolateZeros{Q}
    -\PolPrintIntervals{Q}
    -% reports 1.0 < Z_1 < 1.1, 1.10 < Z_2 < 1.11, 1.110 < Z_3 < 1.111, and 1.111 < Z_4 < 1.112
    -% but the above bounds do not allow minimizing separation between roots
    -% so we refine:
    -\PolRefineInterval*{Q}{1}
    -\PolRefineInterval*{Q}{2}
    -\PolRefineInterval*{Q}{3}
    -\PolRefineInterval*{Q}{4}
    -\PolPrintIntervals{Q}
    -% reports 1.05 < Z_1 < 1.06, 1.105 < Z_2 < 1.106, 1.1105 < Z_3 < 1.1106,
    -% and 1.11105 < Z_4 < 1.11106.
    -\PolEnsureIntervalLengths{Q}{-6}
    -\PolPrintIntervals{Q}
    -% of course finds here all roots exactly
    -
    -
    -

    The degree nine polynomial with 0.99, 0.999, 0.9999 as triple roots

    -
    % define a user command (xinttools is loaded automatically by polexpr)
    -\def\showmultiplicities#1{% #1 = "sturmname"
    -\xintFor* ##1 in {\xintSeq{1}{\PolSturmNbOfIsolatedZeros{#1}}}\do{%
    -    The multiplicity is \PolSturmIsolatedZeroMultiplicity{#1}{##1}
    -    \PolSturmIfZeroExactlyKnown{#1}{##1}%
    -    {at the root $x=\PolSturmIsolatedZeroLeft{#1}{##1}$}
    -    {for the root such that
    -    $\PolSturmIsolatedZeroLeft{#1}{##1}<x<\PolSturmIsolatedZeroRight{#1}{##1}$}
    -    \par
    -}}%
    -\PolDef{f}{(x-0.99)^3(x-0.999)^3(x-0.9999)^3}
    -\def\PolTypesetOne#1{\PolDecToString{\xintREZ{#1}}}
    -\PolTypeset{f}\par
    -\PolToSturm{f}{f}% it is allowed to use "polname" as "sturmname" too
    -\PolSturmIsolateZerosAndGetMultiplicities{f}% use the "sturmname" here
    -% or \PolSturmIsolateZeros*{f} which is exactly the same, but shorter..
    -
    -\showmultiplicities{f}
    -

    In this example, the output will look like this (but using math mode):

    -
    x^9 - 8.9667x^8 + 35.73400293x^7 - 83.070418400109x^6 + 124.143648875193123x^5
    -- 123.683070924326075877x^4 + 82.149260397553075617891x^3
    -- 35.07602992699900159127007x^2 + 8.7364078733314648368671733x
    -- 0.967100824643585986488103299
    -
    -The multiplicity is 3 at the root x = 0.99
    -The multiplicity is 3 at the root x = 0.999
    -The multiplicity is 3 at the root x = 0.9999
    -

    On first pass, these rational roots were found (due to their relative -magnitudes, using \PolSturmIsolateZeros** was not needed here). But -multiplicity computation works also with (decimal) roots not yet -identified or with non-decimal or irrational roots.

    -

    It is fun to modify only a tiny bit the polynomial and see if polexpr -survives:

    -
    \PolDef{g}{f(x)+1e-27}
    -\PolTypeset{g}\par
    -\PolToSturm{g}{g}
    -\PolSturmIsolateZeros*{g}
    -
    -\showmultiplicities{g}
    -

    This produces:

    -
    x^9 - 8.9667x^8 + 35.73400293x^7 - 83.070418400109x^6 + 124.143648875193123x^5
    -- 123.683070924326075877x^4 + 82.149260397553075617891x^3
    -- 35.07602992699900159127007x^2 + 8.7364078733314648368671733x
    -- 0.967100824643585986488103298
    -
    -The multiplicity is 1 for the root such that 0.98 < x < 0.99
    -The multiplicity is 1 for the root such that 0.9991 < x < 0.9992
    -The multiplicity is 1 for the root such that 0.9997 < x < 0.9998
    -

    Which means that the multiplicity-3 roots each became a real and a pair of -complex ones. Let's see them better:

    -
    \PolEnsureIntervalLengths{g}{-10}
    -
    -\showmultiplicities{g}
    -

    which produces:

    -
    The multiplicity is 1 for the root such that 0.9899888032 < x < 0.9899888033
    -The multiplicity is 1 for the root such that 0.9991447980 < x < 0.9991447981
    -The multiplicity is 1 for the root such that 0.9997663986 < x < 0.9997663987
    -
    -
    -

    A degree five polynomial with three rational roots

    -
    \poldef Q(x) :=  1581755751184441 x^5
    -               -14907697165025339 x^4
    -               +48415668972339336 x^3
    -               -63952057791306264 x^2
    -               +46833913221154895 x
    -               -49044360626280925;
    -
    -\PolToSturm{Q}{Q}
    -  \def\PolTypesetCmdPrefix#1{\allowbreak\xintiiifSgn{#1}{}{+}{+}}%
    -  $Q_0(x) = \PolTypeset{Q_0}$
    -\PolSturmIsolateZeros**{Q}
    -\PolPrintIntervals{Q}
    -
    -$Q_{norr}(x) = \PolTypeset{Q_norr}$
    -

    Here, all real roots are rational:

    -
    Z_1 = 833719/265381
    -Z_2 = 165707065/52746197
    -Z_3 = 355/113
    -
    -Q_norr(x) = x^2 + 1
    -

    And let's get their decimal expansion too:

    -
    % print decimal expansion of the found roots
    -\def\PolPrintIntervalsPrintExactZero
    -            {\xintTrunc{20}{\PolPrintIntervalsTheLeftEndPoint}\dots}
    -\PolPrintIntervals{Q}
    -
    -Z_1 = 3.14159265358107777120...
    -Z_2 = 3.14159265358979340254...
    -Z_3 = 3.14159292035398230088...
    -
    -
    -

    A Mignotte type polynomial

    -
    \PolDef{P}{x^10 - (10x-1)^2}%
    -\PolTypeset{P}              % prints it in expanded form
    -\PolToSturm{P}{P}           % we can use same prefix for Sturm chain
    -\PolSturmIsolateZeros{P}    % finds 4 real roots
    -This polynomial has \PolSturmNbOfIsolatedZeros{P} distinct real roots:
    -\PolPrintIntervals{P}%
    -% reports  -2 < Z_1 < -1, 0.09 < Z_2 < 0.10, 0.1 < Z_3 < 0.2, 1 < Z_4 < 2
    -Let us refine the second and third intervals to separate the corresponding
    -roots:
    -\PolRefineInterval*{P}{2}% will refine to 0.0999990 < Z_2 < 0.0999991
    -\PolRefineInterval*{P}{3}% will refine to 0.100001 < Z_3 < 0.100002
    -\PolPrintIntervals{P}%
    -Let us now get to know all roots with 10 digits after decimal mark:
    -\PolEnsureIntervalLengths{P}{-10}%
    -\PolPrintIntervals{P}% now all roots are known 10 decimal digits after mark
    -Finally, we display 20 digits of the second root:
    -\PolEnsureIntervalLength{P}{2}{-20}% makes Z_2 known with 20 digits after mark
    -$$\PolSturmIsolatedZeroLeft{P}{2}<Z_2<\PolSturmIsolatedZeroRight{P}{2}$$
    -

    The last line produces:

    -
    0.09999900004999650028 < Z_2 < 0.09999900004999650029
    -
    -
    -

    The Wilkinson polynomial

    -

    See Wilkinson polynomial.

    -
    %\xintverbosetrue % for the curious...
    -
    -\poldef f(x) := mul((x - i), i = 1..20);
    -
    -\def\PolTypesetCmdPrefix#1{\allowbreak\xintiiifSgn{#1}{}{+}{+}}%
    -\def\PolTypesetOne#1{\xintDecToString{#1}}%
    -
    -\noindent\PolTypeset{f}
    -
    -\PolToSturm{f}{f}
    -\PolSturmIsolateZeros{f}
    -\PolPrintIntervals{f}
    -
    -% \vfill\eject
    -
    -% This page is commented out because it takes about 30s on a 2GHz CPU
    -% \poldef g(x) := f(x) - 2**{-23} x**19;
    -
    -% \PolToSturm{g}{g}
    -% \noindent\PolTypeset{g_0}% integer coefficient primitive polynomial
    -
    -% \PolSturmIsolateZeros{g}
    -% \PolEnsureIntervalLengths{g}{-10}
    -
    -% \let\PolPrintIntervalsPrintMultiplicity\empty
    -% \PolPrintIntervals*{g}
    -

    The first polynomial:

    -
    f(x) = x**20
    -- 210 x**19
    -+ 20615 x**18
    -- 1256850 x**17
    -+ 53327946 x**16
    -- 1672280820 x**15
    -+ 40171771630 x**14
    -- 756111184500 x**13
    -+ 11310276995381 x**12
    -- 135585182899530 x**11
    -+ 1307535010540395 x**10
    -- 10142299865511450 x**9
    -+ 63030812099294896 x**8
    -- 311333643161390640 x**7
    -+ 1206647803780373360 x**6
    -- 3599979517947607200 x**5
    -+ 8037811822645051776 x**4
    -- 12870931245150988800 x**3
    -+ 13803759753640704000 x**2
    -- 8752948036761600000 x
    -+ 2432902008176640000
    -

    is handled fast enough, but the modified one f(x) - 2**-23 x**19 takes about 20x longer.

    -

    The Sturm chain polynomials -have integer coefficients with up to 321 digits, whereas (surprisingly -perhaps) those of the Sturm chain polynomials derived from f never -have more than 21 digits ...

    -

    Once the Sturm chain is computed and the zeros isolated, obtaining their -decimal digits is relatively faster. Here is for the ten real roots of -f(x) - 2**-23 x**19 as computed by the code above:

    -
    Z_1 = 0.9999999999...
    -Z_2 = 2.0000000000...
    -Z_3 = 2.9999999999...
    -Z_4 = 4.0000000002...
    -Z_5 = 4.9999999275...
    -Z_6 = 6.0000069439...
    -Z_7 = 6.9996972339...
    -Z_8 = 8.0072676034...
    -Z_9 = 8.9172502485...
    -Z_10 = 20.8469081014...
    -
    -
    -

    The second Wilkinson polynomial

    -
    \poldef f(x) := mul(x - 2^-i, i = 1..20);
    -
    -%\PolTypeset{f}
    -
    -\PolToSturm{f}{f}
    -\PolSturmIsolateZeros**{f}
    -\PolPrintIntervals{f}
    -

    This takes more time than the polynomial with 1, 2, .., 20 as roots but -less than the latter modified by the 2**-23 tiny change to one of its -coefficient.

    -

    Here is the output (with release 0.7.2):

    -
    Z_1  = 0.00000095367431640625
    -Z_2  = 0.0000019073486328125
    -Z_3  = 0.000003814697265625
    -Z_4  = 0.00000762939453125
    -Z_5  = 0.0000152587890625
    -Z_6  = 0.000030517578125
    -Z_7  = 0.00006103515625
    -Z_8  = 0.0001220703125
    -Z_9  = 1/4096
    -Z_10 = 1/2048
    -Z_11 = 1/1024
    -Z_12 = 1/512
    -Z_13 = 1/256
    -Z_14 = 1/128
    -Z_15 = 0.015625
    -Z_16 = 0.03125
    -Z_17 = 0.0625
    -Z_18 = 0.125
    -Z_19 = 0.25
    -Z_20 = 0.5
    -

    There is some incoherence in output format which has its source in the -fact that some roots are found in branches which can only find decimal -roots, whereas some are found in branches which could find general -fractions and they use \xintIrr before storage of the found root. -This may evolve in future.

    -
    -
    -

    The degree 41 polynomial with -2, -1.9, -1.8, ..., 0, 0.1, ..., 1.9, 2 as roots

    -
    \PolDef{P}{mul((x-i*1e-1), i=-20..20)}% i/10 is same but less efficient
    -

    In the defining expression we could have used i/10 but this gives -less efficient internal form for the coefficients (the 10's end up -in denominators).

    -

    Using \PolToExpr{P} after having done

    -
    \def\PolToExprCmd#1{\PolDecToString{\xintREZ{#1}}}
    -

    we get this expanded form:

    -
    x^41
    --28.7*x^39
    -+375.7117*x^37
    --2975.11006*x^35
    -+15935.28150578*x^33
    --61167.527674162*x^31
    -+173944.259366417394*x^29
    --373686.963560544648*x^27
    -+613012.0665016658846445*x^25
    --771182.31133138163125495*x^23
    -+743263.86672885754888959569*x^21
    --545609.076599482896371978698*x^19
    -+301748.325708943677229642930528*x^17
    --123655.8987669450434698869844544*x^15
    -+36666.1782054884005855608205864192*x^13
    --7607.85821367459445649518380016128*x^11
    -+1053.15135918687298508885950223794176*x^9
    --90.6380005918141132650786081964032*x^7
    -+4.33701563847327366842552218288128*x^5
    --0.0944770968420804735498178265088*x^3
    -+0.00059190121813899276854174416896*x
    -

    which shows coefficients with up to 36 significant digits...

    -

    Stress test: not a hard challenge to xint + polexpr, but be a bit -patient!

    -
    \PolDef{P}{mul((x-i*1e-1), i=-20..20)}%
    -\PolToSturm{P}{S}           % dutifully computes S_0, ..., S_{41}
    -% the [1] optional argument limits the search to interval (-10,10)
    -\PolSturmIsolateZeros[1]{S} % finds *exactly* (but a bit slowly) all 41 roots!
    -\PolPrintIntervals{S}       % nice, isn't it?
    -
    -

    Note

    -

    Release 0.5 has experimental addition of optional argument -E to \PolSturmIsolateZeros. It instructs to search roots only -in interval (-10^E, 10^E). Important: the extremities are -assumed to not be roots. In this example, the [1] in -\PolSturmIsolateZeros[1]{S} gives some speed gain; without it, it -turns out in this case that polexpr would have started with -(-10^6, 10^6) interval.

    -

    Please note that this will probably get replaced in future by the -specification of a general interval. Do not rely on meaning of this -optional argument keeping the same.

    -
    -
    -
    -

    Roots of Chebyshev polynomials

    -
    \poldef T_0(x) := 1;
    -\poldef T_1(x) := x;
    -\catcode`@ 11
    -\count@ 2
    -\xintloop
    -  \poldef T_\the\count@(x) :=
    -          2x*T_\the\numexpr\count@-1\relax
    -           - T_\the\numexpr\count@-2\relax;
    -\ifnum\count@<15
    -\advance\count@ 1
    -\repeat
    -\catcode`@ 12
    -
    -$$T_{15} = \PolTypeset[X]{T_15}$$
    -\PolToSturm{T_15}{T_15}
    -\PolSturmIsolateZeros{T_15}
    -\PolEnsureIntervalLengths{T_15}{-10}
    -\PolPrintIntervals{T_15}
    -
    -
    -

    Non-expandable macros

    +

    Non-expandable macros

    Note

    At 0.8 polexpr is usable with Plain TeX and not only with LaTeX. Some examples given in this section may be using LaTeX syntax -such as \renewcommand. Convert to TeX primitives as appropriate -if testing with a non LaTeX macro format.

    +such as \renewcommand.

    -

    \poldef polname(letter):= expression using the letter as indeterminate;

    +

    \poldef polname(letter):= expression using the letter as indeterminate;

    This evaluates the polynomial expression and stores the coefficients in a private structure accessible later via other @@ -2206,7 +1782,7 @@ package macros, used with argument polname expression can make use of previously defined polynomials.

    Polynomial names must start with a letter and are constituted of letters, digits, underscores and the right tick '.

    -

    The whole xintexpr syntax is authorized, as long as the final +

    The whole xintexpr syntax is authorized, as long as the final result is of polynomial type:

    \poldef polname(z) := add((-1)^i z^(2i+1)/(2i+1)!, i = 0..10);

    With fractional coefficients, beware the tacit multiplication issue.

    @@ -2224,7 +1800,7 @@ item).

    only algebraic operations (and ople indexing or slicing operations) should work fine in \xintexpr/\xinteval with such polynomial names as argument.

    -

    In the case of a constant polynomial, the xintexpr variable (not the +

    In the case of a constant polynomial, the xintexpr variable (not the internal data structure on which the package macros operate) associated to it is indistinguishable from a scalar, it is actually a scalar and has lost all traces from its origins as a polynomial @@ -2267,7 +1843,7 @@ the original expression has to be done manually, if needed.

    -

    \PolDef[<letter>]{<polname>}{<expr. using the letter as indeterminate>}

    +

    \PolDef[<letter>]{<polname>}{<expr. using the letter as indeterminate>}

    Does the same as \poldef in an undelimited macro format, the main interest is to avoid potential problems with the @@ -2277,7 +1853,7 @@ of a [<letter>] optional argument, t

    -

    \PolGenFloatVariant{<polname>}

    +

    \PolGenFloatVariant{<polname>}

    Makes the polynomial also usable in the \xintfloatexpr/\xintfloateval parser. It will therein evaluates @@ -2294,7 +1870,7 @@ the new polynomial is to be used in \xintfloateva

    -

    \PolTypeset{<pol. expr.>}

    +

    \PolTypeset{<pol. expr.>}

    Typesets in descending powers, switching to math mode if in text mode, after evaluating the polynomial expression:

    @@ -2311,7 +1887,7 @@ can be re-defined for customization. Their default definitions are expandable, but this is not a requirement.

    -

    \PolTypesetCmd{<raw_coeff>}

    +

    \PolTypesetCmd{<raw_coeff>}

    Its package definition checks if the coefficient is 1 or -1 and then skips printing the 1, except for the coefficient of @@ -2321,7 +1897,7 @@ degree zero. Also it sets the conditional deciding behaviour of minus one, is handled by \PolTypesetOne{<raw_coeff>}.

    -

    \PolIfCoeffIsPlusOrMinusOne{T}{F}

    +

    \PolIfCoeffIsPlusOrMinusOne{T}{F}

    This macro is a priori undefined.

    It is defined via the default \PolTypesetCmd{<raw_coeff>} to be @@ -2335,10 +1911,10 @@ plus or minus one, and F if not. It choos

    -

    \PolTypesetOne{<raw_coeff>}

    +

    \PolTypesetOne{<raw_coeff>}

    Defaults to \xintTeXsignedFrac (LaTeX) or \xintTeXsignedOver -(else). But these xintfrac old legacy macros are a bit +(else). But these xintfrac old legacy macros are a bit annoying as they insist in exhibiting a power of ten rather than using simpler decimal notation.

    As alternative, one can do definitions such as:

    @@ -2350,7 +1926,7 @@ using simpler decimal notation.

    -

    \PolTypesetMonomialCmd

    +

    \PolTypesetMonomialCmd

    This decides how a monomial (in variable \PolVar and with exponent \PolIndex) is to be printed. The default does nothing @@ -2361,7 +1937,7 @@ for the constant term, \PolVar for the fir

    -

    \PolTypesetCmdPrefix{<raw_coeff>}

    +

    \PolTypesetCmdPrefix{<raw_coeff>}

    Expands to a + if the raw_coeff is zero or positive, and to nothing if raw_coeff is negative, as in latter case the @@ -2373,7 +1949,7 @@ separator in the typeset formula. Not used for the first term.

    -

    \PolTypeset*{<pol. expr.>}

    +

    \PolTypeset*{<pol. expr.>}

    Typesets in ascending powers. Use [<letter>] optional argument (after the *) to use another letter than x.

    @@ -2383,14 +1959,14 @@ expression another letter than default x.<
    -

    \PolSturmIsolateZeros*{<sturmname>}

    +

    \PolSturmIsolateZeros*{<sturmname>}

    The macro does the same as \PolSturmIsolateZeros{<sturmname>} and then in addition it does the extra work to determine all @@ -2595,7 +2171,7 @@ multiplicities of the real roots.

    to the multiplicity of the root located in the index-th interval (intervals are enumerated from left to right, with index starting at 1).

    -

    Furthermore, if for example the <sturmname> is S, xintexpr +

    Furthermore, if for example the <sturmname> is S, xintexpr variables SM_1, SM_2... hold the multiplicities thus computed.

    @@ -2606,18 +2182,17 @@ execution, \PolToSturm, eve non-square-free Sturm chain polynomials as user-level genuine polynomials, stores their data in private macros.

    -

    See The degree nine polynomial with 0.99, 0.999, 0.9999 as triple -roots for an example.

    +

    See The degree nine polynomial with 0.99, 0.999, 0.9999 as triple roots example in polexpr-examples.pdf.

    -

    \PolSturmIsolateZeros**{<sturmname>}

    +

    \PolSturmIsolateZeros**{<sturmname>}

    The macro does the same as \PolSturmIsolateZeros*{<sturmname>} and in addition it does the extra work to determine all the rational @@ -2637,18 +2212,17 @@ between the degrees of these two polynomials (see also roots have been removed (see \polexprsetup), i.e. it contains the irrational roots of the original polynomial, with the same multiplicities.

    -

    See A degree five polynomial with three rational -roots for an example.

    +

    See A degree five polynomial with three rational roots in polexpr-examples.pdf.

    -

    \PolSturmIsolateZerosAndFindRationalRoots{<sturmname>}

    +

    \PolSturmIsolateZerosAndFindRationalRoots{<sturmname>}

    This works exactly like \PolSturmIsolateZeros**{<sturmname>} (inclusive of declaring the polynomials sturmname_sqf_norr and @@ -2661,7 +2235,7 @@ their multiplicities at the same time.

    Attention!

    -

    This macro does not define xintexpr variables +

    This macro does not define xintexpr variables sturmnameM_1, sturmnameM_2, ... holding the multiplicities and it leaves the multiplicity array (whose accessor is \PolSturmIsolatedZeroMultiplicity{<sturmname>}{<index>}) into @@ -2678,7 +2252,7 @@ rational root anyhow).

    -

    \PolRefineInterval*{<sturmname>}{<index>}

    +

    \PolRefineInterval*{<sturmname>}{<index>}

    The index-th interval (starting indexing at one) is further subdivided as many times as is necessary in order for the newer @@ -2688,7 +2262,7 @@ strictly separated from the other roots.

    -

    \PolRefineInterval[N]{<sturmname>}{<index>}

    +

    \PolRefineInterval[N]{<sturmname>}{<index>}

    The index-th interval (starting count at one) is further subdivided once, reducing its length by a factor of 10. This is done @@ -2696,7 +2270,7 @@ subdivided once, reducing its length by a factor of 10. This is done

    -

    \PolEnsureIntervalLength{<sturmname>}{<index>}{<exponent>}

    +

    \PolEnsureIntervalLength{<sturmname>}{<index>}{<exponent>}

    The index-th interval is subdivided until its length becomes at most 10^E. This means (for E<0) that the first -E digits @@ -2704,7 +2278,7 @@ after decimal mark of the kth root will th

    -

    \PolEnsureIntervalLengths{<sturmname>}{<exponent>}

    +

    \PolEnsureIntervalLengths{<sturmname>}{<exponent>}

    The intervals as obtained from \PolSturmIsolateZeros are (if necessary) subdivided further by (base 10) dichotomy in order for @@ -2714,7 +2288,7 @@ each of them to have length at most 10^E.<

    -

    \PolPrintIntervals[<varname>]{<sturmname>}

    +

    \PolPrintIntervals[<varname>]{<sturmname>}

    This is a convenience macro which prints the bounds for the roots Z_1, Z_2, ... (the optional argument varname allows to @@ -2735,7 +2309,7 @@ primitives.

    See next macros which govern its output.

    -

    \PolPrintIntervalsNoRealRoots

    +

    \PolPrintIntervalsNoRealRoots

    Executed in place of an array environment, when there are no real roots. Default definition:

    @@ -2743,21 +2317,34 @@ real roots. Default definition:

    -

    \PolPrintIntervalsBeginEnv

    +

    \PolPrintIntervalsBeginEnv

    -

    Default definition:

    +

    Default definition (given here for LaTeX, Plain has a variant):

    \newcommand\PolPrintIntervalsBeginEnv{\[\begin{array}{rcccl}}
    +

    A simpler center environment provides a straightforward way to +obtain a display allowing pagebreaks. Of course redefinitions must +at any rate be kept in sync with \PolPrintIntervalsKnownRoot and +\PolPrintIntervalsUnknownRoot.

    +

    Prior to 0.8.6 it was not possible to use here for example +\begin{align} due to the latter executing twice in contents.

    -

    \PolPrintIntervalsEndEnv

    +

    \PolPrintIntervalsEndEnv

    Default definition:

    \newcommand\PolPrintIntervalsEndEnv{\end{array}\]}
    +
    +

    \PolPrintIntervalsRowSeparator

    +
    +

    Expands by default to \\ with LaTeX and to \cr with Plain

    +

    Added at 0.8.6.

    +
    +
    -

    \PolPrintIntervalsKnownRoot

    +

    \PolPrintIntervalsKnownRoot

    Default definition:

    \newcommand\PolPrintIntervalsKnownRoot{%
    @@ -2767,7 +2354,7 @@ real roots. Default definition:

    -

    \PolPrintIntervalsUnknownRoot

    +

    \PolPrintIntervalsUnknownRoot

    Default definition:

    \newcommand\PolPrintIntervalsUnknownRoot{%
    @@ -2778,21 +2365,21 @@ real roots. Default definition:

    -

    \PolPrintIntervalsPrintExactZero

    +

    \PolPrintIntervalsPrintExactZero

    Default definition:

    \newcommand\PolPrintIntervalsPrintExactZero{\PolPrintIntervalsTheLeftEndPoint}
    -

    \PolPrintIntervalsPrintLeftEndPoint

    +

    \PolPrintIntervalsPrintLeftEndPoint

    Default definition:

    \newcommand\PolPrintIntervalsPrintLeftEndPoint{\PolPrintIntervalsTheLeftEndPoint}
    -

    \PolPrintIntervalsPrintRightEndPoint

    +

    \PolPrintIntervalsPrintRightEndPoint

    Default definition is:

    \newcommand\PolPrintIntervalsPrintRightEndPoint{\PolPrintIntervalsTheRightEndPoint}
    @@ -2800,7 +2387,7 @@ real roots. Default definition:

    -

    \PolPrintIntervals*[<varname>]{<sturmname>}

    +

    \PolPrintIntervals*[<varname>]{<sturmname>}

    This starred variant produces an alternative output (which displays the root multiplicity), and is provided as an @@ -2817,7 +2404,7 @@ definition:

    Multiplicities are printed using this auxiliary macro:

    -

    \PolPrintIntervalsPrintMultiplicity

    +

    \PolPrintIntervalsPrintMultiplicity

    whose default definition is:

    \newcommand\PolPrintIntervalsPrintMultiplicity{(\mbox{mult. }\PolPrintIntervalsTheMultiplicity)}
    @@ -2825,19 +2412,19 @@ definition:

    -

    \PolSetToSturmChainSignChangesAt{\foo}{<sturmname>}{<value>}

    +

    \PolSetToSturmChainSignChangesAt{\foo}{<sturmname>}{<value>}

    Sets macro \foo to store the number of sign changes in the already computed normalized Sturm chain with name prefix <sturmname>, at location <value> (which must be in format as -acceptable by the xintfrac macros.)

    +acceptable by the xintfrac macros.)

    The definition is made with global scope. For local scope, use [\empty] as extra optional argument.

    One can use this immediately after creation of the Sturm chain.

    -

    \PolSetToNbOfZerosWithin{\foo}{<sturmname>}{<value_left>}{<value_right>}

    +

    \PolSetToNbOfZerosWithin{\foo}{<sturmname>}{<value_left>}{<value_right>}

    Sets, assuming the normalized Sturm chain has been already computed, macro \foo to store the number of roots of sturmname_0 in @@ -2861,7 +2448,7 @@ which requires prior execution of

    -

    \PolLet{<polname_2>}={<polname_1>}

    +

    \PolLet{<polname_2>}={<polname_1>}

    Makes a copy of the already defined polynomial polname_1 to a new one polname_2. This has the same effect as @@ -2871,20 +2458,20 @@ new one polname_2. This has the same effec

    -

    \PolAssign{<polname>}\toarray\macro

    +

    \PolAssign{<polname>}\toarray\macro

    Defines a one-argument expandable macro \macro{#1} which expands to the (raw) #1th polynomial coefficient.

    • Attention, coefficients here are indexed starting at 1. This is an unfortunate legacy situation related to the original indexing -convention in xinttools arrays.

    • +convention in xinttools arrays.

    • With #1=-1, -2, ..., \macro{#1} returns leading coefficients.

    • With #1=0, returns the number of coefficients, i.e. 1 + deg f for non-zero polynomials.

    • @@ -2894,12 +2481,12 @@ for non-zero polynomials.

    -

    \PolGet{<polname>}\fromarray\macro

    +

    \PolGet{<polname>}\fromarray\macro

    Does the converse operation to \PolAssign{<polname>}\toarray\macro. Each individual \macro{<value>} gets expanded in an \edef and then normalized -via xintfrac's macro \xintRaw.

    +via xintfrac's macro \xintRaw.

    The leading zeros are removed from the polynomial.

    (contrived) Example:

    \xintAssignArray{1}{-2}{5}{-3}\to\foo
    @@ -2908,14 +2495,14 @@ via xintfrac
     
    -

    \PolFromCSV{<polname>}{<csv>}

    +

    \PolFromCSV{<polname>}{<csv>}

    Defines a polynomial directly from the comma separated list of values (or a macro expanding to such a list) of its coefficients, the first item gives the constant term, the last item gives the leading coefficient, except if zero, then it is dropped (iteratively). List items are each expanded in an \edef and then put into normalized -form via xintfrac's macro \xintRaw.

    +form via xintfrac's macro \xintRaw.

    As leading zero coefficients are removed:

    \PolFromCSV{f}{0, 0, 0, 0, 0, 0, 0, 0, 0, 0}

    defines the zero polynomial, which holds only one coefficient.

    @@ -2923,7 +2510,7 @@ form via xintf
    -

    \PolMapCoeffs{\macro}{<polname>}

    +

    \PolMapCoeffs{\macro}{<polname>}

    It modifies ('in-place': original coefficients get lost) each coefficient of the defined polynomial via the expandable macro @@ -2931,9 +2518,9 @@ coefficient of the defined polynomial via the expandable macro coefficients vanish after the operation.

    In the replacement text of \macro, \index expands to the coefficient index (starting at zero for the constant term).

    -

    Notice that \macro will have to handle inputs in the xintfrac +

    Notice that \macro will have to handle inputs in the xintfrac internal format. This means that it probably will have to be -expressed in terms of macros from the xintfrac package.

    +expressed in terms of macros from the xintfrac package.

    Example:

    \def\foo#1{\xintMul{#1}{\the\numexpr\index*\index\relax}}

    (or with \xintSqr{\index}) to replace n-th coefficient @@ -2941,20 +2528,20 @@ expressed in terms of macros from the -

    \PolReduceCoeffs{<polname>}

    +

    \PolReduceCoeffs{<polname>}

    Reduces the internal representations of the coefficients to their lowest terms.

    -

    \PolReduceCoeffs*{<polname>}

    +

    \PolReduceCoeffs*{<polname>}

    Reduces the internal representations of the coefficients to their lowest terms, but ignoring a possible separated "power of ten part".

    -

    For example, xintfrac stores an 30e2/50 input as 30/50 with +

    For example, xintfrac stores an 30e2/50 input as 30/50 with a separate 10^2 part. This will thus get replaced by 3e^2/5 -(or rather whatever xintfrac uses for internal representation), and +(or rather whatever xintfrac uses for internal representation), and not by 60 as would result from complete reduction.

    Evaluations with polynomials treated by this can be much faster than with those handled by the non-starred variant @@ -2963,7 +2550,7 @@ remain generally smaller.

    -

    \PolMakeMonic{<polname>}

    +

    \PolMakeMonic{<polname>}

    Divides by the leading coefficient. It is recommended to execute \PolReduceCoeffs*{<polname>} immediately afterwards. This is not @@ -2973,7 +2560,7 @@ denominator for typesetting purposes.

    -

    \PolMakePrimitive{<polname>}

    +

    \PolMakePrimitive{<polname>}

    Divides by the integer content see (\PolIContent). This thus produces a polynomial with integer @@ -2982,7 +2569,7 @@ coefficient is not modified.

    -

    \PolDiff{<polname_1>}{<polname_2>}

    +

    \PolDiff{<polname_1>}{<polname_2>}

    This sets polname_2 to the first derivative of polname_1. It is allowed to issue \PolDiff{f}{f}, effectively replacing f @@ -2992,7 +2579,7 @@ by f'.

    -

    \PolDiff[N]{<polname_1>}{<polname_2>}

    +

    \PolDiff[N]{<polname_1>}{<polname_2>}

    This sets polname_2 to the N-th derivative of polname_1. Identical arguments is allowed. With N=0, same effect as @@ -3001,7 +2588,7 @@ using \PolAntiDiff.

    -

    \PolAntiDiff{<polname_1>}{<polname_2>}

    +

    \PolAntiDiff{<polname_1>}{<polname_2>}

    This sets polname_2 to the primitive of polname_1 vanishing at zero.

    @@ -3010,14 +2597,14 @@ at zero.

    -

    \PolAntiDiff[N]{<polname_1>}{<polname_2>}

    +

    \PolAntiDiff[N]{<polname_1>}{<polname_2>}

    This sets polname_2 to the result of N successive integrations on polname_1. With negative N, it switches to using \PolDiff.

    -

    \PolDivide{<polname_1>}{<polname_2>}{<polname_Q>}{<polname_R>}

    +

    \PolDivide{<polname_1>}{<polname_2>}{<polname_Q>}{<polname_R>}

    This sets polname_Q and polname_R to be the quotient and remainder in the Euclidean division of polname_1 by @@ -3025,21 +2612,21 @@ remainder in the Euclidean division of polname_1<

    -

    \PolQuo{<polname_1>}{<polname_2>}{<polname_Q>}

    +

    \PolQuo{<polname_1>}{<polname_2>}{<polname_Q>}

    This sets polname_Q to be the quotient in the Euclidean division of polname_1 by polname_2.

    -

    \PolRem{<polname_1>}{<polname_2>}{<polname_R>}

    +

    \PolRem{<polname_1>}{<polname_2>}{<polname_R>}

    This sets polname_R to be the remainder in the Euclidean division of polname_1 by polname_2.

    -

    \PolGCD{<polname_1>}{<polname_2>}{<polname_GCD>}

    +

    \PolGCD{<polname_1>}{<polname_2>}{<polname_GCD>}

    This sets polname_GCD to be the (monic) GCD of polname_1 and polname_2. It is a unitary polynomial except if both @@ -3049,7 +2636,7 @@ zero polynomial.

    -

    Expandable macros

    +

    Expandable macros

    Note

    At 0.8 polexpr is usable with Plain TeX and not only with @@ -3061,7 +2648,7 @@ if testing with a non LaTeX macro format.

    \PolToFloatExpr which need a \write, \edef or a \csname...\endcsname context.

    -

    \PolToExpr{<pol. expr.>}

    +

    \PolToExpr{<pol. expr.>}

    Produces expandably 4 the string coeff_N*x^N+..., i.e. the polynomial is using descending powers.

    @@ -3072,19 +2659,17 @@ polynomial is using descending powers.

    Since 0.8 the input is not restricted to be a polynomial name but -is allowed to be an arbitrary expression (where by default the -letter x is recognized as the indeterminate; see -\PolToExprInVar).

    -

    The default output (which also by default uses the letter x and is -completely configurable, see in particular \PolToExprVar) is -compatible with both

    +is allowed to be an arbitrary expression. Then x is expected as +indeterminate but this can be customized via \PolToExprInVar.

    +

    The output uses the letter x by default, this is customizable +via \PolToExprVar. The default output is compatible both with

    • the Maple's input format,

    • and the PSTricks \psplot[algebraic] input format.

    -

    Attention that it is not compatible with Python, but see -\PolToExprCaret in this regard.

    -

    It has the following characteristics:

    +

    Attention that it is not compatible with Python, see further +\PolToExprCaret in this context.

    +

    The following applies:

    • vanishing coefficients are skipped (issue \poltoexpralltrue to override this and produce output such as x^3+0*x^2+0*x^1+0),

    • @@ -3106,15 +2691,16 @@ is not supposed to be a typesetting macro.

      redefinition must maintain the expandability property.

    -

    \PolToExprVar

    +

    \PolToExprVar

    -

    Defaults to x. The letter used in input.

    +

    Defaults to x. The letter used in the macro output.

    -

    \PolToExprInVar

    +

    \PolToExprInVar

    -

    Defaults to x: the letter used as the polynomial indeterminate.

    +

    Defaults to x: the letter used as the polynomial indeterminate +in the macro input.

    Recall that declared polynomials are more efficiently used in algebraic expressions without the (x), i.e. P*Q is better than P(x)*Q(x). Thus the input, even if an expression, does not @@ -3123,13 +2709,13 @@ have to contain any x.

    -

    \PolToExprTimes

    +

    \PolToExprTimes

    Defaults to *.

    -

    \PolToExprCaret

    +

    \PolToExprCaret

    Defaults to ^ of catcode 12. Set it to expand to ** for Python compatible output.

    @@ -3137,7 +2723,7 @@ expand to ** for Python compatible output
    -

    \PolToExprCmd{<raw_coeff>}

    +

    \PolToExprCmd{<raw_coeff>}

    Defaults to \xintPRaw{\xintRawWithZeros{#1}}.

    This means that the coefficient value is printed-out as a fraction @@ -3156,7 +2742,7 @@ and not their finite decimal expansion with no denominator.

    -

    \PolToExprOneTerm{<raw_coeff>}{<exponent>}

    +

    \PolToExprOneTerm{<raw_coeff>}{<exponent>}

    This is the macro which from the coefficient and the exponent produces the corresponding term in output, such as 2/3*x^7.

    @@ -3166,13 +2752,13 @@ produces the corresponding term in output, such as -

    \PolToExprOneTermStyleA{<raw_coeff>}{<exponent>}

    +

    \PolToExprOneTermStyleA{<raw_coeff>}{<exponent>}

    This holds the default package meaning of \PolToExprOneTerm.

    -

    \PolToExprOneTermStyleB{<raw_coeff>}{<exponent>}

    +

    \PolToExprOneTermStyleB{<raw_coeff>}{<exponent>}

    This holds an alternative meaning, which puts the fractional part of a coefficient after the monomial, i.e. like this:

    @@ -3185,7 +2771,7 @@ To revert to the package default behaviour, issue
    -

    \PolToExprTermPrefix{<raw_coeff>}

    +

    \PolToExprTermPrefix{<raw_coeff>}

    It receives as argument the coefficient. Its default behaviour is to produce a + if the coefficient is positive, which will thus @@ -3196,7 +2782,7 @@ positive coefficient does not output an explicit

    -

    \PolToFloatExpr{<pol. expr.>}

    +

    \PolToFloatExpr{<pol. expr.>}

    Similar to \PolToExpr{<pol. expr.>} but using \PolToFloatExprCmd{<raw_coeff>} which by default rounds and @@ -3213,14 +2799,14 @@ in between).

    Extended at 0.8 to accept general expressions as input.

    -

    \PolToFloatExprCmd{<raw_coeff>}

    +

    \PolToFloatExprCmd{<raw_coeff>}

    The one-argument macro used by \PolToFloatExprOneTerm. It defaults to \xintPFloat{#1}, which trims trailing @@ -3230,7 +2816,7 @@ zeroes.

    -

    \PolToExpr*{<pol. expr.>}

    +

    \PolToExpr*{<pol. expr.>}

    Ascending powers: coeff_0+coeff_1*x+coeff_2*x^2+....

    Extended at 0.8 to accept general expressions as input.

    @@ -3239,38 +2825,38 @@ zeroes.

    -

    \PolToFloatExpr*{<pol. expr.>}

    +

    \PolToFloatExpr*{<pol. expr.>}

    Ascending powers.

    Extended at 0.8 to accept general expressions as input.

    -

    \PolNthCoeff{<polname>}{<index>}

    +

    \PolNthCoeff{<polname>}{<index>}

    It expands to the raw N-th coefficient (N=0 corresponds to the constant coefficient). If N is out of range, zero (in its -default xintfrac format 0/1[0]) is returned.

    +default xintfrac format 0/1[0]) is returned.

    Negative indices N=-1, -2, ... return the leading coefficient, sub-leading coefficient, ..., and finally 0/1[0] for N<-1-degree.

    -

    \PolLeadingCoeff{<polname>}

    +

    \PolLeadingCoeff{<polname>}

    Expands to the leading coefficient.

    -

    \PolDegree{<polname>}

    +

    \PolDegree{<polname>}

    It expands to the degree. This is -1 if zero polynomial but this may change in future. Should it then expand to -\infty ?

    -

    \PolIContent{<polname>}

    +

    \PolIContent{<polname>}

    It expands to the contents of the polynomial, i.e. to the positive fraction such that dividing by this fraction produces a polynomial @@ -3279,7 +2865,7 @@ with integer coefficients having no common prime divisor.

    -

    \PolToList{<polname>}

    +

    \PolToList{<polname>}

    Expands to {coeff_0}{coeff_1}...{coeff_N} with N = degree, and coeff_N the leading coefficient @@ -3288,7 +2874,7 @@ empty output.)

    -

    \PolToCSV{<polname>}

    +

    \PolToCSV{<polname>}

    Expands to coeff_0, coeff_1, coeff_2, ....., coeff_N, starting with constant term and ending with leading coefficient. Converse @@ -3296,35 +2882,35 @@ to \PolFromCSV{<

    -

    \PolEval{<polname>}\AtExpr{<num. expr.>}

    +

    \PolEval{<polname>}\AtExpr{<num. expr.>}

    Same output as \xinteval{polname(numerical expression)}.

    -

    \PolEval{<polname>}\At{<value>}

    +

    \PolEval{<polname>}\At{<value>}

    Evaluates the polynomial at the given value which must be in (or -expand to) a format acceptable to the xintfrac macros.

    +expand to) a format acceptable to the xintfrac macros.

    -

    \PolEvalReduced{<polname>}\AtExpr{<num. expr.>}

    +

    \PolEvalReduced{<polname>}\AtExpr{<num. expr.>}

    Same output as \xinteval{reduce(polname(numerical expression))}.

    -

    \PolEvalReduced{<polname>}\At{<value>}

    +

    \PolEvalReduced{<polname>}\At{<value>}

    Evaluates the polynomial at the value which must be in (or expand -to) a format acceptable to the xintfrac macros, and outputs an +to) a format acceptable to the xintfrac macros, and outputs an irreducible fraction.

    -

    \PolFloatEval{<polname>}\AtExpr{<num. expr.>}

    +

    \PolFloatEval{<polname>}\AtExpr{<num. expr.>}

    Same output as \xintfloateval{polname(numerical expression)}.

    @@ -3338,22 +2924,22 @@ the following syntax can be used: \xintfloateval{3.27*\xintexpr f(2.53)\relax^2}
    5
    -

    Cf. xintexpr documentation about nested expressions.

    +

    Cf. xintexpr documentation about nested expressions.

    -

    \PolFloatEval{<polname>}\At{<value>}

    +

    \PolFloatEval{<polname>}\At{<value>}

    Evaluates the polynomial at the value which must be in (or expand -to) a format acceptable to the xintfrac macros.

    +to) a format acceptable to the xintfrac macros.

    -

    \PolSturmNbOfIsolatedZeros{<sturmname>}

    +

    \PolSturmNbOfIsolatedZeros{<sturmname>}

    Expands to the number of real roots of the polynomial <sturmname>_0, i.e. the number of distinct real roots of the @@ -3421,11 +3006,11 @@ documented package macros anyway.

    -

    \PolSturmNbOfRootsOf{<sturmname>}\LessThanOrEqualTo{<value>}

    +

    \PolSturmNbOfRootsOf{<sturmname>}\LessThanOrEqualTo{<value>}

    Expands to the number of distinct roots (of the polynomial used to create the Sturm chain) less than or equal to the value (i.e. a -number of fraction recognizable by the xintfrac macros).

    +number of fraction recognizable by the xintfrac macros).

    Attention!

    \PolSturmIsolateZeros{<sturmname>} must have been executed @@ -3437,7 +3022,7 @@ of the above constraint.

    -

    \PolSturmNbOfRootsOf{<sturmname>}\LessThanOrEqualToExpr{<num. expr.>}

    +

    \PolSturmNbOfRootsOf{<sturmname>}\LessThanOrEqualToExpr{<num. expr.>}

    Expands to the number of distinct roots (of the polynomial used to create the Sturm chain) which are less than or equal to the @@ -3450,7 +3035,7 @@ beforehand.

    -

    \PolSturmNbWithMultOfRootsOf{<sturmname>}\LessThanOrEqualTo{<value>}

    +

    \PolSturmNbWithMultOfRootsOf{<sturmname>}\LessThanOrEqualTo{<value>}

    Expands to the number counted with multiplicities of the roots (of the polynomial used to create the Sturm chain) which are less than @@ -3463,7 +3048,7 @@ variant) must have been executed beforehand.

    -

    \PolSturmNbWithMultOfRootsOf{<sturmname>}\LessThanOrEqualToExpr{<num. expr.>}

    +

    \PolSturmNbWithMultOfRootsOf{<sturmname>}\LessThanOrEqualToExpr{<num. expr.>}

    Expands to the total number of roots (counted with multiplicities) which are less than or equal to the given expression.

    @@ -3475,7 +3060,7 @@ variant) must have been executed beforehand.

    -

    \PolSturmNbOfRationalRoots{<sturmname>}

    +

    \PolSturmNbOfRationalRoots{<sturmname>}

    Expands to the number of rational roots (without multiplicities).

    @@ -3486,7 +3071,7 @@ beforehand.

    -

    \PolSturmNbOfRationalRootsWithMultiplicities{<sturmname>}

    +

    \PolSturmNbOfRationalRootsWithMultiplicities{<sturmname>}

    Expands to the number of rational roots (counted with multiplicities).

    @@ -3497,7 +3082,7 @@ beforehand.

    -

    \PolSturmRationalRoot{<sturmname>}{<k>}

    +

    \PolSturmRationalRoot{<sturmname>}{<k>}

    Expands to the k-th rational root. They are enumerated from left to right starting at index value 1.

    @@ -3509,7 +3094,7 @@ beforehand.

    -

    \PolSturmRationalRootIndex{<sturmname>}{<k>}

    +

    \PolSturmRationalRootIndex{<sturmname>}{<k>}

    Expands to the index of the kth rational root as part of the ordered real roots (counted without multiplicities). So @@ -3524,7 +3109,7 @@ beforehand.

    -

    \PolSturmRationalRootMultiplicity{<sturmname>}{<k>}

    +

    \PolSturmRationalRootMultiplicity{<sturmname>}{<k>}

    Expands to the multiplicity of the kth rational root.

    @@ -3535,14 +3120,14 @@ beforehand.

    -

    \PolIntervalWidth{<sturmname>}{<index>}

    +

    \PolIntervalWidth{<sturmname>}{<index>}

    The 10^E width of the current index-th root localization -interval. Output is in xintfrac raw 1/1[E] format (if not zero).

    +interval. Output is in xintfrac raw 1/1[E] format (if not zero).

    -

    Expandable macros for use within execution of \PolPrintIntervals

    +

    Expandable macros for use within execution of \PolPrintIntervals

    These macros are for usage within custom user redefinitions of \PolPrintIntervalsKnownRoot, \PolPrintIntervalsUnknownRoot, or in redefinitions of PolPrintIntervalsPrintExactZero (used in the @@ -3551,7 +3136,7 @@ default for the former) and of -

    \PolPrintIntervalsTheVar

    +

    \PolPrintIntervalsTheVar

    Expands to the name (default Z) used for representing the roots, which was passed as optional argument varname to @@ -3559,21 +3144,21 @@ which was passed as optional argument varname

    -

    \PolPrintIntervalsTheIndex

    +

    \PolPrintIntervalsTheIndex

    Expands to the index of the considered interval (indexing starting at 1 for the leftmost interval).

    -

    \PolPrintIntervalsTheLeftEndPoint

    +

    \PolPrintIntervalsTheLeftEndPoint

    The left end point of the interval, as would be produced by \PolSturmIsolatedZeroLeft if it was @@ -3583,7 +3168,7 @@ by \PolPrint

    -

    \PolPrintIntervalsTheRightEndPoint

    +

    \PolPrintIntervalsTheRightEndPoint

    The right end point of the interval, as would be produced by \PolSturmIsolatedZeroRight for @@ -3591,7 +3176,7 @@ this Sturm chain name and index.

    -

    \PolPrintIntervalsTheMultiplicity

    +

    \PolPrintIntervalsTheMultiplicity

    The multiplicity of the unique root within the interval of index \PolPrintIntervalsTheIndex. Makes sense only if the starred (or @@ -3601,11 +3186,11 @@ double-starred) variant of -

    Booleans (with default setting as indicated)

    +

    Booleans (with default setting as indicated)

    -

    \xintverbosefalse

    +

    \xintverbosefalse

    -

    This is actually an xintexpr configuration. Setting it to +

    This is actually an xintexpr configuration. Setting it to true triggers the writing of information to the log when new polynomial or scalar variables are defined.

    @@ -3616,7 +3201,7 @@ considered unstable and undocumented internal structures.

    -

    \polnewpolverbosefalse

    +

    \polnewpolverbosefalse

    When \poldef is used, both a variable and a function are defined. The default \polnewpolverbosefalse setting suppresses @@ -3636,14 +3221,14 @@ roots obey only the \xintverbos

    -

    \poltypesetallfalse

    +

    \poltypesetallfalse

    If true, \PolTypeset will also typeset the vanishing coefficients.

    -

    \poltoexprallfalse

    +

    \poltoexprallfalse

    If true, \PolToExpr{<pol. expr.>} and \PolToFloatExpr{<pol. expr.>} will also include the vanishing coefficients in their outputs.

    @@ -3651,9 +3236,9 @@ also include the vanishing coefficients in their outputs.

    -

    Utilies

    +

    Utilies

    -

    \PolDecToString{decimal number}

    +

    \PolDecToString{decimal number}

    This is a utility macro to print decimal numbers. It is an alias for \xintDecToString.

    @@ -3667,12 +3252,12 @@ illustrates that trailing zeros are not trimmed.

    \PolDecToString{\xintREZ{#1}}.

    Attention that a.t.t.o.w. if the argument is for example 1/5, the macro does not identify that this is in fact a number with a finite -decimal expansion and it outputs 1/5. See current xintfrac +decimal expansion and it outputs 1/5. See current xintfrac documentation.

    -

    \polexprsetup

    +

    \polexprsetup

    Serves to customize the package. Currently only two keys are recognized:

    @@ -3693,14 +3278,14 @@ no rational roots”).

    -

    Technicalities

    +

    Technicalities

    • The catcode of the semi-colon is reset temporarily by \poldef macro in case some other package (for example the French babel module) may have made it active. This will fail though if the whole thing was already part of a macro argument, in such cases one can use \PolDef rather. The colon in := may be active with no consequences.

    • -
    • As a consequence of xintfrac addition and subtraction always using +

    • As a consequence of xintfrac addition and subtraction always using least common multiples for the denominators, user-chosen common denominators survive additions and multiplications. For example, this:

      \poldef P(x):= 1/2 + 2/2*x + 3/2*x^3 + 4/2*x^4;
      @@ -3731,7 +3316,7 @@ documented and unstable. Don't use them.

    -

    CHANGE LOG

    +

    CHANGE LOG

    • v0.1 (2018/01/11): initial release. Features:

        @@ -3910,7 +3495,7 @@ for localization of the real roots of polynomials.

      • bug fixes:

      • @@ -3922,14 +3507,13 @@ This speeds up localization of roots via will make available again the code producing the bona fide Sturm polynomials as used formerly.

      • polynomials created from \PolFromCSV or \PolGet -get their coefficients normalized via xintfrac's \xintRaw.

      • +get their coefficients normalized via xintfrac's \xintRaw.

    • experimental change:

    • @@ -4124,7 +3708,7 @@ start letting \xintexpr recognize a polyno variable. This has allowed:

      • to solve the reduced inter-operability problems between polexpr -and xintexpr which arose as consequences to the deep xintexpr 1.4 +and xintexpr which arose as consequences to the deep xintexpr 1.4 evolution,

      • to make available most of the functionality associated to expandable macros directly in the \xinteval syntax as @@ -4153,8 +3737,8 @@ description.

      • Sadly, diff1(), diff2(), diffn() were broken for polynomials of degrees 8 or more, due to a typo and insufficient testing.

      • -
      • The package should have (as documented) required xintexpr 1.4d -but in practice it accepted to work with xintexpr 1.4c, whose +

      • The package should have (as documented) required xintexpr 1.4d +but in practice it accepted to work with xintexpr 1.4c, whose \xinteval does not know how to "output" a polynomial.

      • The definition of one of the two variants of \PolSturmNbOfRootsOf was broken by an end-of-line space, left-over from mass conversion from LaTeX to TeX syntax.

      • @@ -4178,7 +3762,7 @@ from mass conversion from LaTeX to TeX syntax.

      • improved:

          -
        • Some xintexpr functions such as rseq() use the semi-colon, +

        • Some xintexpr functions such as rseq() use the semi-colon, and it was mentioned in the documentation that \poldef will be confused by this and that inner semi-colons could be set within braces {;} as a work-around. It was not clear from @@ -4187,12 +3771,12 @@ this work-around. With this relase only \PolDef needs the work-around.

      • -
      • track xintexpr 1.4e changes relative to powers.

      • +
      • track xintexpr 1.4e changes relative to powers.

    • v0.8.3 (2021/05/27)

        -
      • small internal update to track an xintexpr 1.4h change +

      • small internal update to track an xintexpr 1.4h change regarding handling of exceptions. Will require this version at least on loading.

      @@ -4209,14 +3793,23 @@ polynomials if original polynomial had no real root!

    • bugfix: support for the intfrom() function was in the code, but the declaration to the polynomial parser had not been done.

    • track (belatedly) upstream deprecation of \xintSignedFrac and -\xintSignedFwOver at xintexpr 1.4g

    • +\xintSignedFwOver at xintexpr 1.4g

      +
    + +
  • v0.8.6 (2022/01/09)

    +
  • -

    Acknowledgments

    -

    Thanks to Jürgen Gilg whose question about xintexpr usage for +

    Acknowledgments

    +

    Thanks to Jürgen Gilg whose question about xintexpr usage for differentiating polynomials was the initial trigger leading to this package, and to Jürgen Gilg and Thomas Söll for testing it on some concrete problems.

    diff --git a/macros/generic/polexpr/polexpr.sty b/macros/generic/polexpr/polexpr.sty index 04d189de8b..7d3dbb36bd 100644 --- a/macros/generic/polexpr/polexpr.sty +++ b/macros/generic/polexpr/polexpr.sty @@ -2,7 +2,7 @@ % License: LPPL 1.3c (author-maintained) % Usage: \input polexpr.sty (Plain or other macro formats) % or \usepackage{polexpr} (LaTeX macro format) -% Release 0.8.5 (2021/11/30) of polexpr.sty. This file inputs +% Release 0.8.6 (2022/01/09) of polexpr.sty. This file inputs % polexprcore.tex % polexprexpr.tex % polexprsturm.tex @@ -54,12 +54,12 @@ \XINTsetupcatcodes% (does \endlinechar13 in particular) \XINT_providespackage \ProvidesPackage{polexpr}% - [2021/05/27 v0.8.3 Polynomial expressions with rational coefficients (JFB)]% + [2022/01/09 v0.8.6 Polynomial expressions with rational coefficients (JFB)]% \begingroup \def\x#1/#2/#3 #4\xint:{#1#2#3}% \ifnum\expandafter\x\expanded{\csname ver@xintexpr.sty\endcsname}\xint: <20210527 % xint 1.4h - \immediate\write128{! Package polexpr error: xintexpr too old, aborting input}% + \errmessage{Package polexpr error: xintexpr too old, aborting input}% \else\expandafter\xint_gobble_i \fi \endinput\endgroup @@ -475,7 +475,7 @@ }% % %% Euclidean division -% now based on the expandable routine from polexprcore.tex +% since 0.8 based on the expandable routine from polexprcore.tex % \def\PolDivide#1#2#3#4{% #3=quotient, #4=remainder of #1 by #2 \POL@divide{#1}{#2}% diff --git a/macros/generic/polexpr/polexprcore.tex b/macros/generic/polexpr/polexprcore.tex index 3648bc8ccb..8dcc893844 100644 --- a/macros/generic/polexpr/polexprcore.tex +++ b/macros/generic/polexpr/polexprcore.tex @@ -1,7 +1,9 @@ -%% This file polexprcore.tex is part of the polexpr package (0.8.5, 2021/11/30) -%% Core routines to match infix operators +, -, *, //, /:, ^, ** and some -%% functions -%% The atoms representing polynomials inside \xintexpr are +%% filename: polexprcore.tex +%% Part of the polexpr package (0.8.6, 2022/01/09) +%% +%% Core routines for infix operators +, -, *, //, /:, ^, ** and functions +%% +%% Memo: the atoms representing polynomials inside \xintexpr are %% - for constants: a numeric value (indistinguishable. from scalars) %% - for degree at least 1: P.{c0}{c1}....{cN} with N = degree %% Auxiliaries diff --git a/macros/generic/polexpr/polexprexpr.tex b/macros/generic/polexpr/polexprexpr.tex index f3cc5ac28e..bbc860cbca 100644 --- a/macros/generic/polexpr/polexprexpr.tex +++ b/macros/generic/polexpr/polexprexpr.tex @@ -1,5 +1,7 @@ -%% This file polexprexpr.tex is part of the polexpr package (0.8.5, 2021/11/30) -%% Extending \xintexpr syntax: +%% filename: polexprexpr.tex +%% Part of the polexpr package (0.8.6, 2022/01/09) +%% +%% Polynomial extensions to the \xintexpr syntax: %% %% 1. Authorize ' in variable and function names %% This partially breaks infix operators 'and', 'or', 'xor', 'mod' diff --git a/macros/generic/polexpr/polexprsturm.tex b/macros/generic/polexpr/polexprsturm.tex index d590d48aa5..0edc8b8f0a 100644 --- a/macros/generic/polexpr/polexprsturm.tex +++ b/macros/generic/polexpr/polexprsturm.tex @@ -1,7 +1,11 @@ -%% This file polexprsturm.tex is part of the polexpr package (0.8.5, 2021/11/30) -%% Sturm Algorithm (polexpr 0.4) +%% filename: polexprsturm.tex +%% Part of the polexpr package (0.8.6, 2022/01/09) +%% +%% Implements the Sturm localization Algorithm +%% Added at polexpr 0.4 +%% %% 0.5 uses primitive polynomials for faster evaluations afterwards -%% 0.6 corrects misuse of \@ifstar! (mumble). \PolToSturm* was broken. +%% 0.6 corrects misuse of \@ifstar (mumble). \PolToSturm* was broken. %% 0.6's \PolToSturm* defines both normalized and unnormalized, the %% unnormalized using two underscores, so both are available %% Sole difference is that \PolToSturm* also declares them as @@ -9,19 +13,20 @@ %% holding the coefficients in memory %% 0.6 fixes the case of a constant polynomial P which caused division %% by zero error from P'. -%% 0.8 - fixes 0.7.5 failure to have updated to xint 1.4 format the defined -%% \xintexpr variables holding the localization intervals extremities -%% - also, it uses the prem() in computing the Sturm chain, for a 3X -%% speed gain in the case of the "perturbed" first Wilkinson example -%% +%% 0.8 - fixes 0.7.5 compatibility bug with xint 1.4 internal format +%% regarding the defined \xintexpr variables holding the localization +%% intervals extremities +%% - also, it uses the prem() in computing the Sturm chain, with a 3X +%% speed gain in the case of the "perturbed" first Wilkinson example +%% 0.8.6 has better a priori bounds for positive and negative roots \newcount\POL@count \newif\ifPOL@tosturm@makefirstprimitive\POL@tosturm@makefirstprimitivetrue \newif\ifPOL@isolz@nextwillneedrefine %% \def\PolToSturm{\POL@ifstar{\PolToSturm@@}{\PolToSturm@}}% \def\POL@aux@toint#1{\xintREZ{\xintNum{#1}}}% for polynomials with int. coeffs! -%% Attention that some macros rely upon this one setting \POL@sturmname -%% and \POL@sturm@N as it does +%% Attention that some macros rely upon this one defining \POL@sturmname +%% and \POL@sturm@N as it currently does \def\PolToSturm@#1#2{% \edef\POL@sturmname{#2}% % 0.6 uses 2 underscores (one before index, one after) to keep in memory @@ -61,11 +66,9 @@ }% \def\POL@tosturm@dosturm{% \POL@Diff@@one{\POL@sturmname _0_}{\POL@sturmname _1_}% - % re-utiliser \POL@varcoeffs directement? \POL@makeprimitive{\POL@sturmname _1_}% does not do \POL@newpol \POL@count\@ne \xintloop - % prior to 0.8, code was using here \POL@divide \POL@getprem{\POL@sturmname _\the\numexpr\POL@count-\@ne\relax _}% {\POL@sturmname _\the\POL@count _}% \expandafter\POL@split\POL@R;\POL@degR\POL@polR @@ -117,7 +120,8 @@ \POL@sturmchain@getSV@at\POL@sturmchain@X #1\let#2\POL@sturmchain@SV }% -\def\POL@sturmchain@getSV@at#1{% ATTENTION USES \POL@count +% attention that this modifies current \POL@count value +\def\POL@sturmchain@getSV@at#1{% \def\POL@sturmchain@SV{0}% \edef\POL@sturmchain@sign{\xintiiSgn{\POL@eval{\POL@sturmname _0}{#1}}}% \let\POL@isolz@lastsign\POL@sturmchain@sign @@ -166,7 +170,6 @@ {\PolSturmIsolateZerosGetMultiplicitiesAndRationalRoots}% {\PolSturmIsolateZerosAndGetMultiplicities@}% }% -% on aurait besoin de ça dans xint, mais il aurait un \xintRaw{#1} alors \def\POL@xintfrac@getNDE #1% {\expandafter\POL@xintfrac@getNDE@i\romannumeral`&&@#1}% \def\POL@xintfrac@getNDE@i #1/#2[#3]#4#5#6{\def#4{#1}\def#5{#2}\def#6{#3}}% @@ -196,10 +199,6 @@ \edef\POL@sturm@N{\@nameuse{PolSturmChainLength_\POL@sturmname}}% % isolate the roots (detects case of constant polynomial) \PolSturmIsolateZeros@{\POL@sturmname}% - % 0.8.4 fix: these declarations were formerly not executed in absence of roots! - % on ne va pas utiliser de Horner, mais des divisions par X - x, et ces - % choses vont évoluer, ainsi que le coefficient dominant entier - % (pour \POL@divide entre autres if faut des noms de user pol) \XINT_global \expandafter\let \csname POLuserpol@\POL@sturmname\POL@sqfnorr\expandafter\endcsname @@ -219,7 +218,6 @@ \begingroup\globaldefs\@ne \expandafter\POL@initarray\csname POL_ZM\POL@sturmname*\endcsname{1}% \endgroup - % attention formé avec\xintREZ d'où le \xintAbs pas \xintiiAbs % D and its exponent E will get updated along the way \edef\POL@findrat@D{\xintAbs{\PolLeadingCoeff{\POL@sturmname _0}}}% \POL@xintfrac@getNDE\POL@findrat@D\POL@findrat@Dint\POL@_\POL@findrat@Dexp @@ -227,12 +225,10 @@ {\let\POL@findrat@E\POL@findrat@Dexp} % aussi ok pour 1[0] {\edef\POL@findrat@E{\the\numexpr\xintLen{\POL@findrat@Dint}% +\POL@findrat@Dexp}}% -% ATTENTION QUE LA CONVENTION DE SIGNE POUR \POL@findrat@E EST OPPOSÉE À CELLE -% POUR LE CODE PLUS ANCIEN FAISANT "REFINE" \POL@initarray\POL@IfMultIsKnown\xint_secondoftwo \let\POL@findrat@nbofirrroots\POL@isolz@NbOfRoots % find all rational roots, and their multiplicities, - % factor them out in passing from original (Sturm root) polynomial + % factor them out from original (Sturm root) polynomial \ifnum\POL@findrat@E<7 % \def\POL@findrat@index{1}% \POL@findrat@loop@secondpass@direct @@ -252,7 +248,6 @@ \POL@newpol{\POL@sturmname\POL@norr}% with multiplicities }% \def\POL@findrat@doRRarray#1{% - % il faudrait un \xintAssignArray* qui fasse même expansion que \xintFor* \edef\POL@temp{% \xintiloop[1+1] \romannumeral0\csname POL_ZK\POL@sturmname*\xintiloopindex\endcsname @@ -261,8 +256,6 @@ \ifnum\xintiloopindex<\POL@isolz@NbOfRoots\space \repeat }% \begingroup\globaldefs\@ne - % attention de ne surtout pas faire un \expandafter ici, car en cas d'un - % seul item, \xintAssignArray l'unbraces... \xintAssignArray\POL@temp\to#1% \endgroup }% @@ -286,11 +279,6 @@ }% \def\POL@findrat@loop@decimal{% we have an already found decimal root % we do not go via @storeit, as it is already stored - % j'ai beaucoup hésité néanmoins, car je pourrais faire \xintIrr ici, - % mais attention aussi à l'interaction avec le \PolDecToString. Les racines - % trouvées directement (qui peuvent être des nombres décimaux) sont elles - % stockées comme fraction irréductibles (modulo action additionnelle de - % \PolDecToString). \POL@xintfrac@getNDE {\xintIrr{\POL@xintexprGetVar{\POL@sturmname L_\POL@findrat@index}}[0]}% \POL@findrat@xN\POL@findrat@xD\POl@_ @@ -313,15 +301,13 @@ \else\expandafter\xint_stop_atfirstoftwo \fi }% -\def\POL@findrat@getE #1/1[#2]{#2}% /1 as it should be there. -% so an error will arise if not but cf \POL@refine@getE where I did not put it +\def\POL@findrat@getE #1/1[#2]{#2}% \def\POL@findrat@loop@a{% % attention that the width may have been already smaller than 10^{-6} \POL@get@IsoLeft@rawin \POL@get@IsoRight@rawin \edef\POL@findrat@localW {\the\numexpr-\expandafter\POL@findrat@getE - % do I really need the \xintREZ? \romannumeral0\xintrez {\xintSub{\POL@IsoRight@rawin}{\POL@IsoLeft@rawin}}% }% at least 6, maybe larger @@ -364,9 +350,7 @@ \xintAssign \xintiiDivision\POL@findrat@gcdloop@Ap\POL@findrat@gcdloop@A \to\POL@findrat@gcdloop@B\POL@findrat@gcdloop@An - % on fait de la tambouille pour n'utiliser que \numexpr par la suite - % le reste @An est < 2.10^9 au pire donc ok pour \numexpr - % we will drop integral part in our updating P +% we will drop integral part in our updating P \let\POL@findrat@gcdloop@Binitial\POL@findrat@gcdloop@B \def\POL@findrat@gcdloop@B{0}% do as if B1 = 0 \def\POL@findrat@gcdloop@Pp{1}% P0 @@ -382,7 +366,6 @@ \POL@findrat@gcdloop@body }% \def\POL@findrat@gcdloop@body{% - % annoying that \numexpr has no divmod... use counts? but groups annoying \edef\POL@findrat@gcdloop@B {\the\numexpr(\POL@findrat@gcdloop@Ap+\POL@findrat@gcdloop@A/2)/% \POL@findrat@gcdloop@A - \@ne}% @@ -474,7 +457,8 @@ {\POL@xintexprGetVar{\POL@sturmname L_\POL@findrat@index}}}% \edef\POL@findrat@Rscaled{\xintMul{\POL@findrat@D}% {\POL@xintexprGetVar{\POL@sturmname R_\POL@findrat@index}}}% - \xintiiifNeg{\POL@findrat@Lscaled}% using ii version is an abuse +% using ii version is an abuse + \xintiiifNeg{\POL@findrat@Lscaled}% {% negative interval (right bound possibly zero!) % truncate towards zero (i.e. to the right) the left bound \edef\POL@findrat@Num{\xintNum{\POL@findrat@Lscaled}/1[0]}% @@ -572,13 +556,8 @@ % first get the GCD of remaining pol with its derivative \POL@divide{\POL@sturmname\POL@norr}{\POL@sturmname\POL@sqfnorr}% \expandafter\let - % attention au _ (cf. grosse astuce pour \POL@isolzmult@loop) \csname POLuserpol@@_1\POL@sturmname _\endcsname\POL@Q \ifnum\PolDegree{@_1\POL@sturmname _}>\z@ - % il reste des multiplicités (mais peut-être pour des racines complexes) - % (ou pour des racines en-dehors de l'intervalle optionnel) - % attention recyclage ici de \POL@isolzmult@loop qui dépend de - % la grosse astuce avec \@gobble \POL@makeprimitive{@_1\POL@sturmname _}% \let\POL@originalsturmname\POL@sturmname % trick to get isolzmult@loop to define @@lastGCD to @_1sturmname_ @@ -640,7 +619,7 @@ \fi }% \def\POL@isolzmult@defvar@M{% - % Attention that is used not only in ...GetMultiplicities@ but also + % Attention that this is used not only in ...GetMultiplicities@ but also % in FindRationalRoots \begingroup\xintglobaldefstrue % added at 0.7 @@ -739,7 +718,7 @@ % #1 optional E such that roots are searched in -10^E < x < 10^E % both -10^E and +10^E must not be roots! % #2 name of Sturm chain (already pre-computed from a given polynomial) - % For reasons I have forgotten (no time now) this code **must** be used + % For reasons I have forgotten this code **must** be used % with a *normalized* Sturm chain. \edef\POL@sturmname{#2}% \edef\POL@sturmlength{\PolSturmChainLength{#2}}% @@ -749,22 +728,23 @@ \POL@isolz@getsignchanges@plusinf \POL@isolz@getsignchanges@minusinf \else - \edef\POL@isolz@E{\the\numexpr\xint_zapspaces #1 \xint_gobble_i\relax}% - \POL@sturmchain@getSV@at{1[\POL@isolz@E]}% + \edef\POL@isolz@E@pos{\the\numexpr\xint_zapspaces #1 \xint_gobble_i\relax}% + \let\POL@isolz@E@neg\POL@isolz@E@pos + \POL@sturmchain@getSV@at{1[\POL@isolz@E@pos]}% \let\POL@isolz@plusinf@SV \POL@sturmchain@SV \let\POL@isolz@plusinf@sign\POL@sturmchain@sign - \POL@sturmchain@getSV@at{-1[\POL@isolz@E]}% + \POL@sturmchain@getSV@at{-1[\POL@isolz@E@neg]}% \let\POL@isolz@minusinf@SV \POL@sturmchain@SV \let\POL@isolz@minusinf@sign\POL@sturmchain@sign \ifnum\POL@isolz@plusinf@sign=\z@ \PackageError{polexpr}% -{The polynomial #2 vanishes at set upper bound 10^\POL@isolz@E}% -{Compile again with a bigger exponent in source. (X to abort).}% +{The polynomial #2 vanishes at set upper bound 10^\POL@isolz@E@pos}% +{Try again with a larger exponent. (X to abort).}% \fi \ifnum\POL@isolz@minusinf@sign=\z@ \PackageError{polexpr}% -{The polynomial #2 vanishes at set lower bound -10^\POL@isolz@E}% -{Compile again with a bigger exponent in source. (X to abort).}% +{The polynomial #2 vanishes at set lower bound -10^\POL@isolz@E@neg}% +{Try again with a larger exponent. (X to abort).}% \fi \fi \edef\POL@isolz@NbOfRoots @@ -792,7 +772,8 @@ }% \def\POL@initarray#1#2{% % ATTENTION, if only one item, \xintAssignArray UNBRACES IT -% so we use an \empty trick to avoid that. Maybe considered a bug of xinttools? +% (is this to be considered as a bug of xinttools?) +% We use an \empty trick to avoid that. \expandafter\xintAssignArray\expandafter\empty \romannumeral\xintreplicate{\POL@isolz@NbOfRoots}{{#2}}\to#1% }% @@ -836,9 +817,18 @@ \advance\POL@count\@ne \repeat }% -% utility macro for a priori bound on root decimal exponent, via Float Rounding -\def\POL@isolz@updateE #1e#2;% - {\unless\ifnum#2<\POL@isolz@E\space\edef\POL@isolz@E{\the\numexpr#2+\@ne}\fi}% +% This utility macro bounds positive roots (strictly) by a 10^Epos +% and negative roots strictly by some -10^Eneg. +% (prior to 0.8.6, an E was found with -10^E < all roots < 10^E) +% To obtain Epos, the Cauchy bound "1 + max_j {-a_j/lc(P)|}" +% is used, where non-negative a_j/lc(P)'s are ignored. +% In case the a_j's all have same sign as lc(P) or vanish, there are +% no positive roots. And the macro in this case outputs an E=0 exponent. +% But if at least one non-zero a_j has opposite sign to the leading coeff, +% the produced E will be at least 1. +% Thus if E=0 on exit, it is proof that there are no (positive) roots. +\def\POL@isolz@updateE #1;% + {\unless\ifnum#1<\POL@isolz@E\space\edef\POL@isolz@E{\the\numexpr#1+\@ne}\fi}% \def\POL@isolz@getaprioribound{% \PolAssign{\POL@sturmname _0}\toarray\POL@arrayA \edef\POL@isolz@leading{\POL@arrayA{\POL@arrayA{0}}}% @@ -849,19 +839,47 @@ \expandafter\edef\csname POL@arrayA\the\POL@count\endcsname {\xintDiv{\POL@arrayA\POL@count}\POL@isolz@leading}% \repeat - \def\POL@isolz@E{1}% WE SEEK SMALLEST E SUCH HAT -10^E < roots < +10^E +% We want an E such that 0 < positive roots < +10^E + \def\POL@isolz@E{0}% \advance\POL@count\m@ne \xintloop \ifnum\POL@count>\z@ - \expandafter\POL@isolz@updateE - % use floating point to get decimal exponent - \romannumeral0\xintfloat[4]% should I use with [2] rather? (should work) - {\xintAdd{1/1[0]}{\xintAbs{\POL@arrayA\POL@count}}};% +% only those coefficients with opposite sign to the leading coefficient +% trigger an E update + \xintiiifSgn{\POL@arrayA\POL@count}% + {\expandafter\POL@isolz@updateE + \the\numexpr\xintilogten{\xintAdd{1/1[0]}{\xintiiOpp{\POL@arrayA\POL@count}}};% + }{}{}% \advance\POL@count\m@ne \repeat - % \ifxintverbose\xintMessage{polexpr}{Info}% - % {Roots a priori bounded in absolute value by 10 to the \POL@isolz@E.}% - % \fi + \let\POL@isolz@E@pos\POL@isolz@E +% We want an E such that 0 > negative roots > -10^E + \def\POL@isolz@E{0}% + \POL@count\POL@arrayA{0}\relax + \advance\POL@count\m@ne + \xintloop + \ifnum\POL@count>\@ne + \xintiiifSgn{\xintiiOpp{\POL@arrayA\POL@count}}% + {\expandafter\POL@isolz@updateE + \the\numexpr\xintilogten{\xintAdd{1/1[0]}{\POL@arrayA\POL@count}};% + }{}{}% + \advance\POL@count\m@ne + \xintiiifSgn{\POL@arrayA\POL@count}% + {\expandafter\POL@isolz@updateE + \the\numexpr\xintilogten{\xintAdd{1/1[0]}{\xintiiOpp{\POL@arrayA\POL@count}}};% + }{}{}% + \advance\POL@count\m@ne + \repeat + \ifnum\POL@count=\@ne + \xintiiifSgn{\xintiiOpp{\POL@arrayA\POL@count}}% + {\expandafter\POL@isolz@updateE + \the\numexpr\xintilogten{\xintAdd{1/1[0]}{\POL@arrayA\POL@count}};% + }{}{}% + \fi + \let\POL@isolz@E@neg\POL@isolz@E + \ifxintverbose + \xintMessage{polexpr}{Info}{Epos=\POL@isolz@E@pos, Eneg=\POL@isolz@E@neg.}% + \fi }% \def\POL@IsoRight@raw{\POL@IsoRight@Int/1[\POL@isolz@E]}% \def\POL@IsoLeft@raw {\POL@IsoLeft@Int/1[\POL@isolz@E]}% @@ -875,8 +893,6 @@ {\POL@IsoLeft@Int/1[\POL@isolz@E]}% }% \def\POL@isolz@main {% -% NOTE 2018/02/16. THIS WILL PRESUMABLY BE RE-ORGANIZED IN FUTURE TO DO -% FIRST POSITIVE ROOTS THEN NEGATIVE ROOTS VIA CHANGE OF VARIABLE TO OPPOSITE. \global\POL@isolz@nextwillneedrefinefalse \def\POL@IsoRight@Int{0}% \POL@sturmchain@getSV@at\POL@IsoRight@raw @@ -899,12 +915,13 @@ % \POL@IsoRight@SV was modified if zero is a root \edef\POL@isolz@NbOfNegRoots{\the\numexpr\POL@IsoLeftSV-\POL@IsoRightSV}% \gdef\POL@isolz@IntervalIndex{0}% - \let\POL@isolz@@E\POL@isolz@E +% 0.8.6 has separate initial E's for positive and negative roots + \let\POL@isolz@E\POL@isolz@E@neg \ifnum\POL@isolz@NbOfNegRoots>\z@ -% refactored at 0.7 to fix cases leading to an intervals with zero as end-point +% refactored at 0.7 to fix cases leading to intervals having zero as end-point \POL@isolz@findroots@neg \fi - \let\POL@isolz@E\POL@isolz@@E + \let\POL@isolz@E\POL@isolz@E@pos \def\POL@IsoLeft@Int{0}% \let\POL@IsoLeftSV \POL@IsoAtZeroSV % véritable SV en zéro \let\POL@IsoLeftSign\POL@IsoAtZeroSign% véritable signe en zéro @@ -973,10 +990,6 @@ \repeat }% \def\POL@isolz@findroots@pos{% - % remark (2018/12/08), this needs some refactoring, I hardly understand - % the logic and it hides most into the recursion done by \POL@isolz@check - % It would probably make more sense to proceed like done for the negative - % but here finding the largest roots first. \def\POL@IsoRight@Int{1}% \POL@isolz@findnextzeroboundeddecade@pos \unless\ifnum\POL@IsoRightSV=\POL@IsoLeftSV\space @@ -985,7 +998,7 @@ % and none are larger \POL@isolz@check % will recurse inside groups if needed with modified E \fi - % we know get the roots in the last 9 decades from 10^{e-1} to 10^{e} + % we now get the roots in the last 9 decades from 10^{e-1} to 10^{e} % we should arguably do a more efficient dichotomy here \def\POL@IsoLeft@Int{1}% \let\POL@IsoLeftSV\POL@IsoRightSV @@ -1101,14 +1114,6 @@ \ifnum\POL@IsoRightSign=\POL@@IsoRightSign\space \repeat % now second root has been separated from the one at left end point -% we update the storage of the root at left for it to have the same number -% of digits in mantissa. No, I decided not to do that to avoid complications. - % \begingroup - % \let\POL@IsoRight@Int\POL@IsoLeft@Int - % \def\POL@IsoRightSign{0}% - % \edef\POL@isolz@IntervalIndex{\the\numexpr\POL@isolz@IntervalIndex-\@ne}% - % \POL@refine@storeleftandright - % \endgroup \edef\POL@@IsoRight@Int{\xintDSL{\xintInc{\xintDSR{\POL@IsoLeft@Int}}}}% \let\POL@IsoLeft@Int\POL@IsoRight@Int \let\POL@IsoLeftSign\POL@IsoRightSign @@ -1128,7 +1133,7 @@ % the IsoRightSign is now wrong but here we don't care \fi\fi \fi - % on exit, exact root found iff \POL@IsoRightSign is zero + % on exit, exact root has been found iff \POL@IsoRightSign is zero \POL@refine@storeleftandright \endgroup }% @@ -1224,7 +1229,6 @@ \fi \begingroup\xintglobaldefstrue % skip some overhead of \xintdefvar... - % Let me repeat: ATTENTION to change of internal format at xint 1.4 \XINT_expr_defvar_one{\POL@sturmname L_\POL@isolz@IntervalIndex}% {{\POL@IsoLeft@rawout}}% \XINT_expr_defvar_one{\POL@sturmname R_\POL@isolz@IntervalIndex}% @@ -1235,7 +1239,6 @@ \endgroup }% %% \PolRefineInterval -%% ATTENTION TO xint 1.4 INTERNAL CHANGES \def\POL@xintexprGetVar#1{\expandafter\expandafter\expandafter\xint_firstofone \csname XINT_expr_varvalue_#1\endcsname}% % attention, also used by \POL@findrat@loop@a @@ -1346,9 +1349,6 @@ % % \def\PolIntervalWidth#1#2{% -% le \xintRez est à cause des E positifs, car trailing zéros explicites -% si je travaillais à partir des variables xintexpr directement ne devrait -% pas être nécessaire, mais trop fragile par rapport à chgt internes possibles \romannumeral0\xintrez{\xintSub{\@nameuse{POL_ZR#1*}{#2}}% {\@nameuse{POL_ZL#1*}{#2}}} }% @@ -1363,7 +1363,8 @@ }% \def\POL@ensureintervallengths{% \POL@count\z@ - % \POL@count used by \POL@sturmchain@getSV@at but latter not used + % attention that \POL@count would be modified by \POL@sturmchain@getSV@at + % but this latter macro not invoked by \POL@ensure@one \xintloop \advance\POL@count\@ne \edef\POL@isolz@IntervalIndex{\the\POL@count}% @@ -1377,11 +1378,8 @@ \edef\POL@sturmname{#1}% \edef\POL@ensure@targetE{\the\numexpr#3}% \edef\POL@isolz@IntervalIndex{\the\numexpr#2}% -% peut-être autoriser -1, -2, ... ? \ifnum\POL@isolz@IntervalIndex>\z@ -% 0.7, add this safeguard but attention means this structure must be in place \ifnum\csname POL_ZL\POL@sturmname*0\endcsname>\z@ -% je ne fais pas les \expandafter mais je préfèrerais ne pas être à l'intérieur \POL@ensure@one \fi \fi @@ -1438,8 +1436,9 @@ \catcode`_ 8 % \catcode`& 4 % \def\PolPrintIntervals{\POL@ifstar{\PolPrintIntervals@@}{\PolPrintIntervals@}}% -% As explained in the docs, this is an example of customization so is not -% itself customizable, apart from redefining it entirely! +% As explained in the docs, the starred version is an example of customization +% It is itself basically not easily customizable, except for this: +\def\PolPrintIntervals@@arraystretch{2}% (the 2 was hardcoded prior to 0.8.6) \def\PolPrintIntervals@@{% \begingroup \def\POL@AfterPrintIntervals{\endgroup}% @@ -1447,14 +1446,14 @@ \let\PolPrintIntervalsUnknownRoot\POL@@PrintIntervalsUnknownRoot \let\PolPrintIntervalsKnownRoot\POL@@PrintIntervalsKnownRoot \ifdefined\array - \def\arraystretch{2}% + \let\arraystretch\PolPrintIntervals@@arraystretch \def\PolPrintIntervalsBeginEnv{\[\begin{array}{cl}}%\] \def\PolPrintIntervalsEndEnv{\end{array}\]}% \else \def\PolPrintIntervalsBeginEnv{$$\tabskip0pt plus 1000pt minus 1000pt \halign to\displaywidth\bgroup - \hfil\vrule height 2\ht\strutbox - depth 2\dp\strutbox + \hfil\vrule height \PolPrintIntervals@@arraystretch\ht\strutbox + depth \PolPrintIntervals@@arraystretch\dp\strutbox width \z@ $####$\tabskip6pt&$####$\hfil \tabskip0pt plus 1000pt minus 1000pt\cr}%$$ @@ -1476,6 +1475,10 @@ \begingroup\edef\POL@tmp{\endgroup \unexpanded\expandafter{\PolPrintIntervalsBeginEnv}% \unexpanded\expandafter{\POL@PrintIntervals@Loop}% +% This is added at 0.8.6 to allow usage of amsmath environment as they typeset +% twice: we must prepare for a second execution. Adds slight general overhead. + \gdef\noexpand\PolPrintIntervalsTheIndex{1}% + \noexpand\POL@PrintIntervals@DoDefs \unexpanded\expandafter{\PolPrintIntervalsEndEnv}% }\POL@tmp \fi @@ -1485,7 +1488,7 @@ }% \let\POL@AfterPrintIntervals\empty \let\PolPrintIntervalsNoRealRoots\empty -\def\PolPrintIntervalsArrayStretch{1}% +\def\PolPrintIntervalsArrayStretch{1}% used by non-starred version \ifdefined\array \def\PolPrintIntervalsBeginEnv{\[\begin{array}{rcccl}}% \def\PolPrintIntervalsEndEnv{\end{array}\]}% @@ -1558,7 +1561,6 @@ }% \catcode`& 7 % \catcode`_ 11 % -\def\POL@PrintIntervals@Loop#1{% \def\POL@PrintIntervals@Loop{% \POL@SturmIfZeroExactlyKnown\PolPrintIntervalsTheSturmName \PolPrintIntervalsTheIndex @@ -1568,10 +1570,15 @@ \unless\ifnum\PolPrintIntervalsTheIndex> \@nameuse{POL_ZL\PolPrintIntervalsTheSturmName*0} \POL@PrintIntervals@DoDefs - \xint_afterfi{#1\POL@PrintIntervals@Loop}% + \xint_afterfi{\PolPrintIntervalsRowSeparator\POL@PrintIntervals@Loop}% \fi -}}% -\ifdefined\array\POL@PrintIntervals@Loop{\\}\else\POL@PrintIntervals@Loop{\cr}\fi +}% +% added at 0.8.6: +\ifdefined\array + \def\PolPrintIntervalsRowSeparator{\\}% +\else + \def\PolPrintIntervalsRowSeparator{\cr}% +\fi \def\POL@PrintIntervals@DoDefs{% \xdef\PolPrintIntervalsTheLeftEndPoint{% \csname POL_ZL\PolPrintIntervalsTheSturmName*\PolPrintIntervalsTheIndex -- cgit v1.2.3