From c7531f5b2309ae03216e21e4f57faa2d1240be62 Mon Sep 17 00:00:00 2001 From: Karl Berry Date: Sat, 1 Feb 2020 22:17:01 +0000 Subject: polexpr (1feb20) git-svn-id: svn://tug.org/texlive/trunk@53633 c570f23f-e606-0410-a88d-b1316a301751 --- Master/texmf-dist/tex/latex/polexpr/polexpr.sty | 424 ++++++++++++++++++------ 1 file changed, 321 insertions(+), 103 deletions(-) (limited to 'Master/texmf-dist/tex/latex/polexpr') diff --git a/Master/texmf-dist/tex/latex/polexpr/polexpr.sty b/Master/texmf-dist/tex/latex/polexpr/polexpr.sty index e9509d89428..30fef289141 100644 --- a/Master/texmf-dist/tex/latex/polexpr/polexpr.sty +++ b/Master/texmf-dist/tex/latex/polexpr/polexpr.sty @@ -1,33 +1,178 @@ % author: Jean-François Burnol % License: LPPL 1.3c (author-maintained) \ProvidesPackage{polexpr}% - [2019/02/12 v0.7.4 Polynomial expressions with rational coefficients (JFB)]% -\RequirePackage{xintexpr}[2018/06/17]% xint 1.3c for \ifxintglobaldefs boolean -\edef\POL@restorecatcodes + [2020/01/31 v0.7.5 Polynomial expressions with rational coefficients (JFB)]% +\RequirePackage{xintexpr}[2020/01/31]% xint 1.4 +\edef\POL@restorecatcodes % TODO: think better about what is reasonable here {\catcode`\noexpand\_ \the\catcode`\_ % \catcode`\noexpand\! \the\catcode`\! % \catcode`\noexpand\* \the\catcode`\* % + \catcode`\noexpand\~ \the\catcode`\~ % + \catcode`\noexpand\: \the\catcode`\: % \catcode0 \the\catcode0\relax}% \catcode`\_ 11 \catcode0 12 \catcode`\* 12 \long\def\xint_stop_atfirstoftwo #1#2{ #1}% not yet in xint 1.3c \long\def\xint_stop_atsecondoftwo #1#2{ #2}% -%% PATCH xintexpr TO AUTHORIZE ' IN NAMES (0.5.1) -\catcode`\! 11 +%% 0.7.5 VERY SERIOUS TROUBLES TO GET polexpr TO WORK WITH xintexpr 1.4 + +%% I hesitated about incorporating it directly into xint 1.4 +%% Don't do this at home, only xint gurus are allowed. +\let\POL@originalXINT_expr_redefinemacros\XINT_expr_redefinemacros +\def\XINT_expr_redefinemacros +{% + \POL@originalXINT_expr_redefinemacros + \POL@activateNEhook +}% +%% Using \def's and not \let's to get better readable trace +%% in case I need to debug but this never happens +\def\POL@activateNEhook@xint % done in a group +{% + \def\POL@NEhook@polfunc{\POL@NE@polfunc}% +}% +\def\POL@activateNEhook@pol +{% + \def\POL@NEhook@polfunc{\POL@NP@polfunc}% +}% +\def\POL@activateNEhook{\POL@activateNEhook@xint}% +% +% +\catcode`~ 12 +\catcode`! 11 +\catcode`: 11 +% We drop consideration of \XINT_global matters +% because we have other more urgent and arduous problems +\def\POL@defpolfunc #1#2% +{% + \expandafter\POL@defpolfunc_a + \csname XINT_#2_func_#1\expandafter\endcsname + \csname XINT_#2_polfunc_#1\endcsname {#1}{#2}% +}% +\def\POL@defpolfunc_a #1#2#3#4% +{% + \protected % xintexpr 1.4 does things such as \expandafter\xintAdd\expanded + \expandafter\def\expandafter#2\expandafter##\expandafter1\expandafter + {% + #2{##1}% + }% + \def#1##1##2##3% + {% + % put it directly at the correct level of bracing + % don't worry for now about minimizing how many times ##3 is grabbed + \expandafter##1\expandafter##2\expandafter{\expandafter + {\romannumeral`^^@\POL@NEhook@polfunc{XINT_#4_polfunc_#3}#2{##3}}}% + }% +}% +% +\def\POL@polfunc@go #1#2#3{#2#3}% brace stripping intentional +\def\POL@NEhook@polfunc{\POL@polfunc@go}% default for pure numerics +% +% Hook for expansion in \poldef +\def\POL@NP@polfunc #1{% +\def\POL@NP@polfunc ##1##2##3% +{% + \if0\expandafter\XINT:NE:hastilde\detokenize{##3}~!\relax + \expandafter\XINT:NE:hashash\detokenize{##3}#1!\relax 0% + \expandafter\POL@polfunc@go + \else + \expandafter\POL:NP:polfunc:p + \fi {##1}{##2}{##3}% +}}\expandafter\POL@NP@polfunc\string#% +\def\POL:NP:polfunc:p #1#2#3% +{% + ~romannumeral~POL:usepolfunc:pol{#1}{#3}% +}% +\def\POL:usepolfunc:pol #1%#2% +{% +% Here we are in the core of \poldef and we really +% need to get rid of some \expanded tokens so +% we accept being exposed to \expanded but arrange to +% remain invariant. Then we will try to speed up +% polynomial composition (at this time the \#1 +% is a nested Horner type macro) by «pre-expanding» +% the argument, but this means using the \POL@get +% methods inside an \hbox +% +% \POL@applypolfunc will be defined \protected +% + \expandafter\xint_c_\expandafter\POL@applypolfunc +% This will be \protected + \csname#1\endcsname +% #2% brace stripping is deliberate +}% +% +% Hook for expansion in \xintexpr +\def\POL@NE@polfunc #1{% +\def\POL@NE@polfunc ##1##2##3% +{% + \if0\expandafter\XINT:NE:hastilde\detokenize{##3}~!\relax + \expandafter\XINT:NE:hashash\detokenize{##3}#1!\relax 0% + \expandafter\POL@polfunc@go + \else + \expandafter\POL:NE:polfunc:p + \fi {##1}{##2}{##3}% +}}\expandafter\POL@NE@polfunc\string#% +\def\POL:NE:polfunc:p #1#2#3% +{% + ~romannumeral~POL:usepolfunc:xint{#1}{#3}% +}% +\def\POL:usepolfunc:xint #1% +{% +% This is done to overcome \protected and is useful +% in case the polynomial function ends up nested +% in some non-polynomial user declared function +% as the latter (and other things) tries to pre-expand +% its arguments (as they may be used multiple time) +% using \expanded, but \#1 is protected. +% And this works recursively. We are inside braces. +% However we have a very big problem with constant +% polynomial functions. We have to handle them +% in a special way. + -`0\csname#1\expandafter\endcsname\expanded +}% +\catcode`~ 13 +\catcode`: 12 + + +%% Start defining some \protected ones here +\protected\def\POL@empty{}% +\newif\ifPOL@pol +\protected\def\POL@polglobaltrue {\global\let\ifPOL@pol\iftrue}% +\protected\def\POL@polglobalfalse{\global\let\ifPOL@pol\iffalse}% + + +%% Patch xintexpr to authorize ' in names (0.5.1) +%% Adapted 0.7.5 to follow-up on xintexpr 1.4 internal changes +%% (much simpler than previous stuff...) +%% This allows ' as a character in a polynomial name (not initial one) \def\POL@XINT_expr_scanfunc_b #1% {% - \ifx !#1\xint_dothis{(_}\fi - \ifcat \relax#1\xint_dothis{(_}\fi - \if (#1\xint_dothis{\xint_firstoftwo{(`}}\fi - \if '#1\xint_dothis \XINT_expr_scanfunc_a \fi - \if @#1\xint_dothis \XINT_expr_scanfunc_a \fi - \if _#1\xint_dothis \XINT_expr_scanfunc_a \fi - \ifnum \xint_c_ix<1\string#1 \xint_dothis \XINT_expr_scanfunc_a \fi - \ifcat a#1\xint_dothis \XINT_expr_scanfunc_a \fi - \xint_orthat {(_}% - #1% + \ifcat \relax#1\xint_dothis{\iffalse{\fi}(_#1}\fi + \if (#1\xint_dothis{\iffalse{\fi}(`}\fi + \if 1\ifcat a#10\fi + \ifnum\xint_c_ix<1\string#1 0\fi + \if @#10\fi + \if _#10\fi + \if '#10\fi + 1% + \xint_dothis{\iffalse{\fi}(_#1}\fi + \xint_orthat {#1\XINT_expr_scanfunc_a}% }% + +%% Activate polexp's modified xintexpr (only during definitions +%% of polynomials) +\def\POL@hackxintexpr {% + \let\POL@originalXINT_expr_scanfunc_b\XINT_expr_scanfunc_b + \let\XINT_expr_scanfunc_b\POL@XINT_expr_scanfunc_b + \def\POL@activateNEhook{\POL@activateNEhook@pol}% +}% +\def\POL@restorexintexpr {% + \let\XINT_expr_scanfunc_b\POL@originalXINT_expr_scanfunc_b + \def\POL@activateNEhook{\POL@activateNEhook@xint}% +}% + + %% AUXILIARIES \catcode`! 3 %% added at 0.7 @@ -46,7 +191,6 @@ \polexprsetup{norr=_norr, sqfnorr=_sqf_norr} \newcount\POL@count -\newif\ifPOL@pol \newif\ifxintveryverbose \newif\ifpoltypesetall \newif\ifPOL@tosturm@makefirstprimitive @@ -54,7 +198,7 @@ \newif\ifPOL@isolz@nextwillneedrefine \newif\ifpoltoexprall %% the main exchange structure (stored in macros \POLuserpol@) -%% is: degree.\empty{coeff0}{coeff1}....{coeffN} +%% is: degree.\POL@empty{coeff0}{coeff1}....{coeffN} %% (degree=N except zero polynomial recognized from degree set to -1 %% but it has always the {0/1[0]} coeff0.) \def\POL@ifZero#1{\expandafter\POL@ifZero@aux#1;}% @@ -67,13 +211,17 @@ % \def\POL@resultfromarray #1{% ATTENTION, **MUST** be executed with % \count@ set to 1 + degree (\count@ = 0 for zero polynomial) - \edef\POL@result{\ifnum\count@>\z@ - \the\numexpr\count@-\@ne.\noexpand\empty +% Attention to the \protected here at 0.7.5 +% They are many all over the place + \protected\edef\POL@result{\ifnum\count@>\z@ + \the\numexpr\count@-\@ne.\POL@empty \xintiloop [1+1]% \expandafter\POL@braceit\csname POL@array#1\xintiloopindex\endcsname \ifnum\xintiloopindex<\count@ \repeat - \else-1.\noexpand\empty{0/1[0]}\fi}% +% Attention to this \protected\POL@empty +% They are many all over the place + \else-1.\POL@empty{0/1[0]}\fi}% }% \def\POL@braceit#1{{#1}}% needed as \xintiloopindex can not "see" through braces @@ -85,12 +233,11 @@ \POL@restoresemicolon \edef\POL@tmp{\ifxintverbose1\else0\fi}% \unless\ifxintveryverbose\xintverbosefalse\fi - \let\POL@originalXINT_expr_scanfunc_b\XINT_expr_scanfunc_b - \let\XINT_expr_scanfunc_b\POL@XINT_expr_scanfunc_b + \POL@hackxintexpr \xintdeffunc __pol(#2):=0+(#4);% force conversion to raw if a constant + \POL@restorexintexpr \if1\POL@tmp\xintverbosetrue\fi \edef\POL@polname{\xint_zapspaces #1 \xint_gobble_i}% - \let\XINT_expr_scanfunc_b\POL@originalXINT_expr_scanfunc_b \begingroup \setbox0\hbox{% \let\xintScalarAdd\xintAdd @@ -107,48 +254,79 @@ \def\xintSub ##1##2{\xintAdd{##1}{\xintOpp{##2}}}% % \xintAdd{0} to get \POL@result defined even if numerical only expression % I could also test \ifPOL@pol, but this is anyhow small overhead - \xintAdd{0}% - {\csname XINT_expr_userfunc___pol\endcsname - {\global\POL@poltrue\def\POL@result{1.\empty{0/1[0]}{1/1[0]}}}}% +% Attention that xintexpr 1.4 has braces all over the place + \expandafter\xintAdd\expandafter{\expandafter0\expandafter}% + \romannumeral0\csname XINT_expr_userfunc___pol\endcsname + {\POL@polglobaltrue\protected\def\POL@result{1.\POL@empty{0/1[0]}{1/1[0]}}}% \expandafter}\expandafter \endgroup\expandafter \def\csname POLuserpol@\POL@polname\expandafter\endcsname \expandafter{\POL@result}% \expandafter\POL@newpol\expandafter{\POL@polname}% }% -%% +% + + \def\POL@newpol#1{% - \expandafter\POL@ifZero\csname POLuserpol@#1\endcsname - {\@namedef{XINT_expr_userfunc_#1}##1{0/1[0]}}% - {\POL@newpolhorner{#1}}% - \expandafter\XINT_expr_defuserfunc - \csname XINT_expr_func_#1\endcsname{#1}{expr}% +%% We must handle specially constant polynomials because they must +%% be made to work expandably in \poldef of other polynomials due +%% to complicated matters having to do with the \POL@ifpol conditional + \ifnum\PolDegree{#1}<\@ne + % non-zero constant + % I am defining this one only for the Info message, no time now + \expandafter\edef\csname XINT_expr_polfunc_#1\endcsname + ##1{\PolNthCoeff{#1}{0}}% + % No hooks here! + \expandafter\edef\csname XINT_expr_func_#1\endcsname ##1##2##3% + {##1##2{{\PolNthCoeff{#1}{0}}}}% + \else + % polynomial of degree at least 1. This means that mechanism + % to get \POL@result will get activated and we must be very careful + % to never \edef when the Horner macro will be converted to + % a polynomial + \POL@newpolhorner{#1}% + \POL@defpolfunc{#1}{expr}% + \fi \expandafter\let\csname XINT_flexpr_func_#1\endcsname\@undefined \ifxintverbose\POL@info{#1}\fi }% \def\POL@newfloatpol#1{% - \expandafter\POL@ifZero\csname POLuserpol@#1\endcsname - {\@namedef{XINT_flexpr_userfunc_#1}##1{0[0]}}% - {\POL@newfloatpolhorner{#1}}% - \expandafter\XINT_expr_defuserfunc - \csname XINT_flexpr_func_#1\endcsname{#1}{flexpr}% +%% We must handle specially constant polynomials because they must +%% be made to work expandably in \poldef of other polynomials due +%% to complicated matters having to do with the \POL@ifpol conditional + \ifnum\PolDegree{#1}<\@ne + % non-zero constant + % I am defining this one only for the Info message, no time now + \expandafter\edef\csname XINT_flexpr_polfunc_#1\endcsname + ##1{\PolNthCoeff{#1}{0}}% + % No hooks here! + \expandafter\edef\csname XINT_flexpr_func_#1\endcsname ##1##2##3% + {##1##2{{\PolNthCoeff{#1}{0}}}}% + \else + % polynomial of degree at least 1. This means that mechanism + % to get \POL@result will get activated and we must be very careful + % to never \edef when the Horner macro will be converted to + % a polynomial + \POL@newfloatpolhorner{#1}% + \POL@defpolfunc{#1}{flexpr}% + \fi \ifxintverbose\POL@floatinfo{#1}\fi }% \def\POL@info #1{% \xintMessage {polexpr}{Info}% {Function #1 for the \string\xintexpr\space parser is - associated to \string\XINT_expr_userfunc_#1\space + associated to \string\XINT_expr_polfunc_#1\space whose meaning uses Horner scheme: \expandafter\meaning - \csname XINT_expr_userfunc_#1\endcsname}% + \csname XINT_expr_polfunc_#1\endcsname}% }% \def\POL@floatinfo #1{% \xintMessage {polexpr}{Info}% {Function #1 for the \string\xintfloatexpr\space parser is - associated to \string\XINT_flexpr_userfunc_#1\space + associated to \string\XINT_flexpr_polfunc_#1\space whose meaning uses Horner scheme: \expandafter\meaning - \csname XINT_flexpr_userfunc_#1\endcsname}% + \csname XINT_flexpr_polfunc_#1\endcsname}% }% % \def\POL@newpolhorner#1{% @@ -162,7 +340,7 @@ \expandafter\POL@newpol@horner\POL@var@coeffs\relax \expandafter \endgroup - \expandafter\def\csname XINT_expr_userfunc_#1\expandafter\endcsname + \expandafter\def\csname XINT_expr_polfunc_#1\expandafter\endcsname \expandafter##\expandafter1\expandafter{\POL@tmp{##1}}% }% \def\POL@newfloatpolhorner#1{% @@ -176,7 +354,7 @@ \expandafter\POL@newpol@floathorner\POL@var@coeffs\relax \expandafter \endgroup - \expandafter\def\csname XINT_flexpr_userfunc_#1\expandafter\endcsname + \expandafter\def\csname XINT_flexpr_polfunc_#1\expandafter\endcsname \expandafter##\expandafter1\expandafter{\POL@tmp{##1}}% }% \def\POL@newpol@horner#1{\let\xintAdd\relax\let\xintMul\relax @@ -211,10 +389,9 @@ \def\POL@let#1#2{% \expandafter\let\csname POLuserpol@#1\expandafter\endcsname \csname POLuserpol@#2\endcsname - \expandafter\let\csname XINT_expr_userfunc_#1\expandafter\endcsname - \csname XINT_expr_userfunc_#2\endcsname - \expandafter\XINT_expr_defuserfunc - \csname XINT_expr_func_#1\endcsname{#1}{expr}% + \expandafter\let\csname XINT_expr_polfunc_#1\expandafter\endcsname + \csname XINT_expr_polfunc_#2\endcsname + \POL@defpolfunc{#1}{expr}% \ifxintverbose\POL@info{#1}\fi }% \newcommand\PolGlobalLet[2]{\begingroup @@ -259,7 +436,7 @@ \def\POL@getfromarray#1#2{% \count@=#2{0} %<- intentional space \ifnum\count@=\z@ - \def\POL@result{-1.\empty{0/1[0]}}% 0.5 fix for empty array + \protected\def\POL@result{-1.\POL@empty{0/1[0]}}% 0.5 fix for empty array \else \xintloop \edef\POL@tmp{#2{\count@}}% @@ -283,7 +460,7 @@ \repeat \count@\count\tw@ \def\POL@tmp##1.{{\csname POL@tmparray##1\endcsname}}% - \edef\POL@result{\the\numexpr\count@-\@ne.\noexpand\empty + \protected\edef\POL@result{\the\numexpr\count@-\@ne.\POL@empty \xintiloop[1+1]% \expandafter\POL@tmp\xintiloopindex.% \ifnum\xintiloopindex<\count@ @@ -480,7 +657,7 @@ {\ifnum\POL@degB<\z@ \expandafter\xint_firstoftwo\else\expandafter\xint_secondoftwo \fi - {\def\POL@result{-1.\empty{0/1[0]}}}% + {\protected\def\POL@result{-1.\POL@empty{0/1[0]}}}% {\xintAssignArray\POL@polB\to\POL@arrayB \POL@normalize{B}% \POL@gcd@exit BA}}% @@ -606,11 +783,11 @@ \expandafter\expandafter\expandafter\POL@split \csname POLuserpol@#1\endcsname;\POL@var@deg\POL@var@coeffs \ifnum\POL@var@deg<\@ne - \@namedef{POLuserpol@#2}{-1.\empty{0/1[0]}}% + \@namedef{POLuserpol@#2}{-1.\POL@empty{0/1[0]}}% \else \edef\POL@var@coeffs{\expandafter\POL@diff\POL@var@coeffs\relax}% \expandafter\edef\csname POLuserpol@#2\endcsname - {\the\numexpr\POL@var@deg-\@ne.\noexpand\empty\POL@var@coeffs}% + {\the\numexpr\POL@var@deg-\@ne.\POL@empty\POL@var@coeffs}% \fi }% % lazy way but allows to share with AntiDiff @@ -666,11 +843,11 @@ \expandafter\expandafter\expandafter\POL@split \csname POLuserpol@#1\endcsname;\POL@var@deg\POL@var@coeffs \ifnum\POL@var@deg<\z@ - \@namedef{POLuserpol@#2}{-1.\empty{0/1[0]}}% + \@namedef{POLuserpol@#2}{-1.\POL@empty{0/1[0]}}% \else \edef\POL@var@coeffs{\expandafter\POL@antidiff\POL@var@coeffs\relax}% \expandafter\edef\csname POLuserpol@#2\endcsname - {\the\numexpr\POL@var@deg+\@ne.\noexpand\empty{0/1[0]}\POL@var@coeffs}% + {\the\numexpr\POL@var@deg+\@ne.\POL@empty{0/1[0]}\POL@var@coeffs}% \fi }% @@ -737,7 +914,7 @@ \POL@count\z@ % if I applied the same as for positive degree, I should make it -1 % if constant is negative. I also don't worry if polynomial is zero. - \@namedef{POLuserpol@\POL@sturmname _0}{0.\empty{1/1[0]}}% + \@namedef{POLuserpol@\POL@sturmname _0}{0.\POL@empty{1/1[0]}}% \else \ifPOL@tosturm@makefirstprimitive\POL@makeprimitive{\POL@sturmname _0_}\fi \POL@tosturm@dosturm @@ -793,7 +970,7 @@ \POL@mapcoeffs\POL@aux@toint{\POL@sturmname _\the\POL@count}% \ifnum\POL@count>\z@ \repeat - \@namedef{POLuserpol@\POL@sturmname _\POL@sturm@N}{0.\empty{1/1[0]}}% + \@namedef{POLuserpol@\POL@sturmname _\POL@sturm@N}{0.\POL@empty{1/1[0]}}% \else % they are already normalized \advance\POL@count\@ne % attention to include last one also \xintloop @@ -984,7 +1161,7 @@ \POL@findrat@xN\POL@findrat@xD\POl@_ % we can't move this to updatequotients because other branch will % need to do the division first anyhow - \edef\POLuserpol@_findrat@oneterm{1.\noexpand\empty + \edef\POLuserpol@_findrat@oneterm{1.\POL@empty {\xintiiOpp\POL@findrat@xN/1[0]}{\POL@findrat@xD/1[0]}}% \POL@divide{\POL@sturmname\POL@sqfnorr}{_findrat@oneterm}% the one without mult. %\expandafter\POL@split\POL@R;\POL@degR\POL@polR @@ -1118,7 +1295,7 @@ % zero should never occur here \POL@findrat@ifnegative{\edef\POL@findrat@x{-\POL@findrat@x}}{}% \POL@xintfrac@getNDE\POL@findrat@x\POL@findrat@xN\POL@findrat@xD\POL@_ - \edef\POLuserpol@_findrat@oneterm{1.\noexpand\empty + \edef\POLuserpol@_findrat@oneterm{1.\POL@empty {\xintiiOpp{\POL@findrat@xN}/1[0]}{\POL@findrat@xD/1[0]}}% \POL@divide{\POL@sturmname\POL@sqfnorr}{_findrat@oneterm}% the one without mult. \expandafter\POL@split\POL@R;\POL@degR\POL@polR @@ -1185,7 +1362,7 @@ % safer to do the edef as \POL@findrat@x used later in storeit \edef\POL@findrat@x{\xintIrr{\xintDiv\POL@findrat@Num\POL@findrat@D}[0]}% \POL@xintfrac@getNDE\POL@findrat@x\POL@findrat@xN\POL@findrat@xD\POL@_ - \edef\POLuserpol@_findrat@oneterm{1.\noexpand\empty + \edef\POLuserpol@_findrat@oneterm{1.\POL@empty {\xintiiOpp{\POL@findrat@xN}/1[0]}{\POL@findrat@xD/1[0]}}% \POL@divide{\POL@sturmname\POL@sqfnorr}{_findrat@oneterm}% the one without mult. \expandafter\POL@split\POL@R;\POL@degR\POL@polR @@ -1210,11 +1387,11 @@ \begingroup\xintglobaldefstrue % skip some overhead of \xintdefvar... \XINT_expr_defvar_one{\POL@sturmname L_\POL@findrat@index}% - {\csname .=\POL@findrat@x\endcsname}% + {\POL@findrat@x}% \XINT_expr_defvar_one{\POL@sturmname R_\POL@findrat@index}% - {\csname .=\POL@findrat@x\endcsname}% + {\POL@findrat@x}% \XINT_expr_defvar_one{\POL@sturmname Z_\POL@findrat@index _isknown}% - {\csname .=1\endcsname}% + {1}% \endgroup }% \def\POL@findrat@loop@updatequotients{% @@ -1326,7 +1503,7 @@ \xintloop % skip some overhead of \xintdefvar... \XINT_expr_defvar_one{\POL@sturmname M_\x}% - {\csname .=\csname POL_ZM\POL@sturmname*\x\endcsname\endcsname}% + {\csname POL_ZM\POL@sturmname*\x\endcsname}% \edef\x{\the\numexpr\x-\@ne}% \ifnum\x>\z@ \repeat @@ -1901,17 +2078,16 @@ \begingroup\xintglobaldefstrue % skip some overhead of \xintdefvar... \XINT_expr_defvar_one{\POL@sturmname L_\POL@isolz@IntervalIndex}% - {\csname .=\POL@IsoLeft@rawout\endcsname}% + {\POL@IsoLeft@rawout}% \XINT_expr_defvar_one{\POL@sturmname R_\POL@isolz@IntervalIndex}% - {\csname .=\POL@IsoRight@rawout\endcsname}% + {\POL@IsoRight@rawout}% % added at 0.7 \XINT_expr_defvar_one{\POL@sturmname Z_\POL@isolz@IntervalIndex _isknown}% - {\csname .=\ifnum\POL@IsoRightSign=\z@ 1\else 0\fi\endcsname}% + {\ifnum\POL@IsoRightSign=\z@ 1\else 0\fi}% \endgroup }% %% \PolRefineInterval -\def\POL@xintexprGetVar#1{\expandafter\expandafter\expandafter - \XINT_expr_unlock\csname XINT_expr_var_#1\endcsname}% +\def\POL@xintexprGetVar#1{\csname XINT_expr_varvalue_#1\endcsname}% % attention, also used by \POL@findrat@loop@a \def\POL@get@IsoLeft@rawin{% \edef\POL@IsoLeft@rawin @@ -2277,28 +2453,70 @@ %% The idea is to execute it with another meaning given to \xintAdd etc.., %% so that it operates on "polynomials". This is a mixture of expandable %% and non-expandable techniques. +%% +%% And it was complicated to let it work with xintexpr 1.4 +%% \def\POL@get#1#2#3{% - \global\POL@polfalse + \relax %!! part de la tambouille pour fonctionner en xint 1.4 + \POL@polglobalfalse \begingroup - \def\POL@result{#3}% + \protected\def\POL@result{#3}% #3% \expandafter \endgroup \expandafter\def\expandafter#1\expandafter{\POL@result}% \unless\ifPOL@pol % avoid expanding more than twice #3 + % #3 must be purely numerical or at least compatible with \edef + % this is why at 0.7.5 I had to handle especially constant + % polynomial functions to remove any protection from them + % (because the protection triggers the COMPOSITION when + % the polynomial is found as argument of another one and + % this is not expandable) \edef#1{#3}% \xintiiifZero{#1}% - {\def#1{-1.\empty{0/1[0]}}}% - {\edef#1{0.\noexpand\empty{#1}}}% + {\def#1{-1.\POL@empty{0/1[0]}}}% + {\edef#1{0.\POL@empty{#1}}}% \fi #2% }% + +%% COMPOSITION +%% This did not exist before 0.7.5 and is part of its adaptation to xint 1.4 +%% We thus took up this opportunity to speed up substantially composition. +%% Very serious difficulties with constant polynomials. Had to handle them +%% especially. +%% OK, that was really tough, but advantage now is that composition +%% at 0.7.5 should be more efficient than before. However when polynomials +%% become big via composition, coefficients also are big and the time +%% taken by arithmetic dominates. No time to test really, though, relieved +%% I can release xint 1.4 at last. My basic polexpr test suite passes, +%% but it goes back already to old releases. +\protected\def\POL@applypolfunc#1#2% +{% +% This #2 may be also invoing \POL@applypolfunc... + \POL@get\POL@A\POL@applypolfunc@b#2#1% +}% +\def\POL@applypolfunc@b #1% +{% +% and now the have our Horner scheme nested macro +% which hopefully will do its job with \POL@add, \POL@mul etc... + \POL@polglobalfalse + \expandafter#1\expanded + {{\POL@polglobaltrue\protected\def\noexpand\POL@result{\POL@A}}}% + \unless\ifPOL@pol + \odef\POL@result{#1{0}}% + \xintiiifZero{\POL@result}% + {\protected\def\POL@result{-1.\POL@empty{0/1[0]}}}% + {\protected\edef\POL@result{0.\POL@empty{\POL@result}}}% + \fi +}% + %% ADDITION \def\POL@add {\POL@get\POL@A\POL@add@b}% \def\POL@add@b{\POL@get\POL@B\POL@add@c}% \def\POL@add@c{% - \global\POL@poltrue + \POL@polglobaltrue \POL@ifZero\POL@A {\let\POL@result\POL@B}% {\POL@ifZero\POL@B @@ -2341,11 +2559,11 @@ \def\POL@mul {\POL@get\POL@A\POL@mul@b}% \def\POL@mul@b{\POL@get\POL@B\POL@mul@c}% \def\POL@mul@c{% - \global\POL@poltrue + \POL@polglobaltrue \POL@ifZero\POL@A - {\def\POL@result{-1.\empty{0/1[0]}}}% + {\protected\def\POL@result{-1.\POL@empty{0/1[0]}}}% {\POL@ifZero\POL@B - {\def\POL@result{-1.\empty{0/1[0]}}}% + {\protected\def\POL@result{-1.\POL@empty{0/1[0]}}}% {\POL@@mul}}% }% \def\POL@@mul{% @@ -2436,9 +2654,9 @@ %% POWERS (SCALAR EXPONENT...) \def\POL@pow #1#2{% - \global\POL@polfalse + \POL@polglobalfalse \begingroup - \def\POL@result{#1}% + \protected\def\POL@result{#1}% #1% \expandafter \endgroup @@ -2446,39 +2664,39 @@ \unless\ifPOL@pol \edef\POL@A{\xintScalarPow{#1}{#2}}% no error check \xintiiifZero{\POL@A}% - {\def\POL@result{-1.\empty{0/1[0]}}}% - {\edef\POL@result{0.\noexpand\empty{\POL@A}}}% + {\protected\def\POL@result{-1.\POL@empty{0/1[0]}}}% + {\protected\edef\POL@result{0.\POL@empty{\POL@A}}}% \else \edef\POL@B{\numexpr\xintNum{#2}\relax}% no check on exponent >= 0 \ifcase\POL@B - \def\POL@result{0.\empty{1/1[0]}}% + \protected\def\POL@result{0.\POL@empty{1/1[0]}}% \or \let\POL@result\POL@A \else \POL@@pow@check \fi \fi - \global\POL@poltrue + \POL@polglobaltrue }% \def\POL@@pow@check {% % no problem here with leftover tokens! % should I have used that I-don't-care technique more elsewhere? \ifnum\@ne>\POL@A - % polynomial is a constant, must get rid of dot and \empty + % polynomial is a constant, must get rid of dot and \empty (\POL@empty) \edef\POL@A{\expandafter\xintScalarPow\romannumeral`^^@% \expandafter\xint_gob_til_dot\POL@A{\POL@B}}% \xintiiifZero{\POL@A}% - {\def\POL@result{-1.\empty{0/1[0]}}}% - {\edef\POL@result{0.\noexpand\empty{\POL@A}}}% + {\protected\def\POL@result{-1.\POL@empty{0/1[0]}}}% + {\protected\edef\POL@result{0.\POL@empty{\POL@A}}}% \else \ifnum\@ne=\POL@A % perhaps a constant times X, check constant term \xintiiifZero {\expandafter\xint_firstoftwo\romannumeral`^^@% \expandafter\xint_gob_til_dot\POL@A} - {\edef\POL@result + {\protected\edef\POL@result {\the\POL@B.% here at least 2. - \noexpand\empty + \POL@empty \romannumeral\xintreplicate{\POL@B}{{0/1[0]}}% {\xintScalarPow {\expandafter\xint_secondoftwo\romannumeral`^^@% @@ -2531,8 +2749,8 @@ {#2}% \expandafter\POL@mul\expandafter {\expandafter\def\expandafter\POL@result\expandafter - {\POL@result}\global\POL@poltrue}% - {\def\POL@result{#1}\global\POL@poltrue}% + {\POL@result}\POL@polglobaltrue}% + {\protected\def\POL@result{#1}\POL@polglobaltrue}% }% %% DIVISION @@ -2540,7 +2758,7 @@ \def\POL@div {\POL@get\POL@A\POL@div@b}% \def\POL@div@b{\POL@get\POL@B\POL@div@c}% \def\POL@div@c{% - \global\POL@poltrue + \POL@polglobaltrue \expandafter\POL@split\POL@A;\POL@degA\POL@polA \expandafter\POL@split\POL@B;\POL@degB\POL@polB \ifnum\POL@degA<\POL@degB\space @@ -2599,9 +2817,9 @@ %% MINUS SIGN AS UNARY OPERATOR \def\POL@opp #1{% - \global\POL@polfalse + \POL@polglobalfalse \begingroup - \def\POL@result{#1}% + \protected\def\POL@result{#1}% #1% \expandafter \endgroup @@ -2609,13 +2827,13 @@ \unless\ifPOL@pol \edef\POL@A{\xintScalarOpp{#1}}% \xintiiifZero{\POL@A}% - {\def\POL@result{-1.\empty{0/1[0]}}}% - {\edef\POL@result{0.\noexpand\empty{\POL@A}}}% + {\protected\def\POL@result{-1.\POL@empty{0/1[0]}}}% + {\protected\edef\POL@result{0.\POL@empty{\POL@A}}}% \else - \edef\POL@B{0.\noexpand\empty{-1/1[0]}}% + \edef\POL@B{0.\POL@empty{-1/1[0]}}% \POL@@mul \fi - \global\POL@poltrue + \POL@polglobaltrue }% @@ -2626,9 +2844,9 @@ \At\PolEvalAtExpr\krof {#1}{#3}% }% \newcommand\PolEvalAt[2] - {\xintpraw{\csname XINT_expr_userfunc_#1\endcsname{#2}}}% + {\xintpraw{\csname XINT_expr_polfunc_#1\endcsname{#2}}}% \newcommand\POL@eval[2] - {\csname XINT_expr_userfunc_#1\endcsname{#2}}% + {\csname XINT_expr_polfunc_#1\endcsname{#2}}% \newcommand\PolEvalAtExpr[2]{\xinttheexpr #1(#2)\relax}% % \newcommand\PolEvalReduced[3]{\romannumeral`^^@\POL@eval@fork @@ -2637,11 +2855,11 @@ }% \newcommand\PolEvalReducedAt[2]{% \xintpraw % in order not to print denominator if the latter equals 1 - {\xintIrr{\csname XINT_expr_userfunc_#1\endcsname{#2}}[0]}% + {\xintIrr{\csname XINT_expr_polfunc_#1\endcsname{#2}}[0]}% }% \newcommand\PolEvalReducedAtExpr[2]{% \xintpraw - {\xintIrr{\romannumeral`^^@\xintthebareeval#1(#2)\relax}[0]}% + {\expandafter\xintIrr\romannumeral`^^@\xintthebareeval#1(#2)\relax[0]}% }% % \newcommand\PolFloatEval[3]{\romannumeral`^^@\POL@eval@fork @@ -2649,7 +2867,7 @@ \At\PolFloatEvalAtExpr\krof {#1}{#3}% }% \newcommand\PolFloatEvalAt[2] - {\xintpfloat{\csname XINT_flexpr_userfunc_#1\endcsname{#2}}}% + {\xintpfloat{\csname XINT_flexpr_polfunc_#1\endcsname{#2}}}% \newcommand\PolFloatEvalAtExpr[2]{\xintthefloatexpr #1(#2)\relax}% @@ -2898,12 +3116,12 @@ \expandafter#1% \fi {#3}#2}% % -\def\POL@toexprA #1#2\empty#3{% +\def\POL@toexprA #1#2\POL@empty#3{% \ifpoltoexprall\expandafter\POL@toexprall@b \else\expandafter\POL@toexpr@b \fi {#3}#2{0}1.% }% -\def\POL@toexprD #1#2#3\relax{% #3 has \empty to prevent brace removal +\def\POL@toexprD #1#2#3\relax{% #3 has \empty (\POL@empty) to prevent brace removal \expandafter\POL@toexprD@a\expandafter#2% \the\numexpr #1\expandafter.\romannumeral0\xintrevwithbraces{#3}\relax }% -- cgit v1.2.3