diff options
Diffstat (limited to 'Master/texmf-dist/tex/generic/polexpr/polexprsturm.tex')
-rw-r--r-- | Master/texmf-dist/tex/generic/polexpr/polexprsturm.tex | 211 |
1 files changed, 109 insertions, 102 deletions
diff --git a/Master/texmf-dist/tex/generic/polexpr/polexprsturm.tex b/Master/texmf-dist/tex/generic/polexpr/polexprsturm.tex index d590d48aa56..0edc8b8f0a2 100644 --- a/Master/texmf-dist/tex/generic/polexpr/polexprsturm.tex +++ b/Master/texmf-dist/tex/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 |