diff options
Diffstat (limited to 'macros/generic/polexpr/polexpr-ref.rst.txt')
-rw-r--r-- | macros/generic/polexpr/polexpr-ref.rst.txt | 3184 |
1 files changed, 3184 insertions, 0 deletions
diff --git a/macros/generic/polexpr/polexpr-ref.rst.txt b/macros/generic/polexpr/polexpr-ref.rst.txt new file mode 100644 index 0000000000..028e68626f --- /dev/null +++ b/macros/generic/polexpr/polexpr-ref.rst.txt @@ -0,0 +1,3184 @@ +.. comment: -*- fill-column: 72; mode: rst -*- + +=================== + polexpr reference +=================== + +.. _quick: + +Syntax overview via examples +---------------------------- + +The syntax to define a new polynomial is:: + + \poldef polname(x):= expression in variable x; + +.. + +The expression will be parsed by the services of xintexpr_, with some +polynomial aware functions added to its syntax; they are described in +detail :ref:`below <polexpr08>`. The parser accepts and will handle +exactly arbitrarily big integers or fractions. + +.. note:: + + xintexpr_ does not automatically reduce fractions to lowest terms, + and, so far (but this may change in future) neither does :ref:`\\poldef + <poldef;>`. + See :ref:`rdcoeffs() <rdcoeffs>` and the macro + :ref:`\\PolReduceCoeffs <PolReduceCoeffs>`. + + +- In place of ``x`` an arbitrary *dummy variable* is authorized, + i.e. per default one ``a, .., z, A, .., Z`` (more letters can be declared + under Unicode engines). + +- ``polname`` consists of *letters*, *digits*, and also the ``_`` and + ``'`` characters are allowed. The polynomial name **must** start with + a letter: do not use the underscore ``_`` as *first character* of a + polynomial name (even if of catcode letter). No warning is emitted + but dire consequences will ensue. The ``@`` is also allowed + (independently of its catcode "letter" or "other", which does not + matter). It is recommended to avoid using it as first character, + except for temporary polynomial variables. + +- The colon before the equality sign is optional and its (reasonable) + catcode does not matter. + +- The semi-colon at the end of the expression is mandatory. It is not + allowed to arise from expansion (despite the fact that the expression + itself will be parsed using only expansion), it must be "visible" + immediately. + +There are some potential problems (refer to the Technicalities_ section at +bottom of this page) with the semi-colon as expression terminator, so an +alternative syntax is provided, which avoids it altogether:: + + \PolDef[optional letter]{<polname>}{<expr. using letter as indeterminate>} + +The ``\PolDef`` optional first argument defaults to ``x`` and must be +used as the indeterminate in the expression. + +Examples: + +``\poldef f(x):= 1 - x + quo(x^5,1 - x + x^2);`` + +``\PolDef{f}{1 - x + quo(x^5,1 - x + x^2)}`` + Both parse the polynomial + expression, and they create internally macros serving to + incarnate the polynomial, its coefficients, and the associated + polynomial function. + + The polynomial can then be used in further polynomial definitions, + be served as argument to package macros, or appear as a variable in + various functions `described later <polexpr08_>`_. + + .. warning:: + + Both the function ``quo()`` (as shown in the example above), and + the infix operator ``/`` are mapped to the Euclidean quotient. + + This usage of ``/`` to stand for the Euclidean quotient is + **deprecated** and reserved for a (somewhat improbable) possible + extension of the package to handle rational functions as well. + + .. _warningtacit: + + .. attention:: + + Tacit multiplication rules let the parser when encountering + ``1/2 x^2`` skip the space and thus handle it as ``1/(2*x^2)``. + But then it gives zero, because `/` stands for the Euclidean + quotient operation here. + + Thus one must use ``(1/2)x^2`` or ``1/2*x^2`` or + ``(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 + gets interpreted as ``1/(2*(x-1)*(x-2))`` not as + ``(1/2)*(x-1)*(x-2)`` and then gives zero by + polynomial division. Thus, in such cases, use one of + ``(1/2)(x-1)(x-2)``, ``1/2*(x-1)(x-2)`` or ``(x-1)(x-2)/2``. + + ``\poldef P(x):=...;`` defines ``P`` as a *polynomial function*, + which can be used inside ``\xinteval``, as:: + + \xinteval{P(3 + 7 + 11)} + + or even as:: + + \xinteval{P(Q1 + Q2 + Q3)} + + where ``Q1``, ``Q2``, ``Q3`` are polynomials. The evaluation result, + if not a scalar, will then be printed as ``pol([c0,c1,...])`` which + stands for a polynomial variable having the listed coefficients; see + :ref:`pol() <pol>`. + + Indeed, as seen above with ``Q1``, the symbol ``P`` also stands for + a *variable of polynomial type*, which serves as argument to + polynomial specific functions such as :ref:`deg() <deg>` or + :ref:`polgcd() <polgcd>`, or as argument to other polynomials (as + above), or even simply stands for its own in algebraic expressions + such as:: + + \poldef Q(z):= P^2 + z^10; + + Notice that in the above, the ``(z)`` part is mandatory, as it informs + ``\poldef`` of the letter used for the indeterminate. In the above + ``P(z)^2`` would give the same as ``P^2`` but the latter is slightly + more efficient. + + One needs to acquire a good understanding of when the symbol ``P`` + will stand for a function and when it will stand for a variable. + + - If ``P`` and + ``Q`` are both declared polynomials then:: + + (P+Q)(3)% <--- attention, does (P+Q)*3, not P(3)+Q(3) + + is currently evaluated as ``(P+Q)*3``, because ``P+Q`` is not + known as a *function*, but *only as a variable of polynomial + type*. Note that :ref:`evalp(P+Q,3) <evalp>` gives as expected + the same as ``P(3)+Q(3)``. + + - Also:: + + (P)(3)% <--- attention, does P*3, not P(3) + + 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 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 intuitive. Anyway, do not rely too + extensively on tacit ``*`` and use explicit ``(P+Q)*(1+2)`` if this + is what is intended. + + +``\PolLet{g}={f}`` + saves a copy of ``f`` under name ``g``. Also usable without ``=``. + + Has exactly the same effect as ``\poldef g(x):=f;`` or ``\poldef + g(w):=f(w);``\ . + +``\poldef f(z):= f^2;`` + redefines ``f`` in terms of itself. Prior to ``0.8`` one needed + the right hand side to be ``f(z)^2``. Also, now ``sqr(f)`` is + possible (also ``sqr(f(x))`` but not ``sqr(f)(x)``). + + It may look strange that an indeterminate variable is used on + left-hand-side even though it may be absent of right-hand-side, as + it seems to define ``f`` always as a polynomial function. + + This is a legacy of pre-``0.8`` context. + + .. important:: + + Note that ``f^2(z)`` or ``sqr(f)(z)`` will give a logical but + perhaps unexpected result: first ``f^2`` is computed, then the + opening parenthesis is seen which inserts a tacit multiplication + ``*``, so in the end it is as if the input had been ``f^2 * z``. + Although ``f`` is both a variable and a function, ``f^2`` is + computed as a polynomial *variable* and ceases being a function. + +``\poldef f(T):= f(f);`` + again modifies ``f``. Here it is used both as variable and as + a function. Prior to ``0.8`` it needed to be ``f(f(T))``. + +``\poldef k(z):= f-g(g^2)^2;`` + if everybody followed, this should now define the zero polynomial... + And ``f-sqr(g(sqr(g)))`` computes the same thing. + + We can check this in a typeset document like this:: + + \poldef f(x):= 1 - x + quo(x^5,1 - x + x^2);% + \PolLet{g}={f}% + \poldef f(z):= f^2;% + \poldef f(T):= f(f);% + \poldef k(w):= f-sqr(g(sqr(g)));% + $$f(x) = \vcenter{\hsize10cm \PolTypeset{f}} $$ + $$g(z) = \PolTypeset{g} $$ + $$k(z) = \PolTypeset{k} $$ + \immediate\write128{f(x)=\PolToExpr{f}}% ah, here we see it also + +``\poldef f'(x):= diff1(f);`` + (new at ``0.8``) + +``\PolDiff{f}{f'}`` + Both set ``f'`` (or any other chosen name) to the derivative + of ``f``. + + .. important:: + + This is not done automatically. If some new definition needs to use + the derivative of some available polynomial, that derivative + polynomial must have been previously defined: something such as + ``f'(3)^2`` will not work without a prior definition of ``f'``. + + But one can now use ``diff1(f)`` for on-the-spot construction with no + permanent declaration, so here ``evalp(diff1(f),3)^2``. And + ``diff1(f)^2`` is same as ``f'^2``, assuming here ``f'`` was declared + to be the derived polynomial. + + Notice that the name ``diff1()`` is experimental and may change. Use + ``\PolDiff{f}{f'}`` as the stable interface. + +``\PolTypeset{P}`` + Typesets (switching to math mode if in text mode):: + + \poldef f(x):=(3+x)^5;% + \PolDiff{f}{f'}\PolDiff{f'}{f''}\PolDiff{f''}{f'''}% + $$f(z) = \PolTypeset[z]{f} $$ + $$f'(z) = \PolTypeset[z]{f'} $$ + $$f''(z) = \PolTypeset[z]{f''} $$ + $$f'''(z)= \PolTypeset[z]{f'''} $$ + + See `its documentation <PolTypeset_>`_ for the configurability + via macros. + + Since ``0.8`` `\\PolTypeset <PolTypeset_>`_ accepts directly an + expression, it does not have to be a pre-declared polynomial name:: + + \PolTypeset{mul(x-i,i=1..5)} + +``\PolToExpr{P}`` + Expandably (contrarily to `\\PolTypeset <PolTypeset_>`_) + produces ``c_n*x^n + ... + c_0`` starting from the leading + coefficient. The ``+`` signs are omitted if followed by negative + coefficients. + + This is useful for console or file output. This syntax is Maple and + PSTricks ``\psplot[algebraic]`` compatible; and also it is + compatible with ``\poldef`` input syntax, of course. See + `\\PolToExprCaret`_ for configuration of the ``^``, for example to + use rather ``**`` for Python syntax compliance. + + Changed at ``0.8``: the ``^`` in output is by default of catcode 12 + so in a draft document one can use ``\PolToExpr{P}`` inside the + typesetting flow (without requiring math mode, where the ``*`` would + be funny and ``^12`` would only put the ``1`` as exponent anyhow; + but arguably in text mode the ``+`` and ``-`` are not satisfactory + for math, except sometimes in monospace typeface, and anyhow TeX is + unable to break the expression across lines, barring special help). + + See :ref:`\\PolToExpr{\<pol. expr.\>} <PolToExpr>` and related macros for customization. + + Extended at ``0.8`` to accept as argument not only the name of a + polynomial variable but more generally any polynomial expression. + + +Using defined polynomials in floating point context +--------------------------------------------------- + +Exact manipulations with fractional coefficients may quickly lead to +very large denominators. For numerical evaluations, it is advisable +to a use a floating point context. But for the polynomial to be +usable as a function in floating point context, an extra step beyond +``\poldef`` is required: see `\\PolGenFloatVariant`_. Then the +``\xintfloateval`` macro from xintexpr_ will recognize the polynomial +as a genuine function (with already float-rounded coefficients, and +using a Horner scheme). + +But `\\PolGenFloatVariant`_ must be used each time the polynomial gets +redefined or a new polynomial is created out of it. Functions such as +for example :ref:`deg() <deg>` which handle the polynomial as an entity +are only available within the ``\poldef`` and ``\xinteval`` (or +``\xintexpr``) parsers. Inside ``\xintfloateval`` a polynomial can only +serve as a numerical function (and only after declaration via +`\\PolGenFloatVariant`_), and not as a variable. + +In some cases one may wish to replace a polynomial having acquired +very big fractional coefficients with a new one whose coefficients +have been float-rounded. See :ref:`\\PolMapCoeffs <PolMapCoeffs>` +which can be used for example with the ``\xintFloat`` macro from the +xintfrac_ package to achieve this. + + +.. _polexpr08: + +The polexpr ``0.8`` extensions to the ``\xintexpr`` syntax +---------------------------------------------------------- + +All the syntax elements described in this section can be used in the +``\xintexpr/\xinteval`` context (where polynomials can be obtained from +the ``pol([])`` constructor, once polexpr is loaded): their usage is +not limited to only ``\poldef`` context. + +.. note:: + + If a variable ``myPol`` defined via ``\xintdefvar`` turns out + to be a polynomial, the difference with those declared via ``\poldef`` + will be: + + 1. ``myPol`` is not usable as *function*, but only as a variable. + Attention that ``f(x)`` if ``f`` is only a variable (even a + polynomial one) will actually compute ``f * x``. + + 2. ``myPol`` is not known to the polexpr package, hence for example the + macros to achieve localization of its roots are unavailable. + + In a parallel universe I perhaps have implemented this expandably + which means it could then be accessible with syntax such as + ``rightmostroot(pol([42,1,34,2,-8,1]))`` but... + + +Warning about unstability of the new syntax +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +.. warning:: + + Consider the entirety of this section as **UNSTABLE** and + **EXPERIMENTAL** (except perhaps regarding ``+``, ``-`` and ``*``). + + And this applies even to items not explicitly flagged with one of + **unstable**, **Unstable**, or **UNSTABLE** which only reflect that + documentation was written over a period of time exceeding one minute, + enough for the author mood changes to kick in. + + It is hard to find good names at the start of a life-long extension + program of functionalities, and perhaps in future it will be + preferred to rename everything or give to some functions other + meanings. Such quasi-complete renamings happened already a few times + during the week devoted to development. + + +Infix operators ``+, -, *, /, **, ^`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + As has been explained in the `Syntax overview via examples`_ + section these infix operators have been made polynomial aware, not + only in the ``\poldef`` context, but generally in any + ``\xintexpr/\xinteval`` context, inclusive of ``\xintdeffunc``. + + Conversely functions declared via ``\xintdeffunc`` and making use of + these operators will automatically be able to accept polynomials + declared from ``\poldef`` as variables. + + Usage of ``/`` for euclidean division of polynomials is **deprecated**. + Only in case of a scalar denominator is it to be considered stable. + Please use rather ``quo()``. + +Experimental infix operators ``//, /:`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + Here is the tentative behaviour of ``A//B`` according to types: + + - ``A`` non scalar and ``B`` non scalar: euclidean quotient, + + - ``A`` scalar and ``B`` scalar: floored division, + + - ``A`` scalar and ``B`` non scalar: produces zero, + + - ``A`` non scalar and ``B`` scalar: coefficient per + coefficient floored division. + + This is an **experimental** overloading of the ``//`` and ``/:`` + from ``\xintexpr``. + + The behaviour in the last case, but not only, is to be considerd + **unstable**. The alternative would be for ``A//B`` with ``B`` + scalar to act as ``quo(A,B)``. But, we have currently chosen to let + ``//B`` for a scalar ``B`` act coefficient-wise on the numerator. + Beware that it thus means it can be employed with the idea of doing + euclidean division only by checking that ``B`` is non-scalar. + + The ``/:`` operator provides the associated remainder so always + ``A`` is reconstructed from ``(A//B)*B + A/:B``. + + If ``:`` is active character use ``/\string:`` (it is safer to use + ``/\string :`` if it is not known if ``:`` has catcode other, letter, + or is active, but note that ``/:`` is fine and needs no precaution if + ``:`` has catcode letter, it is only an active ``:`` which is + problematic, like for all other characters possibly used in an + expression). + + **UNSTABLE** + + As explained above, there are (among other things) hesitations + about behaviour with ``pol2`` a scalar. + +Comparison operators ``<, >, <=, >=, ==, !=`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + **NOT YET IMPLEMENTED** + + 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 + 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 + difference, which is a bit costly. And of course the ``deg()`` + function allows comparing degrees. In this context note the + following syntax:: + + (deg(Q)) ?? { zero } { non-zero scalar } { non-scalar } + + for branching. + + +.. _pol: + +``pol(<nutple expression>)`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + This converts a nutple ``[c0,c1,...,cN]`` into the polynomial + variable having these coefficients. Attention that the square + brackets are **mandatory**, except of course if the argument is + actually an expression producing such a "nutple". + + Currently, this process will not normalize the coefficients (such + as reducing to lowest terms), it only trims out the leading zero + coefficients. + + Inside ``\xintexpr``, this is the only (allowed) way to create ex + nihilo a polynomial variable; inside ``\poldef`` it is an alternative + input syntax which is more efficient than the input ``c0 + c1 * x + c2 * + x^2 + ...``. + +.. important:: + + Whenever an expression with polynomials collapses to a constant, it + becomes a scalar. There is currently no distinction during the + parsing of expressions by ``\poldef`` + or ``\xintexpr`` between constant polynomial variables and scalar + variables. + + Naturally, ``\poldef`` can be used to declare a constant polynomial + ``P``, then ``P`` can also be used as function having a value + independent of argument, but as a variable, it is non-distinguishable + from a scalar (of course functions such as ``deg()`` tacitly + consider scalars to be constant polynomials). + + Notice that we tend to use the vocable "variable" to refer to + arbitrary expressions used as function arguments, without implying + that we are actually referring to pre-declared variables in the sense + of ``\xintdefvar``. + +.. _lpol: + +``lpol(<nutple expression>)`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + This converts a nutple ``[cN,...,c1,c0]`` into the polynomial + variable having these coefficients, with leading coefficients coming + first in the input. Attention that the square brackets are + **mandatory**, except of course if the argument is actually an + expression producing such a "nutple". + + Currently, this process will not normalize the coefficients (such + as reducing to lowest terms), it only trims out the leading zero + coefficients. + + **NAME UNSTABLE** + + It can be used in ``\poldef`` as an alternative input syntax, which + is more efficient than using the algebraic notation with monomials. + + (new with ``0.8.1``, an empty nutple will cause breakage) + +.. _xintevalpolexpr: + +``\xinteval{<pol. expr.>}`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + This is documented here for lack of a better place: it evaluates the + polynomial expression then outputs the "string" ``pol([c0, c1, ..., cN])`` + if the degree ``N`` is at least one (and the usual scalar output else). + + The "pol" word uses letter catcodes, which is actually mandatory for + this output to be usable as input, but it does not make sense to use + this inside ``\poldef`` or ``\xintexpr`` at it means basically + executing ``pol(coeffs(..expression..))`` which is but a convoluted + way to obtain the same result as ``(..expression..)`` (the + parentheses delimiting the polynomial expression). + + For example, ``\xinteval{(1+pol([0,1]))^10}`` expands (in two steps) + to:: + + pol([1, 10, 45, 120, 210, 252, 210, 120, 45, 10, 1]) + + You do need loading polexpr for this, else of course ``pol([])`` + remains unknown to ``\xinteval{}`` as well as the polynomial algebra ! + This example can also be done as + ``\xinteval{subs((1+x)^10,x=pol([0,1]))}``. + + I hesitated using as output the polynomial notation as produced by + `\\PolToExpr{} <poltoexpr_>`_, but finally opted for this. + +.. _evalp: + +``evalp(<pol. expr.>, <pol. expr>)`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + Evaluates the first argument as a polynomial function of the + second. Usually the second argument will be scalar, but this is not + required:: + + \poldef K(x):= evalp(-3x^3-5x+1,-27x^4+5x-2); + + 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 [#]_ (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. + + .. [#] 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 + Maple results by polexpr sometimes cumbersome, but perhaps + they will update it at some point. + + .. + + **name unstable** + + ``poleval``? ``evalpol``? ``peval``? ``evalp``? ``value``? + ``eval``? ``evalat``? ``eval1at2``? ``evalat2nd``? + + Life is so complicated when one asks questions. Not everybody does, + though, as is amply demonstrated these days. + + **syntax unstable** + + I am hesitating about permuting the order of the arguments. + +.. _deg: + +``deg(<pol. expr.>)`` +~~~~~~~~~~~~~~~~~~~~~ + + Computes the degree. + +.. important:: + + As ``\xintexpr`` does not yet support infinities, the degree of + the zero polynomial is ``-1``. Beware that this breaks additivity + of degrees, but ``deg(P)<0`` correctly detects the zero polynomial, + and ``deg(P)<=0`` detects scalars. + +``coeffs(<pol. expr.>)`` +~~~~~~~~~~~~~~~~~~~~~~~~ + + Produces the nutple ``[c0,c1,...,cN]`` of coefficients. The highest + degree coefficient is always non zero (except for the zero + 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_. + +.. _lcoeffs: + +``lcoeffs(<pol. expr.>)`` +~~~~~~~~~~~~~~~~~~~~~~~~~ + + Produces the nutple ``[cN,....,c1,c0]`` of coefficients, starting + with the highest degree coefficient. + + (new with ``0.8.1``) + +``coeff(<pol. expr.>, <num. expr.>)`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + As expected. Produces zero if the numerical index is negative or + 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_. + + The current behaviour is at odds with legacy + :ref:`\\PolNthCoeff{\<polname\>}{\<index\>} <PolNthCoeff>` regarding negative indices. + Accessing leading or sub-leading coefficients can be done with + other syntax, see `lc(<pol. expr.>)`_, and in some contexts it + is useful to be able to rely on the fact that coefficients with + negative indices do vanish, so I am for time being maintaining this. + +.. _lc: + +``lc(<pol. expr.>)`` +~~~~~~~~~~~~~~~~~~~~ + + 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 + Python-like indexing syntax. + +``monicpart(<pol. expr.>)`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + Divides by the leading coefficient, except that ``monicpart(0)==0``. + + **unstable** + + Currently the coefficients are reduced to lowest terms (contrarily + to legacy behaviour of `\\PolMakeMonic <polmakemonic_>`_), and + 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. + +.. _cont: + +``cont(<pol. expr.>)`` +~~~~~~~~~~~~~~~~~~~~~~ + + The (fractional) greatest common divisor of the polynomial + coefficients. It is always produced as an irreducible (non-negative) + fraction. According to Gauss theorem the content of a product is the + product of the contents. + + .. commentaire 8 avril 2021 + + surprenamment après avoir utilisé `\\PolIContent <PolIContent_>`_ + une fois on peut utiliser `\\PolIContent`_ directement. + + avec docutils 0.16 + + .. + + **name and syntax unstable** + + At ``0.8`` it was created as ``icontent()`` to match the legacy + macro `\\PolIContent <PolIContent_>`_, whose name in 2018 was + chosen in relation to Maple's function ``icontent()``, possibly + because at that time I had not seen that Maple also had a + ``content()`` function. Name changed at ``0.8.1``. + + It will change syntax if in future multivariate polynomials are + supported, and ``icontent()`` will then make a come-back. + +``primpart(<pol. expr.>)`` +~~~~~~~~~~~~~~~~~~~~~~~~~~ + + The quotient (except for the zero polynomial) by + ``cont(<pol. expr.>)``. This is thus a polynomial with + integer coefficients having ``1`` as greatest common divisor. The + sign of the leading coefficient is the same as in the original. + + And ``primpart(0)==0``. + + The trailing zeros of the integer coefficients are extracted + into a power of ten exponent part, in the internal representation. + +``quorem(<pol. expr.>, <pol. expr.>)`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + Produces a nutple ``[Q,R]`` with ``Q`` the euclidean quotient and + ``R`` the remainder. + + **name unstable** + + ``poldiv()``? + +``quo(<pol. expr.>, <pol. expr.>)`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + The euclidean quotient. + + The deprecated ``pol1/pol2`` syntax computes the same polynomial. + +``rem(<pol. expr.>, <pol. expr.>)`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + The euclidean remainder. If ``pol2`` is a (non-zero) scalar, this is + zero. + + There is no infix operator associated to this, for lack of evident + notation. Please advise. + + ``/:`` can be used if one is certain that ``pol2`` is of + degree at least one. But read the warning about it being unstable + even in that case. + +.. not implemented + + ``spquorem(pol1,pol2)`` + ~~~~~~~~~~~~~~~~~~~~~~~ + + Produces a tuple ``[Q,R]`` with the pseudo-quotient and + pseudo-remainder. See `prem(pol1, pol2) <prem_>`_ for + their definitions. + + **NOT IMPLEMENTED** + + I am hesitating returning rather the nutple ``[b^f, Q, R]`` or + ``[f, Q, R]``. Note that the number of non-zero coefficients of + a polynomial ``P`` can be computed as ``add(?(c),c=coeffs(P))``, + and in this context I am hesitating abstracting a function to + provide this [#]_. The usual problem is that I don't know how to + name the function. + + I am also hesitating providing rather a function returning only + ``f`` and ``R``, not ``Q``, which for modular computations we don't + need to carry along. + + .. [#] one can embed ``\xintiiexpr add(?(c),c=coeffs(P))\relax`` + inside ``\xintexpr`` and it will be more efficient for long + polynomials, but naturally a core implementation using a + single ``\numexpr`` would be quite more efficient still. + +.. _prem: + +``prem(<pol. expr. 1>, <pol. expr. 2>)`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + Produces a nutple ``[m, spR]`` where ``spR`` is the (special) pseudo + Euclidean remainder. Its description is: + + - the standard euclidean remainder ``R`` is ``spR/m`` + + - ``m = b^f`` with ``b`` equal to the **absolute value** of the + leading coefficient of ``pol2``, + + - ``f`` is the number of non-zero coefficients in the euclidean + quotient, if ``deg(pol2)>0`` (even if the remainder vanishes). + + If ``pol2`` is a scalar however, the function outputs ``[1,0]``. + + With these definitions one can show that if both ``pol1`` and + ``pol2`` have integer coefficients, then this is also the case of + ``spR``, which makes its interest (and also ``m*Q`` has integer + coefficients, with ``Q`` the euclidean quotient, if ``deg(pol2)>0``). + Also, ``prem()`` is computed faster than ``rem()`` for such integer + coefficients polynomials. + + .. hint:: + + If you want the euclidean quotient ``R`` evaluated via ``spR/m`` + (which may be faster, even with non integer coefficients) use + ``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 + 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:: + + \xintdeffunc lastoverfirst(x):=last(x)/first(x); + \xintdeffunc myR(x)=lastoverfirst(prem(x)); + + Then, ``myR(pol1,pol2)`` will evaluate ``prem(pol1,pol2)`` only + once and compute a polynomial identical to the euclidean + remainder (internal representations of coefficients may differ). + + In this case of integer coefficients polynomials, the polexpr + internal representation of the integer coefficients in the pseudo + remainder will be with unit denominators only if that was already the + case for those of ``pol1`` and ``pol2`` (no automatic reduction to + lowest terms is made prior or after computation). + + Pay attention here that ``b`` is the **absolute value** of the + leading coefficient of ``pol2``. Thus the coefficients of the + pseudo-remainder have the same signs as those of the standard + remainder. This diverges from Maple's function with the same name. + + +``divmod(<pol. expr. 1>, <pol. expr. 2>)`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + Overloads the scalar ``divmod()`` and associates it with the + experimental ``//`` and ``/:`` as extended to the polynomial type. + + In particular when both ``pol1`` and ``pol2`` are scalars, this is + the usual ``divmod()`` (as in Python) and for ``pol1`` and ``pol2`` + non constant polynomials, this is the same as ``quorem()``. + + **Highly unstable** overloading of ``\xinteval``\ 's ``divmod()``. + +``mod(<pol. expr. 1>, <pol. expr. 2>)`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + The ``R`` of the ``divmod()`` output. Same as ``R`` of ``quorem()`` + when the second argument ``pol2`` is of degree at least one. + + **Highly unstable** overloading of ``\xinteval``\ 's ``mod()``. + +``polgcd(<pol. expr. 1>, <pol. expr. 2>, ...)`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + Evaluates to the greatest common polynomial divisor of all the + polynomial inputs. The output is a **primitive** (in particular, + with integer coefficients) polynomial. It is zero if and only if all + inputs vanish. + + Attention, there must be either at least two polynomial variables, or + 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_). + + The two variable case could (and was, during development) have been + defined at user level like this:: + + \xintdeffunc polgcd_(P,Q):= + (deg(Q))??{P}{1}{polgcd_(Q,primpart(last(prem(P,Q))))}; + \xintdeffunc polgcd(P,Q):=polgcd_(primpart(P),primpart(Q));% + + This is basically what is done internally for two polynomials, up + to some internal optimizations. + + **UNSTABLE** + + I hesitate between returning a *primitive* or a *monic* polynomial. + Maple returns a primitive polynomial if all inputs [#]_ have integer + coefficients, else it returns a monic polynomial, but this is + complicated technically for us to add such a check and would add + serious overhead. + + Internally, computations are done using primitive + integer-coefficients polynomials (as can be seen in the function + template above). So I decided finally to output a primitive + polynomial, as one can always apply ``monicpart()`` to it. + + Attention that this is at odds with behaviour of the legacy + `\\PolGCD <PolGCD_>`_ (non expandable) macro. + + .. [#] actually, only two polynomial arguments are allowed by Maple's + ``gcd()`` as far as I know. + +``resultant(<pol. expr. 1>, <pol. expr. 2>)`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + The resultant. + + **NOT YET IMPLEMENTED** + +``disc(<pol. expr.>)`` +~~~~~~~~~~~~~~~~~~~~~~ + + The discriminant. + + **NOT YET IMPLEMENTED** + +``polpowmod(<pol. expr. 1>, <num. expr.>, <pol. expr. 2>)`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + Modular exponentiation: ``mod(pol1^N, pol2)`` in a more efficient + manner than first computing ``pol1^N`` then reducing modulo ``pol2``. + + Attention that this is using the ``mod()`` operation, whose current + experimental status is as follows: + + - if ``deg(pol2)>0``, the euclidean remainder operation, + - if ``pol2`` is a scalar, coefficient-wise reduction modulo ``pol2``. + + + **UNSTABLE** + + This is currently implemented at high level via ``\xintdeffunc`` and + recursive definitions, which were copied over from a scalar example + in the xintexpr_ manual:: + + \xintdeffunc polpowmod_(P, m, Q) := + isone(m)? + % m=1: return P modulo Q + { mod(P,Q) } + % m > 1: test if odd or even and do recursive call + { odd(m)? { mod(P*sqr(polpowmod_(P, m//2, Q)), Q) } + { mod( sqr(polpowmod_(P, m//2, Q)), Q) } + } + ;% + \xintdeffunc polpowmod(P, m, Q) := (m)?{polpowmod_(P, m, Q)}{1};% + + Negative exponents are not currently implemented. + + For example:: + + \xinteval{subs(polpowmod(1+x,100,x^7),x=pol([0,1]))} + \xinteval{subs(polpowmod(1+x,20,10), x=pol([0,1]))} + + produce respectively:: + + pol([1, 100, 4950, 161700, 3921225, 75287520, 1192052400]) + pol([1, 0, 0, 0, 5, 4, 0, 0, 0, 0, 6, 0, 0, 0, 0, 4, 5, 0, 0, 0, 1]) + +.. perte de temps terrible pourquoi j'écris cela + When ``pol2`` is as scalar then the degrees of the modular powers + ``mod(pol1^N, pol2)`` will in general increase linearly in ``N`` + hence become big. But one can play with modifying the above + template and nesting two ``mod()``, one with an integer modulus, + say ``7``, and the other the a monic integer coefficients + polynomial such as ``Q = x^2+1``. Then an integer coefficients + polynomial ``P`` will have an integer coefficient remainder modulo + ``Q``, and + +.. _rdcoeffs: + +``rdcoeffs(<pol. expr.>)`` +~~~~~~~~~~~~~~~~~~~~~~~~~~ + + This operates on the internal representation of the coefficients, + reducing them to lowest terms. + + **name HIGHLY undecided** + +``rdzcoeffs(<pol. expr.>)`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + This operates on the internal representation of the coefficients, + reducing them to lowest terms then extracting from numerator + or denominator the maximal power of ten to store as a decimal + exponent. + + This is sometimes favourable to more efficient polynomial algebra + computations. + + **name HIGHLY undecided** + +``diff1(<pol. expr.>)`` +~~~~~~~~~~~~~~~~~~~~~~~ + + The first derivative. + + **name UNSTABLE** + + This name may be used in future to be the partial derivative with + respect to a first variable. + +``diff2(<pol. expr.>)`` +~~~~~~~~~~~~~~~~~~~~~~~ + + The second derivative. + + **name UNSTABLE** + + This name may be used in future to be the partial derivative with + respect to a second variable. + + +``diffn(<pol. expr. P>, <num. expr. n>)`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + The ``n``\ th derivative of ``P``. For ``n<0`` computes iterated primitives + vanishing at the origin. + + The coefficients are not reduced to lowest terms. + + **name and syntax UNSTABLE** + + I am also considering reversing the order of the arguments. + +``antider(<pol. expr. P>)`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + The primitive of ``P`` with no constant term. Same as ``diffn(P,-1)``. + +``intfrom(<pol. expr. P>, <pol. expr. c>)`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + The primitive of ``P`` vanishing at ``c``, i.e. ``\int_c^x P(t)dt``. + + Also ``c`` can be a polynomial... so if ``c`` is monomial ``x`` + this will give zero! + + **UNSTABLE** + + Allowing general polynomial variable for ``c`` adds a bit of + overhead to the case of a pure scalar. So I am hesitating + maintaining this feature whose interest appears dubious. + + .. attention:: + + As the two arguments are both allowed to be polynomials, if by + inadvertance one exchanges the two, there is no error but the + meaning of ``intfrom(c,P)`` is completely otherwise, as it + produces ``c*(x - P)`` if ``c`` is a scalar:: + + >>> &pol + pol mode (i.e. function definitions use \poldef) + >>> P(x):=1+x^2; + P = x^2+1 + --> &GenFloat(P) lets P become usable as function in fp mode + --> &ROOTS(P) (resp. &ROOTS(P,N)) finds all rational roots exactly and + all irrational roots with at least 10 (resp. N) fractional digits + >>> intfrom(P,1); + @_1 pol([-4/3, 1, 0, 1/3]) + >>> intfrom(1,P); + @_2 pol([-1, 1, -1]) + >>> &bye + + + +.. grosse hésitation ici + + ``intto(<pol. expr. P>, <pol. expr. c>)`` + ----------------------------------------- + + ``\int_x^c P(t)dt``. + + c'est l'opposé du précédent + + mais le nom pourrait faire penser à \int_0^x plutôt + +``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*. No real + recoverable-from error check is done on the input syntax. The + input can be an xintexpr_ variable which happens to be a nutple + with two items, or any expression which evaluates to such a + nutple. + + ``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)``. + + Similary to compute ``\int_x^{x+1} P(t)dt``, use ``-intfrom(x+1)``. + + **UNSTABLE** + + Am I right to allow general polynomials ``a`` and ``b`` hence add + overhead to the pure scalar case ? + + + +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``. + +.. _poldef;: + +``\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 + package macros, used with argument ``polname``. Of course the + *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 + 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 + <warningtacit_>`_. + + Furthermore: + + - a variable ``polname`` is defined which can be used in ``\poldef`` + as well as in ``\xinteval`` for algebraic computations or as + argument to polynomial aware functions, + + - a function ``polname()`` is defined which can be used in ``\poldef`` + as well as in ``\xinteval``. It accepts there as argument scalars + and also other polynomials (via their names, thanks to previous + item). + + Notice that any function defined via ``\xintdeffunc`` and using + 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 + 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 + (so for example can be used as argument to the ``cos()`` function). + + The *function* on the other hand remains a one-argument function, + which simply has a constant value. + + .. attention:: + + The function ``polname()`` is defined **only** for + ``\xintexpr/\xinteval`` + context. It will be unknown to ``\xintfloateval``. + + Worse, a + previously existing floating point function of the same name will + be let undefined again, to avoid hard to debug mismatches between + exact and floating point polynomials. This also applies when the + polynomial is produced not via ``\poldef`` or ``\PolDef`` but + as result of usage of the other package macros. + + See :ref:`\\PolGenFloatVariant{\<polname\>} <PolGenFloatVariant>` to generate a **function** + usable in ``\xintfloateval``. + + .. attention:: + + Using the **variable** ``mypol`` inside ``\xintfloateval`` will + generate low-level errors because the infix operators there are + not polynomial-aware, and the polynomial specific functions such + as ``deg()`` are only defined for usage inside ``\xintexpr``. + + In short, currently polynomials defined via ``polexpr`` can + be used in floating point context only for numerical evaluations, + via **functions** obtained from :ref:`\\PolGenFloatVariant{\<polname\>} <PolGenFloatVariant>` + usage. + + Changes to the original polynomial via package macros are not + automatically mapped to the numerical floating point evaluator + which must be manually updated as necessary when the original + rational coefficient polynomial is modified. + + The original expression is lost after parsing, and in particular the + package provides no way to typeset it (of course the package + provides macros to typeset the computed polynomial). Typesetting + the original expression has to be done manually, if needed. + +.. _PolDef: + +``\PolDef[<letter>]{<polname>}{<expr. using the letter as indeterminate>}`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + Does the same as `\\poldef <poldef;_>`_ in an undelimited macro + format, the main interest is to avoid potential problems with the + catcode of the semi-colon in presence of some packages. In absence + of a ``[<letter>]`` optional argument, the variable is assumed to be + ``x``. + + +.. _PolGenFloatVariant: + +``\PolGenFloatVariant{}`` +~~~~~~~~~~~~~~~~~~~~~~~~~ + +Syntax: ``\PolGenFloatVariant{<polname>}`` + + Makes the polynomial also usable in the + ``\xintfloatexpr/\xintfloateval`` parser. It will therein evaluates + via an Horner scheme using polynomial coefficients already + pre-rounded to the float precision. + + See also :ref:`\\PolToFloatExpr{\<pol. expr.\>} <PolToFloatExpr>`. + + .. attention:: + + Any operation, for example generating the derivative polynomial, + or dividing two polynomials or using the ``\PolLet``, must be + followed by explicit usage of ``\PolGenFloatVariant{<polname>}`` if + the new polynomial is to be used in ``\xintfloateval``. + +.. _PolTypeset: + +``\PolTypeset{}`` +~~~~~~~~~~~~~~~~~ + +Syntax: ``\PolTypeset{<pol. expr.>}`` + + Typesets in descending powers, switching to math mode if in text + mode, after evaluating the polynomial expression:: + + \PolTypeset{mul(x-i,i=1..5)}% possible since polexpr 0.8 + + The letter used in the input expression is by default ``x``, + but can be modified by a redefinition of `\\PolToExprInVar`_. + + It uses also by default the letter ``x`` on output but this one can + be changed via an optional argument:: + + \PolTypeset[z]{polname or polynomial expression} + + By default zero coefficients are skipped (use ``\poltypesetalltrue`` + to get all of them in output). + + The following macros (whose meanings will be found in the package code) + can be re-defined for customization. Their default definitions are + expandable, but this is not a requirement. + +.. _PolTypesetCmd: + +``\PolTypesetCmd{}`` +^^^^^^^^^^^^^^^^^^^^ + +Syntax: ``\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 + degree zero. Also it sets the conditional deciding behaviour of + :ref:`\\PolIfCoeffIsPlusOrMinusOne{T}{F} <PolIfCoeffIsPlusOrMinusOne>`. + + The actual printing of the coefficients, when not equal to plus or + minus one, is handled by :ref:`\\PolTypesetOne{\<raw_coeff\>} <PolTypesetOne>`. + +.. _PolIfCoeffIsPlusOrMinusOne: + +``\PolIfCoeffIsPlusOrMinusOne{}{}`` +*********************************** + +Syntax: ``\PolIfCoeffIsPlusOrMinusOne{T}{F}`` + + This macro is a priori undefined. + + It is defined via the default :ref:`\\PolTypesetCmd{\<raw_coeff\>} <PolTypesetCmd>` to be + used if needed in the execution of `\\PolTypesetMonomialCmd`_, + e.g. to insert a ``\cdot`` in front of ``\PolVar^{\PolIndex}`` if + the coefficient is not plus or minus one. + + The macro will execute ``T`` if the coefficient has been found to be + plus or minus one, and ``F`` if not. It chooses expandably between + ``T`` and ``F``. + +.. _PolTypesetOne: + +``\PolTypesetOne{}`` +^^^^^^^^^^^^^^^^^^^^ + +Syntax: ``\PolTypesetOne{<raw_coeff>}`` + + Defaults to ``\xintTeXsignedFrac`` (LaTeX) or ``\xintTeXsignedOver`` + (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:: + + \def\PolTypesetOne#1{\xintDecToString{\xintREZ{#1}}} + % or with LaTeX+siunitx for example + \renewcommand\PolTypesetOne[1]{\num{\xintPFloat[5]{#1}}} + % (as \num of siunitx understands floating point notation) + \renewcommand\PolTypesetOne[1]{\num{\xintRound{4}{#1}}} + +.. _PolTypesetMonomialCmd: + +``\PolTypesetMonomialCmd`` +^^^^^^^^^^^^^^^^^^^^^^^^^^ + + This decides how a monomial (in variable ``\PolVar`` and with + exponent ``\PolIndex``) is to be printed. The default does nothing + for the constant term, ``\PolVar`` for the first degree and + ``\PolVar^{\PolIndex}`` for higher degrees monomials. Beware that + ``\PolIndex`` expands to digit tokens and needs termination in + ``\ifnum`` tests. + +.. _PolTypesetCmdPrefix: + +``\PolTypesetCmdPrefix{}`` +^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Syntax: ``\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 + ``\xintTeXsignedFrac`` (or ``\xintTeXsignedOver``) used by + :ref:`\\PolTypesetCmd{\<raw_coeff\>} <PolTypesetCmd>` will put the ``-`` sign in front of + the fraction (if it is a fraction) and this will thus serve as + separator in the typeset formula. Not used for the first term. + + +.. _PolTypeset*: + +``\PolTypeset*{}`` +~~~~~~~~~~~~~~~~~~ + +Syntax: ``\PolTypeset*{<pol. expr.>}`` + + Typesets in ascending powers. Use ``[<letter>]`` optional argument + (after the ``*``) to use another letter than ``x``. + + Extended at ``0.8`` to accept general expressions and not only + polynomial names. Redefine `\\PolToExprInVar`_ to use in the + expression another letter than default ``x``. + + +.. _PolLet: + +``\PolLet{}={}`` +~~~~~~~~~~~~~~~~ + +Syntax: ``\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 + ``\PolDef{<polname_2>}{<polname_1>(x)}`` or (better) + ``\PolDef{<polname_2>}{<polname_1>}`` but with less overhead. The + ``=`` is optional. + +.. _PolGlobalLet: + +``\PolGlobalLet{}={}`` +~~~~~~~~~~~~~~~~~~~~~~ + +Syntax: ``\PolGlobalLet{<polname_2>}={<polname_1>}`` + + Acts globally. + +.. _PolAssign: + +``\PolAssign{}\toarray{}`` +~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Syntax: ``\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. + + - 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. + + - Out-of-range #1's return ``0/1[0]``. + + See also :ref:`\\PolNthCoeff{\<polname\>}{\<index\>} <PolNthCoeff>`. + +.. _PolGet: + +``\PolGet{}\fromarray{}`` +~~~~~~~~~~~~~~~~~~~~~~~~~ + +Syntax: ``\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``. + + The leading zeros are removed from the polynomial. + + (contrived) Example:: + + \xintAssignArray{1}{-2}{5}{-3}\to\foo + \PolGet{f}\fromarray\foo + + This will define ``f`` as would have ``\poldef f(x):=1-2x+5x^2-3x^3;``. + + .. vieux commentaire + + Prior to ``0.5``, coefficients were not normalized via + ``\xintRaw`` for internal storage. + +.. _PolFromCSV: + +``\PolFromCSV{}{}`` +~~~~~~~~~~~~~~~~~~~ + +Syntax: ``\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``. + + 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. + + See also expandable macro :ref:`\\PolToCSV{\<polname\>} <PolToCSV>`. + + .. vieux commentaire + + Prior to ``0.5``, coefficients were not normalized via + ``\xintRaw`` for internal storage. + + +.. _PolMapCoeffs: + +``\PolMapCoeffs{}{}`` +~~~~~~~~~~~~~~~~~~~~~ + +Syntax: ``\PolMapCoeffs{\macro}{<polname>}`` + + It modifies ('in-place': original coefficients get lost) each + coefficient of the defined polynomial via the *expandable* macro + ``\macro``. The degree is adjusted as necessary if some leading + 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_ + internal format. This means that it probably will have to be + 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 + ``f_n`` by ``f_n*n^2``. + +.. _PolReduceCoeffs: + +``\PolReduceCoeffs{}`` +~~~~~~~~~~~~~~~~~~~~~~ + +Syntax: ``\PolReduceCoeffs{<polname>}`` + + Reduces the internal representations of the coefficients to + their lowest terms. + +.. _PolReduceCoeffs*: + +``\PolReduceCoeffs*{}`` +~~~~~~~~~~~~~~~~~~~~~~~ + +Syntax: ``\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 + a separate ``10^2`` part. This will thus get replaced by ``3e^2/5`` + (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 + :ref:`\\PolReduceCoeffs{\<polname\>} <PolReduceCoeffs>`: as the numerators and denominators + remain generally smaller. + +.. _PolMakeMonic: + +``\PolMakeMonic{}`` +~~~~~~~~~~~~~~~~~~~ + +Syntax: ``\PolMakeMonic{<polname>}`` + + Divides by the leading coefficient. It is recommended to execute + :ref:`\\PolReduceCoeffs*{\<polname\>} <PolReduceCoeffs*>` immediately afterwards. This is not + done automatically, in case the original polynomial had integer + coefficients and the user wants to keep the leading one as common + denominator for typesetting purposes. + +.. _PolMakePrimitive: + +``\PolMakePrimitive{}`` +~~~~~~~~~~~~~~~~~~~~~~~ + +Syntax: ``\PolMakePrimitive{<polname>}`` + + Divides by the integer content see (`\\PolIContent`_). + This thus produces a polynomial with integer + coefficients having no common factor. The sign of the leading + coefficient is not modified. + +.. _PolDiff: + +``\PolDiff{}{}`` +~~~~~~~~~~~~~~~~ + +Syntax: ``\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`` + by ``f'``. + + Coefficients of the result ``polname_2`` are irreducible fractions + (see `Technicalities`_ for the whole story.) + +.. _PolDiff[]: + +``\PolDiff[]{}{}`` +~~~~~~~~~~~~~~~~~~ + +Syntax: ``\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 + ``\PolLet{<polname_2>}={<polname_1>}``. With negative ``N``, switches to + using ``\PolAntiDiff``. + +.. _PolAntiDiff: + +``\PolAntiDiff{}{}`` +~~~~~~~~~~~~~~~~~~~~ + +Syntax: ``\PolAntiDiff{<polname_1>}{<polname_2>}`` + + This sets ``polname_2`` to the primitive of ``polname_1`` vanishing + at zero. + + Coefficients of the result ``polname_2`` are irreducible fractions + (see `Technicalities`_ for the whole story.) + +.. _PolAntiDiff[]: + +``\PolAntiDiff[]{}{}`` +~~~~~~~~~~~~~~~~~~~~~~~ + +Syntax: ``\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: + +``\PolDivide{}{}{}{}`` +~~~~~~~~~~~~~~~~~~~~~~ + +Syntax: ``\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 + ``polname_2``. + +.. _PolQuo: + +``\PolQuo{}{}{}`` +~~~~~~~~~~~~~~~~~ + +Syntax: ``\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: + +``\PolRem{}{}{}`` +~~~~~~~~~~~~~~~~~ + +Syntax: ``\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: + +``\PolGCD{}{}{}`` +~~~~~~~~~~~~~~~~~ + +Syntax: ``\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 + ``polname_1`` and ``polname_2`` vanish, then ``polname_GCD`` is the + zero polynomial. + +.. ``\PolIGCD{<polname_1>}{<polname_2>}{polname_iGCD}`` + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + **NOT YET** + + This **assumes** that the two polynomials have integer coefficients. + It then computes the greatest common divisor in the integer + polynomial ring, normalized to have a positive leading coefficient + (if the inputs are not both zero). + + +Root localization routines via the `Sturm Theorem`_ +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +As :ref:`\\PolToSturm{\<polname\>}{\<sturmname\>} <PolToSturm>` and +:ref:`\\PolSturmIsolateZeros{\<sturmname\>} <PolSturmIsolateZeros>` and variants declare +additional polynomial or scalar variables with names based on ``<sturmname>`` as +prefix, it is advisable to keep the ``<sturmname>`` namespace separate from +the one applying to ``\xintexpr`` variables generally, or to polynomials. + +.. _PolToSturm: + +``\PolToSturm{}{}`` +^^^^^^^^^^^^^^^^^^^ + +Syntax: ``\PolToSturm{<polname>}{<sturmname>}`` + + With ``<polname>`` being for example ``P``, and ``<sturmname>`` being + for example ``S``, the macro starts by computing the derivative + ``P'``, then computes the opposite of the remainder in the euclidean + division of ``P`` by ``P'``, then the opposite of the remainder in + the euclidean division of ``P'`` by the first obtained polynomial, + etc... Up to signs following the ``--++--++...`` pattern, these are + the same remainders as in the Euclide algorithm applied to the + computation of the GCD of ``P`` and ``P'``. + + The precise process differs from the above description: the + algorithm first sets ``S_0_`` to be the *primitive part* of ``P`` + and ``S_1_`` to be the *primitive part* of ``P'`` (see + :ref:`\\PolIContent{\<polname\>} <PolIContent>`), then at each step + the remainder is made primitive and stored for internal reference as + ``S_k_``, so only integer-coefficients polynomials are manipulated. + + .. warning:: + + This exact procedure will perhaps in future be replaced by a + *sub-resultant algorithm*, which may bring some speed gain in + obtaining a pseudo-Sturm sequence, but some experimenting is + needed, in the context of realistically realizable computations + by the package; primitive polynomials although a bit costly + have the smallest coefficients hence are the best for the kind of + computations done for root localization, after having computed a + Sturm sequence. + + The last non-zero primitivized remainder ``S_N_`` is, up to sign, + the primitive part of the GCD of ``P`` and ``P'``. Its roots (real + and complex) are the multiple roots of the original ``P``. The + original ``P`` was "square-free" (i\.e\. did not have multiple real + or complex roots) if and only if ``S_N_`` is a constant, which is + then ``+1`` or ``-1`` (its value before primitivization is lost). + + The macro then divides each ``S_k_`` by ``S_N_`` and declares the + quotients ``S_k`` as user polynomials for future use. By Gauss + theorem about the contents of integer-coefficients polynomials, + these ``S_k`` also are primitive integer-coefficients polynomials. + + This step will be referred to as *normalization*, and in this + documentation the obtained polynomials are said to constitute the + "Sturm chain" (or "Sturm sequence"), i.e. by convention the "Sturm + chain polynomials" are square-free and primitive. The possibly + non-square-free ones are referred to as *non-normalized*. + + As an exception to the rule, if the original ``P`` was "square-free" + (i\.e\. did not have multiple real or complex roots) then + normalization is skipped (in that case ``S_N_`` is either ``+1`` or + ``-1``), so ``S_0_`` is exactly the primitive part of starting + polynomial ``P``, in the "square-free" case. + + The next logical step is to execute `\\PolSturmIsolateZeros{S} + <PolSturmIsolateZeros_>`_ or one of its variants. Be careful not to + use the names ``sturmname_0``, ``sturmname_1``, etc... for defining + other polynomials after having done + ``\PolToSturm{<polname>}{<sturmname>}`` and before executing + ``\PolSturmIsolateZeros{<sturmname>}`` or its variants else the + latter will behave erroneously. + + .. note:: + + The declaration of the ``S_k``\ 's will overwrite + with no warning previously declared polynomials with identical + names ``S_k``. This is original reason why the macro expects two + names: ``<polname>`` and ``<sturmname>``. + + It is allowed to use the polynomial name ``P`` as Sturm chain + name ``S``: ``\PolToSturm{f}(f}``, but of course fusing the + namespaces is slightly dangerous. And, also `\\PolSturmIsolateZeros + <PolSturmIsolateZeros_>`_ creates variables sharing + the ``<sturmname>`` prefix, which must be taken into account to + avoid name clashes. + + .. warning:: + + The reason why the ``S_k``\ 's are declared as polynomials is + that the associated polynomial functions are needed to compute + the sign changes in the Sturm sequence evaluated at a given + location, as this is the basis mechanism of `\\PolSturmIsolateZeros + <PolSturmIsolateZeros_>`_ (on the basis of the `Sturm theorem`_). + + It is possible that in future the package will only internally + construct such polynomial functions and only the starred variant + will make the normalized (i.e. square-free) Sturm sequence public. + + The integer ``N`` giving the length of the Sturm chain ``S_0``, + ``S_1``, ..., ``S_N`` is available as + :ref:`\\PolSturmChainLength{\<sturmname\>} <PolSturmChainLength>`. If all roots of original ``P`` + are real, then ``N`` is both the number of distinct real roots and + the degree of ``S_0``. In the case of existence of complex roots, + the number of distinct real roots is at most ``N`` and ``N`` is at + most the degree of ``S_0``. + +.. _PolToSturm*: + +``\PolToSturm*{}{}`` +^^^^^^^^^^^^^^^^^^^^ + +Syntax: ``\PolToSturm*{<polname>}{<sturmname>}`` + + Does the same as `un-starred version <PolToSturm_>`_ and additionally it + keeps for user usage the memory of the *un-normalized* (but still + made primitive) Sturm chain + polynomials ``sturmname_k_``, ``k=0,1, ..., N``, with + ``N`` being :ref:`\\PolSturmChainLength{\<sturmname\>} <PolSturmChainLength>`. + + .. comment + + The square-free part of ``<polname>`` is ``sturmname_0``, and their + quotient is the polynomial with name + ``sturmname_\PolSturmChainLength{<sturmname>}_``. It thus easy to + set-up a loop iteratively computing the latter until the last one + is a constant, thus obtaining the decomposition of an ``f`` as + a product ``c f_1 f_2 f_3 ...`` of a constant and square-free (primitive) + polynomials, where each ``f_i`` divides its predecessor. + +.. _PolSturmIsolateZeros: + +``\PolSturmIsolateZeros{}`` +^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Syntax: ``\PolSturmIsolateZeros{<sturmname>}`` + + The macro locates, using the `Sturm Theorem`_, as many disjoint + intervals as there are distinct real roots. + + .. important:: + + The Sturm chain must have been produced by an earlier + :ref:`\\PolToSturm{\<polname\>}{\<sturmname\>} <PolToSturm>`. + + After its execution they are two types of such intervals (stored in + memory and accessible via macros or xintexpr_ variables, see below): + + - singleton ``{a}``: then ``a`` is a root, (necessarily a decimal + number, but not all such decimal numbers are exactly identified yet). + + - open intervals ``(a,b)``: then there is exactly one root ``z`` + such that ``a < z < b``, and the end points are guaranteed to not + be roots. + + The interval boundaries are decimal numbers, originating + in iterated decimal subdivision from initial intervals + ``(-10^E, 0)`` and ``(0, 10^E)`` with ``E`` chosen initially large + enough so that all roots are enclosed; if zero is a root it is always + identified as such. The non-singleton intervals are of the + type ``(a/10^f, (a+1)/10^f)`` with ``a`` an integer, which is + neither ``0`` nor ``-1``. Hence either ``a`` and ``a+1`` are both positive + or they are both negative. + + One does not *a priori* know what will be the lengths of these + intervals (except that they are always powers of ten), they + vary depending on how many digits two successive roots have in + common in their respective decimal expansions. + + .. important:: + + If some two consecutive intervals share an end-point, no + information is yet gained about the separation between the two + roots which could at this stage be arbitrarily small. + + See :ref:`\\PolRefineInterval*{\<sturmname\>}{\<index\>} <PolRefineInterval*>` which addresses + this issue. + + .. This procedure is covariant + with the independent variable ``x`` becoming ``-x``. + Hmm, pas sûr et trop fatigué + + Let us suppose ``<sturmname>`` is ``S``. + + The interval boundaries (and exactly found roots) are made available + for future computations in ``\xintexpr/xinteval`` or ``\poldef`` as + variables ``SL_1``, ``SL_2``, etc..., for the left end-points and + ``SR_1``, ``SR_2``, ..., for the right end-points. + + Additionally, xintexpr_ variable ``SZ_1_isknown`` will have value + ``1`` if the root in the first interval is known, and ``0`` + otherwise. And similarly for the other intervals. + + .. important:: + + The variable declarations are done with no check of existence of + previously existing variables with identical names. + + Also, macros :ref:`\\PolSturmIsolatedZeroLeft{\<sturmname\>}{\<index\>} <PolSturmIsolatedZeroLeft>` and + :ref:`\\PolSturmIsolatedZeroRight{\<sturmname\>}{\<index\>} <PolSturmIsolatedZeroRight>` are provided which + expand to these same values, written in decimal notation (i.e. + pre-processed by `\\PolDecToString <PolDecToString_>`_.) And there + is also :ref:`\\PolSturmIfZeroExactlyKnown{\<sturmname\>}{\<index\>}{T}{F} <PolSturmIfZeroExactlyKnown>`. + + .. important:: + + Trailing zeroes in the stored decimal numbers accessible via the + macros are significant: they are also present in the decimal + expansion of the exact root, so as to be able for example to + print out bounds of real roots with as many digits as is + significant, even if the digits are zeros. + + The start of the decimal expansion of the ``<index>``-th root is given by + `\\PolSturmIsolatedZeroLeft{<sturmname>}{<index>} + <PolSturmIsolatedZeroLeft_>`_ if the root is positive, and by + `\PolSturmIsolatedZeroRight{<sturmname>}{<index>} + <PolSturmIsolatedZeroRight_>`_ if the root is neagtive. These two + decimal numbers are either both zero or both of the same sign. + + The number of distinct roots is obtainable expandably as + :ref:`\\PolSturmNbOfIsolatedZeros{\<sturmname\>} <PolSturmNbOfIsolatedZeros>`. + + Furthermore + :ref:`\\PolSturmNbOfRootsOf{\<sturmname\>}\\LessThanOrEqualTo{\<value\>} <PolSturmNbOfRootsOfLessThanOrEqualTo>` and + :ref:`\\PolSturmNbOfRootsOf{\<sturmname\>}\\LessThanOrEqualToExpr{\<num. expr.\>} <PolSturmNbOfRootsOfLessThanOrEqualToExpr>`. + will expandably compute respectively the number of real roots at + most equal to ``value`` or ``expression``, and the same but with + multiplicities. + + These variables and macros are automatically updated in case of + subsequent usage of :ref:`\\PolRefineInterval*{\<sturmname\>}{\<index\>} <PolRefineInterval*>` or + other localization improving macros. + + .. note:: + + The current polexpr implementation defines the xintexpr_ variables + and xinttools_ arrays as described above with global scope. On the + other hand the Sturm sequence polynomials obey the current scope. + + This is perhaps a bit inconsistent and may change in future. + + .. note:: + + The results are exact + bounds for the mathematically exact real roots. + + Future releases will perhaps also provide macros based on Newton + or Regula Falsi methods. Exact computations with such methods + lead however quickly to very big fractions, and this forces usage + of some rounding scheme for the abscissas if computation times + are to remain reasonable. This raises issues of its own, which + are studied in numerical mathematics. + +.. _PolSturmIsolateZeros*: + +``\PolSturmIsolateZeros*{}`` +^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Syntax: ``\PolSturmIsolateZeros*{<sturmname>}`` + + The macro does the same as :ref:`\\PolSturmIsolateZeros{\<sturmname\>} <PolSturmIsolateZeros>` and + then in addition it does the extra work to determine all + multiplicities of the real roots. + + After execution, + :ref:`\\PolSturmIsolatedZeroMultiplicity{\<sturmname\>}{\<index\>} <PolSturmIsolatedZeroMultiplicity>` expands + 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_ + variables ``SM_1``, ``SM_2``... hold the multiplicities thus + computed. + + .. note:: + + Somewhat counter-intuitively, it is not necessary to have + executed the :ref:`\\PolToSturm* <PolToSturm*>` + starred variant: during its + execution, :ref:`\\PolToSturm <PolToSturm>`, + even though it does not declare the + 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`` example in ``polexpr-examples.pdf``. + +.. _PolSturmIsolateZerosAndGetMultiplicities: + +``\PolSturmIsolateZerosAndGetMultiplicities{}`` +*********************************************** + +Syntax: ``\PolSturmIsolateZerosAndGetMultiplicities{<sturmname>}`` + + This is another name for :ref:`\\PolSturmIsolateZeros*{\<sturmname\>} <PolSturmIsolateZeros*>`. + +.. _PolSturmIsolateZeros**: + +``\PolSturmIsolateZeros**{}`` +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Syntax: ``\PolSturmIsolateZeros**{<sturmname>}`` + + The macro does the same as :ref:`\\PolSturmIsolateZeros*{\<sturmname\>} <PolSturmIsolateZeros*>` and + in addition it does the extra work to determine all the *rational* + roots. + + .. note:: + + After execution of this macro, a root is "known" if and only if + it is rational. + + Furthermore, primitive polynomial ``sturmname_sqf_norr`` is created + to match the (square-free) ``sturmname_0`` from which all rational + roots have been removed. The number of distinct rational roots is + thus the difference between the degrees of these two polynomials + (see also :ref:`\\PolSturmNbOfRationalRoots{\<sturmname\>} + <PolSturmNbOfRationalRoots>`). + + And ``sturmname_norr`` is ``sturmname_0_`` from which all rational + roots have been removed, i.e. it contains the irrational roots of + the original polynomial, with the same multiplicities. + + See ``A degree five polynomial with three rational + roots`` in ``polexpr-examples.pdf``. + +.. _PolSturmIsolateZerosGetMultiplicitiesAndRationalRoots: + +``\PolSturmIsolateZerosGetMultiplicitiesAndRationalRoots`` +********************************************************** + +Syntax: ``\PolSturmIsolateZerosGetMultiplicitiesAndRationalRoots`` + + This is another name for :ref:`\\PolSturmIsolateZeros**{\<sturmname\>} <PolSturmIsolateZeros**>`. + +.. _PolSturmIsolateZerosAndFindRationalRoots: + +``\PolSturmIsolateZerosAndFindRationalRoots{}`` +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Syntax: ``\PolSturmIsolateZerosAndFindRationalRoots{<sturmname>}`` + + This works exactly like :ref:`\\PolSturmIsolateZeros**{\<sturmname\>} <PolSturmIsolateZeros**>` + (inclusive of declaring the polynomials ``sturmname_sqf_norr`` and + ``sturmname_norr`` with no rational roots) except that it does *not* + compute the multiplicities of the *non-rational* roots. + + .. note:: + + There is no macro to find the rational roots but not compute + their multiplicities at the same time. + + .. attention:: + + This macro does *not* define xintexpr_ variables + ``sturmnameM_1``, ``sturmnameM_2``, ... holding the + multiplicities and it leaves the multiplicity array (whose accessor + is :ref:`\\PolSturmIsolatedZeroMultiplicity{\<sturmname\>}{\<index\>} <PolSturmIsolatedZeroMultiplicity>`) into + a broken state, as all non-rational roots will supposedly have + multiplicity one. This means that the output of + `\\PolPrintIntervals* <PolPrintIntervals*_>`_ will be + erroneous regarding the multiplicities of irrational roots. + + I decided to document it because finding multiplicities of the + non rational roots is somewhat costly, and one may be interested + only into finding the rational roots (of course random + polynomials with integer coefficients will not have *any* + rational root anyhow). + + +.. _PolRefineInterval*: + +``\PolRefineInterval*{}{}`` +^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Syntax: ``\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 + interval to have both its end-points distinct from the end-points of + the original interval. As a consequence, the ``k``\ th root is then + strictly separated from the other roots. + +.. _PolRefineInterval[]: + +``\PolRefineInterval[]{}{}`` +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Syntax: ``\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 + ``N`` times if the optional argument ``[N]`` is present. + +.. _PolEnsureIntervalLength: + +``\PolEnsureIntervalLength{}{}{}`` +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Syntax: ``\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 + after decimal mark of the ``k``\ th root will then be known exactly. + +.. _PolEnsureIntervalLengths: + +``\PolEnsureIntervalLengths{}{}`` +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Syntax: ``\PolEnsureIntervalLengths{<sturmname>}{<exponent>}`` + + The intervals as obtained from ``\PolSturmIsolateZeros`` are (if + necessary) subdivided further by (base 10) dichotomy in order for + each of them to have length at most ``10^E``. + + This means that decimal expansions of all roots will be known with + ``-E`` digits (for ``E<0``) after decimal mark. + +.. _PolSetToSturmChainSignChangesAt: + +``\PolSetToSturmChainSignChangesAt{}{}{}`` +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Syntax: ``\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.) + + 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: + +``\PolSetToNbOfZerosWithin{}{}{}{}`` +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Syntax: ``\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 + the interval ``(value_left, value_right]``. The macro first + re-orders end-points if necessary for ``value_left <= value_right`` + to hold. + + In accordance to `Sturm Theorem`_ this is computed as the difference + between the number of sign changes of the Sturm chain at ``value_right`` + and the one at ``value_left``. + + The definition is made with global scope. For local scope, use + ``[\empty]`` as extra optional argument. + + One can use this immediately after creation of a Sturm chain. + + See also the expandable + :ref:`\\PolSturmNbOfRootsOf{\<sturmname\>}\\LessThanOrEqualTo{value} <PolSturmNbOfRootsOfLessThanOrEqualTo>`, + which however requires prior execution of `\\PolSturmIsolateZeros + <PolSturmIsolateZeros_>`_. + + See also the expandable + :ref:`\\PolSturmNbWithMultOfRootsOf{\<sturmname\>}\\LessThanOrEqualTo{value} <PolSturmNbWithMultOfRootsOfLessThanOrEqualTo>` + which requires prior execution of + `\\PolSturmIsolateZeros* <PolSturmIsolateZeros*_>`_. + +.. _PolPrintIntervals: + +Displaying the found roots: ``\PolPrintIntervals[<varname>]{}`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Syntax: ``\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 + specify a replacement for the default ``Z``). This will be done (by + default) in a + math mode ``array``, one interval per row, and pattern ``rcccl``, + where the second and fourth column hold the ``<`` sign, except when + the interval reduces to a singleton, which means the root is known + exactly. + + .. note:: + + The explanations here and in this section are for LaTeX. With + other TeX macro formats, the LaTeX syntax such as for example + ``\begin{array}{rcccl}`` which appears in the documentation here + is actually replaced with quasi-equivalent direct use of TeX + primitives. + + The next macros which govern its output. + +.. _PolPrintIntervalsNoRealRoots: + +``\PolPrintIntervalsNoRealRoots`` +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + + Executed in place of an ``array`` environment, when there are no + real roots. Default definition:: + + \newcommand\PolPrintIntervalsNoRealRoots{} + +.. _PolPrintIntervalsBeginEnv: + +``\PolPrintIntervalsBeginEnv`` +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + + 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: + +``\PolPrintIntervalsRowSeparator`` +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + + Expands by default to ``\\`` with LaTeX and to ``\cr`` with Plain + + Added at ``0.8.6``. + +.. _PolPrintIntervalsKnownRoot: + +``\PolPrintIntervalsKnownRoot`` +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + + Default definition:: + + \newcommand\PolPrintIntervalsKnownRoot{% + &&\PolPrintIntervalsTheVar_{\PolPrintIntervalsTheIndex}% + &=&\PolPrintIntervalsPrintExactZero + } + +.. _PolPrintIntervalsUnknownRoot: + +``\PolPrintIntervalsUnknownRoot`` +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + + Default definition:: + + \newcommand\PolPrintIntervalsUnknownRoot{% + \PolPrintIntervalsPrintLeftEndPoint&<&% + \PolPrintIntervalsTheVar_{\PolPrintIntervalsTheIndex}&<&% + \PolPrintIntervalsPrintRightEndPoint + } + + +.. _PolPrintIntervalsPrintExactZero: + +``\PolPrintIntervalsPrintExactZero`` +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + + Default definition:: + + \newcommand\PolPrintIntervalsPrintExactZero{\PolPrintIntervalsTheLeftEndPoint} + + +.. _PolPrintIntervalsPrintLeftEndPoint: + +``\PolPrintIntervalsPrintLeftEndPoint`` +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + + Default definition:: + + \newcommand\PolPrintIntervalsPrintLeftEndPoint{\PolPrintIntervalsTheLeftEndPoint} + +.. _PolPrintIntervalsPrintRightEndPoint: + +``\PolPrintIntervalsPrintRightEndPoint`` +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + + Default definition is:: + + \newcommand\PolPrintIntervalsPrintRightEndPoint{\PolPrintIntervalsTheRightEndPoint} + +.. _PolPrintIntervals*: + +``\PolPrintIntervals*[<varname>]{}`` +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Syntax: ``\PolPrintIntervals*[<varname>]{<sturmname>}`` + + This starred variant produces an alternative output (which + displays the root multiplicity), and is provided as an + example of customization. + + As replacement for `\\PolPrintIntervalsKnownRoot`_, + `\\PolPrintIntervalsPrintExactZero`_, + `\\PolPrintIntervalsUnknownRoot`_ it uses its own + ``\POL@@PrintIntervals...`` macros. We only reproduce here one + definition:: + + \newcommand\POL@@PrintIntervalsPrintExactZero{% + \displaystyle + \xintTeXsignedFrac{\PolPrintIntervalsTheLeftEndPoint}% + }% + + Multiplicities are printed using this auxiliary macro: + +.. _PolPrintIntervalsPrintMultiplicity: + +``\PolPrintIntervalsPrintMultiplicity`` +*************************************** + + whose default definition is:: + + \newcommand\PolPrintIntervalsPrintMultiplicity{(\mbox{mult. }\PolPrintIntervalsTheMultiplicity)} + + +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. + +These macros expand completely in two steps except ``\PolToExpr`` and +``\PolToFloatExpr`` which need a ``\write``, ``\edef`` or a +``\csname...\endcsname`` context. + +.. _PolToExpr: + +``\PolToExpr{}`` +~~~~~~~~~~~~~~~~ + +Syntax: ``\PolToExpr{<pol. expr.>}`` + + Produces expandably [#]_ the string ``coeff_N*x^N+...``, i.e. the + polynomial is using descending powers. + + .. [#] requires exhaustive expansion, for example as triggered by + ``\write`` or ``\edef``. + + Since ``0.8`` the input is not restricted to be a polynomial name but + 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, 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``), + + - negative coefficients are not prefixed by a ``+`` sign (else, + Maple would not be happy), + + - coefficients numerically equal to ``1`` (or ``-1``) are present + only via their sign, + + - the letter ``x`` is used and the degree one monomial is output as + ``x``, not as ``x^1``. + + - (``0.8``) the caret ``^`` is of catcode 12. This means that one + can for convenience typeset in regular text mode, for example + using ``\texttt`` (in LaTeX). But TeX will not know how to break + the expression across end-of-lines anyhow. Formerly ``^`` was + suitable for math mode but as the exponent is not braced this + worked only for polynomials of degrees at most 9. Anyhow this + is not supposed to be a typesetting macro. + + Complete customization is possible, see the next macros. Any user + redefinition must maintain the expandability property. + +.. _PolToExprVar: + +``\PolToExprVar`` +^^^^^^^^^^^^^^^^^ + + Defaults to ``x``. The letter used in the macro output. + + +.. _PolToExprInVar: + +``\PolToExprInVar`` +^^^^^^^^^^^^^^^^^^^ + + 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 + have to contain any ``x``. + + (new with ``0.8``) + +.. _PolToExprTimes: + +``\PolToExprTimes`` +^^^^^^^^^^^^^^^^^^^ + + Defaults to ``*``. + +.. _PolToExprCaret: + +``\PolToExprCaret`` +^^^^^^^^^^^^^^^^^^^ + + Defaults to ``^`` of catcode 12. Set it to + expand to ``**`` for Python compatible output. + + (new with ``0.8``) + +.. _PolToExprCmd: + +``\PolToExprCmd{}`` +^^^^^^^^^^^^^^^^^^^ + +Syntax: ``\PolToExprCmd{<raw_coeff>}`` + + Defaults to ``\xintPRaw{\xintRawWithZeros{#1}}``. + + This means that the coefficient value is printed-out as a fraction + ``a/b``, skipping the ``/b`` part if ``b`` turns out to be one. + + Configure it to be ``\xintPRaw{\xintIrr{#1}}`` if the fractions + must be in irreducible terms. + + An alternative is ``\xintDecToString{\xintREZ{#1}}`` which uses + integer or decimal fixed point format such as ``23.0071`` if the + internal representation of the number only has a power of ten as + denominator (the effect of ``\xintREZ`` here is to remove trailing + decimal zeros). The behaviour of ``\xintDecToString`` is not yet + stable for other cases, and for example at time of writing no + attempt is made to identify inputs having a finite decimal expansion + so for example ``23.007/2`` or ``23.007/25`` can appear in output + and not their finite decimal expansion with no denominator. + +.. _PolToExprOneTerm: + +``\PolToExprOneTerm{}{}`` +^^^^^^^^^^^^^^^^^^^^^^^^^ + +Syntax: ``\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``. + + For its default definition, see the source code. It uses + `\\PolToExprCmd <PolToExprCmd_>`_, `\\PolToExprTimes + <PolToExprTimes_>`_, `\\PolToExprVar <PolToExprVar_>`_ and + `\\PolToExprCaret`_. + +.. _PolToExprOneTermStyleA: + +``\PolToExprOneTermStyleA{}{}`` +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Syntax: ``\PolToExprOneTermStyleA{<raw_coeff>}{<exponent>}`` + + This holds the default package meaning of ``\PolToExprOneTerm``. + +.. _PolToExprOneTermStyleB: + +``\PolToExprOneTermStyleB{}{}`` +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Syntax: ``\PolToExprOneTermStyleB{<raw_coeff>}{<exponent>}`` + + This holds an alternative meaning, which puts the fractional part of + a coefficient after the monomial, i.e. like this:: + + 2*x^11/3+3*x^8/7-x^5-x^4/4-x^3-x^2/2-2*x+1 + + `\\PolToExprCmd <PolToExprCmd_>`_ isn't used at all in this style. But + `\\PolToExprTimes <PolToExprTimes_>`_, `\\PolToExprVar + <PolToExprVar_>`_ and `\\PolToExprCaret`_ are obeyed. + + To activate it use ``\let\PolToExprOneTerm\PolToExprOneTermStyleB``. + To revert to the package default behaviour, issue + ``\let\PolToExprOneTerm\PolToExprOneTermStyleA``. + +.. _PolToExprTermPrefix: + +``\PolToExprTermPrefix{}`` +^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Syntax: ``\PolToExprTermPrefix{<raw_coeff>}`` + + It receives as argument the coefficient. Its default behaviour is + to produce a ``+`` if the coefficient is positive, which will thus + serve to separate the monomials in the output. This is to match + the default for :ref:`\\PolToExprCmd{\<raw_coeff\>} <PolToExprCmd>` which in case of a + positive coefficient does not output an explicit ``+`` prefix. + +.. _PolToFloatExpr: + +``\PolToFloatExpr{}`` +~~~~~~~~~~~~~~~~~~~~~ + +Syntax: ``\PolToFloatExpr{<pol. expr.>}`` + + Similar to :ref:`\\PolToExpr{\<pol. expr.\>} <PolToExpr>` but using + :ref:`\\PolToFloatExprCmd{\<raw_coeff\>} <PolToFloatExprCmd>` which by default rounds and + converts the coefficients to floating point format. + + .. note:: + + This is unrelated to :ref:`\\PolGenFloatVariant{\<polname\>} <PolGenFloatVariant>`: + :ref:`\\PolToFloatExprCmd{\<raw_coeff\>} <PolToFloatExprCmd>` operates on the *exact* + coefficients anew (and may thus produce something else than + the coefficients of the polynomial function acting + in ``\xintfloateval`` if the floating point precision was changed + in between). + + Extended at ``0.8`` to accept general expressions as input. + +.. _PolToFloatExprOneTerm: + +``\PolToFloatExprOneTerm{}{}`` +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Syntax: ``\PolToFloatExprOneTerm{<raw_coeff>}{<exponent>}`` + + Similar to :ref:`\\PolToExprOneTerm{\<raw_coeff\>}{\<exponent\>} <PolToExprOneTerm>`. But does not treat + especially coefficients equal to plus or minus one. + +.. _PolToFloatExprCmd: + +``\PolToFloatExprCmd{}`` +^^^^^^^^^^^^^^^^^^^^^^^^ + +Syntax: ``\PolToFloatExprCmd{<raw_coeff>}`` + + The one-argument macro used by ``\PolToFloatExprOneTerm``. + It defaults to ``\xintPFloat{#1}``, which trims trailing + zeroes. + + *changed at 0.8.2* Formerly it was using ``\xintFloat``. + +.. _PolToExpr*: + +``\PolToExpr*{}`` +~~~~~~~~~~~~~~~~~ + +Syntax: ``\PolToExpr*{<pol. expr.>}`` + + Ascending powers: ``coeff_0+coeff_1*x+coeff_2*x^2+...``. + + Extended at ``0.8`` to accept general expressions as input. + + Customizable with the same macros as for + :ref:`\\PolToExpr{\<pol. expr.\>} <PolToExpr>`. + +.. _PolToFloatExpr*: + +``\PolToFloatExpr*{}`` +~~~~~~~~~~~~~~~~~~~~~~ + +Syntax: ``\PolToFloatExpr*{<pol. expr.>}`` + + Ascending powers. + + Extended at ``0.8`` to accept general expressions as input. + +.. _PolNthCoeff: + +``\PolNthCoeff{}{}`` +~~~~~~~~~~~~~~~~~~~~ + +Syntax: ``\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. + + Negative indices ``N=-1``, ``-2``, ... return the leading + coefficient, sub-leading coefficient, ..., and finally ``0/1[0]`` + for ``N<-1-degree``. + +.. _PolLeadingCoeff: + +``\PolLeadingCoeff{}`` +~~~~~~~~~~~~~~~~~~~~~~ + +Syntax: ``\PolLeadingCoeff{<polname>}`` + + Expands to the leading coefficient. + +.. _PolDegree: + +``\PolDegree{}`` +~~~~~~~~~~~~~~~~ + +Syntax: ``\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: + +``\PolIContent{}`` +~~~~~~~~~~~~~~~~~~ + +Syntax: ``\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 + with integer coefficients having no common prime divisor. + + See `\\PolMakePrimitive <PolMakePrimitive_>`_. + +.. _PolToList: + +``\PolToList{}`` +~~~~~~~~~~~~~~~~ + +Syntax: ``\PolToList{<polname>}`` + + Expands to ``{coeff_0}{coeff_1}...{coeff_N}`` with ``N`` = degree, and + ``coeff_N`` the leading coefficient + (the zero polynomial does give ``{0/1[0]}`` and not an + empty output.) + +.. _PolToCSV: + +``\PolToCSV{}`` +~~~~~~~~~~~~~~~ + +Syntax: ``\PolToCSV{<polname>}`` + + Expands to ``coeff_0, coeff_1, coeff_2, ....., coeff_N``, starting + with constant term and ending with leading coefficient. Converse + to :ref:`\\PolFromCSV{\<polname\>}{\<csv\>} <PolFromCSV>`. + + +.. _PolEvalAtExpr: + +``\PolEval{}\AtExpr{}`` +~~~~~~~~~~~~~~~~~~~~~~~ + +Syntax: ``\PolEval{<polname>}\AtExpr{<num. expr.>}`` + + Same output as + ``\xinteval{polname(numerical expression)}``. + +.. _PolEvalAt: + +``\PolEval{}\At{}`` +~~~~~~~~~~~~~~~~~~~ + +Syntax: ``\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. + +.. _PolEvalReducedAtExpr: + +``\PolEvalReduced{}\AtExpr{}`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Syntax: ``\PolEvalReduced{<polname>}\AtExpr{<num. expr.>}`` + + Same output as ``\xinteval{reduce(polname(numerical expression))}``. + +.. _PolEvalReducedAt: + +``\PolEvalReduced{}\At{}`` +~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Syntax: ``\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 + irreducible fraction. + +.. _PolFloatEvalAtExpr: + +``\PolFloatEval{}\AtExpr{}`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Syntax: ``\PolFloatEval{<polname>}\AtExpr{<num. expr.>}`` + + Same output as ``\xintfloateval{polname(numerical expression)}``. + + .. attention:: + + `\\PolGenFloatVariant <PolGenFloatVariant_>`_ must have + been issued before. + + To use the *exact coefficients* with *exactly executed* additions + and multiplications and do the rounding only as the final last step, + the following syntax can be used: [#]_ + + :: + + \xintfloateval{3.27*\xintexpr f(2.53)\relax^2} + + + .. [#] Cf. xintexpr_ documentation about nested expressions. + +.. _PolFloatEvalAt: + +``\PolFloatEval{}\At{}`` +~~~~~~~~~~~~~~~~~~~~~~~~ + +Syntax: ``\PolFloatEval{<polname>}\At{<value>}`` + + Evaluates the polynomial at the value which must be in (or expand + to) a format acceptable to the xintfrac_ macros. + + +Expandable macros in relation to root localization via `Sturm Theorem`_ +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +.. _PolSturmChainLength: + +``\PolSturmChainLength{}`` +^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Syntax: ``\PolSturmChainLength{<sturmname>}`` + + Returns the integer ``N`` such that ``sturmname_N`` is the last one + in the Sturm chain ``sturmname_0``, ``sturmname_1``, ... + + See :ref:`\\PolToSturm{\<polname\>}{\<sturmname\>} <PolToSturm>`. + +.. _PolSturmIfZeroExactlyKnown: + +``\PolSturmIfZeroExactlyKnown{}{}{}{}`` +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Syntax: ``\PolSturmIfZeroExactlyKnown{<sturmname>}{<index>}{T}{F}`` + + Executes ``T`` if the ``index``\ -th interval reduces to a singleton, + i.e. the root is known exactly, else ``F``. + + .. vieux commentaire + + ``index`` is allowed to be something like ``1+2*3`` as it is fed + to ``\the\numexpr...\relax``. + +.. _PolSturmIsolatedZeroLeft: + +``\PolSturmIsolatedZeroLeft{}{}`` +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Syntax: ``\PolSturmIsolatedZeroLeft{<sturmname>}{<index>}`` + + Expands to the left end-point for the ``index``\ -th interval, as + computed by some earlier :ref:`\\PolSturmIsolateZeros{\<sturmname\>} <PolSturmIsolateZeros>`. + + .. note:: + + Execution of this macro after some + `\\PolRefineInterval{<sturmname>}{<index>} <PolRefineInterval[]_>`_ + will take into account the now known tighter bounds. + + The value is pre-formatted using `\\PolDecTostring + <PolDecToString_>`_. + +.. _PolSturmIsolatedZeroRight: + +``\PolSturmIsolatedZeroRight{}{}`` +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Syntax: ``\PolSturmIsolatedZeroRight{<sturmname>}{<index>}`` + + Expands to the right end-point for the ``index``\ -th interval as + computed by some earlier :ref:`\\PolSturmIsolateZeros{\<sturmname\>} <PolSturmIsolateZeros>` and + possibly refined afterwards. + + The value is pre-formatted using `\\PolDecTostring + <PolDecToString_>`_. + +.. _PolSturmIsolatedZeroMultiplicity: + +``\PolSturmIsolatedZeroMultiplicity{}{}`` +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Syntax: ``\PolSturmIsolatedZeroMultiplicity{<sturmname>}{<index>}`` + + Expands to the multiplicity of the unique root contained in the + ``index``\ -th interval. + + .. attention:: + + A prior execution of :ref:`\\PolSturmIsolateZeros*{\<sturmname\>} <PolSturmIsolateZeros*>` is mandatory. + + See ``The degree nine polynomial with 0.99, 0.999, 0.9999 as triple + roots`` in ``polexpr-examples.pdf``. + +.. _PolSturmNbOfIsolatedZeros: + +``\PolSturmNbOfIsolatedZeros{}`` +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Syntax: ``\PolSturmNbOfIsolatedZeros{<sturmname>}`` + + Expands to the number of real roots of the polynomial + ``<sturmname>_0``, i.e. the number of distinct real roots of the + polynomial originally used to create the Sturm chain via + :ref:`\\PolToSturm{\<polname\>}{\<sturmname\>} <PolToSturm>`. + +.. warning:: + + The next few macros counting roots, with or without multiplicities, + less than or equal to some value, are under evaluation and may be + removed from the package if their utility is judged to be not high + enough. They can be re-coded at user level on the basis of the other + documented package macros anyway. + +.. _PolSturmNbOfRootsOfLessThanOrEqualTo: + +``\PolSturmNbOfRootsOf{}\LessThanOrEqualTo{}`` +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Syntax: ``\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). + + .. attention:: + + :ref:`\\PolSturmIsolateZeros{\<sturmname\>} <PolSturmIsolateZeros>` must have been executed + beforehand. + + And the argument is a ``<sturmname>``, not a ``<polname>`` (this is + why the macro contains Sturm in its name), simply to be reminded + of the above constraint. + +.. _PolSturmNbOfRootsOfLessThanOrEqualToExpr: + +``\PolSturmNbOfRootsOf{}\LessThanOrEqualToExpr{}`` +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Syntax: ``\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 + given numerical expression. + + .. attention:: + + :ref:`\\PolSturmIsolateZeros{\<sturmname\>} <PolSturmIsolateZeros>` must have been executed + beforehand. + +.. _PolSturmNbWithMultOfRootsOfLessThanOrEqualTo: + +``\PolSturmNbWithMultOfRootsOf{}\LessThanOrEqualTo{}`` +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Syntax: ``\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 + or equal to the given ``value``. + + .. attention:: + + :ref:`\\PolSturmIsolateZeros*{\<sturmname\>} <PolSturmIsolateZeros*>` (or the double starred + variant) must have been executed beforehand. + +.. _PolSturmNbWithMultOfRootsOfLessThanOrEqualToExpr: + +``\PolSturmNbWithMultOfRootsOf{}\LessThanOrEqualToExpr{}`` +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Syntax: ``\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``. + + .. attention:: + + :ref:`\\PolSturmIsolateZeros*{\<sturmname\>} <PolSturmIsolateZeros*>` (or the double starred + variant) must have been executed beforehand. + +.. _PolSturmNbOfRationalRoots: + +``\PolSturmNbOfRationalRoots{}`` +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Syntax: ``\PolSturmNbOfRationalRoots{<sturmname>}`` + + Expands to the number of rational roots (without multiplicities). + + .. attention:: + + :ref:`\\PolSturmIsolateZeros**{\<sturmname\>} <PolSturmIsolateZeros**>` must have been executed + beforehand. + +.. _PolSturmNbOfRationalRootsWithMultiplicities: + +``\PolSturmNbOfRationalRootsWithMultiplicities{}`` +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Syntax: ``\PolSturmNbOfRationalRootsWithMultiplicities{<sturmname>}`` + + Expands to the number of rational roots (counted with multiplicities). + + .. attention:: + + :ref:`\\PolSturmIsolateZeros**{\<sturmname\>} <PolSturmIsolateZeros**>` must have been executed + beforehand. + +.. _PolSturmRationalRoot: + +``\PolSturmRationalRoot{}{}`` +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Syntax: ``\PolSturmRationalRoot{<sturmname>}{<k>}`` + + Expands to the k-th rational root. They are enumerated from left to + right starting at index value ``1``. + + .. attention:: + + :ref:`\\PolSturmIsolateZeros**{\<sturmname\>} <PolSturmIsolateZeros**>` must have been executed + beforehand. + +.. _PolSturmRationalRootIndex: + +``\PolSturmRationalRootIndex{}{}`` +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Syntax: ``\PolSturmRationalRootIndex{<sturmname>}{<k>}`` + + Expands to the index of the ``k``\ th rational root as part of the + ordered real roots (counted without multiplicities). So + :ref:`\\PolSturmRationalRoot{\<sturmname\>}{\<k\>} <PolSturmRationalRoot>` is equivalent to + this nested call:: + + \PolSturmIsolatedZeroLeft{<sturmname>}{\PolSturmRationalRootIndex{<sturmname>}{<k>}} + + .. attention:: + + :ref:`\\PolSturmIsolateZeros**{\<sturmname\>} <PolSturmIsolateZeros**>` must have been executed + beforehand. + +.. _PolSturmRationalRootMultiplicity: + +``\PolSturmRationalRootMultiplicity{}{}`` +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Syntax: ``\PolSturmRationalRootMultiplicity{<sturmname>}{<k>}`` + + Expands to the multiplicity of the ``k``\ th rational root. + + .. attention:: + + :ref:`\\PolSturmIsolateZeros**{\<sturmname\>} <PolSturmIsolateZeros**>` must have been executed + beforehand. + +.. _PolIntervalWidth: + +``\PolIntervalWidth{}{}`` +^^^^^^^^^^^^^^^^^^^^^^^^^ + +Syntax: ``\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). + + .. renommer cela en \PolSturmIntervalWidth ? + +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 +default for the former) and of `\\PolPrintIntervalsPrintLeftEndPoint`_, +`\\PolPrintIntervalsPrintRightEndPoint`_ (used in the default for the +latter). + +.. vieux commentaire + + Some macros formerly mentioned here got removed at 0.7: + ``\PolPrintIntervalsTheEndPoint``, + ``\PolIfEndPointIsPositive{T}{F}``, + ``\PolIfEndPointIsNegative{T}{F}``, + ``\PolIfEndPointIsZero{T}{F}``. + +.. _PolPrintIntervalsTheVar: + +``\PolPrintIntervalsTheVar`` +^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + + Expands to the name (default ``Z``) used for representing the roots, + which was passed as optional argument ``varname`` to + :ref:`\\PolPrintIntervals[varname]{\<sturmname\>} <PolPrintIntervals>`. + +.. _PolPrintIntervalsTheIndex: + +``\PolPrintIntervalsTheIndex`` +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + + Expands to the index of the considered interval (indexing starting + at 1 for the leftmost interval). + +.. _PolPrintIntervalsTheSturmName: + +``\PolPrintIntervalsTheSturmName`` +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + + Expands to the argument which was passed as ``<sturmname>`` to + :ref:`\\PolPrintIntervals[varname]{\<sturmname\>} <PolPrintIntervals>`. + +.. _PolPrintIntervalsTheLeftEndPoint: + +``\PolPrintIntervalsTheLeftEndPoint`` +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + + The left end point of the interval, as would be produced by + `\\PolSturmIsolatedZeroLeft <PolSturmIsolatedZeroLeft_>`_ if it was + used with arguments the Sturm chain name and interval index returned + by `\\PolPrintIntervalsTheSturmName`_ and + `\\PolPrintIntervalsTheIndex`_. + +.. _PolPrintIntervalsTheRightEndPoint: + +``\PolPrintIntervalsTheRightEndPoint`` +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + + The right end point of the interval, as would be produced by + `\\\PolSturmIsolatedZeroRight <PolSturmIsolatedZeroRight_>`_ for + 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 + double-starred) variant of `\\PolSturmIsolateZeros + <PolSturmIsolateZeros_>`_ was used earlier. + + +TeX Booleans (with names enacting their defaults) +------------------------------------------------- + +.. _xintverbosefalse: + +``\xintverbosefalse`` +~~~~~~~~~~~~~~~~~~~~~ + + 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. + + .. caution:: + + The macro and variable meanings as written to the log are to be + 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 + the print-out to the log and terminal of the function macro meaning, + as it only duplicates the information contained in the variable + which is already printed out to the log and terminal. + + However :ref:`\\PolGenFloatVariant{\<polname\>} <PolGenFloatVariant>` + does still print out the information relative to the polynomial + function it defines for use in ``\xintfloateval{}`` as there is no + float polynomial variable, only the + + function, and it is the only way to see its rounded coefficients + (``\xintverbosefalse`` suppresses also that info). + + If set to ``true``, it overrides in both cases + ``\xintverbosefalse``. The setting only affects polynomial + declarations. Scalar variables such as those holding information on + roots obey only the ``\xintverbose...`` setting. + + (new with ``0.8``) + +.. _poltypesetallfalse: + +``\poltypesetallfalse`` +~~~~~~~~~~~~~~~~~~~~~~~ + + If ``true``, `\\PolTypeset <PolTypeset_>`_ will also typeset the vanishing + coefficients. + + +.. _poltoexprallfalse: + +``\poltoexprallfalse`` +~~~~~~~~~~~~~~~~~~~~~~ + + If ``true``, :ref:`\\PolToExpr{\<pol. expr.\>} <PolToExpr>` and + :ref:`\\PolToFloatExpr{\<pol. expr.\>} <PolToFloatExpr>` will also + include the vanishing coefficients in their outputs. + + +Utilities +--------- + +.. _PolDecToString: + +``\PolDecToString{}`` +~~~~~~~~~~~~~~~~~~~~~ + +Syntax: ``\PolDecToString{decimal number}`` + + This is a utility macro to print decimal numbers. It is an alias + for ``\xintDecToString``. + +.. vieux commentaire + + It has been + backported to xintfrac_ (release ``1.3`` of ``2018/03/01``) under + the name ``\xintDecToString``, and the ``polexpr`` macro is simply + now an alias to it. + +.. + + For example + ``\PolDecToString{123.456e-8}`` will expand to ``0.00000123456`` + and ``\PolDecToString{123.450e-8}`` to ``0.00000123450`` which + illustrates that trailing zeros are not trimmed. + + To trim trailing zeroes, one can use + ``\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_ + documentation. + +.. vieux commentaire + + The precise behaviour of this macro may evolve in future releases of + xintexpr_. + +.. + + +.. _polexprsetup: + +``\polexprsetup{key=val,...}`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + Serves to customize the package. Currently only two keys are + recognized: + + - ``norr``: the postfix that :ref:`\\PolSturmIsolateZeros**{\<sturmname\>} <PolSturmIsolateZeros**>` + should append to ``<sturmname>`` to declare the primitive polynomial + obtained from original one after removal of all rational roots. + The default value is ``_norr`` (standing for “no rational roots”). + + - ``sqfnorr``: the postfix that :ref:`\\PolSturmIsolateZeros**{\<sturmname\>} <PolSturmIsolateZeros**>` + should append to ``<sturmname>`` to declare the primitive polynomial + obtained from original one after removal of all rational roots and + suppression of all multiplicities. + The default value is ``_sqf_norr`` (standing for “square-free with + no rational roots”). + + The package executes ``\polexprsetup{norr=_norr, + sqfnorr=_sqf_norr}`` as default. + + +Technicalities +-------------- + + +- The ``@`` is allowed in the name of a polynomial (independently of + whether it is of catcode letter or other.) This has always been the + case, but was not documented by polexpr prior to ``0.8``, as the + author has never found the time to provide some official guidelines on + how to name temporary variables and the ``@`` is used already as such + internally; time has still not yet been found to review the situation + but it seems reasonable to recommend at any rate to restrict usage of + ``@`` to scratch variables of defined macros and to avoid using it to + name document variable. + +- Catcodes are set temporarily by `\\poldef <poldef;_>`_ macro to safe + values prior to grab the polynomial expression up to the terminator + ``;``, and also by `\\PolDef <PolDef_>`_ prior to grab the + brace-enclosed polynomial expression. This gives a layer of + protection in case some package (for example the ``babel-french`` module) + has made some characters active. It will fail though if the whole + thing is located inside some definition of a macro done at a time the + characters are active. + +- .. + + .. attention:: + + Contrarily to ``\xintdefvar`` and ``\xintdeffunc`` from xintexpr_, + ``\poldef`` uses a naive delimited macro to fetch up to the + expression terminator ``";"``, hence it will be fooled if some + ``;`` is used inside the expression (which is possible as it + appears in some xintexpr_ constructs). Work-around is to use curly + braces around the inner semi-colons, or simpler to use + ``\PolDef``. + +- As a consequence of xintfrac_ addition and subtraction always using + least common multiples for the denominators, user-chosen common + denominators (currently) survive additions and multiplications. For + example, this:: + + \poldef P(x):= 1/2 + 2/2*x + 3/2*x^3 + 4/2*x^4; + \poldef Q(x):= 1/3 + (2/3)x + (3/3)x^3 + (4/3)x^4; + \poldef PQ(x):= P*Q; + + gives internally the polynomial:: + + 1/6+4/6*x^1+4/6*x^2+6/6*x^3+20/6*x^4+16/6*x^5+9/6*x^6+24/6*x^7+16/6*x^8 + + where all coefficients have the same denominator 6. Notice though that + ``\PolToExpr{PQ}`` outputs the ``6/6*x^3`` as ``x^3`` because (by + default) it recognizes and filters out coefficients equal to one or + minus one. One can use for example + ``\PolToCSV{PQ}`` to see the internally stored coefficients. + + .. vieux commentaire + + prior to ``0.4.1``, ``polexpr`` used to temporarily patch + during the parsing of polynomials the xintfrac_ macros. This + patch was backported to xintexpr_ at release ``1.3``. + +- :ref:`\\PolDiff{\<polname_1\>}{\<polname_2\>} <PolDiff>` always applies ``\xintPIrr`` to the + resulting coefficients, which means that fractions are reduced to + lowest terms but ignoring an already separated *power of ten* part ``[N]`` + present in the internal representation. This is tentative and may change. + + Same remark for :ref:`\\PolAntiDiff{\<polname_1\>}{\<polname_2\>} <PolAntiDiff>`. + +- Currently, the package stores all coefficients from index ``0`` to + index equal to the polynomial degree inside a single macro, as a list. + This data structure is obviously very inefficient for polynomials of + high degree and few coefficients (as an example with ``\poldef + f(x):=x^1000 + x^500;`` the subsequent definition ``\poldef g(x):= + f(x)^2;`` will do of the order of 1,000,000 multiplications and + additions involvings only zeroes... which does take time). This + may change in the future. + +- As is to be expected internal structures of the package are barely + documented and unstable. Don't use them. + + +.. _xinttools: +.. _xintfrac: +.. _xint: https://www.ctan.org/pkg/xint + +.. _xintexpr: https://www.ctan.org/pkg/xintexpr + +.. _xintsession: https://www.ctan.org/pkg/xintsession + +.. _Wilkinson polynomial: https://en.wikipedia.org/wiki/Wilkinson%27s_polynomial + +.. _Sturm algorithm: +.. _Sturm Theorem: https://en.wikipedia.org/wiki/Sturm%27s_theorem + +.. _DocUtils: http://docutils.sourceforge.net/docs/index.html + + +.. Local variables: +.. sentence-end-double-space: t; +.. End: |