From f8e05edb088c3b5246e016f68df9c4cadccfd34d Mon Sep 17 00:00:00 2001 From: Norbert Preining Date: Sun, 15 May 2022 03:00:49 +0000 Subject: CTAN sync 202205150300 --- macros/generic/polexpr/README.md | 151 +- macros/generic/polexpr/polexpr-changes.html | 629 ++++ macros/generic/polexpr/polexpr-changes.rst.txt | 513 +++ macros/generic/polexpr/polexpr-examples.pdf | Bin 58706 -> 57444 bytes macros/generic/polexpr/polexpr-examples.tex | 86 +- macros/generic/polexpr/polexpr-ref.html | 2898 +++++++++++++++++ macros/generic/polexpr/polexpr-ref.rst.txt | 3184 +++++++++++++++++++ macros/generic/polexpr/polexpr.css | 826 +++++ macros/generic/polexpr/polexpr.html | 3988 ++---------------------- macros/generic/polexpr/polexpr.rst.txt | 157 + macros/generic/polexpr/polexpr.sty | 19 +- macros/generic/polexpr/polexprcore.tex | 2 +- macros/generic/polexpr/polexprexpr.tex | 2 +- macros/generic/polexpr/polexprsturm.tex | 2 +- 14 files changed, 8512 insertions(+), 3945 deletions(-) create mode 100644 macros/generic/polexpr/polexpr-changes.html create mode 100644 macros/generic/polexpr/polexpr-changes.rst.txt create mode 100644 macros/generic/polexpr/polexpr-ref.html create mode 100644 macros/generic/polexpr/polexpr-ref.rst.txt create mode 100644 macros/generic/polexpr/polexpr.css create mode 100644 macros/generic/polexpr/polexpr.rst.txt (limited to 'macros/generic') diff --git a/macros/generic/polexpr/README.md b/macros/generic/polexpr/README.md index 4a74900100..0f70c6cb34 100644 --- a/macros/generic/polexpr/README.md +++ b/macros/generic/polexpr/README.md @@ -1,88 +1,65 @@ Package polexpr README ====================== +Version ``0.8.7`` of ``2022/05/14``. + +Abstract +-------- + +The package provides a parser `\poldef` of algebraic expressions. +As it is based on [xintexpr](http://www.ctan.org/pkg/xintexpr) the +polynomial coefficients are allowed to be arbitrary rational +numbers. Operations on declared polynomials, such as computing +G.C.D.'s or evaluating definite and indefinite integrals are +available directly inside the parser via a functional syntax, or +also via dedicated package macros. + +Root localization is available via package macros. All real roots +can be obtained with arbitrarily long decimal expansions, and all +rational rounds found exactly. + +In memoriam: Jürgen Gilg +------------------------ + +`polexpr` is dedicated to the memory of Jürgen Gilg (1967-2022). + +His question in January 2018 about using +[xintexpr](http://www.ctan.org/pkg/xintexpr) to compute derivatives +of polynomials was the original motivation for the creation of this +package. Jointly with Thomas Söll, he used it and kept expressing +his interest in it throughout the subsequent years, and provided +motivation and encouragements for time-consuming tasks such as (as +was done finally in 2021) re-enacting full interoperability with +[xintexpr](http://www.ctan.org/pkg/xintexpr) after its `1.4` update +from 2020. + +I will remember with gratitude his generous and unassuming +character, which I witnessed during our numerous exchanges on a wide +range of topics. + Usage ----- -The package can be used with TeX based formats incorporating the -e-TeX primitives. The `\expanded` primitive available generally -since TeXLive 2019 is required. +The package can be used with eTeX based formats via \input polexpr.sty -with Plain or other non-LaTeX macro formats, or: +or with LaTeX via \usepackage{polexpr} -with the LaTeX macro format. +[xintexpr](http://www.ctan.org/pkg/xintexpr) `1.4h` or later is +required. -The package currently requires xintexpr.sty `1.4d` or later. - -Abstract --------- +Recent changes +-------------- -The package provides a parser `\poldef` of algebraic polynomial -expressions. As it is based on -[xintexpr](http://www.ctan.org/pkg/xint) -the coefficients are allowed to be arbitrary rational numbers. - -Once defined, a polynomial is usable by its name either as a numerical -function in `\xintexpr/\xinteval`, or for additional polynomial -definitions, or as argument to the package macros. The localization of -real roots to arbitrary precision as well as the determination of all -rational roots is implemented via such macros. - -Since release `0.8`, polexpr extends the -[xintexpr](http://www.ctan.org/pkg/xint) syntax to recognize -polynomials as a new variable type (and not only as functions). -Functionality which previously was implemented via macros such as the -computation of a greatest common divisor is now available directly in -`\xintexpr`, `\xinteval` or `\poldef` via infix or functional syntax. - -Releases --------- - -- 0.1 (2018/01/11) - Initial release (files README, polexpr.sty). -- 0.2 (2018/01/14) - Documentation moved to polexpr.{txt,html}. -- 0.3 (2018/01/17) - Make polynomials known to `\xintfloatexpr` and improve - documentation. -- 0.3.1 (2018/01/18) - Fix two typos in documentation. -- 0.4 (2018/02/16) - - Revert 0.3 automatic generation of floating point variants. - - Move CHANGE LOG from README.md to HTML documentation. - - A few bug fixes and breaking changes. Please refer to - `polexpr.html`. - - Main new feature: root localization via [Sturm - Theorem](https://en.wikipedia.org/wiki/Sturm%27s_theorem). -- 0.4.1 (2018/03/01) - Synced with xintexpr 1.3. -- 0.4.2 (2018/03/03) - Documentation fix. -- 0.5 (2018/04/08) - - new macros `\PolMakePrimitive` and `\PolIContent`. - - main (breaking) change: `\PolToSturm` creates a chain of primitive - integer coefficients polynomials. -- 0.5.1 (2018/04/22) - The `'` character can be used in polynomial names. -- 0.6 (2018/11/20) - New feature: multiplicity of roots. -- 0.7 (2018/12/08), 0.7.1 (bugfix), 0.7.2 (bugfix) (2018/12/09) - New feature: finding all rational roots. -- 0.7.3 (2019/02/04) - Bugfix: polynomial names ending in digits caused errors. Thanks to - Thomas Söll for report. -- 0.7.4 (2019/02/12) - Bugfix: 20000000000 is too big for \numexpr, shouldn't I know that? - Thanks to Jürgen Gilg for report. -- 0.7.5 (2020/01/31) - Synced with xintexpr 1.4. Requires it. - 0.8 (2021/03/29) - Complete refactoring of the package core for better integration with - and enhancement of xintexpr 1.4. + Complete refactoring of the package core for better interoperability + with `xintexpr` internal changes at its release `1.4 (2020/01/31)`. + Extension of the functional syntax to cover operations such as + G.C.D.'s, derivatives or indefinite integrals previously available + via macros. - 0.8.1 (2021/04/12) Bugfix: a typo broke the 0.8 ``diff1()`` and related functions. - 0.8.2 (2021/05/05) @@ -96,21 +73,13 @@ Releases Bugfix: `intfrom()` was documented at `0.8` but not declared to parser. Track (belatedly) `xintexpr` 1.4g changes - 0.8.6 (2022/01/09) - Separate `polexpr-examples.{tex,pdf}` from the `polexpr.html` reference - -Files of the 0.8.6 release: -- polexpr.sty, polexprcore.tex, polexprexpr.tex, polexprsturm.tex, -- README.md, -- polexpr.html (reference documentation), -- polexpr-examples.pdf, polexpr-examples.tex (pdf doc and its source). + Separate `polexpr-examples.{tex,pdf}` from the `polexpr.html` reference. +- 0.8.7 (2022/05/14) + CSS styling of the `html` documentation, which is now split over + three files. Catcode protection for `\poldef` now matches + long-standing behaviour of `\xintdefvar`. This fixes issues + with ``babel+french``. -Acknowledgments ---------------- - -Thanks to Jürgen Gilg whose question about -[xintexpr](http://www.ctan.org/pkg/xint) usage for differentiating -polynomials was the initial trigger leading to this package, and to -Jürgen Gilg and Thomas Söll for testing it on some concrete problems. License ------- @@ -133,6 +102,14 @@ This Work has the LPPL maintenance status author-maintained. The Author of this Work is Jean-François Burnol. -This Work consists of the package files polexpr.sty, polexprcore.tex, -polexprexpr.tex, polexprsturm.tex, this README.md and documentation -polexpr.html, polexpr-examples.tex, polexpr-examples.pdf +This Work consists of: + +- the package files: polexpr.sty, polexprcore.tex, + polexprexpr.tex, polexprsturm.tex, +- this README.md, +- the documentation files: + polexpr.html, polexpr-ref.html, polexpr-changes.html, + polexpr.css, polexpr-examples.pdf, + polexpr.rst.txt, polexpr-ref.rst.txt, polexpr-changes.rst.txt, + polexpr-examples.tex + diff --git a/macros/generic/polexpr/polexpr-changes.html b/macros/generic/polexpr/polexpr-changes.html new file mode 100644 index 0000000000..51392f6565 --- /dev/null +++ b/macros/generic/polexpr/polexpr-changes.html @@ -0,0 +1,629 @@ + + + + + + + + + CHANGES — polexpr 0.8.7 documentation + + + + + +
+
+
+
+ +
+

CHANGES

+
+

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

+ +

Only one-variable polynomials so far.

+
+
+

v0.2 (2018/01/14)

+
    +
  • Fix: "README thinks \numexpr recognizes ^ operator".

  • +
  • Convert README to reStructuredText markup.

  • +
  • Move main documentation from README to separate polexpr.txt file.

  • +
  • Provide polexpr.html as obtained via DocUtils rst2html.py.

  • +
  • Convert README to (CTAN compatible) Markdown markup.

  • +
+

Due to lack of available time the test suite might not be extensive +enough. Bug reports are very welcome!

+
+
+

v0.3 (2018/01/17)

+
    +
  • bug fixes:

    +
      +
    • the 0.1 \PolEval accepted expressions for its +second argument, but this was removed by mistake at 0.2. Restored.

      +

      Attention: at 0.4 this has been reverted again, and +\PolEval{P}\AtExpr{foo} syntax is needed for +using expressions in the second argument.

      +
    • +
    +
  • +
  • incompatible or breaking changes:

    +
      +
    • \PolToExpr now by default uses descending +powers (it also treats differently coefficients equal to 1 or -1.) +Use \PolToExpr* for ascending powers.

    • +
    • \PolEval reduced the output to smallest terms, +but as this is costly with big fractions and not needed if e.g. +wrapped in an \xintRound or \xintFloat, this step has been +removed; the former meaning is available as +\PolEvalReduced.

    • +
    +
  • +
  • new (or newly documented) macros:

    + +
  • +
  • improvements:

    +
      +
    • documentation has a table of contents, internal hyperlinks, +standardized signature notations and added explanations.

    • +
    • one can do \PolLet{g}={f} or \PolLet{g}{f}.

    • +
    • \PolToExpr{f} is highly customizable.

    • +
    • \poldef and other defining macros prepare the +polynomial functions for usage within \xintthefloatexpr (or +\xintdeffloatvar). Coefficients are pre-rounded to the floating +point precision. Indispensible for numerical algorithms, as exact +fractions, even reduced, quickly become very big. See the documentation +about how to use the exact polynomials also in floating point context.

      +

      Attention: this has been reverted at 0.4. The macro +\PolGenFloatVariant must be used for +generation floating point polynomial functions.

      +
    • +
    +
  • +
+
+
+

v0.3.1 (2018/01/18)

+

Fixes two typos in example code included in the documentation.

+
+
+

v0.4 (2018/02/16)

+ +
+
+

v0.4.1 (2018/03/01)

+

Synced with xint 1.3.

+
+
+

v0.4.2 (2018/03/03)

+

Documentation fix.

+
+
+

v0.5 (2018/04/08)

+
    +
  • bug fixes:

    + +
  • +
  • breaking changes:

    +
      +
    • \PolToSturm creates primitive integer coefficients +polynomials. This speeds up localization of roots via +\PolSturmIsolateZeros. In case of user +protests the author will make available again the code producing the +bona fide Sturm polynomials as used formerly.

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

    • +
    +
  • +
  • experimental change:

    +
      +
    • optional argument to \PolSturmIsolateZeros +(see The degree 41 polynomial with -2, -1.9, -1.8, ..., 0, 0.1, ..., +1.9, 2 as roots in polexpr-examples.pdf). It will presumably be +replaced in future by an interval specification.

    • +
    +
  • +
  • new non-expandable macro:

    + +
  • +
  • new expandable macro:

    + +
  • +
+
+
+

v0.5.1 (2018/04/22)

+
    +
  • new feature:

    +
      +
    • the character ' can be used in polynomial names.

    • +
    +
  • +
+
+
+

v0.6 (2018/11/20)

+ +
+
+

v0.7 (2018/12/08), v0.7.1 (bugfix), v0.7.2 (2nd bugfix) (2018/12/09)

+ +
+
+

v0.7.3 (2019/02/04)

+ +
+
+

v0.7.4 (2019/02/12)

+
    +
  • bugfix:

    +
      +
    • 20000000000 is too big for \numexpr, shouldn’t I know that? +Thanks to Jürgen Gilg for report.

    • +
    +
  • +
+
+
+

v0.7.5 (2020/01/31)

+

Synced with xintexpr 1.4. Requires it.

+
+
+

v0.8 (2021/03/29)

+

Synced with xintexpr 1.4d. Requires it.

+
    +
  • breaking changes:

    +
      +
    • As the usability of character ' in names has been extended +from \poldef to also generally \xintexpr, \xintdefvar, +and \xintdeffunc, it means that the infix operators +'and', 'or', and 'mod' must be replaced +by &&, ||, and /: if they +follow immediately a variable name (similarly 'xor' must +be replaced by the xor() function in such case).

    • +
    • \PolToExpr by default uses a catcode 12 +^. See its documentation and the new configuration +\PolToExprCaret.

    • +
    +
  • +
  • deprecated:

    +
      +
    • Usage of P/Q for the euclidean quotient of two polynomials is +deprecated. Start using quo(P,Q) in its place.

    • +
    +
  • +
  • bugfix:

    +
      +
    • The \xintglobaldefstrue setting was obeyed only partially +by the polexpr macros defining polynomials.

    • +
    • The \xintexpr variables storing the values of the extremities of the +intervals as found by \PolSturmIsolateZeros were not updated at 0.7.5 to the xintexpr 1.4 +format and thus caused low-level TeX errors if used.

    • +
    • Attempting to use in \poldef a function previously declared +via \xintdeffunc which made usage of the indexing or slicing +“ople” syntax typically caused TeX capacity exceeded error. +Indeed 0.7.5 only partially made polexpr able to cope with the +extended possibilities for xintexpr 1.4 user-declared functions. +Hopefully 0.8 achieves full functionality in this context.

    • +
    +
  • +
  • new macros:

    + +
  • +
  • new features:

    +
      +
    • The package is usable under Plain and probably most any TeX format, +and not only under LaTeX.

    • +
    • The core of the package has been rewritten entirely in order to +start letting \xintexpr recognize a polynomial type as a genuine +variable. This has allowed:

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

      • +
      • to make available most of the functionality associated to +expandable macros directly in the \xinteval syntax as +operators or functions,

      • +
      • to provide (expandable) functional interface in \xinteval to +features previously available only via (for some, non-expandable) +macro interface such as gcd computations.

      • +
      +
    • +
    +
  • +
+

See the updated Quick syntax overview and then +the extended syntax description.

+
+
+

v0.8.1 (2021/04/12)

+
    +
  • breaking changes:

    +
      +
    • renamed v0.8’s icontent() to cont().

    • +
    • renamed v0.8’s lcoeff() to lc().

    • +
    +
  • +
  • bugfix:

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

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

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

    • +
    +
  • +
  • added:

    + +
  • +
+
+
+

v0.8.2 (2021/05/05)

+
    +
  • breaking change:

    + +
  • +
  • improved:

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

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

  • +
+
+
+

v0.8.3 (2021/05/27)

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

  • +
+
+
+

v0.8.4 (2021/11/01)

+ +
+
+

v0.8.5 (2021/11/30)

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

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

  • +
+
+
+

v0.8.6 (2022/01/09)

+ +
+
+

v0.8.7 (2022/05/14)

+
    +
  • bugfix: catcode sanitization by \poldef was minimal +ever since 0.1 and handled only the semi-colon. Thus e.g. the +active ! from babel-french caused errors and \string! was +needed as work-around for factorials. Now the same sanitization as +for \xintdefvar and \xintdeffunc is applied. This however can +only work at locations where the catcodes are not yet frozen at the +time \poldef expands.

  • +
  • split the html documentation into three files and enhance it via CSS +styling.

  • +
+
+
+ + +
+
+
+
+ +
+
+ + + + \ No newline at end of file diff --git a/macros/generic/polexpr/polexpr-changes.rst.txt b/macros/generic/polexpr/polexpr-changes.rst.txt new file mode 100644 index 0000000000..c1f2c834ec --- /dev/null +++ b/macros/generic/polexpr/polexpr-changes.rst.txt @@ -0,0 +1,513 @@ +.. comment: -*- fill-column: 72; mode: rst -*- + +========= + CHANGES +========= + +.. _firstrelease: + +v0.1 (2018/01/11): initial release. Features: +--------------------------------------------- + +* The :ref:`\\poldef ` parser itself, +* Differentiation and anti-differentiation, +* Euclidean division and GCDs, +* Various utilities such as :ref:`\\PolFromCSV `, + :ref:`\\PolMapCoeffs `, + :ref:`\\PolToCSV `, :ref:`\\PolToExpr `, ... + +Only one-variable polynomials so far. + +v0.2 (2018/01/14) +----------------- + +* Fix: ``"README thinks \numexpr recognizes ^ operator"``. +* Convert README to reStructuredText markup. +* Move main documentation from README to separate ``polexpr.txt`` file. +* Provide ``polexpr.html`` as obtained via DocUtils_ ``rst2html.py``. +* Convert README to (CTAN compatible) Markdown markup. + +Due to lack of available time the test suite might not be extensive +enough. Bug reports are very welcome! + +v0.3 (2018/01/17) +----------------- + +* bug fixes: + + - the ``0.1`` :ref:`\\PolEval ` accepted expressions for its + second argument, but this was removed by mistake at ``0.2``. Restored. + + **Attention**: at ``0.4`` this has been reverted again, and + :ref:`\\PolEval{P}\\AtExpr{foo} ` syntax is needed for + using expressions in the second argument. +* incompatible or breaking changes: + + - :ref:`\\PolToExpr ` now by default uses *descending* + powers (it also treats differently coefficients equal to 1 or -1.) + Use :ref:`\\PolToExpr* ` for *ascending* powers. + - :ref:`\\PolEval ` reduced the output to smallest terms, + but as this is costly with big fractions and not needed if e.g. + wrapped in an ``\xintRound`` or ``\xintFloat``, this step has been + removed; the former meaning is available as + :ref:`\\PolEvalReduced `. +* new (or newly documented) macros: + + - :ref:`\\PolTypesetCmd ` + - :ref:`\\PolTypesetCmdPrefix ` + - :ref:`\\PolTypesetMonomialCmd ` + - :ref:`\\PolEvalReducedAt ` + - :ref:`\\PolToFloatExpr ` + - :ref:`\\PolToExprOneTerm ` + - :ref:`\\PolToFloatExprOneTerm ` + - :ref:`\\PolToExprCmd ` + - :ref:`\\PolToFloatExprCmd ` + - :ref:`\\PolToExprTermPrefix ` + - :ref:`\\PolToExprVar ` + - :ref:`\\PolToExprTimes ` +* improvements: + + - documentation has a table of contents, internal hyperlinks, + standardized signature notations and added explanations. + - one can do ``\PolLet{g}={f}`` or ``\PolLet{g}{f}``. + - ``\PolToExpr{f}`` is highly customizable. + - :ref:`\\poldef ` and other defining macros prepare the + polynomial functions for usage within ``\xintthefloatexpr`` (or + ``\xintdeffloatvar``). Coefficients are pre-rounded to the floating + point precision. Indispensible for numerical algorithms, as exact + fractions, even reduced, quickly become very big. See the documentation + about how to use the exact polynomials also in floating point context. + + **Attention**: this has been reverted at ``0.4``. The macro + :ref:`\\PolGenFloatVariant ` must be used for + generation floating point polynomial functions. + +v0.3.1 (2018/01/18) +------------------- + +Fixes two typos in example code included in the documentation. + +v0.4 (2018/02/16) +----------------- + +* bug fixes: + + - when Euclidean division gave a zero remainder, the internal + representation of this zero polynomial could be faulty; this + could cause mysterious bugs in conjunction with other package + macros such as :ref:`\\PolMapCoeffs `. + - :ref:`\\PolGCD ` was buggy in case of first polynomial being + of lesser degree than the second one. +* breaking changes: + + - formerly :ref:`\\PolEval{P}\\At{foo} ` allowed ``foo`` to + be an expression, which was transparently handled via + ``\xinttheexpr``. Now, ``foo`` must be a fraction (or a macro + expanding to such) in the format acceptable by ``xintfrac.sty`` + macros. Use :ref:`\\PolEval{P}\\AtExpr{foo} ` for more + general arguments using expression syntax. E.g., if ``foo`` is the + name of a variable known to ``\xintexpr``. + + The same holds for :ref:`\\PolEvalReduced ` + and :ref:`\\PolFloatEval `. + - the ``3.0`` automatic generation of floating point variants has + been reverted. Not only do *not* the package macros automatically + generate floating point variants of newly created polynomials, + they actually make pre-existing such variant undefined. + + See :ref:`\\PolGenFloatVariant `. +* new non-expandable macros: + + - :ref:`\\PolGenFloatVariant ` + - :ref:`\\PolGlobalLet ` + - :ref:`\\PolTypesetOne ` + - :ref:`\\PolQuo ` + - :ref:`\\PolRem ` + - :ref:`\\PolToSturm ` + - :ref:`\\PolToSturm\* ` + - :ref:`\\PolSetToSturmChainSignChangesAt ` + - :ref:`\\PolSetToNbOfZerosWithin ` + - :ref:`\\PolSturmIsolateZeros ` + - :ref:`\\PolRefineInterval* ` + - :ref:`\\PolRefineInterval[N] ` + - :ref:`\\PolEnsureIntervalLength ` + - :ref:`\\PolEnsureIntervalLengths ` + - :ref:`\\PolPrintIntervals ` + - :ref:`\\PolPrintIntervalsPrintExactZero ` + - :ref:`\\PolPrintIntervalsPrintLeftEndPoint ` + - :ref:`\\PolPrintIntervalsPrintRightEndPoint ` + - :ref:`\\PolReduceCoeffs* ` + - :ref:`\\PolMakeMonic ` +* new expandable macros: + + - :ref:`\\PolToExprOneTermStyleA ` + - :ref:`\\PolIfCoeffIsPlusOrMinusOne ` + - :ref:`\\PolLeadingCoeff ` + - :ref:`\\PolSturmChainLength ` + - :ref:`\\PolSturmNbOfIsolatedZeros ` + - :ref:`\\PolSturmIfZeroExactlyKnown ` + - :ref:`\\PolSturmIsolatedZeroLeft ` + - :ref:`\\PolSturmIsolatedZeroRight ` + - ``\PolPrintIntervalsTheEndPoint`` (removed at 0.7) + - :ref:`\\PolPrintIntervalsTheIndex ` + - ``\PolIfEndPointIsPositive`` (removed at 0.7) + - ``\PolIfEndPointIsNegative`` (removed at 0.7) + - ``\PolIfEndPointIsZero`` (removed at 0.7) + - :ref:`\\PolIntervalWidth ` + - :ref:`\\PolDecToString ` +* improvements: + + The main new feature is implementation of the `Sturm algorithm`_ + for localization of the real roots of polynomials. + +v0.4.1 (2018/03/01) +------------------- + +Synced with xint 1.3. + +v0.4.2 (2018/03/03) +------------------- + +Documentation fix. + +v0.5 (2018/04/08) +----------------- + +* bug fixes: + + - :ref:`\\PolGet{polname}\\fromarray\\macro ` + crashed when ``\macro`` was + an xinttools_ array macro with no items. It now produces the zero + polynomial. +* breaking changes: + + - :ref:`\\PolToSturm ` creates primitive integer coefficients + polynomials. This speeds up localization of roots via + :ref:`\\PolSturmIsolateZeros `. In case of user + protests the author will make available again the code producing the + bona fide Sturm polynomials as used formerly. + - polynomials created from :ref:`\\PolFromCSV ` or + :ref:`\\PolGet ` + get their coefficients normalized via xintfrac_\ 's ``\xintRaw``. +* experimental change: + + - optional argument to :ref:`\\PolSturmIsolateZeros ` + (see ``The degree 41 polynomial with -2, -1.9, -1.8, ..., 0, 0.1, ..., + 1.9, 2 as roots`` in ``polexpr-examples.pdf``). It will presumably be + replaced in future by an interval specification. +* new non-expandable macro: + + - :ref:`\\PolMakePrimitive ` +* new expandable macro: + + - :ref:`\\PolIContent ` + +v0.5.1 (2018/04/22) +------------------- + +* new feature: + + - the character ``'`` can be used in polynomial names. + +v0.6 (2018/11/20) +----------------- + +* bugfix: + + - the starred variant + :ref:`\\PolToSturm*{\}{\} ` + was broken. On the occasion of the fix, its meaning has + been modified, see its documentation. + + - using :ref:`\\PolToSturm ` with a constant polynomial + caused a division by zero error. + +* new macro: + + - :ref:`\\PolSturmIsolateZeros* ` + acts like the :ref:`non-starred variant + ` then computes all the multiplicities. + +* new expandable macros: + + - :ref:`\\PolSturmIsolatedZeroMultiplicity{\}{\} ` + - :ref:`\\PolSturmNbOfRootsOf{\}\\LessThanOrEqualTo{\} ` + - :ref:`\\PolSturmNbOfRootsOf{\}\\LessThanOrEqualToExpr{\} ` + - :ref:`\\PolSturmNbWithMultOfRootsOf{\}\\LessThanOrEqualTo{\} ` + - :ref:`\\PolSturmNbWithMultOfRootsOf{\}\\LessThanOrEqualToExpr{\} ` + +v0.7 (2018/12/08), v0.7.1 (bugfix), v0.7.2 (2nd bugfix) (2018/12/09) +-------------------------------------------------------------------- + +* breaking changes: + + - although :ref:`\\PolPrintIntervals[\]{\} ` default output + remains the same, some auxiliary macros for user-customization + have been removed: ``\PolPrintIntervalsTheEndPoint``, + ``\PolIfEndPointIsPositive{T}{F}``, + ``\PolIfEndPointIsNegative{T}{F}``, and + ``\PolIfEndPointIsZero{T}{F}``. + +* bugfix: + + - it could happen that, contrarily to documentation, an interval computed + by :ref:`\\PolSturmIsolateZeros{\} ` had + zero as an endpoint, + - :ref:`\\PolEnsureIntervalLength{\}{\}{\} + ` could under certain circumstances erroneously + replace a non-zero root by zero, + - :ref:`\\PolEnsureIntervalLengths{\}{\} + ` crashed when used with a polynomial with no + real roots, hence for which no isolation intervals existed (thanks to + Thomas Söll for report). + +* new macros: + + - :ref:`\\PolSturmIsolateZeros**{\} ` + - :ref:`\\PolSturmIsolateZerosGetMultiplicitiesAndRationalRoots{\} ` + - :ref:`\\PolSturmIsolateZerosAndFindRationalRoots{\} ` + - :ref:`\\polexprsetup ` + - :ref:`\\PolPrintIntervals* ` + - :ref:`\\PolPrintIntervalsNoRealRoots ` + - :ref:`\\PolPrintIntervalsBeginEnv ` + - :ref:`\\PolPrintIntervalsEndEnv ` + - :ref:`\\PolPrintIntervalsKnownRoot ` + - :ref:`\\PolPrintIntervalsUnknownRoot ` + - :ref:`\\PolPrintIntervalsPrintMultiplicity ` + +* new expandable macros: + + - :ref:`\\PolSturmNbOfRationalRoots{\} ` + - :ref:`\\PolSturmNbOfRationalRootsWithMultiplicities{\} ` + - :ref:`\\PolSturmRationalRoot{\}{\} ` + - :ref:`\\PolSturmRationalRootIndex{\}{\} ` + - :ref:`\\PolSturmRationalRootMultiplicity{\}{\} ` + - :ref:`\\PolPrintIntervalsTheVar ` + - :ref:`\\PolPrintIntervalsTheSturmName ` + - :ref:`\\PolPrintIntervalsTheMultiplicity ` + +v0.7.3 (2019/02/04) +------------------- + +* bugfix: + + - Debugging information not destined to user showed in log if root + finding was done under ``\xintverbosetrue`` regime. + - :ref:`\\PolPrintIntervalsTheVar ` remained + defined after :ref:`\\PolPrintIntervals ` but was + left undefined after :ref:`\\PolPrintIntervals* ` + (reported by Jürgen Gilg). Now remains defined in both cases, and + :ref:`\\PolPrintIntervalsTheSturmName ` + also. + - Polynomial names ending in digits caused errors (reported by Thomas + Söll). + +v0.7.4 (2019/02/12) +------------------- + +* bugfix: + + - 20000000000 is too big for ``\numexpr``, shouldn't I know that? + Thanks to Jürgen Gilg for report. + +v0.7.5 (2020/01/31) +------------------- + +Synced with xintexpr 1.4. Requires it. + +.. _polexpr08release: + +v0.8 (2021/03/29) +----------------- + +Synced with xintexpr 1.4d. Requires it. + +* breaking changes: + + - As the usability of character ``'`` in names has been extended + from ``\poldef`` to also generally ``\xintexpr``, ``\xintdefvar``, + and ``\xintdeffunc``, it means that the infix operators + ``'and'``, ``'or'``, and ``'mod'`` must be replaced + by ``&&``, ``||``, and ``/:`` if they + follow immediately a variable name (similarly ``'xor'`` must + be replaced by the ``xor()`` function in such case). + + - :ref:`\\PolToExpr ` by default uses a catcode 12 + ``^``. See its documentation and the new configuration + :ref:`\\PolToExprCaret `. + +* deprecated: + + - Usage of ``P/Q`` for the euclidean quotient of two polynomials is + deprecated. Start using ``quo(P,Q)`` in its place. + +* bugfix: + + - The ``\xintglobaldefstrue`` setting was obeyed only partially + by the polexpr macros defining polynomials. + + - The ``\xintexpr`` variables storing the values of the extremities of the + intervals as found by :ref:`\\PolSturmIsolateZeros + ` were not updated at 0.7.5 to the xintexpr 1.4 + format and thus caused low-level TeX errors if used. + + - Attempting to use in ``\poldef`` a function previously declared + via ``\xintdeffunc`` which made usage of the indexing or slicing + "ople" syntax typically caused ``TeX capacity exceeded`` error. + Indeed 0.7.5 only partially made polexpr able to cope with the + extended possibilities for xintexpr 1.4 user-declared functions. + Hopefully ``0.8`` achieves full functionality in this context. + +* new macros: + + - :ref:`\\polnewpolverbosefalse ` + - :ref:`\\PolToExprCaret ` + - :ref:`\\PolToExprInVar ` + - alongside the major new functionalities described in the next item + :ref:`\\PolTypeset ` and :ref:`\\PolToExpr ` have + been enhanced to accept as argument a general expression and not + only a pre-declared polynomial name. + +* new features: + + - The package is usable under Plain and probably most any TeX format, + and not only under LaTeX. + + - The core of the package has been rewritten entirely in order to + start letting ``\xintexpr`` recognize a polynomial type as a genuine + variable. This has allowed: + + - to solve the reduced inter-operability problems between polexpr + and xintexpr_ which arose as consequences to the deep xintexpr_ ``1.4`` + evolution, + + - to make available most of the functionality associated to + expandable macros directly in the ``\xinteval`` syntax as + operators or functions, + + - to provide (expandable) functional interface in ``\xinteval`` to + features previously available only via (for some, non-expandable) + macro interface such as gcd computations. + +See the updated :ref:`Quick syntax overview ` and then +:ref:`the extended syntax description `. + +v0.8.1 (2021/04/12) +------------------- + +* breaking changes: + + - renamed v0.8's ``icontent()`` to :ref:`cont() `. + - renamed v0.8's ``lcoeff()`` to :ref:`lc() `. + +* bugfix: + + - Sadly, ``diff1()``, ``diff2()``, ``diffn()`` were broken + for polynomials of degrees 8 or more, due to a typo and + insufficient testing. + + - The package should have (as documented) required xintexpr_ 1.4d + but in practice it accepted to work with xintexpr_ 1.4c, whose + ``\xinteval`` does not know how to "output" a polynomial. + + - The definition of one of the two variants of + :ref:`\\PolSturmNbOfRootsOf... ` + was broken by an end-of-line space, left-over + from mass conversion from LaTeX to TeX syntax. + +* added: + + - :ref:`lpol() ` + - :ref:`lcoeffs() ` + +v0.8.2 (2021/05/05) +------------------- + +* breaking change: + + - usage of ``\xintPFloat`` in place of ``\xintFloat`` for + :ref:`\\PolToFloatExprCmd `. + +* improved: + + - Some xintexpr_ functions such as ``rseq()`` use the semi-colon, + and it was mentioned in the documentation that :ref:`\\poldef ` + will be confused by this and that inner semi-colons could be + set within braces ``{;}`` as a work-around. It was not clear from + this documentation that also :ref:`\\PolDef ` required + this work-around. With this relase only :ref:`\\poldef ` but + not :ref:`\\PolDef ` needs the work-around. + +* track xintexpr_ ``1.4e`` changes relative to powers. + +v0.8.3 (2021/05/27) +------------------- + +* small internal update to track an xintexpr_ ``1.4h`` change + regarding handling of exceptions. Will require this version at + least on loading. + +v0.8.4 (2021/11/01) +------------------- + +* bugfix: :ref:`\\PolSturmIsolateZeros**{\} + ` did not declare the ``_norr`` and + ``_sqf_norr`` polynomials if original polynomial had no real + root! + +v0.8.5 (2021/11/30) +------------------- + +* bugfix: support for the ``intfrom()`` function was in the code, + but the declaration to the polynomial parser had not been done. + +* track (belatedly) upstream deprecation of ``\xintSignedFrac`` and + ``\xintSignedFwOver`` at xintexpr_ ``1.4g`` + +v0.8.6 (2022/01/09) +------------------- + +* provide a separate ``polexpr-examples.pdf`` with examples formerly + shown as part of the html documentation. + +* minor improvement to the computation of a priori bounds on real roots. + +* add :ref:`\\PolPrintIntervalsRowSeparator ` + and allow usage of ``amsmath`` environments in custom + :ref:`\\PolPrintIntervalsBeginEnv ` and + :ref:`\\PolPrintIntervalsEndEnv `. + +v0.8.7 (2022/05/14) +------------------- + +* bugfix: catcode sanitization by :ref:`\\poldef ` was minimal + ever since ``0.1`` and handled only the semi-colon. Thus e.g. the + active ``!`` from babel-french caused errors and ``\string!`` was + needed as work-around for factorials. Now the same sanitization as + for ``\xintdefvar`` and ``\xintdeffunc`` is applied. This however can + only work at locations where the catcodes are not yet frozen at the + time ``\poldef`` expands. + +* split the html documentation into three files and enhance it via CSS + styling. + + +.. _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: diff --git a/macros/generic/polexpr/polexpr-examples.pdf b/macros/generic/polexpr/polexpr-examples.pdf index 1c67b4e533..5be0a95a42 100644 Binary files a/macros/generic/polexpr/polexpr-examples.pdf and b/macros/generic/polexpr/polexpr-examples.pdf differ diff --git a/macros/generic/polexpr/polexpr-examples.tex b/macros/generic/polexpr/polexpr-examples.tex index fa2f330513..564c1912da 100644 --- a/macros/generic/polexpr/polexpr-examples.tex +++ b/macros/generic/polexpr/polexpr-examples.tex @@ -145,25 +145,12 @@ \makeatletter \catcode`_ 11 -\def\everbatimtop {\MacroFont\small}% default -\let\everbatimbottom\empty -\let\everbatimhook\empty - \def\everbatim {\s@everbatim\@everbatim } -\@namedef{everbatim*}{\s@everbatim\expandafter\@everbatimx\expandafter - {\the\newlinechar}} -\let\everbatimbgcolorcmd\empty -\def\everbatimeverypar{\strut - {\everbatimbgcolorcmd\vrule\@width\linewidth }% - \kern-\linewidth - \kern\everbatimindent } -\def\everbatimindent {\z@} -% voir plus loin atbegindocument +%! ancienne méthode sans doute motivé par possibilité code ferme un groupe? +%! \@namedef{everbatim*}{\s@everbatim\@everbatimx\expandafter +%! {\the\newlinechar}} +\@namedef{everbatim*}{\s@everbatim\@everbatimx } -\def\endeverbatim {\if@newlist \leavevmode\fi\endtrivlist } - -\@namedef{endeverbatim*}{\endeverbatim\aftergroup\everbatimundoparskip} -\def\everbatimundoparskip{\vbox{}\kern-\baselineskip\kern-\parskip} % Note 25 juin 2021 % On ne peut pas emboîter un everbatim à l'intérieur d'un everbatim % ou un everbatim* à l'intérieur d'un everbatim*... @@ -197,6 +184,14 @@ }% \obeylines \@vobeyspaces } +\def\everbatimtop {\MacroFont\small}% default +\let\everbatimhook\empty +\def\everbatimeverypar{\strut + {\everbatimbgcolorcmd\vrule\@width\linewidth }% + \kern-\linewidth + \kern\everbatimindent } +\let\everbatimbgcolorcmd\empty +\def\everbatimindent {\z@} \begingroup \lccode`X 13 @@ -210,31 +205,47 @@ |lowercase[|endgroup% both freezes catcodes and converts X to active ^^M |def|@everbatim #1X#2\end{everbatim}% [#2|end[everbatim]|everbatimbottom ] -|def|@everbatimx #1#2X#3\end{everbatimY}]% - {#3\end{everbatim*}% - \everbatimbottom +|def|@everbatimx #1X#2\end{everbatimY}]% + {#2\end{everbatim*}% +% refactored 2022/01/11, rather than passing \newlinechar value +% as was done formerly via everbatim* (see above) and fetching it here as #1 +% it is thus assumed executed contents will not terminate a scope + \edef\everbatimrestorenewlinechar{\newlinechar\the\newlinechar\relax}% \newlinechar 13 +% refactored 2022/01/11: +% attention, \parskip set to zero for execution of contents +% reason: avoid extra space if everbatim* is in an \item of a list +% between verbatim and output of execution, if it starts a paragraph +% \vskip-\parskip would be no good in case contents create a display + \edef\everbatimrestoreparskip{\parskip\the\parskip}% + \parskip\z@skip % execution as LaTeX code of contents \everbatimxprehook - \scantokens {#3}% - \newlinechar #1\relax + \scantokens {#2}% + \everbatimrestorenewlinechar + \everbatimrestoreparskip \everbatimxposthook }% - % L'espace venant du endofline final mis par \scantokens sera inhibé si #3 se % termine par un % ou un \x, etc... -\let\everbatimxfgcolorcmd\empty +\let\everbatimbottom\empty + +\def\endeverbatim {\if@newlist \leavevmode\fi\endtrivlist } +\@namedef{endeverbatim*}{\endeverbatim} +% \@namedef{endeverbatim*}{\endeverbatim\aftergroup\everbatimundoparskip} +% \def\everbatimundoparskip{\vbox{}\kern-\baselineskip\kern-\parskip} +% \let\everbatimundoparskip\empty + +% rationale: we do not want a group +% see xint.dtx for better way avoiding colorstack overflow problem +% with latex+dvipdfmx \def\everbatimxprehook {\colorlet{everbsavedcolor}{.}% - \everbatimxfgcolorcmd - \smallskip % pour polexpr-examples.tex - % à cause de problèmes avec les - % output en "display" - }% + \everbatimxfgcolorcmd}% +\let\everbatimxfgcolorcmd\empty % default \def\everbatimxposthook {\color{everbsavedcolor}} - \catcode`_ 8 \makeatother @@ -251,9 +262,9 @@ % \verb %\colorlet{verbcolor}{DarkCyan} -\colorlet{verbcolor}{black} +\colorlet{verbcolor}{Maroon} \colorlet{verbsoftwrapiconcolor}{DarkBlue} -\def\MicroFont{\ttfamily%\color{verbcolor} +\def\MicroFont{\ttfamily\color{verbcolor} \makestarlowast\makequotesstraight}% % everbatim/everbatim* @@ -265,11 +276,13 @@ \def\MacroFont{\ttfamily\color{everbatimfgcolor}} %\colorlet{everbatimbgcolor}{WhiteSmoke} -\colorlet{everbatimbgcolor}{Ivory} +%\colorlet{everbatimbgcolor}{Ivory} +\colorlet{everbatimbgcolor}{Beige} \def\everbatimbgcolorcmd{\color{everbatimbgcolor}} %\colorlet{everbatimxfgcolor}{MidnightBlue} -\colorlet{everbatimxfgcolor}{OliveDrab} +%\colorlet{everbatimxfgcolor}{OliveDrab} +\colorlet{everbatimxfgcolor}{Maroon} \def\everbatimxfgcolorcmd{\color{everbatimxfgcolor}} % Notice that \macrocode uses \macro@font which stores the \MacroFont meaning @@ -281,7 +294,7 @@ The package provides a parser |\poldef| of algebraic polynomial -expressions. +expressions. Once defined, a polynomial is usable by its name either as a numerical function in |\xintexpr/\xinteval|, or for additional polynomial @@ -373,11 +386,10 @@ file. \section{A first example} - In this example the polynomial is square-free. \begin{everbatim*} \poldef f(x) := x^7 - x^6 - 2x + 1; - +% \PolToSturm{f}{f} \PolSturmIsolateZeros{f} The \PolTypeset{f} polynomial has \PolSturmNbOfIsolatedZeros{f} distinct real diff --git a/macros/generic/polexpr/polexpr-ref.html b/macros/generic/polexpr/polexpr-ref.html new file mode 100644 index 0000000000..9f3767c48d --- /dev/null +++ b/macros/generic/polexpr/polexpr-ref.html @@ -0,0 +1,2898 @@ + + + + + + + + + polexpr reference — polexpr 0.8.7 documentation + + + + + + +
+
+
+
+ +
+

polexpr reference

+
+

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 below. 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 \poldef. +See rdcoeffs() and the macro +\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.

+
+

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.

+
+
+

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 +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 deg() or +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 evalp(P+Q,3) 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 for the configurability +via macros.

+

Since 0.8 \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) +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 \PolToExpr{<pol. expr.>} 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 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 \PolMapCoeffs +which can be used for example with the \xintFloat macro from the +xintfrac package to achieve this.

+
+
+

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. +
  3. 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…

    +
  4. +
+
+
+

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(<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(<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)

+
+
+
+

\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{}, but finally opted for this.

+
+
+
+

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 [1] (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.

+ +
+

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(<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(<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 +\PolNthCoeff{<polname>}{<index>} 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(<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), 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(<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.

+
+

name and syntax unstable

+

At 0.8 it was created as icontent() to match the legacy +macro \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.

+
+
+
+

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 [2] 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 (non expandable) macro.

+ +
+
+
+

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])
+
+
+
+
+
+
+

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 nth 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
+
+
+
+
+
+
+

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 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.

+

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 \PolGenFloatVariant{<polname>} 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 \PolGenFloatVariant{<polname>} +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[<letter>]{<polname>}{<expr. using the letter as indeterminate>}

+
+

Does the same as \poldef in an undelimited macro +format, the main interest is to avoid potential problems with the +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{}

+

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 \PolToFloatExpr{<pol. expr.>}.

+
+

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{}

+

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{}

+

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 +\PolIfCoeffIsPlusOrMinusOne{T}{F}.

+

The actual printing of the coefficients, when not equal to plus or +minus one, is handled by \PolTypesetOne{<raw_coeff>}.

+
+
+
\PolIfCoeffIsPlusOrMinusOne{}{}
+

Syntax: \PolIfCoeffIsPlusOrMinusOne{T}{F}

+
+

This macro is a priori undefined.

+

It is defined via the default \PolTypesetCmd{<raw_coeff>} 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{}

+

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

+
+

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{}

+

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 +\PolTypesetCmd{<raw_coeff>} 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*{}

+

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{}={}

+

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{}={}

+

Syntax: \PolGlobalLet{<polname_2>}={<polname_1>}

+
+

Acts globally.

+
+
+
+

\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 \PolNthCoeff{<polname>}{<index>}.

+
+
+
+

\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;.

+
+
+
+

\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 \PolToCSV{<polname>}.

+
+
+
+

\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{}

+

Syntax: \PolReduceCoeffs{<polname>}

+
+

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

+
+
+
+

\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 +\PolReduceCoeffs{<polname>}: as the numerators and denominators +remain generally smaller.

+
+
+
+

\PolMakeMonic{}

+

Syntax: \PolMakeMonic{<polname>}

+
+

Divides by the leading coefficient. It is recommended to execute +\PolReduceCoeffs*{<polname>} 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{}

+

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{}{}

+

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[]{}{}

+

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{}{}

+

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[]{}{}

+

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{}{}{}{}

+

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{}{}{}

+

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{}{}{}

+

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{}{}{}

+

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.

+
+
+
+

Root localization routines via the Sturm Theorem

+

As \PolToSturm{<polname>}{<sturmname>} and +\PolSturmIsolateZeros{<sturmname>} 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{}{}

+

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 +\PolIContent{<polname>}), 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} 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 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 (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 +\PolSturmChainLength{<sturmname>}. 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*{}{}

+

Syntax: \PolToSturm*{<polname>}{<sturmname>}

+
+

Does the same as un-starred version 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 \PolSturmChainLength{<sturmname>}.

+
+
+
+

\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 +\PolToSturm{<polname>}{<sturmname>}.

+
+

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 \PolRefineInterval*{<sturmname>}{<index>} which addresses +this issue.

+
+

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 \PolSturmIsolatedZeroLeft{<sturmname>}{<index>} and +\PolSturmIsolatedZeroRight{<sturmname>}{<index>} are provided which +expand to these same values, written in decimal notation (i.e. +pre-processed by \PolDecToString.) And there +is also \PolSturmIfZeroExactlyKnown{<sturmname>}{<index>}{T}{F}.

+
+

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>} if the root is positive, and by +PolSturmIsolatedZeroRight{<sturmname>}{<index>} 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 +\PolSturmNbOfIsolatedZeros{<sturmname>}.

+

Furthermore +\PolSturmNbOfRootsOf{<sturmname>}\LessThanOrEqualTo{<value>} and +\PolSturmNbOfRootsOf{<sturmname>}\LessThanOrEqualToExpr{<num. expr.>}. +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 \PolRefineInterval*{<sturmname>}{<index>} 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*{}

+

Syntax: \PolSturmIsolateZeros*{<sturmname>}

+
+

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

+

After execution, +\PolSturmIsolatedZeroMultiplicity{<sturmname>}{<index>} 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 \PolToSturm* +starred variant: during its +execution, \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{}
+

Syntax: \PolSturmIsolateZerosAndGetMultiplicities{<sturmname>}

+
+

This is another name for \PolSturmIsolateZeros*{<sturmname>}.

+
+
+
+
+

\PolSturmIsolateZeros**{}

+

Syntax: \PolSturmIsolateZeros**{<sturmname>}

+
+

The macro does the same as \PolSturmIsolateZeros*{<sturmname>} 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 \PolSturmNbOfRationalRoots{<sturmname>}).

+

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
+

Syntax: \PolSturmIsolateZerosGetMultiplicitiesAndRationalRoots

+
+

This is another name for \PolSturmIsolateZeros**{<sturmname>}.

+
+
+
+
+

\PolSturmIsolateZerosAndFindRationalRoots{}

+

Syntax: \PolSturmIsolateZerosAndFindRationalRoots{<sturmname>}

+
+

This works exactly like \PolSturmIsolateZeros**{<sturmname>} +(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 \PolSturmIsolatedZeroMultiplicity{<sturmname>}{<index>}) into +a broken state, as all non-rational roots will supposedly have +multiplicity one. This means that the output of +\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*{}{}

+

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 kth root is then +strictly separated from the other roots.

+
+
+
+

\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{}{}{}

+

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 kth root will then be known exactly.

+
+
+
+

\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{}{}{}

+

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{}{}{}{}

+

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 +\PolSturmNbOfRootsOf{<sturmname>}\LessThanOrEqualTo{value}, +which however requires prior execution of \PolSturmIsolateZeros.

+

See also the expandable +\PolSturmNbWithMultOfRootsOf{<sturmname>}\LessThanOrEqualTo{value} +which requires prior execution of +\PolSturmIsolateZeros*.

+
+
+
+
+

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

+
+

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

+
\newcommand\PolPrintIntervalsNoRealRoots{}
+
+
+
+
+
+

\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

+
+

Default definition:

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

\PolPrintIntervalsRowSeparator

+
+

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

+

Added at 0.8.6.

+
+
+
+

\PolPrintIntervalsKnownRoot

+
+

Default definition:

+
\newcommand\PolPrintIntervalsKnownRoot{%
+  &&\PolPrintIntervalsTheVar_{\PolPrintIntervalsTheIndex}%
+  &=&\PolPrintIntervalsPrintExactZero
+}
+
+
+
+
+
+

\PolPrintIntervalsUnknownRoot

+
+

Default definition:

+
\newcommand\PolPrintIntervalsUnknownRoot{%
+  \PolPrintIntervalsPrintLeftEndPoint&<&%
+  \PolPrintIntervalsTheVar_{\PolPrintIntervalsTheIndex}&<&%
+  \PolPrintIntervalsPrintRightEndPoint
+}
+
+
+
+
+
+

\PolPrintIntervalsPrintExactZero

+
+

Default definition:

+
\newcommand\PolPrintIntervalsPrintExactZero{\PolPrintIntervalsTheLeftEndPoint}
+
+
+
+
+
+

\PolPrintIntervalsPrintLeftEndPoint

+
+

Default definition:

+
\newcommand\PolPrintIntervalsPrintLeftEndPoint{\PolPrintIntervalsTheLeftEndPoint}
+
+
+
+
+
+

\PolPrintIntervalsPrintRightEndPoint

+
+

Default definition is:

+
\newcommand\PolPrintIntervalsPrintRightEndPoint{\PolPrintIntervalsTheRightEndPoint}
+
+
+
+
+
+

\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
+
+

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{}

+

Syntax: \PolToExpr{<pol. expr.>}

+
+

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

+ +

Since 0.8 the input is not restricted to be a polynomial name but +is allowed to be an arbitrary expression. 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

+
+

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

+
+
+
+

\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

+
+

Defaults to *.

+
+
+
+

\PolToExprCaret

+
+

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

+

(new with 0.8)

+
+
+
+

\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{}{}

+

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, \PolToExprTimes, \PolToExprVar and +\PolToExprCaret.

+
+
+
+

\PolToExprOneTermStyleA{}{}

+

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

+
+

This holds the default package meaning of \PolToExprOneTerm.

+
+
+
+

\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 isn’t used at all in this style. But +\PolToExprTimes, \PolToExprVar and \PolToExprCaret are obeyed.

+

To activate it use \let\PolToExprOneTerm\PolToExprOneTermStyleB. +To revert to the package default behaviour, issue +\let\PolToExprOneTerm\PolToExprOneTermStyleA.

+
+
+
+

\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 \PolToExprCmd{<raw_coeff>} which in case of a +positive coefficient does not output an explicit + prefix.

+
+
+
+
+

\PolToFloatExpr{}

+

Syntax: \PolToFloatExpr{<pol. expr.>}

+
+

Similar to \PolToExpr{<pol. expr.>} but using +\PolToFloatExprCmd{<raw_coeff>} which by default rounds and +converts the coefficients to floating point format.

+
+

Note

+

This is unrelated to \PolGenFloatVariant{<polname>}: +\PolToFloatExprCmd{<raw_coeff>} 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{}{}

+

Syntax: \PolToFloatExprOneTerm{<raw_coeff>}{<exponent>}

+
+

Similar to \PolToExprOneTerm{<raw_coeff>}{<exponent>}. But does not treat +especially coefficients equal to plus or minus one.

+
+
+
+

\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*{}

+

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 +\PolToExpr{<pol. expr.>}.

+
+
+
+

\PolToFloatExpr*{}

+

Syntax: \PolToFloatExpr*{<pol. expr.>}

+
+

Ascending powers.

+

Extended at 0.8 to accept general expressions as input.

+
+
+
+

\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{}

+

Syntax: \PolLeadingCoeff{<polname>}

+
+

Expands to the leading coefficient.

+
+
+
+

\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{}

+

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.

+
+
+
+

\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{}

+

Syntax: \PolToCSV{<polname>}

+
+

Expands to coeff_0, coeff_1, coeff_2, ....., coeff_N, starting +with constant term and ending with leading coefficient. Converse +to \PolFromCSV{<polname>}{<csv>}.

+
+
+
+

\PolEval{}\AtExpr{}

+

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

+
+

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

+
+
+
+

\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.

+
+
+
+

\PolEvalReduced{}\AtExpr{}

+

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

+
+

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

+
+
+
+

\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.

+
+
+
+

\PolFloatEval{}\AtExpr{}

+

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

+
+

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

+
+

Attention

+

\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: [4]

+
\xintfloateval{3.27*\xintexpr f(2.53)\relax^2}
+
+
+ +
+
+
+

\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{}

+

Syntax: \PolSturmChainLength{<sturmname>}

+
+

Returns the integer N such that sturmname_N is the last one +in the Sturm chain sturmname_0, sturmname_1, …

+

See \PolToSturm{<polname>}{<sturmname>}.

+
+
+
+

\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.

+
+
+
+

\PolSturmIsolatedZeroLeft{}{}

+

Syntax: \PolSturmIsolatedZeroLeft{<sturmname>}{<index>}

+
+

Expands to the left end-point for the index-th interval, as +computed by some earlier \PolSturmIsolateZeros{<sturmname>}.

+
+

Note

+

Execution of this macro after some +\PolRefineInterval{<sturmname>}{<index>} +will take into account the now known tighter bounds.

+
+

The value is pre-formatted using \PolDecTostring.

+
+
+
+

\PolSturmIsolatedZeroRight{}{}

+

Syntax: \PolSturmIsolatedZeroRight{<sturmname>}{<index>}

+
+

Expands to the right end-point for the index-th interval as +computed by some earlier \PolSturmIsolateZeros{<sturmname>} and +possibly refined afterwards.

+

The value is pre-formatted using \PolDecTostring.

+
+
+
+

\PolSturmIsolatedZeroMultiplicity{}{}

+

Syntax: \PolSturmIsolatedZeroMultiplicity{<sturmname>}{<index>}

+
+

Expands to the multiplicity of the unique root contained in the +index-th interval.

+
+

Attention

+

A prior execution of \PolSturmIsolateZeros*{<sturmname>} is mandatory.

+
+

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

+
+
+
+

\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 +\PolToSturm{<polname>}{<sturmname>}.

+
+
+

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.

+
+
+
+

\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

+

\PolSturmIsolateZeros{<sturmname>} 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.

+
+
+
+
+

\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

+

\PolSturmIsolateZeros{<sturmname>} must have been executed +beforehand.

+
+
+
+
+

\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

+

\PolSturmIsolateZeros*{<sturmname>} (or the double starred +variant) must have been executed beforehand.

+
+
+
+
+

\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

+

\PolSturmIsolateZeros*{<sturmname>} (or the double starred +variant) must have been executed beforehand.

+
+
+
+
+

\PolSturmNbOfRationalRoots{}

+

Syntax: \PolSturmNbOfRationalRoots{<sturmname>}

+
+

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

+
+

Attention

+

\PolSturmIsolateZeros**{<sturmname>} must have been executed +beforehand.

+
+
+
+
+

\PolSturmNbOfRationalRootsWithMultiplicities{}

+

Syntax: \PolSturmNbOfRationalRootsWithMultiplicities{<sturmname>}

+
+

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

+
+

Attention

+

\PolSturmIsolateZeros**{<sturmname>} must have been executed +beforehand.

+
+
+
+
+

\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

+

\PolSturmIsolateZeros**{<sturmname>} must have been executed +beforehand.

+
+
+
+
+

\PolSturmRationalRootIndex{}{}

+

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

+
+

Expands to the index of the kth rational root as part of the +ordered real roots (counted without multiplicities). So +\PolSturmRationalRoot{<sturmname>}{<k>} is equivalent to +this nested call:

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

Attention

+

\PolSturmIsolateZeros**{<sturmname>} must have been executed +beforehand.

+
+
+
+
+

\PolSturmRationalRootMultiplicity{}{}

+

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

+
+

Expands to the multiplicity of the kth rational root.

+
+

Attention

+

\PolSturmIsolateZeros**{<sturmname>} must have been executed +beforehand.

+
+
+
+
+

\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).

+
+
+
+
+

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).

+
+

\PolPrintIntervalsTheVar

+
+

Expands to the name (default Z) used for representing the roots, +which was passed as optional argument varname to +\PolPrintIntervals[varname]{<sturmname>}.

+
+
+
+

\PolPrintIntervalsTheIndex

+
+

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

+
+
+
+

\PolPrintIntervalsTheSturmName

+
+

Expands to the argument which was passed as <sturmname> to +\PolPrintIntervals[varname]{<sturmname>}.

+
+
+
+

\PolPrintIntervalsTheLeftEndPoint

+
+

The left end point of the interval, as would be produced by +\PolSturmIsolatedZeroLeft if it was +used with arguments the Sturm chain name and interval index returned +by \PolPrintIntervalsTheSturmName and +\PolPrintIntervalsTheIndex.

+
+
+
+

\PolPrintIntervalsTheRightEndPoint

+
+

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

+
+
+
+

\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 was used earlier.

+
+
+
+
+
+

TeX Booleans (with names enacting their defaults)

+
+

\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

+
+

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 \PolGenFloatVariant{<polname>} +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

+
+

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

+
+
+
+

\poltoexprallfalse

+
+

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

+
+
+
+
+

Utilities

+
+

\PolDecToString{}

+

Syntax: \PolDecToString{decimal number}

+
+

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

+
+
+

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.

+
+
+
+

\polexprsetup{key=val,...}

+
+

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

+
    +
  • norr: the postfix that \PolSturmIsolateZeros**{<sturmname>} +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 \PolSturmIsolateZeros**{<sturmname>} +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 macro to safe +values prior to grab the polynomial expression up to the terminator +;, and also by \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.

    +
  • +
  • \PolDiff{<polname_1>}{<polname_2>} 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 \PolAntiDiff{<polname_1>}{<polname_2>}.

    +
  • +
  • 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.

  • +
+
+
+ + +
+
+
+
+ +
+
+ + + + \ No newline at end of file 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 `. 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 + `. + See :ref:`rdcoeffs() ` and the macro + :ref:`\\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]{}{} + +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 `_. + + .. 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() `. + + 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() ` or + :ref:`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) ` 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 `_ for the configurability + via macros. + + Since ``0.8`` `\\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 `_) + 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{\} ` 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() ` 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 ` +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()`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + 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()`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + 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{}`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + 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{} `_, but finally opted for this. + +.. _evalp: + +``evalp(, )`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + 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()`` +~~~~~~~~~~~~~~~~~~~~~ + + 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()`` +~~~~~~~~~~~~~~~~~~~~~~~~ + + 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()`` +~~~~~~~~~~~~~~~~~~~~~~~~~ + + Produces the nutple ``[cN,....,c1,c0]`` of coefficients, starting + with the highest degree coefficient. + + (new with ``0.8.1``) + +``coeff(, )`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + 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{\}{\} ` regarding negative indices. + Accessing leading or sub-leading coefficients can be done with + other syntax, see `lc()`_, 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()`` +~~~~~~~~~~~~~~~~~~~~ + + 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()`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + 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 `_), 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()`` +~~~~~~~~~~~~~~~~~~~~~~ + + 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 `_ + 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 `_, 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()`` +~~~~~~~~~~~~~~~~~~~~~~~~~~ + + The quotient (except for the zero polynomial) by + ``cont()``. 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(, )`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + Produces a nutple ``[Q,R]`` with ``Q`` the euclidean quotient and + ``R`` the remainder. + + **name unstable** + + ``poldiv()``? + +``quo(, )`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + The euclidean quotient. + + The deprecated ``pol1/pol2`` syntax computes the same polynomial. + +``rem(, )`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + 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) `_ 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(, )`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + 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(, )`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + 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(, )`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + 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(, , ...)`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + 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 `_ (non expandable) macro. + + .. [#] actually, only two polynomial arguments are allowed by Maple's + ``gcd()`` as far as I know. + +``resultant(, )`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + The resultant. + + **NOT YET IMPLEMENTED** + +``disc()`` +~~~~~~~~~~~~~~~~~~~~~~ + + The discriminant. + + **NOT YET IMPLEMENTED** + +``polpowmod(, , )`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + 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()`` +~~~~~~~~~~~~~~~~~~~~~~~~~~ + + This operates on the internal representation of the coefficients, + reducing them to lowest terms. + + **name HIGHLY undecided** + +``rdzcoeffs()`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + 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()`` +~~~~~~~~~~~~~~~~~~~~~~~ + + The first derivative. + + **name UNSTABLE** + + This name may be used in future to be the partial derivative with + respect to a first variable. + +``diff2()`` +~~~~~~~~~~~~~~~~~~~~~~~ + + The second derivative. + + **name UNSTABLE** + + This name may be used in future to be the partial derivative with + respect to a second variable. + + +``diffn(, )`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + 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()`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + The primitive of ``P`` with no constant term. Same as ``diffn(P,-1)``. + +``intfrom(, )`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + 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(, )`` + ----------------------------------------- + + ``\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(, [, ])`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + ``\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 + `_. + + 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{\} ` 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{\} ` + 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[]{}{}`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + Does the same as `\\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 ``[]`` optional argument, the variable is assumed to be + ``x``. + + +.. _PolGenFloatVariant: + +``\PolGenFloatVariant{}`` +~~~~~~~~~~~~~~~~~~~~~~~~~ + +Syntax: ``\PolGenFloatVariant{}`` + + 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{\} `. + + .. 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{}`` if + the new polynomial is to be used in ``\xintfloateval``. + +.. _PolTypeset: + +``\PolTypeset{}`` +~~~~~~~~~~~~~~~~~ + +Syntax: ``\PolTypeset{}`` + + 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{}`` + + 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} `. + + The actual printing of the coefficients, when not equal to plus or + minus one, is handled by :ref:`\\PolTypesetOne{\} `. + +.. _PolIfCoeffIsPlusOrMinusOne: + +``\PolIfCoeffIsPlusOrMinusOne{}{}`` +*********************************** + +Syntax: ``\PolIfCoeffIsPlusOrMinusOne{T}{F}`` + + This macro is a priori undefined. + + It is defined via the default :ref:`\\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{}`` + + 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{}`` + + 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{\} ` 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*{}`` + + Typesets in ascending powers. Use ``[]`` 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{}={}`` + + Makes a copy of the already defined polynomial ``polname_1`` to a + new one ``polname_2``. This has the same effect as + ``\PolDef{}{(x)}`` or (better) + ``\PolDef{}{}`` but with less overhead. The + ``=`` is optional. + +.. _PolGlobalLet: + +``\PolGlobalLet{}={}`` +~~~~~~~~~~~~~~~~~~~~~~ + +Syntax: ``\PolGlobalLet{}={}`` + + Acts globally. + +.. _PolAssign: + +``\PolAssign{}\toarray{}`` +~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Syntax: ``\PolAssign{}\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{\}{\} `. + +.. _PolGet: + +``\PolGet{}\fromarray{}`` +~~~~~~~~~~~~~~~~~~~~~~~~~ + +Syntax: ``\PolGet{}\fromarray{<\macro>}`` + + Does the converse operation to + ``\PolAssign{}\toarray\macro``. Each individual + ``\macro{}`` 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{}{}`` + + 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{\} `. + + .. vieux commentaire + + Prior to ``0.5``, coefficients were not normalized via + ``\xintRaw`` for internal storage. + + +.. _PolMapCoeffs: + +``\PolMapCoeffs{}{}`` +~~~~~~~~~~~~~~~~~~~~~ + +Syntax: ``\PolMapCoeffs{\macro}{}`` + + 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{}`` + + Reduces the internal representations of the coefficients to + their lowest terms. + +.. _PolReduceCoeffs*: + +``\PolReduceCoeffs*{}`` +~~~~~~~~~~~~~~~~~~~~~~~ + +Syntax: ``\PolReduceCoeffs*{}`` + + 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{\} `: as the numerators and denominators + remain generally smaller. + +.. _PolMakeMonic: + +``\PolMakeMonic{}`` +~~~~~~~~~~~~~~~~~~~ + +Syntax: ``\PolMakeMonic{}`` + + Divides by the leading coefficient. It is recommended to execute + :ref:`\\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{}`` + + 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{}{}`` + + 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]{}{}`` + + This sets ``polname_2`` to the ``N``-th derivative of ``polname_1``. + Identical arguments is allowed. With ``N=0``, same effect as + ``\PolLet{}={}``. With negative ``N``, switches to + using ``\PolAntiDiff``. + +.. _PolAntiDiff: + +``\PolAntiDiff{}{}`` +~~~~~~~~~~~~~~~~~~~~ + +Syntax: ``\PolAntiDiff{}{}`` + + 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]{}{}`` + + 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{}{}{}{}`` + + 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{}{}{}`` + + This sets ``polname_Q`` to be the quotient in the Euclidean division + of ``polname_1`` by ``polname_2``. + +.. _PolRem: + +``\PolRem{}{}{}`` +~~~~~~~~~~~~~~~~~ + +Syntax: ``\PolRem{}{}{}`` + + This sets ``polname_R`` to be the remainder in the Euclidean division + of ``polname_1`` by ``polname_2``. + +.. _PolGCD: + +``\PolGCD{}{}{}`` +~~~~~~~~~~~~~~~~~ + +Syntax: ``\PolGCD{}{}{}`` + + 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_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{\}{\} ` and +:ref:`\\PolSturmIsolateZeros{\} ` and variants declare +additional polynomial or scalar variables with names based on ```` as +prefix, it is advisable to keep the ```` namespace separate from +the one applying to ``\xintexpr`` variables generally, or to polynomials. + +.. _PolToSturm: + +``\PolToSturm{}{}`` +^^^^^^^^^^^^^^^^^^^ + +Syntax: ``\PolToSturm{}{}`` + + With ```` being for example ``P``, and ```` 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{\} `), 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} + `_ 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{}{}`` and before executing + ``\PolSturmIsolateZeros{}`` 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: ```` and ````. + + 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 + `_ creates variables sharing + the ```` 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 + `_ (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{\} `. 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*{}{}`` + + Does the same as `un-starred version `_ 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{\} `. + + .. comment + + The square-free part of ```` is ``sturmname_0``, and their + quotient is the polynomial with name + ``sturmname_\PolSturmChainLength{}_``. 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{}`` + + 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{\}{\} `. + + 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*{\}{\} ` 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 ```` 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{\}{\} ` and + :ref:`\\PolSturmIsolatedZeroRight{\}{\} ` are provided which + expand to these same values, written in decimal notation (i.e. + pre-processed by `\\PolDecToString `_.) And there + is also :ref:`\\PolSturmIfZeroExactlyKnown{\}{\}{T}{F} `. + + .. 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 ````-th root is given by + `\\PolSturmIsolatedZeroLeft{}{} + `_ if the root is positive, and by + `\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{\} `. + + Furthermore + :ref:`\\PolSturmNbOfRootsOf{\}\\LessThanOrEqualTo{\} ` and + :ref:`\\PolSturmNbOfRootsOf{\}\\LessThanOrEqualToExpr{\} `. + 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*{\}{\} ` 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*{}`` + + The macro does the same as :ref:`\\PolSturmIsolateZeros{\} ` and + then in addition it does the extra work to determine all + multiplicities of the real roots. + + After execution, + :ref:`\\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 ```` 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* ` + starred variant: during its + execution, :ref:`\\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{}`` + + This is another name for :ref:`\\PolSturmIsolateZeros*{\} `. + +.. _PolSturmIsolateZeros**: + +``\PolSturmIsolateZeros**{}`` +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Syntax: ``\PolSturmIsolateZeros**{}`` + + The macro does the same as :ref:`\\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{\} + `). + + 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**{\} `. + +.. _PolSturmIsolateZerosAndFindRationalRoots: + +``\PolSturmIsolateZerosAndFindRationalRoots{}`` +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Syntax: ``\PolSturmIsolateZerosAndFindRationalRoots{}`` + + This works exactly like :ref:`\\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{\}{\} `) into + a broken state, as all non-rational roots will supposedly have + multiplicity one. This means that the output of + `\\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*{}{}`` + + 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]{}{}`` + + 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{}{}{}`` + + 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{}{}`` + + 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}{}{}`` + + Sets macro ``\foo`` to store the number of sign changes in the + already computed normalized Sturm chain with name prefix + ````, at location ```` (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}{}{}{}`` + + 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{\}\\LessThanOrEqualTo{value} `, + which however requires prior execution of `\\PolSturmIsolateZeros + `_. + + See also the expandable + :ref:`\\PolSturmNbWithMultOfRootsOf{\}\\LessThanOrEqualTo{value} ` + which requires prior execution of + `\\PolSturmIsolateZeros* `_. + +.. _PolPrintIntervals: + +Displaying the found roots: ``\PolPrintIntervals[]{}`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Syntax: ``\PolPrintIntervals[]{}`` + + 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*[]{}`` +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Syntax: ``\PolPrintIntervals*[]{}`` + + 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{}`` + + 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{}`` + + 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{}{}`` + + 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 `_, `\\PolToExprTimes + `_, `\\PolToExprVar `_ and + `\\PolToExprCaret`_. + +.. _PolToExprOneTermStyleA: + +``\PolToExprOneTermStyleA{}{}`` +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Syntax: ``\PolToExprOneTermStyleA{}{}`` + + This holds the default package meaning of ``\PolToExprOneTerm``. + +.. _PolToExprOneTermStyleB: + +``\PolToExprOneTermStyleB{}{}`` +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Syntax: ``\PolToExprOneTermStyleB{}{}`` + + 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 `_ isn't used at all in this style. But + `\\PolToExprTimes `_, `\\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{}`` + + 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{\} ` which in case of a + positive coefficient does not output an explicit ``+`` prefix. + +.. _PolToFloatExpr: + +``\PolToFloatExpr{}`` +~~~~~~~~~~~~~~~~~~~~~ + +Syntax: ``\PolToFloatExpr{}`` + + Similar to :ref:`\\PolToExpr{\} ` but using + :ref:`\\PolToFloatExprCmd{\} ` which by default rounds and + converts the coefficients to floating point format. + + .. note:: + + This is unrelated to :ref:`\\PolGenFloatVariant{\} `: + :ref:`\\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{}{}`` + + Similar to :ref:`\\PolToExprOneTerm{\}{\} `. But does not treat + especially coefficients equal to plus or minus one. + +.. _PolToFloatExprCmd: + +``\PolToFloatExprCmd{}`` +^^^^^^^^^^^^^^^^^^^^^^^^ + +Syntax: ``\PolToFloatExprCmd{}`` + + 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*{}`` + + 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{\} `. + +.. _PolToFloatExpr*: + +``\PolToFloatExpr*{}`` +~~~~~~~~~~~~~~~~~~~~~~ + +Syntax: ``\PolToFloatExpr*{}`` + + Ascending powers. + + Extended at ``0.8`` to accept general expressions as input. + +.. _PolNthCoeff: + +``\PolNthCoeff{}{}`` +~~~~~~~~~~~~~~~~~~~~ + +Syntax: ``\PolNthCoeff{}{}`` + + 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{}`` + + Expands to the leading coefficient. + +.. _PolDegree: + +``\PolDegree{}`` +~~~~~~~~~~~~~~~~ + +Syntax: ``\PolDegree{}`` + + 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{}`` + + 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 `_. + +.. _PolToList: + +``\PolToList{}`` +~~~~~~~~~~~~~~~~ + +Syntax: ``\PolToList{}`` + + 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{}`` + + Expands to ``coeff_0, coeff_1, coeff_2, ....., coeff_N``, starting + with constant term and ending with leading coefficient. Converse + to :ref:`\\PolFromCSV{\}{\} `. + + +.. _PolEvalAtExpr: + +``\PolEval{}\AtExpr{}`` +~~~~~~~~~~~~~~~~~~~~~~~ + +Syntax: ``\PolEval{}\AtExpr{}`` + + Same output as + ``\xinteval{polname(numerical expression)}``. + +.. _PolEvalAt: + +``\PolEval{}\At{}`` +~~~~~~~~~~~~~~~~~~~ + +Syntax: ``\PolEval{}\At{}`` + + 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{}\AtExpr{}`` + + Same output as ``\xinteval{reduce(polname(numerical expression))}``. + +.. _PolEvalReducedAt: + +``\PolEvalReduced{}\At{}`` +~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Syntax: ``\PolEvalReduced{}\At{}`` + + 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{}\AtExpr{}`` + + Same output as ``\xintfloateval{polname(numerical expression)}``. + + .. attention:: + + `\\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{}\At{}`` + + 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{}`` + + Returns the integer ``N`` such that ``sturmname_N`` is the last one + in the Sturm chain ``sturmname_0``, ``sturmname_1``, ... + + See :ref:`\\PolToSturm{\}{\} `. + +.. _PolSturmIfZeroExactlyKnown: + +``\PolSturmIfZeroExactlyKnown{}{}{}{}`` +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Syntax: ``\PolSturmIfZeroExactlyKnown{}{}{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{}{}`` + + Expands to the left end-point for the ``index``\ -th interval, as + computed by some earlier :ref:`\\PolSturmIsolateZeros{\} `. + + .. note:: + + Execution of this macro after some + `\\PolRefineInterval{}{} `_ + will take into account the now known tighter bounds. + + The value is pre-formatted using `\\PolDecTostring + `_. + +.. _PolSturmIsolatedZeroRight: + +``\PolSturmIsolatedZeroRight{}{}`` +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Syntax: ``\PolSturmIsolatedZeroRight{}{}`` + + Expands to the right end-point for the ``index``\ -th interval as + computed by some earlier :ref:`\\PolSturmIsolateZeros{\} ` and + possibly refined afterwards. + + The value is pre-formatted using `\\PolDecTostring + `_. + +.. _PolSturmIsolatedZeroMultiplicity: + +``\PolSturmIsolatedZeroMultiplicity{}{}`` +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Syntax: ``\PolSturmIsolatedZeroMultiplicity{}{}`` + + Expands to the multiplicity of the unique root contained in the + ``index``\ -th interval. + + .. attention:: + + A prior execution of :ref:`\\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{}`` + + Expands to the number of real roots of the polynomial + ``_0``, i.e. the number of distinct real roots of the + polynomial originally used to create the Sturm chain via + :ref:`\\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{}\LessThanOrEqualTo{}`` + + 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{\} ` must have been executed + beforehand. + + And the argument is a ````, not a ```` (this is + why the macro contains Sturm in its name), simply to be reminded + of the above constraint. + +.. _PolSturmNbOfRootsOfLessThanOrEqualToExpr: + +``\PolSturmNbOfRootsOf{}\LessThanOrEqualToExpr{}`` +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Syntax: ``\PolSturmNbOfRootsOf{}\LessThanOrEqualToExpr{}`` + + 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{\} ` must have been executed + beforehand. + +.. _PolSturmNbWithMultOfRootsOfLessThanOrEqualTo: + +``\PolSturmNbWithMultOfRootsOf{}\LessThanOrEqualTo{}`` +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Syntax: ``\PolSturmNbWithMultOfRootsOf{}\LessThanOrEqualTo{}`` + + 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*{\} ` (or the double starred + variant) must have been executed beforehand. + +.. _PolSturmNbWithMultOfRootsOfLessThanOrEqualToExpr: + +``\PolSturmNbWithMultOfRootsOf{}\LessThanOrEqualToExpr{}`` +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Syntax: ``\PolSturmNbWithMultOfRootsOf{}\LessThanOrEqualToExpr{}`` + + Expands to the total number of roots (counted with multiplicities) + which are less than or equal to the given ``expression``. + + .. attention:: + + :ref:`\\PolSturmIsolateZeros*{\} ` (or the double starred + variant) must have been executed beforehand. + +.. _PolSturmNbOfRationalRoots: + +``\PolSturmNbOfRationalRoots{}`` +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Syntax: ``\PolSturmNbOfRationalRoots{}`` + + Expands to the number of rational roots (without multiplicities). + + .. attention:: + + :ref:`\\PolSturmIsolateZeros**{\} ` must have been executed + beforehand. + +.. _PolSturmNbOfRationalRootsWithMultiplicities: + +``\PolSturmNbOfRationalRootsWithMultiplicities{}`` +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Syntax: ``\PolSturmNbOfRationalRootsWithMultiplicities{}`` + + Expands to the number of rational roots (counted with multiplicities). + + .. attention:: + + :ref:`\\PolSturmIsolateZeros**{\} ` must have been executed + beforehand. + +.. _PolSturmRationalRoot: + +``\PolSturmRationalRoot{}{}`` +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Syntax: ``\PolSturmRationalRoot{}{}`` + + Expands to the k-th rational root. They are enumerated from left to + right starting at index value ``1``. + + .. attention:: + + :ref:`\\PolSturmIsolateZeros**{\} ` must have been executed + beforehand. + +.. _PolSturmRationalRootIndex: + +``\PolSturmRationalRootIndex{}{}`` +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Syntax: ``\PolSturmRationalRootIndex{}{}`` + + Expands to the index of the ``k``\ th rational root as part of the + ordered real roots (counted without multiplicities). So + :ref:`\\PolSturmRationalRoot{\}{\} ` is equivalent to + this nested call:: + + \PolSturmIsolatedZeroLeft{}{\PolSturmRationalRootIndex{}{}} + + .. attention:: + + :ref:`\\PolSturmIsolateZeros**{\} ` must have been executed + beforehand. + +.. _PolSturmRationalRootMultiplicity: + +``\PolSturmRationalRootMultiplicity{}{}`` +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Syntax: ``\PolSturmRationalRootMultiplicity{}{}`` + + Expands to the multiplicity of the ``k``\ th rational root. + + .. attention:: + + :ref:`\\PolSturmIsolateZeros**{\} ` must have been executed + beforehand. + +.. _PolIntervalWidth: + +``\PolIntervalWidth{}{}`` +^^^^^^^^^^^^^^^^^^^^^^^^^ + +Syntax: ``\PolIntervalWidth{}{}`` + + 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]{\} `. + +.. _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 ```` to + :ref:`\\PolPrintIntervals[varname]{\} `. + +.. _PolPrintIntervalsTheLeftEndPoint: + +``\PolPrintIntervalsTheLeftEndPoint`` +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + + The left end point of the interval, as would be produced by + `\\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 `_ 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 + `_ 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{\} ` + 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 `_ will also typeset the vanishing + coefficients. + + +.. _poltoexprallfalse: + +``\poltoexprallfalse`` +~~~~~~~~~~~~~~~~~~~~~~ + + If ``true``, :ref:`\\PolToExpr{\} ` and + :ref:`\\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**{\} ` + should append to ```` 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**{\} ` + should append to ```` 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 `_ macro to safe + values prior to grab the polynomial expression up to the terminator + ``;``, and also by `\\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{\}{\} ` 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{\}{\} `. + +- 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: diff --git a/macros/generic/polexpr/polexpr.css b/macros/generic/polexpr/polexpr.css new file mode 100644 index 0000000000..b95962ac84 --- /dev/null +++ b/macros/generic/polexpr/polexpr.css @@ -0,0 +1,826 @@ +/* + * polexpr.css + * ~~~~~~~~~~~ + * + * stylesheet for polexpr html documentation + * Copyright (c) 2022 by Jean-François Burnol + * + * It has been obtained on May 13, 2022 by Jean-François Burnol via + * copying selected extracts from the css files as found in the output + * of a sphinx-build with "bizstyle" theme, enough for the styling the + * html elements used in polexpr html documentation, and with a few + * changes here and there. + * + * It also incorporate (essentially) the output of `pygmentize -S + * friendly -f html` which specifies the behaviour of the highlighting, + * and is produced by default by Sphinx on all sphinx-build runs. + * + */ + + +/* -- start of extracts from basic.css -------------------------------------- */ + +/* -- main layout ----------------------------------------------------------- */ + +div.section::after { + display: block; + content: ''; + clear: left; +} + +/* -- relbar ---------------------------------------------------------------- */ + +div.related { + width: 100%; + font-size: 90%; +} + +div.related h3 { + display: none; +} + +div.related ul { + margin: 0; + padding: 0 0 0 10px; + list-style: none; +} + +div.related li { + display: inline; +} + +div.related li.right { + float: right; + margin-right: 5px; +} + +/* -- sidebar --------------------------------------------------------------- */ + +div.sphinxsidebarwrapper { + padding: 10px 5px 0 10px; +} + +div.sphinxsidebar { + float: left; + width: 35%; /* polexpr */ + margin-left: -100%; + font-size: 90%; + word-wrap: break-word; + overflow-wrap : break-word; +} + +div.sphinxsidebar ul { + list-style: none; +} + +div.sphinxsidebar ul ul, +div.sphinxsidebar ul.want-points { + margin-left: 20px; + list-style: square; +} + +div.sphinxsidebar ul ul { + margin-top: 0; + margin-bottom: 0; +} + +/* -- general body styles --------------------------------------------------- */ + +div.body { + min-width: 360px; + max-width: 800px; +} + +div.body p, div.body dd, div.body li, div.body blockquote { + -moz-hyphens: auto; + -ms-hyphens: auto; + -webkit-hyphens: auto; + hyphens: auto; +} + +a.headerlink { + visibility: hidden; +} + +a.brackets:before, +span.brackets > a:before{ + content: "["; +} + +a.brackets:after, +span.brackets > a:after { + content: "]"; +} + +h1:hover > a.headerlink, +h2:hover > a.headerlink, +h3:hover > a.headerlink, +h4:hover > a.headerlink, +h5:hover > a.headerlink, +h6:hover > a.headerlink, +dt:hover > a.headerlink, +caption:hover > a.headerlink, +p.caption:hover > a.headerlink, +div.code-block-caption:hover > a.headerlink { + visibility: visible; +} + +div.body p.caption { + text-align: inherit; +} + +div.body td { + text-align: left; +} + +.first { + margin-top: 0 !important; +} + +.align-left { + text-align: left; +} + +.align-center { + text-align: center; +} + +.align-default { + text-align: center; +} + +.align-right { + text-align: right; +} + +/* -- sidebars -------------------------------------------------------------- */ + +div.sidebar, +aside.sidebar { + margin: 0 0 0.5em 1em; + border: 1px solid #ddb; + padding: 7px; + background-color: #ffe; + width: 40%; + float: right; + clear: right; + overflow-x: auto; +} + +p.sidebar-title { + font-weight: bold; +} + +div.admonition, div.topic, blockquote { + clear: left; +} + +/* -- topics ---------------------------------------------------------------- */ + +div.topic { + border: 1px solid #ccc; + padding: 7px; + margin: 10px 0 10px 0; +} + +p.topic-title { + font-size: 1.1em; + font-weight: bold; + margin-top: 10px; +} + +/* -- admonitions ----------------------------------------------------------- */ + +div.admonition { + margin-top: 10px; + margin-bottom: 10px; + padding: 7px; +} + +div.admonition dt { + font-weight: bold; +} + +p.admonition-title { + margin: 0px 10px 5px 0px; + font-weight: bold; +} + +div.body p.centered { + text-align: center; + margin-top: 25px; +} + +/* -- content of sidebars/topics/admonitions -------------------------------- */ + +div.sidebar > :last-child, +aside.sidebar > :last-child, +div.topic > :last-child, +div.admonition > :last-child { + margin-bottom: 0; +} + +div.sidebar::after, +aside.sidebar::after, +div.topic::after, +div.admonition::after, +blockquote::after { + display: block; + content: ''; + clear: both; +} + +.footnote:target { + background-color: #ffa; +} + +/* -- code displays --------------------------------------------------------- */ + +pre { + overflow: auto; + overflow-y: hidden; /* fixes display issues on Chrome browsers */ +} + +pre, div[class*="highlight-"] { + clear: both; +} + +span.pre { + -moz-hyphens: none; + -ms-hyphens: none; + -webkit-hyphens: none; + hyphens: none; + white-space: nowrap; +} + +div[class*="highlight-"] { + margin: 1em 0; +} + +td.linenos pre { + border: 0; + background-color: transparent; + color: #aaa; +} + + +.highlight .hll { + display: block; +} + +div.highlight pre, +table.highlighttable pre { + margin: 0; +} + +table.highlighttable td.linenos, +span.linenos, +div.highlight span.gp { /* gp: Generic.Prompt */ + user-select: none; + -webkit-user-select: text; /* Safari fallback only */ + -webkit-user-select: none; /* Chrome/Safari */ + -moz-user-select: none; /* Firefox */ + -ms-user-select: none; /* IE10+ */ +} + +div.code-block-caption span.caption-number { + padding: 0.1em 0.3em; + font-style: italic; +} + +div.code-block-caption span.caption-text { +} + +div.literal-block-wrapper { + margin: 1em 0; +} + +code.xref, a code { + background-color: transparent; + font-weight: bold; +} + +h1 code, h2 code, h3 code, h4 code, h5 code, h6 code { + background-color: transparent; +} + +/* -- printout stylesheet --------------------------------------------------- */ + +@media print { + div.document, + div.documentwrapper, + div.bodywrapper { + margin: 0 !important; + width: 100%; + } + + div.sphinxsidebar, + div.related, + div.footer, + #top-link { + display: none; + } +} + +/* -- end of extracts from basic.css ---------------------------------------- */ + +/* -- start of extracts from bizstyle.css ----------------------------------- */ + +/* -- page layout ----------------------------------------------------------- */ + +body { + font-family: 'Lucida Grande', 'Lucida Sans Unicode', 'Geneva', + 'Verdana', sans-serif; + /* font-size: 14px; not for polexpr.css */ + letter-spacing: -0.01em; + line-height: 150%; + text-align: center; + background-color: white; + background-image: url(background_b01.png); + color: black; + padding: 0; + border-right: 1px solid #336699; + border-left: 1px solid #336699; + + margin: 0px 40px 0px 40px; +} + +div.document { + background-color: white; + text-align: left; + background-repeat: repeat-x; + + -moz-box-shadow: 2px 2px 5px #000; + -webkit-box-shadow: 2px 2px 5px #000; +} + +div.documentwrapper { + float: left; + width: 100%; +} + +div.bodywrapper { + margin: 0 0 0 240px; + border-left: 1px solid #ccc; +} + +div.body { + margin: 0; + padding: 0.5em 20px 20px 20px; +} +div.bodywrapper { + margin: 0 calc(35% + 30px) 0 0; /* polexpr */ + border-right: 1px solid #ccc; +} + +div.related { + font-size: 1em; + + -moz-box-shadow: 2px 2px 5px #000; + -webkit-box-shadow: 2px 2px 5px #000; +} + +div.related ul { + background-color: #336699; + height: 100%; + overflow: hidden; + border-top: 1px solid #ddd; + border-bottom: 1px solid #ddd; +} + +div.related ul li { + color: white; + margin: 0; + padding: 0; + height: 2em; + float: left; +} + +div.related ul li.right { + float: right; + margin-right: 5px; +} + +div.related ul li a { + margin: 0; + padding: 0 5px 0 5px; + line-height: 1.75em; + color: #fff; +} + +div.related ul li a:hover { + color: #fff; + text-decoration: underline; +} + +div.sphinxsidebarwrapper { + padding: 0; +} + +div.sphinxsidebar { + padding: 0.5em 12px 12px 12px; + width: 35%; /* polexpr */ + float: right; + font-size: 1em; + text-align: left; +} + +div.sphinxsidebar h3, div.sphinxsidebar h4 { + margin: 1em 0 0.5em 0; + font-size: 1em; + padding: 0.1em 0 0.1em 0.5em; + color: white; + border: 1px solid #336699; + background-color: #336699; +} + +div.sphinxsidebar h3 a { + color: white; +} + +div.sphinxsidebar ul { + padding-left: 1.5em; + margin-top: 7px; + padding: 0; + line-height: 130%; +} + +div.sphinxsidebar ul ul { + margin-left: 20px; +} + +div.sphinxsidebar input { + border: 1px solid #336699; +} + +div.footer { + background-color: white; + color: #336699; + padding: 3px 8px 3px 0; + clear: both; + font-size: 0.8em; + text-align: right; + border-bottom: 1px solid #336699; + + -moz-box-shadow: 2px 2px 5px #000; + -webkit-box-shadow: 2px 2px 5px #000; +} + +div.footer a { + color: #336699; + text-decoration: underline; +} + +/* -- body styles ----------------------------------------------------------- */ + +p { + margin: 0.8em 0 0.5em 0; +} + +a { + color: #336699; + text-decoration: none; +} + +a:hover { + color: #336699; + text-decoration: underline; +} + +div.body a { + text-decoration: underline; +} + +h1, h2, h3 { + color: #336699; +} + +h1 { + margin: 0; + padding: 0.7em 0 0.3em 0; + font-size: 1.5em; +} + +h2 { + margin: 1.3em 0 0.2em 0; + font-size: 1.35em; + padding-bottom: .5em; + border-bottom: 1px solid #336699; +} + +h3 { + margin: 1em 0 -0.3em 0; + font-size: 1.2em; + padding-bottom: .3em; + border-bottom: 1px solid #CCCCCC; +} + +div.body h1 a, div.body h2 a, div.body h3 a, +div.body h4 a, div.body h5 a, div.body h6 a { + color: black!important; +} + +h1 a.anchor, h2 a.anchor, h3 a.anchor, +h4 a.anchor, h5 a.anchor, h6 a.anchor { + display: none; + margin: 0 0 0 0.3em; + padding: 0 0.2em 0 0.2em; + color: #aaa!important; +} + +h1:hover a.anchor, h2:hover a.anchor, h3:hover a.anchor, h4:hover a.anchor, +h5:hover a.anchor, h6:hover a.anchor { + display: inline; +} + +h1 a.anchor:hover, h2 a.anchor:hover, h3 a.anchor:hover, h4 a.anchor:hover, +h5 a.anchor:hover, h6 a.anchor:hover { + color: #777; + background-color: #eee; +} + +a.headerlink { + color: #c60f0f!important; + font-size: 1em; + margin-left: 6px; + padding: 0 4px 0 4px; + text-decoration: none!important; +} + +a.headerlink:hover { + background-color: #ccc; + color: white!important; +} + +cite, code, tt { + font-family: 'Consolas', 'Deja Vu Sans Mono', + 'Bitstream Vera Sans Mono', monospace; + /* font-size: 0.95em; not for polexpr */ + letter-spacing: 0.01em; +} + +code { + background-color: #F2F2F2; + border-bottom: 1px solid #ddd; + color: #333; +} + +code.descname, code.descclassname, code.xref { + border: 0; +} + +hr { + border: 1px solid #abc; + margin: 2em; +} + +a code { + border: 0; + color: #CA7900; +} + +a code:hover { + color: #2491CF; +} + +pre { + background-color: transparent !important; + font-family: 'Consolas', 'Deja Vu Sans Mono', + 'Bitstream Vera Sans Mono', monospace; + /* font-size: 0.95em; not for polexpr */ + letter-spacing: 0.015em; + line-height: 120%; + padding: 0.5em; + border-right: 5px solid #ccc; + border-left: 5px solid #ccc; +} + +pre a { + color: inherit; + text-decoration: underline; +} + +td.linenos pre { + padding: 0.5em 0; +} + +div.quotebar { + background-color: #f8f8f8; + max-width: 250px; + float: right; + padding: 2px 7px; + border: 1px solid #ccc; +} + +div.topic { + background-color: #f8f8f8; +} + +div.admonition { + /* font-size: 0.9em; not for polexpr */ + margin: 1em 0 1em 0; + border: 3px solid #cccccc; + background-color: #f7f7f7; + padding: 0; +} + +div.admonition p { + margin: 0.5em 1em 0.5em 1em; + padding: 0; +} + +div.admonition li p { + margin-left: 0; +} + +div.admonition pre, div.warning pre { + margin: 0; +} + +div.highlight { + margin: 0.4em 1em; +} + +div.admonition p.admonition-title { + margin: 0; + padding: 0.1em 0 0.1em 0.5em; + color: white; + border-bottom: 3px solid #cccccc; + font-weight: bold; + background-color: #165e83; +} + +div.danger { border: 3px solid #f0908d; background-color: #f0cfa0; } +div.error { border: 3px solid #f0908d; background-color: #ede4cd; } +div.warning { border: 3px solid #f8b862; background-color: #f0cfa0; } +div.caution { border: 3px solid #f8b862; background-color: #ede4cd; } +div.attention { border: 3px solid #f8b862; background-color: #f3f3f3; } +div.important { border: 3px solid #f0cfa0; background-color: #ede4cd; } +div.note { border: 3px solid #f0cfa0; background-color: #f3f3f3; } +div.hint { border: 3px solid #bed2c3; background-color: #f3f3f3; } +div.tip { border: 3px solid #bed2c3; background-color: #f3f3f3; } + +div.danger p.admonition-title, div.error p.admonition-title { + background-color: #b7282e; + border-bottom: 3px solid #f0908d; +} + +div.caution p.admonition-title, +div.warning p.admonition-title, +div.attention p.admonition-title { + background-color: #f19072; + border-bottom: 3px solid #f8b862; +} + +div.note p.admonition-title, div.important p.admonition-title { + background-color: #f8b862; + border-bottom: 3px solid #f0cfa0; +} + +div.hint p.admonition-title, div.tip p.admonition-title { + background-color: #7ebea5; + border-bottom: 3px solid #bed2c3; +} + +div.admonition ul, div.admonition ol, +div.warning ul, div.warning ol { + margin: 0.1em 0.5em 0.5em 3em; + padding: 0; +} + +div.versioninfo { + margin: 1em 0 0 0; + border: 1px solid #ccc; + background-color: #DDEAF0; + padding: 8px; + line-height: 1.3em; + font-size: 0.9em; +} + +div.literal-block-wrapper div.code-block-caption { + background-color: #EEE; + border-style: solid; + border-color: #CCC; + border-width: 1px 5px; +} + +/* WIDE DESKTOP STYLE */ +@media only screen and (min-width: 1176px) { +body { + margin: 0 40px 0 40px; +} +} + +/* TABLET STYLE */ +@media only screen and (min-width: 768px) and (max-width: 991px) { +body { + margin: 0 40px 0 40px; +} +} + +/* MOBILE LAYOUT (PORTRAIT/320px) */ +@media only screen and (max-width: 767px) { +body { + margin: 0; +} +div.bodywrapper { + margin: 0; + width: 100%; + border: none; +} +div.sphinxsidebar { + display: none; +} +} + +/* MOBILE LAYOUT (LANDSCAPE/480px) */ +@media only screen and (min-width: 480px) and (max-width: 767px) { +body { + margin: 0 20px 0 20px; +} +} + +/* RETINA OVERRIDES */ +@media +only screen and (-webkit-min-device-pixel-ratio: 2), +only screen and (min-device-pixel-ratio: 2) { +} + +/* -- end ------------------------------------------------------------------- */ + +/* -- pygments styling from `pygmentize -S friendly -f html` ---------------- */ + +pre { line-height: 125%; } +td.linenos .normal { color: #666666; background-color: transparent; padding-left: 5px; padding-right: 5px; } +span.linenos { color: #666666; background-color: transparent; padding-left: 5px; padding-right: 5px; } +td.linenos .special { color: #000000; background-color: #ffffc0; padding-left: 5px; padding-right: 5px; } +span.linenos.special { color: #000000; background-color: #ffffc0; padding-left: 5px; padding-right: 5px; } +.highlight .hll { background-color: #ffffcc } +.highlight { background: #f0f0f0; } +.highlight .c { color: #60a0b0; font-style: italic } /* Comment */ +.highlight .err { border: 1px solid #FF0000 } /* Error */ +.highlight .k { color: #007020; font-weight: bold } /* Keyword */ +.highlight .o { color: #666666 } /* Operator */ +.highlight .ch { color: #60a0b0; font-style: italic } /* Comment.Hashbang */ +.highlight .cm { color: #60a0b0; font-style: italic } /* Comment.Multiline */ +.highlight .cp { color: #007020 } /* Comment.Preproc */ +.highlight .cpf { color: #60a0b0; font-style: italic } /* Comment.PreprocFile */ +.highlight .c1 { color: #60a0b0; font-style: italic } /* Comment.Single */ +.highlight .cs { color: #60a0b0; background-color: #fff0f0 } /* Comment.Special */ +.highlight .gd { color: #A00000 } /* Generic.Deleted */ +.highlight .ge { font-style: italic } /* Generic.Emph */ +.highlight .gr { color: #FF0000 } /* Generic.Error */ +.highlight .gh { color: #000080; font-weight: bold } /* Generic.Heading */ +.highlight .gi { color: #00A000 } /* Generic.Inserted */ +.highlight .go { color: #888888 } /* Generic.Output */ +.highlight .gp { color: #c65d09; font-weight: bold } /* Generic.Prompt */ +.highlight .gs { font-weight: bold } /* Generic.Strong */ +.highlight .gu { color: #800080; font-weight: bold } /* Generic.Subheading */ +.highlight .gt { color: #0044DD } /* Generic.Traceback */ +.highlight .kc { color: #007020; font-weight: bold } /* Keyword.Constant */ +.highlight .kd { color: #007020; font-weight: bold } /* Keyword.Declaration */ +.highlight .kn { color: #007020; font-weight: bold } /* Keyword.Namespace */ +.highlight .kp { color: #007020 } /* Keyword.Pseudo */ +.highlight .kr { color: #007020; font-weight: bold } /* Keyword.Reserved */ +.highlight .kt { color: #902000 } /* Keyword.Type */ +.highlight .m { color: #40a070 } /* Literal.Number */ +.highlight .s { color: #4070a0 } /* Literal.String */ +.highlight .na { color: #4070a0 } /* Name.Attribute */ +.highlight .nb { color: #007020 } /* Name.Builtin */ +.highlight .nc { color: #0e84b5; font-weight: bold } /* Name.Class */ +.highlight .no { color: #60add5 } /* Name.Constant */ +.highlight .nd { color: #555555; font-weight: bold } /* Name.Decorator */ +.highlight .ni { color: #d55537; font-weight: bold } /* Name.Entity */ +.highlight .ne { color: #007020 } /* Name.Exception */ +.highlight .nf { color: #06287e } /* Name.Function */ +.highlight .nl { color: #002070; font-weight: bold } /* Name.Label */ +.highlight .nn { color: #0e84b5; font-weight: bold } /* Name.Namespace */ +.highlight .nt { color: #062873; font-weight: bold } /* Name.Tag */ +.highlight .nv { color: #bb60d5 } /* Name.Variable */ +.highlight .ow { color: #007020; font-weight: bold } /* Operator.Word */ +.highlight .w { color: #bbbbbb } /* Text.Whitespace */ +.highlight .mb { color: #40a070 } /* Literal.Number.Bin */ +.highlight .mf { color: #40a070 } /* Literal.Number.Float */ +.highlight .mh { color: #40a070 } /* Literal.Number.Hex */ +.highlight .mi { color: #40a070 } /* Literal.Number.Integer */ +.highlight .mo { color: #40a070 } /* Literal.Number.Oct */ +.highlight .sa { color: #4070a0 } /* Literal.String.Affix */ +.highlight .sb { color: #4070a0 } /* Literal.String.Backtick */ +.highlight .sc { color: #4070a0 } /* Literal.String.Char */ +.highlight .dl { color: #4070a0 } /* Literal.String.Delimiter */ +.highlight .sd { color: #4070a0; font-style: italic } /* Literal.String.Doc */ +.highlight .s2 { color: #4070a0 } /* Literal.String.Double */ +.highlight .se { color: #4070a0; font-weight: bold } /* Literal.String.Escape */ +.highlight .sh { color: #4070a0 } /* Literal.String.Heredoc */ +.highlight .si { color: #70a0d0; font-style: italic } /* Literal.String.Interpol */ +.highlight .sx { color: #c65d09 } /* Literal.String.Other */ +.highlight .sr { color: #235388 } /* Literal.String.Regex */ +.highlight .s1 { color: #4070a0 } /* Literal.String.Single */ +.highlight .ss { color: #517918 } /* Literal.String.Symbol */ +.highlight .bp { color: #007020 } /* Name.Builtin.Pseudo */ +.highlight .fm { color: #06287e } /* Name.Function.Magic */ +.highlight .vc { color: #bb60d5 } /* Name.Variable.Class */ +.highlight .vg { color: #bb60d5 } /* Name.Variable.Global */ +.highlight .vi { color: #bb60d5 } /* Name.Variable.Instance */ +.highlight .vm { color: #bb60d5 } /* Name.Variable.Magic */ +.highlight .il { color: #40a070 } /* Literal.Number.Integer.Long */ diff --git a/macros/generic/polexpr/polexpr.html b/macros/generic/polexpr/polexpr.html index 5f695deb4b..23dafab2c2 100644 --- a/macros/generic/polexpr/polexpr.html +++ b/macros/generic/polexpr/polexpr.html @@ -1,3822 +1,190 @@ - - - - - -polexpr reference documentation - - - - -
-

polexpr reference documentation

-

0.8.6 (2022/01/09)

+ -
-

Introduction

-

This is a TeX and LaTeX macro package.

+ + + + + + Introduction to polexpr — polexpr 0.8.7 documentation + + + + + +
+
+
+
+ +
+

Introduction to polexpr

+

polexpr is a TeX and LaTeX macro package.

To use it with Plain or formats other than LaTeX:

-
\input polexpr.sty
-

To use it with LaTeX:

-
\usepackage{polexpr}
-

The capabilities of the package are implemented via:

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

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

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

  • -
-
-
-

Examples of root localization

-

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

-
texdoc polexpr-examples
+
\input polexpr.sty
+
-
-

Usage via xintsession

+

To use it with LaTeX:

+
\usepackage{polexpr}
+
+
+

polexpr loads xintexpr and extends its syntax with a polynomial type.

+

Polynomials are defined via the \poldef parser and +can then be manipulated via TeX macros for various operations such +as obtaining G.C.D.s, computing derivatives, or indefinite +integrals… many of these functionalities are available directly +via functions in the syntax recognized by the \poldef parser.

+

Apart from the final step of internally creating some TeX macros +associated with the polynomial name, this is all done completely +expandably, and a polynomial expression can be fetched directly to +\xinteval for a completely expandable operation from start to +finish.

+

For polynomials fully declared via \poldef, root localization +implementing the Sturm algorithm is available via macros. +Arbitrarily long decimal expansion of all real roots can be +obtained, and all rational roots can be found exactly.

+

The legacy documentation section which showed examples of root +localization has been moved to the polexpr-examples.pdf document, where both the TeX code and its +output are displayed.

+

To access this document (if the previous link for some reason does not +work):

+
texdoc polexpr-examples
+
+
+
+

Usage via xintsession

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

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

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

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

-

Any input on the command line at the xintsession >>> prompt which +

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

-
-

Contents

- -
-
-
-

Quick syntax overview

-

The syntax to define a new polynomial is:

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

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

-

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

-

As a rule, the functionalities such as getting the degree, or getting -one coefficient, or taking derivatives, etc..., i.e. anything which -handles the polynomial as an entity and not only as a numerical -function, are only available in the \poldef/\xintexpr/\xinteval -context. The \PolGenFloatVariant must be used each time the -polynomial gets modified or a new polynomial created out of it, if -continuing computations in \xintfloatexpr are to follow. But (see -xintexpr documentation) one can always use a sub-expression such as -\xintexpr deg(P)\relax as sub-component inside a -\xintfloatexpr/\xintfloateval.

-

Conversely if perhaps the coefficients of your polynomial have become -too gigantic and you would like to replace them with some approximation -to keep on working in \xinteval, not necessarily \xintfloateval, -see \PolMapCoeffs which can be used for example with \xintFloat -macro to make the float-rounding applied to the exact coefficients.

-
    -
  • 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 the _ and ' -characters. It 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 result.

    -
    -

    Hint

    -

    The @ is usable too, 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 -to package; time has still not yet been found for 0.8 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.

    -
    -
  • -
  • 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. Some -contexts (such as (pdf)LaTeX with babel+frenchb) modify its catcode. -If at top level, \poldef resets temporarily the semi-colon catcode -before fetching the expression, so is immune to this. There is also -naturally no problem either if \poldef is used in the replacement -text of some other macro which is defined at a time the ; has its -standard catcode, as is the case in LaTeX in the document preamble, -even with babel+french loaded.

    -

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

    -
  • -
-

Problems with the semi-colon are avoided via an alternative syntax:

-
\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.

-

\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 convert it internally (currently) to the list -of its coefficients from the constant term to the highest degree -term.

-

The polynomial can then be used in further polynomial definitions or -serve as argument to package macros, or as a variable in various -functions which will be described later.

-
-
-
-

Important

-

Euclidean quotient is mapped to the function quo() (as shown -in the example above), but -for backwards compatibility one can currently still use the / -infix operator:

-
\poldef f(x):= 1 - x + x^5/(1 - x + x^2);
-

Due to precedence rules the first operand is x^5, not of course -1-x+x^5.

-

Note that (1-x^2)/(1-x) produces 1+x -but (1/(1-x))*(1-x^2) produces zero! One also has to be aware -of some precedence rules, for example:

-
\poldef k(x):= (x-1)(x-2)(x-3)(x-4)/(x^2-5x+4);
-

does compute a degree 2 polynomial because the tacit multiplication -ties more than the division operator.

-

In short, it is safer to use the quo() function which avoids -surprises.

-
-
-

Attention!

-

Tacit multiplication means that -1/2 x^2 skips the space and is treated like 1/(2*x^2). -But then it gives zero!

-

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)) which gives zero by -polynomial division. Thus, use in such cases one of -(1/2)(x-1)(x-2), 1/2*(x-1)(x-2) or (x-1)(x-2)/2.

-
-
-

Warning

-

The package does not currently know rational functions, but in order -to leave open this as a future possibility, the usage of / to stand -for the -euclidean quotient is deprecated.

-

Please start using rather the quo() function. It is possible -that in a future major release A/B with B a non-scalar will -raise an error. Or, who knows, rational functions will be -implemented sometime during the next decades, and then A/B will -naturally be the rational function.

-
-
-

Important

-

\poldef P(x):=...; defines P both as a function, -to be used as:

-
P(..numeric or even polynomial expression..)
-

and as a variable which can used inside polynomial expressions or -as argument to some polynomial specific functions such as deg() -or polgcd() 1.

-
-
1
-

Functional syntax accepts expressions as arguments; but the -TeX macros described in the documentation, even the -expandable ones, work only (there are a few exceptions to the -general rule) with arguments being names of declared -polynomials.

-
-
-

One needs to have a clear understanding of the difference between -P used a function and P used as a variable: if P and -Q are both declared polynomials then:

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

is currently evaluated as (P+Q)*3, because P+Q is not known -as a function, but only as a variable of polynomial type. -Even worse:

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

will compute P*3, because one can not in current xintexpr syntax -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.

-

As an alternative to explicit P(3)+Q(3) there is evalp(P+Q,3).

-
-
-
\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 the documentation for the configurability -via macros.

-

Since 0.8 \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) -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 \PolToExpr{<pol. expr.>} 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.

-
-
-
-
-

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. -
  3. 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...

    -
  4. -
-
-
-

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 Quick syntax overview 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(<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 typing 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(<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)

-
-
-
-

\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{}, but finally opted for this.

-
-
-
-

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 2 (see xintexpr documentation):

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

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

-
-
2
-

by the way Maple uses the opposite, hence wrong, order -subs(x=..., P) but was written before computer science -reached the xintexpr heights. However it makes validating -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(<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(<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 -\PolNthCoeff{<polname>}{<index>} 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(<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), 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(<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.

-
-

name and syntax unstable

-

At 0.8 it was created as icontent() to match the legacy -macro \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.

-
-
-
-

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 3 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 (non expandable) macro.

-
-
3
-

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])
-
-
-
-
-

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 nth 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.

-
-
-
-
-

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

-
-

\int_a^b P(t)dt.

-
-

Warning

-

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

-
-

a and b are not restricted to be scalars, they 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 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.

-

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 \PolGenFloatVariant{<polname>} 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 \PolGenFloatVariant{<polname>} -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[<letter>]{<polname>}{<expr. using the letter as indeterminate>}

-
-

Does the same as \poldef in an undelimited macro -format, the main interest is to avoid potential problems with the -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{<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 \PolToFloatExpr{<pol. expr.>}.

-
-

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{<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{<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 -\PolIfCoeffIsPlusOrMinusOne{T}{F}.

-

The actual printing of the coefficients, when not equal to plus or -minus one, is handled by \PolTypesetOne{<raw_coeff>}.

-
-
-

\PolIfCoeffIsPlusOrMinusOne{T}{F}

-
-

This macro is a priori undefined.

-

It is defined via the default \PolTypesetCmd{<raw_coeff>} 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{<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

-
-

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{<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 -\PolTypesetCmd{<raw_coeff>} 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*{<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{<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.

-
-
- -
-

\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 \PolNthCoeff{<polname>}{<index>}.

-
-
-
-

\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;.

-
-
-
-

\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 \PolToCSV{<polname>}.

-
-
-
-

\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{<polname>}

-
-

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

-
-
-
-

\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 -\PolReduceCoeffs{<polname>}: as the numerators and denominators -remain generally smaller.

-
-
-
-

\PolMakeMonic{<polname>}

-
-

Divides by the leading coefficient. It is recommended to execute -\PolReduceCoeffs*{<polname>} 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{<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{<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[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{<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[N]{<polname_1>}{<polname_2>}

-
-

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

-
-
-
-

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

-
-

This sets polname_Q and polname_R to be the quotient and -remainder in the Euclidean division of polname_1 by -polname_2.

-
-
-
-

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

-
-

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

-
-
-
-

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

-
-

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

-
-
-
-

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

-
-

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.

-
-
-
-
-

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{<pol. expr.>}

-
-

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

-
-
4
-

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

-
-

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

-
-
-
-

\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

-
-

Defaults to *.

-
-
-
-

\PolToExprCaret

-
-

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

-

(new with 0.8)

-
-
-
-

\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{<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, \PolToExprTimes, \PolToExprVar and -\PolToExprCaret.

-
-
-
-

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

-
-

This holds the default package meaning of \PolToExprOneTerm.

-
-
-
-

\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 isn't used at all in this style. But -\PolToExprTimes, \PolToExprVar and \PolToExprCaret are obeyed.

-

To activate it use \let\PolToExprOneTerm\PolToExprOneTermStyleB. -To revert to the package default behaviour, issue -\let\PolToExprOneTerm\PolToExprOneTermStyleA.

-
-
-
-

\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 \PolToExprCmd{<raw_coeff>} which in case of a -positive coefficient does not output an explicit + prefix.

-
-
-
-
-

\PolToFloatExpr{<pol. expr.>}

-
-

Similar to \PolToExpr{<pol. expr.>} but using -\PolToFloatExprCmd{<raw_coeff>} which by default rounds and -converts the coefficients to floating point format.

-
-

Note

-

This is unrelated to \PolGenFloatVariant{<polname>}: -\PolToFloatExprCmd{<raw_coeff>} 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{<raw_coeff>}{<exponent>}

-
-

Similar to \PolToExprOneTerm{<raw_coeff>}{<exponent>}. But does not treat -especially coefficients equal to plus or minus one.

-
-
-
-

\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*{<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 -\PolToExpr{<pol. expr.>}.

-
-
-
-

\PolToFloatExpr*{<pol. expr.>}

-
-

Ascending powers.

-

Extended at 0.8 to accept general expressions as input.

-
-
-
-

\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{<polname>}

-
-

Expands to the leading coefficient.

-
-
-
-

\PolDegree{<polname>}

-
-

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

-
-
-
-

\PolIContent{<polname>}

-
-

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.

-
-
-
-

\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{<polname>}

-
-

Expands to coeff_0, coeff_1, coeff_2, ....., coeff_N, starting -with constant term and ending with leading coefficient. Converse -to \PolFromCSV{<polname>}{<csv>}.

-
-
-
-

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

-
-

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

-
-
-
-

\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.

-
-
-
-

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

-
-

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

-
-
-
-

\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.

-
-
-
-

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

-
-

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

-
-

Attention!

-

\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: 5

-
\xintfloateval{3.27*\xintexpr f(2.53)\relax^2}
-
-
5
-

Cf. xintexpr documentation about nested expressions.

-
-
-
-
-
-

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

-
-

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

-
-
- -
-
-

Booleans (with default setting as indicated)

-
-

\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

-
-

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 \PolGenFloatVariant{<polname>} 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

-
-

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

-
-
-
-

\poltoexprallfalse

-
-

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

-
-
-
-
-

Utilies

-
-

\PolDecToString{decimal number}

-
-

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

-
-
-

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.

-
-
-
-

\polexprsetup

-
-

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

-
    -
  • norr: the postfix that \PolSturmIsolateZeros**{<sturmname>} -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 \PolSturmIsolateZeros**{<sturmname>} -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 catcode of the semi-colon is reset temporarily by \poldef macro in case some other package (for example the French -babel module) may have made it active. This will fail though if the -whole thing was already part of a macro argument, in such cases one -can use \PolDef rather. The colon in := may be -active with no consequences.

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

    -
    \poldef P(x):= 1/2 + 2/2*x + 3/2*x^3 + 4/2*x^4;
    -\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.

    -
  • -
  • \PolDiff{<polname_1>}{<polname_2>} 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 \PolAntiDiff{<polname_1>}{<polname_2>}.

    -
  • -
  • 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.

  • -
-
-
-

CHANGE LOG

- -
-
-

Acknowledgments

-

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

-

Renewed thanks to them on occasion of the 0.6, 0.7, and 0.8 -releases for their continued interest.

-

See README.md for the License.

-
-
- - +defined by polexpr itself.

+ +
+

License is LPPL 1.3c

+

This work is distributed under the conditions of the +LaTeX Project Public License version 1.3c.

+

See README.md for details.

+
+
+

In memoriam: Jürgen Gilg (1967-2022)

+

My first contact with Jürgen was in January 2018, and his little +question about usage of xintexpr for differentiating polynomials +proved the direct cause for the creation of polexpr. His regular comments and questions (often, jointly +with Thomas Söll) largely contributed to motivate the author into +investing time and effort into the somewhat strange occupation of +developing such unusual TeX/LaTeX packages. The topics of our +discussions evolved over the years and were not limited to TeX, LaTeX, +PSTricks or PostScript matters.

+

I learned to discover and appreciate his unassuming and kind character. +He was very conscientious in all his projects with others and was often +overly generous in his appreciation of people’s contributions. On +receiving the sad news of his unexpected and untimely death, I initially +thought I had been knowing him for at least 10 years, but it is actually +only a bit more than 4 years… I will sorely miss this friendship with +a gentle soul from over the Rhine.

+

I dedicate the work which has gone into polexpr to Jürgen’s memory.

+
+
+
+ + + +
+
+
+
+ +
+
+ + + + \ No newline at end of file diff --git a/macros/generic/polexpr/polexpr.rst.txt b/macros/generic/polexpr/polexpr.rst.txt new file mode 100644 index 0000000000..3186ab3680 --- /dev/null +++ b/macros/generic/polexpr/polexpr.rst.txt @@ -0,0 +1,157 @@ +.. comment: -*- fill-column: 72; mode: rst -*- + +========================= + Introduction to polexpr +========================= + +polexpr_ is a TeX and LaTeX macro package. + +To use it with Plain or formats other than LaTeX:: + + \input polexpr.sty + +To use it with LaTeX:: + + \usepackage{polexpr} + +polexpr_ loads xintexpr_ and extends its syntax with a polynomial type. + +Polynomials are defined via the :ref:`\\poldef ` parser and +can then be manipulated via TeX macros for various operations such +as obtaining G.C.D.s, computing derivatives, or indefinite +integrals... many of these functionalities are available directly +via functions in the syntax recognized by the ``\poldef`` parser. + +Apart from the final step of internally creating some TeX macros +associated with the polynomial name, this is all done completely +expandably, and a polynomial expression can be fetched directly to +``\xinteval`` for a completely expandable operation from start to +finish. + +For polynomials fully declared via ``\poldef``, root localization +implementing the `Sturm algorithm`_ is available via macros. +Arbitrarily long decimal expansion of all real roots can be +obtained, and all rational roots can be found exactly. + +The legacy documentation section which showed examples of root +localization has been moved to the `polexpr-examples.pdf +`_ document, where both the TeX code and its +output are displayed. + +To access this document (if the previous link for some reason does not +work):: + + texdoc polexpr-examples + + +Usage via xintsession_ +---------------------- + +The simplest manner to get a feeling for the package abilities regarding +in particularl root localization is to use it on the command line +via the xintsession_ interface. Here is an example:: + + $ rlwrap etex xintsession + [...xintsession welcome message...] + Starting in exact mode (floating point evaluations use 16 digits) + >>> &pol + pol mode (i.e. function definitions use \poldef) + >>> f(x) := x^7 - x^6 - 2x + 1; + f = x^7-x^6-2*x+1 + --> &GenFloat(f) lets f become usable as function in fp mode + --> &ROOTS(f) (resp. &ROOTS(f,N)) finds all rational roots exactly and + all irrational roots with at least 10 (resp. N) fractional digits + >>> &ROOTS(f) + Solving for real roots of f and assigning them (please wait...) + (mult. 1) Rootf_1 = -1.0719678841... + (mult. 1) Rootf_2 = 0.4962386948... + (mult. 1) Rootf_3 = 1.3151140860... + Square-free irrational part: x^7-x^6-2*x+1 + --> &REFINEROOTS(f,N) to extend real irr. roots to N fractional digits + >>> &REFINEROOTS(f,40) + Refining real roots of f to 40 digits (please wait...) + (mult. 1) Rootf_1 = -1.0719678841080266034109100331975342338141... + (mult. 1) Rootf_2 = 0.4962386948771497344730618510143671567979... + (mult. 1) Rootf_3 = 1.3151140860165192656960005018679846354234... + +The xintsession_ interface allows to define polynomial variables via its +``&pol`` mode. It also exposes :ref:`all polynomial functions added to the +xintexpr syntax ` by ``polexpr``. Further, as seen in the +example above it also covers some of the ``polexpr`` capabilities +currently implemented via user macros. This is to be considered a work +in progress, the above ``&ROOTS`` and ``&REFINEROOTS`` may be renamed +into something else, and may have been so already since this +documentation was written. + +Any input on the command line at the xintsession_ ``>>>`` prompt which +starts with a backslash is executed as TeX macros, so all macros of +``polexpr`` are in fact already available, including those typesetting +material in background of the interactive session on command line. The +``&ROOTS`` and ``&REFINEROOTS`` direct their outputs to the +terminal rather than to the TeX page as would the typesetting macros +defined by ``polexpr`` itself. + + +License is LPPL 1.3c +-------------------- + +This work is distributed under the conditions of the +LaTeX Project Public License version 1.3c. + +See README.md for details. + + +In memoriam: Jürgen Gilg (1967-2022) +------------------------------------ + +My first contact with Jürgen was in January 2018, and his *little +question* about usage of xintexpr_ for differentiating polynomials +proved the direct cause for the :ref:`creation of polexpr +`. His regular comments and questions (often, jointly +with Thomas Söll) largely contributed to motivate the author into +investing time and effort into the somewhat strange occupation of +developing such unusual TeX/LaTeX packages. The topics of our +discussions evolved over the years and were not limited to TeX, LaTeX, +PSTricks or PostScript matters. + +I learned to discover and appreciate his unassuming and kind character. +He was very conscientious in all his projects with others and was often +overly generous in his appreciation of people's contributions. On +receiving the sad news of his unexpected and untimely death, I initially +thought I had been knowing him for at least 10 years, but it is actually +only a bit more than 4 years... I will sorely miss this friendship with +a gentle soul from *over the Rhine*. + +I dedicate the work which has gone into polexpr_ to Jürgen's memory. + + +.. _polexpr: https://www.ctan.org/pkg/polexpr + +.. _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 + + +.. toctree:: + :hidden: + :maxdepth: 2 + + polexpr-ref + polexpr-changes + + + +.. Local variables: +.. sentence-end-double-space: t; +.. End: diff --git a/macros/generic/polexpr/polexpr.sty b/macros/generic/polexpr/polexpr.sty index 7d3dbb36bd..b652675d91 100644 --- a/macros/generic/polexpr/polexpr.sty +++ b/macros/generic/polexpr/polexpr.sty @@ -2,7 +2,7 @@ % License: LPPL 1.3c (author-maintained) % Usage: \input polexpr.sty (Plain or other macro formats) % or \usepackage{polexpr} (LaTeX macro format) -% Release 0.8.6 (2022/01/09) of polexpr.sty. This file inputs +% Release 0.8.7 (2022/05/14) of polexpr.sty. This file inputs % polexprcore.tex % polexprexpr.tex % polexprsturm.tex @@ -54,7 +54,7 @@ \XINTsetupcatcodes% (does \endlinechar13 in particular) \XINT_providespackage \ProvidesPackage{polexpr}% - [2022/01/09 v0.8.6 Polynomial expressions with rational coefficients (JFB)]% + [2022/05/14 v0.8.7 Polynomial expressions with rational coefficients (JFB)]% \begingroup \def\x#1/#2/#3 #4\xint:{#1#2#3}% \ifnum\expandafter\x\expanded{\csname ver@xintexpr.sty\endcsname}\xint: @@ -199,12 +199,15 @@ %% %% \poldef %% -\def\PolDef{\POL@chkopt\POL@oPolDef[x]}% -\def\POL@oPolDef[#1]#2#3{\poldef #2(#1):={#3};}% -\def\poldef{\edef\POL@restoresemicolon{\catcode59=\the\catcode59\relax}% - \catcode59 12 \POL@defpol}% +%% Ever since 1.0, catcode sanitisation was minimal and only handled +%% the semicolon. At last 0.8.7 uses \xintexprSafeCatcodes to enhance +%% compatibility with hostile contexts such as babel+french. This +%% adds overhead but at least is coherent with \xintdefvar/\xintdeffunc +\def\PolDef{\xintexprSafeCatcodes\POL@chkopt\POL@oPolDef[x]}% +\def\POL@oPolDef[#1]#2#3{\POL@defpol #2(#1):={#3};}% +\def\poldef{\xintexprSafeCatcodes\POL@defpol}% \def\POL@defpol #1(#2)#3=#4;{% - \POL@restoresemicolon + \xintexprRestoreCatcodes \edef\POL@polname{\xint_zapspaces #1 \xint_gobble_i}% \begingroup \unless\ifxintveryverbose\xintverbosefalse\fi @@ -214,7 +217,7 @@ %% the associated macros was then deconstructed in further analysis %% via non-expandable approach. At 0.8 the polynomial algebra has %% been implemented expandably allowing direct plug-in into \xintexpr - \xintdefvar __pol = subs(#4,#2=qraw({{P1.{0/1[0]}{1/1[0]}}}));% + \xintdefvar_a __pol = subs(#4,#2=qraw({{P1.{0/1[0]}{1/1[0]}}}));% \expandafter \endgroup \expandafter\def\expandafter\POL@result\expandafter diff --git a/macros/generic/polexpr/polexprcore.tex b/macros/generic/polexpr/polexprcore.tex index 8dcc893844..8bf7fe2fd0 100644 --- a/macros/generic/polexpr/polexprcore.tex +++ b/macros/generic/polexpr/polexprcore.tex @@ -1,5 +1,5 @@ %% filename: polexprcore.tex -%% Part of the polexpr package (0.8.6, 2022/01/09) +%% Part of the polexpr package (0.8.7, 2022/05/14) %% %% Core routines for infix operators +, -, *, //, /:, ^, ** and functions %% diff --git a/macros/generic/polexpr/polexprexpr.tex b/macros/generic/polexpr/polexprexpr.tex index bbc860cbca..91087bcf4d 100644 --- a/macros/generic/polexpr/polexprexpr.tex +++ b/macros/generic/polexpr/polexprexpr.tex @@ -1,5 +1,5 @@ %% filename: polexprexpr.tex -%% Part of the polexpr package (0.8.6, 2022/01/09) +%% Part of the polexpr package (0.8.7, 2022/05/14) %% %% Polynomial extensions to the \xintexpr syntax: %% diff --git a/macros/generic/polexpr/polexprsturm.tex b/macros/generic/polexpr/polexprsturm.tex index 0edc8b8f0a..2f417c3333 100644 --- a/macros/generic/polexpr/polexprsturm.tex +++ b/macros/generic/polexpr/polexprsturm.tex @@ -1,5 +1,5 @@ %% filename: polexprsturm.tex -%% Part of the polexpr package (0.8.6, 2022/01/09) +%% Part of the polexpr package (0.8.7, 2022/05/14) %% %% Implements the Sturm localization Algorithm %% Added at polexpr 0.4 -- cgit v1.2.3