diff options
Diffstat (limited to 'macros/latex/contrib/polexpr')
-rw-r--r-- | macros/latex/contrib/polexpr/README.md | 100 | ||||
-rw-r--r-- | macros/latex/contrib/polexpr/polexpr.html | 2908 | ||||
-rw-r--r-- | macros/latex/contrib/polexpr/polexpr.sty | 2946 | ||||
-rw-r--r-- | macros/latex/contrib/polexpr/polexpr.txt | 2593 |
4 files changed, 8547 insertions, 0 deletions
diff --git a/macros/latex/contrib/polexpr/README.md b/macros/latex/contrib/polexpr/README.md new file mode 100644 index 0000000000..29c0d2f5ab --- /dev/null +++ b/macros/latex/contrib/polexpr/README.md @@ -0,0 +1,100 @@ +Package polexpr README +====================== + +License +------- + +Copyright (C) 2018-2019 Jean-François Burnol + +See documentation of package [xint](http://www.ctan.org/pkg/xint) for +contact information. + +This Work may be distributed and/or modified under the conditions of the +LaTeX Project Public License version 1.3c. This version of this license +is in + +> <http://www.latex-project.org/lppl/lppl-1-3c.txt> + +and version 1.3 or later is part of all distributions of LaTeX version +2005/12/01 or later. + +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 file polexpr.sty, this README.md and +the documentation file polexpr.txt. + +Abstract +-------- + +The package provides `\poldef`. This a parser of polynomial expressions +based upon the `\xintdeffunc` mechanism of xintexpr. + +The parsed expressions use the operations of algebra (inclusive of +composition of functions) with standard operators, fractional numbers +(possibly in scientific notation) and previously defined polynomial +functions or other constructs as recognized by the `\xintexpr` numerical +parser. + +The polynomials are then not only genuine `\xintexpr` (and +`\xintfloatexpr`) numerical functions but additionally are known to the +package via their coefficients. This allows dedicated macros to +implement polynomial algorithmics. + +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 xint 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. + +Files of 0.7.4 release: + +- README.md, +- polexpr.sty (package file), +- polexpr.txt (documentation), +- polexpr.html (conversion via + [DocUtils](http://docutils.sourceforge.net/docs/index.html) + rst2html.py) + +Acknowledgments +--------------- + +Thanks to Jürgen Gilg whose question about +[xint](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. diff --git a/macros/latex/contrib/polexpr/polexpr.html b/macros/latex/contrib/polexpr/polexpr.html new file mode 100644 index 0000000000..6fc48c2dd6 --- /dev/null +++ b/macros/latex/contrib/polexpr/polexpr.html @@ -0,0 +1,2908 @@ +<?xml version="1.0" encoding="utf-8" ?> +<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> +<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en"> +<head> +<meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> +<meta name="generator" content="Docutils 0.14: http://docutils.sourceforge.net/" /> +<title>Package polexpr documentation</title> +<style type="text/css"> + +/* +:Author: David Goodger (goodger@python.org) +:Id: $Id: html4css1.css 7952 2016-07-26 18:15:59Z milde $ +:Copyright: This stylesheet has been placed in the public domain. + +Default cascading style sheet for the HTML output of Docutils. + +See http://docutils.sf.net/docs/howto/html-stylesheets.html for how to +customize this style sheet. +*/ + +/* used to remove borders from tables and images */ +.borderless, table.borderless td, table.borderless th { + border: 0 } + +table.borderless td, table.borderless th { + /* Override padding for "table.docutils td" with "! important". + The right padding separates the table cells. */ + padding: 0 0.5em 0 0 ! important } + +.first { + /* Override more specific margin styles with "! important". */ + margin-top: 0 ! important } + +.last, .with-subtitle { + margin-bottom: 0 ! important } + +.hidden { + display: none } + +.subscript { + vertical-align: sub; + font-size: smaller } + +.superscript { + vertical-align: super; + font-size: smaller } + +a.toc-backref { + text-decoration: none ; + color: black } + +blockquote.epigraph { + margin: 2em 5em ; } + +dl.docutils dd { + margin-bottom: 0.5em } + +object[type="image/svg+xml"], object[type="application/x-shockwave-flash"] { + overflow: hidden; +} + +/* Uncomment (and remove this text!) to get bold-faced definition list terms +dl.docutils dt { + font-weight: bold } +*/ + +div.abstract { + margin: 2em 5em } + +div.abstract p.topic-title { + font-weight: bold ; + text-align: center } + +div.admonition, div.attention, div.caution, div.danger, div.error, +div.hint, div.important, div.note, div.tip, div.warning { + margin: 2em ; + border: medium outset ; + padding: 1em } + +div.admonition p.admonition-title, div.hint p.admonition-title, +div.important p.admonition-title, div.note p.admonition-title, +div.tip p.admonition-title { + font-weight: bold ; + font-family: sans-serif } + +div.attention p.admonition-title, div.caution p.admonition-title, +div.danger p.admonition-title, div.error p.admonition-title, +div.warning p.admonition-title, .code .error { + color: red ; + font-weight: bold ; + font-family: sans-serif } + +/* Uncomment (and remove this text!) to get reduced vertical space in + compound paragraphs. +div.compound .compound-first, div.compound .compound-middle { + margin-bottom: 0.5em } + +div.compound .compound-last, div.compound .compound-middle { + margin-top: 0.5em } +*/ + +div.dedication { + margin: 2em 5em ; + text-align: center ; + font-style: italic } + +div.dedication p.topic-title { + font-weight: bold ; + font-style: normal } + +div.figure { + margin-left: 2em ; + margin-right: 2em } + +div.footer, div.header { + clear: both; + font-size: smaller } + +div.line-block { + display: block ; + margin-top: 1em ; + margin-bottom: 1em } + +div.line-block div.line-block { + margin-top: 0 ; + margin-bottom: 0 ; + margin-left: 1.5em } + +div.sidebar { + margin: 0 0 0.5em 1em ; + border: medium outset ; + padding: 1em ; + background-color: #ffffee ; + width: 40% ; + float: right ; + clear: right } + +div.sidebar p.rubric { + font-family: sans-serif ; + font-size: medium } + +div.system-messages { + margin: 5em } + +div.system-messages h1 { + color: red } + +div.system-message { + border: medium outset ; + padding: 1em } + +div.system-message p.system-message-title { + color: red ; + font-weight: bold } + +div.topic { + margin: 2em } + +h1.section-subtitle, h2.section-subtitle, h3.section-subtitle, +h4.section-subtitle, h5.section-subtitle, h6.section-subtitle { + margin-top: 0.4em } + +h1.title { + text-align: center } + +h2.subtitle { + text-align: center } + +hr.docutils { + width: 75% } + +img.align-left, .figure.align-left, object.align-left, table.align-left { + clear: left ; + float: left ; + margin-right: 1em } + +img.align-right, .figure.align-right, object.align-right, table.align-right { + clear: right ; + float: right ; + margin-left: 1em } + +img.align-center, .figure.align-center, object.align-center { + display: block; + margin-left: auto; + margin-right: auto; +} + +table.align-center { + margin-left: auto; + margin-right: auto; +} + +.align-left { + text-align: left } + +.align-center { + clear: both ; + text-align: center } + +.align-right { + text-align: right } + +/* reset inner alignment in figures */ +div.align-right { + text-align: inherit } + +/* div.align-center * { */ +/* text-align: left } */ + +.align-top { + vertical-align: top } + +.align-middle { + vertical-align: middle } + +.align-bottom { + vertical-align: bottom } + +ol.simple, ul.simple { + margin-bottom: 1em } + +ol.arabic { + list-style: decimal } + +ol.loweralpha { + list-style: lower-alpha } + +ol.upperalpha { + list-style: upper-alpha } + +ol.lowerroman { + list-style: lower-roman } + +ol.upperroman { + list-style: upper-roman } + +p.attribution { + text-align: right ; + margin-left: 50% } + +p.caption { + font-style: italic } + +p.credits { + font-style: italic ; + font-size: smaller } + +p.label { + white-space: nowrap } + +p.rubric { + font-weight: bold ; + font-size: larger ; + color: maroon ; + text-align: center } + +p.sidebar-title { + font-family: sans-serif ; + font-weight: bold ; + font-size: larger } + +p.sidebar-subtitle { + font-family: sans-serif ; + font-weight: bold } + +p.topic-title { + font-weight: bold } + +pre.address { + margin-bottom: 0 ; + margin-top: 0 ; + font: inherit } + +pre.literal-block, pre.doctest-block, pre.math, pre.code { + margin-left: 2em ; + margin-right: 2em } + +pre.code .ln { color: grey; } /* line numbers */ +pre.code, code { background-color: #eeeeee } +pre.code .comment, code .comment { color: #5C6576 } +pre.code .keyword, code .keyword { color: #3B0D06; font-weight: bold } +pre.code .literal.string, code .literal.string { color: #0C5404 } +pre.code .name.builtin, code .name.builtin { color: #352B84 } +pre.code .deleted, code .deleted { background-color: #DEB0A1} +pre.code .inserted, code .inserted { background-color: #A3D289} + +span.classifier { + font-family: sans-serif ; + font-style: oblique } + +span.classifier-delimiter { + font-family: sans-serif ; + font-weight: bold } + +span.interpreted { + font-family: sans-serif } + +span.option { + white-space: nowrap } + +span.pre { + white-space: pre } + +span.problematic { + color: red } + +span.section-subtitle { + /* font-size relative to parent (h1..h6 element) */ + font-size: 80% } + +table.citation { + border-left: solid 1px gray; + margin-left: 1px } + +table.docinfo { + margin: 2em 4em } + +table.docutils { + margin-top: 0.5em ; + margin-bottom: 0.5em } + +table.footnote { + border-left: solid 1px black; + margin-left: 1px } + +table.docutils td, table.docutils th, +table.docinfo td, table.docinfo th { + padding-left: 0.5em ; + padding-right: 0.5em ; + vertical-align: top } + +table.docutils th.field-name, table.docinfo th.docinfo-name { + font-weight: bold ; + text-align: left ; + white-space: nowrap ; + padding-left: 0 } + +/* "booktabs" style (no vertical lines) */ +table.docutils.booktabs { + border: 0px; + border-top: 2px solid; + border-bottom: 2px solid; + border-collapse: collapse; +} +table.docutils.booktabs * { + border: 0px; +} +table.docutils.booktabs th { + border-bottom: thin solid; + text-align: left; +} + +h1 tt.docutils, h2 tt.docutils, h3 tt.docutils, +h4 tt.docutils, h5 tt.docutils, h6 tt.docutils { + font-size: 100% } + +ul.auto-toc { + list-style-type: none } + +</style> +</head> +<body> +<div class="document" id="package-polexpr-documentation"> +<h1 class="title">Package polexpr documentation</h1> +<h2 class="subtitle" id="id1">0.7.4 (2019/02/12)</h2> + +<!-- comment: -*- fill-column: 72; mode: rst; -*- --> +<div class="contents topic" id="contents"> +<p class="topic-title first">Contents</p> +<ul class="simple"> +<li><a class="reference internal" href="#basic-syntax" id="id38">Basic syntax</a></li> +<li><a class="reference internal" href="#examples-of-localization-of-roots" id="id39">Examples of localization of roots</a><ul> +<li><a class="reference internal" href="#a-typical-example" id="id40">A typical example</a></li> +<li><a class="reference internal" href="#a-degree-four-polynomial-with-nearby-roots" id="id41">A degree four polynomial with nearby roots</a></li> +<li><a class="reference internal" href="#the-degree-nine-polynomial-with-0-99-0-999-0-9999-as-triple-roots" id="id42">The degree nine polynomial with 0.99, 0.999, 0.9999 as triple roots</a></li> +<li><a class="reference internal" href="#a-degree-five-polynomial-with-three-rational-roots" id="id43">A degree five polynomial with three rational roots</a></li> +<li><a class="reference internal" href="#a-mignotte-type-polynomial" id="id44">A Mignotte type polynomial</a></li> +<li><a class="reference internal" href="#the-wilkinson-polynomial" id="id45">The Wilkinson polynomial</a></li> +<li><a class="reference internal" href="#the-second-wilkinson-polynomial" id="id46">The second Wilkinson polynomial</a></li> +<li><a class="reference internal" href="#the-degree-41-polynomial-with-2-1-9-1-8-0-0-1-1-9-2-as-roots" id="id47">The degree 41 polynomial with -2, -1.9, -1.8, ..., 0, 0.1, ..., 1.9, 2 as roots</a></li> +<li><a class="reference internal" href="#roots-of-chebyshev-polynomials" id="id48">Roots of Chebyshev polynomials</a></li> +</ul> +</li> +<li><a class="reference internal" href="#non-expandable-macros" id="id49">Non-expandable macros</a><ul> +<li><a class="reference internal" href="#poldef-polname-letter-expression-in-letter" id="id50"><tt class="docutils literal">\poldef <span class="pre">polname(letter):=</span> expression in letter;</tt></a></li> +<li><a class="reference internal" href="#poldef-letter-polname-expression-in-letter" id="id51"><tt class="docutils literal"><span class="pre">\PolDef[letter]{polname}{expression</span> in letter}</tt></a></li> +<li><a class="reference internal" href="#polgenfloatvariant-polname" id="id52"><tt class="docutils literal">\PolGenFloatVariant{polname}</tt></a></li> +<li><a class="reference internal" href="#pollet-polname-2-polname-1" id="id53"><tt class="docutils literal"><span class="pre">\PolLet{polname_2}={polname_1}</span></tt></a></li> +<li><a class="reference internal" href="#polgloballet-polname-2-polname-1" id="id54"><tt class="docutils literal"><span class="pre">\PolGlobalLet{polname_2}={polname_1}</span></tt></a></li> +<li><a class="reference internal" href="#polassign-polname-toarray-macro" id="id55"><tt class="docutils literal"><span class="pre">\PolAssign{polname}\toarray\macro</span></tt></a></li> +<li><a class="reference internal" href="#polget-polname-fromarray-macro" id="id56"><tt class="docutils literal"><span class="pre">\PolGet{polname}\fromarray\macro</span></tt></a></li> +<li><a class="reference internal" href="#polfromcsv-polname-csv" id="id57"><tt class="docutils literal"><span class="pre">\PolFromCSV{polname}{<csv>}</span></tt></a></li> +<li><a class="reference internal" href="#poltypeset-polname" id="id58"><tt class="docutils literal">\PolTypeset{polname}</tt></a><ul> +<li><a class="reference internal" href="#poltypesetcmd-raw-coeff" id="id59"><tt class="docutils literal">\PolTypesetCmd{raw_coeff}</tt></a></li> +<li><a class="reference internal" href="#poltypesetone-raw-coeff" id="id60"><tt class="docutils literal">\PolTypesetOne{raw_coeff}</tt></a></li> +<li><a class="reference internal" href="#id6" id="id61"><tt class="docutils literal">\PolTypesetMonomialCmd</tt></a></li> +<li><a class="reference internal" href="#poltypesetcmdprefix-raw-coeff" id="id62"><tt class="docutils literal">\PolTypesetCmdPrefix{raw_coeff}</tt></a></li> +</ul> +</li> +<li><a class="reference internal" href="#id8" id="id63"><tt class="docutils literal"><span class="pre">\PolTypeset*{polname}</span></tt></a></li> +<li><a class="reference internal" href="#poldiff-polname-1-polname-2" id="id64"><tt class="docutils literal"><span class="pre">\PolDiff{polname_1}{polname_2}</span></tt></a></li> +<li><a class="reference internal" href="#poldiff-n-polname-1-polname-2" id="id65"><tt class="docutils literal"><span class="pre">\PolDiff[N]{polname_1}{polname_2}</span></tt></a></li> +<li><a class="reference internal" href="#polantidiff-polname-1-polname-2" id="id66"><tt class="docutils literal"><span class="pre">\PolAntiDiff{polname_1}{polname_2}</span></tt></a></li> +<li><a class="reference internal" href="#polantidiff-n-polname-1-polname-2" id="id67"><tt class="docutils literal"><span class="pre">\PolAntiDiff[N]{polname_1}{polname_2}</span></tt></a></li> +<li><a class="reference internal" href="#poldivide-polname-1-polname-2-polname-q-polname-r" id="id68"><tt class="docutils literal"><span class="pre">\PolDivide{polname_1}{polname_2}{polname_Q}{polname_R}</span></tt></a></li> +<li><a class="reference internal" href="#polquo-polname-1-polname-2-polname-q" id="id69"><tt class="docutils literal"><span class="pre">\PolQuo{polname_1}{polname_2}{polname_Q}</span></tt></a></li> +<li><a class="reference internal" href="#polrem-polname-1-polname-2-polname-r" id="id70"><tt class="docutils literal"><span class="pre">\PolRem{polname_1}{polname_2}{polname_R}</span></tt></a></li> +<li><a class="reference internal" href="#polgcd-polname-1-polname-2-polname-gcd" id="id71"><tt class="docutils literal"><span class="pre">\PolGCD{polname_1}{polname_2}{polname_GCD}</span></tt></a></li> +<li><a class="reference internal" href="#poltosturm-polname-sturmname" id="id72"><tt class="docutils literal"><span class="pre">\PolToSturm{polname}{sturmname}</span></tt></a></li> +<li><a class="reference internal" href="#id10" id="id73"><tt class="docutils literal"><span class="pre">\PolToSturm*{polname}{sturmname}</span></tt></a></li> +<li><a class="reference internal" href="#polsettosturmchainsignchangesat-macro-sturmname-fraction" id="id74"><tt class="docutils literal"><span class="pre">\PolSetToSturmChainSignChangesAt{\macro}{sturmname}{fraction}</span></tt></a></li> +<li><a class="reference internal" href="#polsettonbofzeroswithin-macro-sturmname-value-a-value-b" id="id75"><tt class="docutils literal"><span class="pre">\PolSetToNbOfZerosWithin{\macro}{sturmname}{value_a}{value_b}</span></tt></a></li> +<li><a class="reference internal" href="#polsturmisolatezeros-sturmname" id="id76"><tt class="docutils literal">\PolSturmIsolateZeros{sturmname}</tt></a></li> +<li><a class="reference internal" href="#id12" id="id77"><tt class="docutils literal"><span class="pre">\PolSturmIsolateZeros*{sturmname}</span></tt></a></li> +<li><a class="reference internal" href="#id14" id="id78"><tt class="docutils literal"><span class="pre">\PolSturmIsolateZeros**{sturmname}</span></tt></a></li> +<li><a class="reference internal" href="#polsturmisolatezerosandgetmultiplicities-sturmname" id="id79"><tt class="docutils literal">\PolSturmIsolateZerosAndGetMultiplicities{sturmname}</tt></a></li> +<li><a class="reference internal" href="#polsturmisolatezerosgetmultiplicitiesandrationalroots-sturmname" id="id80"><tt class="docutils literal">\PolSturmIsolateZerosGetMultiplicitiesAndRationalRoots{sturmname}</tt></a></li> +<li><a class="reference internal" href="#polsturmisolatezerosandfindrationalroots-sturmname" id="id81"><tt class="docutils literal">\PolSturmIsolateZerosAndFindRationalRoots{sturmname}</tt></a></li> +<li><a class="reference internal" href="#polrefineinterval-sturmname-index" id="id82"><tt class="docutils literal"><span class="pre">\PolRefineInterval*{sturmname}{index}</span></tt></a></li> +<li><a class="reference internal" href="#polrefineinterval-n-sturmname-index" id="id83"><tt class="docutils literal"><span class="pre">\PolRefineInterval[N]{sturmname}{index}</span></tt></a></li> +<li><a class="reference internal" href="#polensureintervallength-sturmname-index-e" id="id84"><tt class="docutils literal"><span class="pre">\PolEnsureIntervalLength{sturmname}{index}{E}</span></tt></a></li> +<li><a class="reference internal" href="#polensureintervallengths-sturmname-e" id="id85"><tt class="docutils literal"><span class="pre">\PolEnsureIntervalLengths{sturmname}{E}</span></tt></a></li> +<li><a class="reference internal" href="#polprintintervals-varname-sturmname" id="id86"><tt class="docutils literal"><span class="pre">\PolPrintIntervals[varname]{sturmname}</span></tt></a><ul> +<li><a class="reference internal" href="#polprintintervalsnorealroots" id="id87"><tt class="docutils literal">\PolPrintIntervalsNoRealRoots</tt></a></li> +<li><a class="reference internal" href="#polprintintervalsbeginenv" id="id88"><tt class="docutils literal">\PolPrintIntervalsBeginEnv</tt></a></li> +<li><a class="reference internal" href="#polprintintervalsendenv" id="id89"><tt class="docutils literal">\PolPrintIntervalsEndEnv</tt></a></li> +<li><a class="reference internal" href="#polprintintervalsknownroot" id="id90"><tt class="docutils literal">\PolPrintIntervalsKnownRoot</tt></a></li> +<li><a class="reference internal" href="#polprintintervalsunknownroot" id="id91"><tt class="docutils literal">\PolPrintIntervalsUnknownRoot</tt></a></li> +<li><a class="reference internal" href="#id15" id="id92"><tt class="docutils literal">\PolPrintIntervalsPrintExactZero</tt></a></li> +<li><a class="reference internal" href="#id16" id="id93"><tt class="docutils literal">\PolPrintIntervalsPrintLeftEndPoint</tt></a></li> +<li><a class="reference internal" href="#id17" id="id94"><tt class="docutils literal">\PolPrintIntervalsPrintRightEndPoint</tt></a></li> +</ul> +</li> +<li><a class="reference internal" href="#id19" id="id95"><tt class="docutils literal"><span class="pre">\PolPrintIntervals*[varname]{sturmname}</span></tt></a><ul> +<li><a class="reference internal" href="#polprintintervalsprintmultiplicity" id="id96"><tt class="docutils literal">\PolPrintIntervalsPrintMultiplicity</tt></a></li> +</ul> +</li> +<li><a class="reference internal" href="#polmapcoeffs-macro-polname" id="id97"><tt class="docutils literal"><span class="pre">\PolMapCoeffs{\macro}{polname}</span></tt></a></li> +<li><a class="reference internal" href="#polreducecoeffs-polname" id="id98"><tt class="docutils literal">\PolReduceCoeffs{polname}</tt></a></li> +<li><a class="reference internal" href="#id21" id="id99"><tt class="docutils literal"><span class="pre">\PolReduceCoeffs*{polname}</span></tt></a></li> +<li><a class="reference internal" href="#polmakemonic-polname" id="id100"><tt class="docutils literal">\PolMakeMonic{polname}</tt></a></li> +<li><a class="reference internal" href="#polmakeprimitive-polname" id="id101"><tt class="docutils literal">\PolMakePrimitive{polname}</tt></a></li> +</ul> +</li> +<li><a class="reference internal" href="#expandable-macros" id="id102">Expandable macros</a><ul> +<li><a class="reference internal" href="#poleval-polname-atexpr-numerical-expression" id="id103"><tt class="docutils literal"><span class="pre">\PolEval{polname}\AtExpr{numerical</span> expression}</tt></a></li> +<li><a class="reference internal" href="#poleval-polname-at-fraction" id="id104"><tt class="docutils literal"><span class="pre">\PolEval{polname}\At{fraction}</span></tt></a></li> +<li><a class="reference internal" href="#polevalreduced-polname-atexpr-numerical-expression" id="id105"><tt class="docutils literal"><span class="pre">\PolEvalReduced{polname}\AtExpr{numerical</span> expression}</tt></a></li> +<li><a class="reference internal" href="#polevalreduced-polname-at-fraction" id="id106"><tt class="docutils literal"><span class="pre">\PolEvalReduced{polname}\At{fraction}</span></tt></a></li> +<li><a class="reference internal" href="#polfloateval-polname-atexpr-numerical-expression" id="id107"><tt class="docutils literal"><span class="pre">\PolFloatEval{polname}\AtExpr{numerical</span> expression}</tt></a></li> +<li><a class="reference internal" href="#polfloateval-polname-at-fraction" id="id108"><tt class="docutils literal"><span class="pre">\PolFloatEval{polname}\At{fraction}</span></tt></a></li> +<li><a class="reference internal" href="#polifcoeffisplusorminusone-a-b" id="id109"><tt class="docutils literal"><span class="pre">\PolIfCoeffIsPlusOrMinusOne{A}{B}</span></tt></a></li> +<li><a class="reference internal" href="#polleadingcoeff-polname" id="id110"><tt class="docutils literal">\PolLeadingCoeff{polname}</tt></a></li> +<li><a class="reference internal" href="#polnthcoeff-polname-number" id="id111"><tt class="docutils literal"><span class="pre">\PolNthCoeff{polname}{number}</span></tt></a></li> +<li><a class="reference internal" href="#poldegree-polname" id="id112"><tt class="docutils literal">\PolDegree{polname}</tt></a></li> +<li><a class="reference internal" href="#policontent-polname" id="id113"><tt class="docutils literal">\PolIContent{polname}</tt></a></li> +<li><a class="reference internal" href="#poltoexpr-polname" id="id114"><tt class="docutils literal">\PolToExpr{polname}</tt></a><ul> +<li><a class="reference internal" href="#poltoexproneterm-raw-coeff-number" id="id115"><tt class="docutils literal"><span class="pre">\PolToExprOneTerm{raw_coeff}{number}</span></tt></a></li> +<li><a class="reference internal" href="#poltoexpronetermstylea-raw-coeff-number" id="id116"><tt class="docutils literal"><span class="pre">\PolToExprOneTermStyleA{raw_coeff}{number}</span></tt></a></li> +<li><a class="reference internal" href="#poltoexpronetermstyleb-raw-coeff-number" id="id117"><tt class="docutils literal"><span class="pre">\PolToExprOneTermStyleB{raw_coeff}{number}</span></tt></a></li> +<li><a class="reference internal" href="#poltoexprcmd-raw-coeff" id="id118"><tt class="docutils literal">\PolToExprCmd{raw_coeff}</tt></a></li> +<li><a class="reference internal" href="#poltoexprtermprefix-raw-coeff" id="id119"><tt class="docutils literal">\PolToExprTermPrefix{raw_coeff}</tt></a></li> +<li><a class="reference internal" href="#id28" id="id120"><tt class="docutils literal">\PolToExprVar</tt></a></li> +<li><a class="reference internal" href="#id29" id="id121"><tt class="docutils literal">\PolToExprTimes</tt></a></li> +</ul> +</li> +<li><a class="reference internal" href="#id31" id="id122"><tt class="docutils literal"><span class="pre">\PolToExpr*{polname}</span></tt></a></li> +<li><a class="reference internal" href="#poltofloatexpr-polname" id="id123"><tt class="docutils literal">\PolToFloatExpr{polname}</tt></a><ul> +<li><a class="reference internal" href="#poltofloatexproneterm-raw-coeff-number" id="id124"><tt class="docutils literal"><span class="pre">\PolToFloatExprOneTerm{raw_coeff}{number}</span></tt></a></li> +<li><a class="reference internal" href="#poltofloatexprcmd-raw-coeff" id="id125"><tt class="docutils literal">\PolToFloatExprCmd{raw_coeff}</tt></a></li> +</ul> +</li> +<li><a class="reference internal" href="#id35" id="id126"><tt class="docutils literal"><span class="pre">\PolToFloatExpr*{polname}</span></tt></a></li> +<li><a class="reference internal" href="#poltolist-polname" id="id127"><tt class="docutils literal">\PolToList{polname}</tt></a></li> +<li><a class="reference internal" href="#poltocsv-polname" id="id128"><tt class="docutils literal">\PolToCSV{polname}</tt></a></li> +<li><a class="reference internal" href="#polsturmchainlength-sturmname" id="id129"><tt class="docutils literal">\PolSturmChainLength{sturmname}</tt></a></li> +<li><a class="reference internal" href="#polsturmifzeroexactlyknown-sturmname-index-a-b" id="id130"><tt class="docutils literal"><span class="pre">\PolSturmIfZeroExactlyKnown{sturmname}{index}{A}{B}</span></tt></a></li> +<li><a class="reference internal" href="#polsturmisolatedzeroleft-sturmname-index" id="id131"><tt class="docutils literal"><span class="pre">\PolSturmIsolatedZeroLeft{sturmname}{index}</span></tt></a></li> +<li><a class="reference internal" href="#polsturmisolatedzeroright-sturmname-index" id="id132"><tt class="docutils literal"><span class="pre">\PolSturmIsolatedZeroRight{sturmname}{index}</span></tt></a></li> +<li><a class="reference internal" href="#polsturmisolatedzeromultiplicity-sturmname-index" id="id133"><tt class="docutils literal"><span class="pre">\PolSturmIsolatedZeroMultiplicity{sturmname}{index}</span></tt></a></li> +<li><a class="reference internal" href="#polsturmnbofisolatedzeros-sturmname" id="id134"><tt class="docutils literal">\PolSturmNbOfIsolatedZeros{sturmname}</tt></a><ul> +<li><a class="reference internal" href="#polsturmnbofrootsof-sturmname-lessthanorequalto-value" id="id135"><tt class="docutils literal"><span class="pre">\PolSturmNbOfRootsOf{sturmname}\LessThanOrEqualTo{value}</span></tt></a></li> +<li><a class="reference internal" href="#polsturmnbofrootsof-sturmname-lessthanorequaltoexpr-expression" id="id136"><tt class="docutils literal"><span class="pre">\PolSturmNbOfRootsOf{sturmname}\LessThanOrEqualToExpr{expression}</span></tt></a></li> +<li><a class="reference internal" href="#polsturmnbwithmultofrootsof-sturmname-lessthanorequalto-value" id="id137"><tt class="docutils literal"><span class="pre">\PolSturmNbWithMultOfRootsOf{sturmname}\LessThanOrEqualTo{value}</span></tt></a></li> +<li><a class="reference internal" href="#polsturmnbwithmultofrootsof-sturmname-lessthanorequaltoexpr-expression" id="id138"><tt class="docutils literal"><span class="pre">\PolSturmNbWithMultOfRootsOf{sturmname}\LessThanOrEqualToExpr{expression}</span></tt></a></li> +</ul> +</li> +<li><a class="reference internal" href="#polsturmnbofrationalroots-sturmname" id="id139"><tt class="docutils literal">\PolSturmNbOfRationalRoots{sturmname}</tt></a></li> +<li><a class="reference internal" href="#polsturmnbofrationalrootswithmultiplicities-sturmname" id="id140"><tt class="docutils literal">\PolSturmNbOfRationalRootsWithMultiplicities{sturmname}</tt></a></li> +<li><a class="reference internal" href="#polsturmrationalroot-sturmname-k" id="id141"><tt class="docutils literal"><span class="pre">\PolSturmRationalRoot{sturmname}{k}</span></tt></a></li> +<li><a class="reference internal" href="#polsturmrationalrootindex-sturmname-k" id="id142"><tt class="docutils literal"><span class="pre">\PolSturmRationalRootIndex{sturmname}{k}</span></tt></a></li> +<li><a class="reference internal" href="#polsturmrationalrootmultiplicity-sturmname-k" id="id143"><tt class="docutils literal"><span class="pre">\PolSturmRationalRootMultiplicity{sturmname}{k}</span></tt></a></li> +<li><a class="reference internal" href="#polintervalwidth-sturmname-index" id="id144"><tt class="docutils literal"><span class="pre">\PolIntervalWidth{sturmname}{index}</span></tt></a></li> +<li><a class="reference internal" href="#expandable-macros-for-use-within-execution-of-polprintintervals" id="id145">Expandable macros for use within execution of <tt class="docutils literal">\PolPrintIntervals</tt></a><ul> +<li><a class="reference internal" href="#polprintintervalsthevar" id="id146"><tt class="docutils literal">\PolPrintIntervalsTheVar</tt></a></li> +<li><a class="reference internal" href="#polprintintervalstheindex" id="id147"><tt class="docutils literal">\PolPrintIntervalsTheIndex</tt></a></li> +<li><a class="reference internal" href="#polprintintervalsthesturmname" id="id148"><tt class="docutils literal">\PolPrintIntervalsTheSturmName</tt></a></li> +<li><a class="reference internal" href="#polprintintervalstheleftendpoint" id="id149"><tt class="docutils literal">\PolPrintIntervalsTheLeftEndPoint</tt></a></li> +<li><a class="reference internal" href="#polprintintervalstherightendpoint" id="id150"><tt class="docutils literal">\PolPrintIntervalsTheRightEndPoint</tt></a></li> +<li><a class="reference internal" href="#polprintintervalsthemultiplicity" id="id151"><tt class="docutils literal">\PolPrintIntervalsTheMultiplicity</tt></a></li> +</ul> +</li> +<li><a class="reference internal" href="#poldectostring-decimal-number" id="id152"><tt class="docutils literal">\PolDecToString{decimal number}</tt></a></li> +</ul> +</li> +<li><a class="reference internal" href="#booleans-with-default-setting-as-indicated" id="id153">Booleans (with default setting as indicated)</a><ul> +<li><a class="reference internal" href="#xintverbosefalse" id="id154"><tt class="docutils literal">\xintverbosefalse</tt></a></li> +<li><a class="reference internal" href="#poltypesetallfalse" id="id155"><tt class="docutils literal">\poltypesetallfalse</tt></a></li> +<li><a class="reference internal" href="#poltoexprallfalse" id="id156"><tt class="docutils literal">\poltoexprallfalse</tt></a></li> +</ul> +</li> +<li><a class="reference internal" href="#polexprsetup" id="id157"><tt class="docutils literal">\polexprsetup</tt></a></li> +<li><a class="reference internal" href="#technicalities" id="id158">Technicalities</a></li> +<li><a class="reference internal" href="#change-log" id="id159">CHANGE LOG</a></li> +<li><a class="reference internal" href="#acknowledgments" id="id160">Acknowledgments</a></li> +</ul> +</div> +<div class="section" id="basic-syntax"> +<h1><a class="toc-backref" href="#id38">Basic syntax</a></h1> +<p>The syntax is:</p> +<pre class="literal-block"> +\poldef polname(x):= expression in variable x; +</pre> +<p>where:</p> +<ul class="simple"> +<li>in place of <tt class="docutils literal">x</tt> an arbitrary <em>dummy variable</em> is authorized, +i.e. per default any of <tt class="docutils literal"><span class="pre">[a-z|A-Z]</span></tt> (more letters can be declared +under Unicode engines.)</li> +<li><tt class="docutils literal">polname</tt> consists of letters, digits, and the <tt class="docutils literal">_</tt> and +<tt class="docutils literal">'</tt> characters. It must start with a letter.</li> +</ul> +<div class="admonition attention"> +<p class="first admonition-title">Attention!</p> +<p class="last">The <tt class="docutils literal">'</tt> is authorized since <tt class="docutils literal">0.5.1</tt>. As a result some constructs +recognized by the <tt class="docutils literal">\xintexpr</tt> parser, such as <tt class="docutils literal">var1 'and' var2</tt> +will get misinterpreted and cause errors. However these constructs +are unlikely to be frequently needed in polynomial expressions, and +the <tt class="docutils literal">\xintexpr</tt> syntax offers alternatives, so it was deemed a +small evil. Of course the <tt class="docutils literal">\xintexpr</tt> parser is modified only +temporarily during execution of <tt class="docutils literal">\poldef</tt>.</p> +</div> +<p>One can also issue:</p> +<pre class="literal-block"> +\PolDef{polname}{expression in variable x} +</pre> +<p>which admits an optional first argument to modify the variable letter +from its default <tt class="docutils literal">x</tt>.</p> +<dl class="docutils"> +<dt><tt class="docutils literal">\poldef <span class="pre">f(x):=</span> <span class="pre">1-x+x^2;</span></tt></dt> +<dd>defines polynomial <tt class="docutils literal">f</tt>. Polynomial names must start with a +letter and may contain letters, digits, underscores and the right +tick character. The +variable must be a single letter. The colon character is optional. +The semi-colon at end of expression is mandatory.</dd> +<dt><tt class="docutils literal"><span class="pre">\PolDef{f}{1-x+x^2}</span></tt></dt> +<dd>does the same as <tt class="docutils literal">\poldef <span class="pre">f(x):=</span> <span class="pre">1-x+x^2;</span></tt> To use another letter +than <tt class="docutils literal">x</tt> in the expression, one must pass it as an extra optional +argument to <tt class="docutils literal">\PolDef</tt>. Useful if the semi-colon has been assigned +some non-standard catcode by some package.</dd> +<dt><tt class="docutils literal"><span class="pre">\PolLet{g}={f}</span></tt></dt> +<dd>saves a copy of <tt class="docutils literal">f</tt> under name <tt class="docutils literal">g</tt>. Also usable without <tt class="docutils literal">=</tt>.</dd> +<dt><tt class="docutils literal">\poldef <span class="pre">f(z):=</span> <span class="pre">f(z)^2;</span></tt></dt> +<dd>redefines <tt class="docutils literal">f</tt> in terms of itself.</dd> +<dt><tt class="docutils literal">\poldef <span class="pre">f(T):=</span> <span class="pre">f(f(T));</span></tt></dt> +<dd>again redefines <tt class="docutils literal">f</tt> in terms of its (new) self.</dd> +<dt><tt class="docutils literal">\poldef <span class="pre">k(z):=</span> <span class="pre">f(z)-g(g(z)^2)^2;</span></tt></dt> +<dd>should now define the zero polynomial... Let's check: +<tt class="docutils literal">\[ k(z) = <span class="pre">\PolTypeset[z]{k}</span> \]</tt></dd> +<dt><tt class="docutils literal"><span class="pre">\PolDiff{f}{f'}</span></tt></dt> +<dd>sets <tt class="docutils literal">f'</tt> to the derivative of <tt class="docutils literal">f</tt>. The name doesn't have to be +<tt class="docutils literal">f'</tt> (in fact the <tt class="docutils literal">'</tt> is licit only since <tt class="docutils literal">0.5.1</tt>).</dd> +</dl> +<div class="admonition important"> +<p class="first admonition-title">Important</p> +<p class="last">This is not done automatically. If some new definition needs to use +the derivative of some available polynomial, that derivative +polynomial must have been defined via <tt class="docutils literal">\PolDiff</tt>: something like +<tt class="docutils literal"><span class="pre">T'(x)^2</span></tt> will not work without a prior <tt class="docutils literal"><span class="pre">\PolDiff{T}{T'}</span></tt>.</p> +</div> +<dl class="docutils"> +<dt><tt class="docutils literal"><span class="pre">\PolDiff{f'}{f''}</span></tt></dt> +<dd>obtains second derivative.</dd> +<dt><tt class="docutils literal"><span class="pre">\PolDiff[3]{f}{f'''}</span></tt></dt> +<dd>computes the third derivative.</dd> +</dl> +<pre class="literal-block"> +$f(z) = \PolTypeset[z]{f} $\newline +$f'(z) = \PolTypeset[z]{f'} $\newline +$f''(z) = \PolTypeset[z]{f''} $\newline +$f'''(z)= \PolTypeset[z]{f'''} $\par +</pre> +<div class="admonition important"> +<p class="first admonition-title">Important</p> +<p>The package does not currently know rational functions: <tt class="docutils literal">/</tt> in +a parsed polynomial expression does the Euclidean quotient:</p> +<pre class="literal-block"> +(1-x^2)/(1-x) +</pre> +<p>does give <tt class="docutils literal">1+x</tt> but</p> +<pre class="literal-block"> +(1/(1-x))*(1-x^2) +</pre> +<p>evaluates to zero. This will work as expected:</p> +<pre class="last literal-block"> +\poldef k(x):= (x-1)(x-2)(x-3)(x-4)/(x^2-5x+4); +</pre> +</div> +<div class="admonition attention" id="warningtacit"> +<p class="first admonition-title">Attention!</p> +<p><tt class="docutils literal">1/2 x^2</tt> skips the space and is treated like <tt class="docutils literal"><span class="pre">1/(2*x^2)</span></tt> because +of the tacit multiplication rules of xintexpr. But this means it +gives zero! Thus one must use <tt class="docutils literal">(1/2)x^2</tt> or <tt class="docutils literal">1/2*x^2</tt> or +<tt class="docutils literal"><span class="pre">(1/2)*x^2</span></tt> for disambiguation: <tt class="docutils literal">x - 1/2*x^2 + <span class="pre">1/3*x^3...</span></tt>. It is +even simpler to move the denominator to the right: <tt class="docutils literal">x - x^2/2 + +x^3/3 - ...</tt>.</p> +<p class="last">It is worth noting that <tt class="docutils literal"><span class="pre">1/2(x-1)(x-2)</span></tt> suffers the same issue: +<a class="reference external" href="http://www.ctan.org/pkg/xint">xint</a> tacit multiplication always "ties more", hence this gets +interpreted as <tt class="docutils literal"><span class="pre">1/(2*(x-1)*(x-2))</span></tt> which gives zero by polynomial +division. Thus, use one of <tt class="docutils literal"><span class="pre">(1/2)(x-1)(x-2)</span></tt>, <tt class="docutils literal"><span class="pre">1/2*(x-1)(x-2)</span></tt> or +<tt class="docutils literal"><span class="pre">(x-1)(x-2)/2</span></tt>.</p> +</div> +<p>After:</p> +<pre class="literal-block"> +\poldef f_1(x):= 25(x-1)(x^2-2)(x-3)(x-4)(x-5);% +\poldef f_2(x):= 37(x-1)(x^2-2)(x-6)(x-7)(x-8);% +</pre> +<p>the macro call <tt class="docutils literal"><span class="pre">\PolGCD{f_1}{f_2}{k}</span></tt> sets <tt class="docutils literal">k</tt> to the (unitary) GCD of +<tt class="docutils literal">f_1</tt> and <tt class="docutils literal">f_2</tt> (hence to the expansion of <tt class="docutils literal"><span class="pre">(x-1)(x^2-2)</span></tt>.)</p> +<dl class="docutils"> +<dt><tt class="docutils literal">\PolToExpr{k}</tt></dt> +<dd>will (expandably) give in this case <tt class="docutils literal"><span class="pre">x^3-x^2-2*x+2</span></tt>. This is +useful for console or file output (the syntax is Maple- and +PSTricks-compatible; the letter used in output can be +(non-expandably) changed via a redefinition of <a class="reference internal" href="#poltoexprvar">\PolToExprVar</a>.)</dd> +<dt><tt class="docutils literal"><span class="pre">\PolToExpr*{k}</span></tt></dt> +<dd>gives ascending powers: <tt class="docutils literal"><span class="pre">2-2*x-x^2+x^3</span></tt>.</dd> +</dl> +</div> +<div class="section" id="examples-of-localization-of-roots"> +<h1><a class="toc-backref" href="#id39">Examples of localization of roots</a></h1> +<ul> +<li><p class="first">To make printed decimal numbers more enjoyable than via +<tt class="docutils literal">\xintSignedFrac</tt>:</p> +<pre class="literal-block"> +\renewcommand\PolTypesetOne[1]{\PolDecToString{\xintREZ{#1}}}% +</pre> +<p><tt class="docutils literal">\PolDecToString</tt> will use decimal notation to incorporate the power +of ten part; and the <tt class="docutils literal">\xintREZ</tt> will have the effect to suppress +trailing zeros if present in raw numerator (if those digits end up +after decimal mark.) Notice that the above are expandable macros and +that one can also do:</p> +<pre class="literal-block"> +\renewcommand\PolToExprCmd[1]{\PolDecToString{\xintREZ{#1}}}% +</pre> +<p>to modify output of <a class="reference internal" href="#poltoexpr-polname">\PolToExpr{polname}</a>.</p> +</li> +<li><p class="first">For extra info in log file use <tt class="docutils literal">\xintverbosetrue</tt>.</p> +</li> +<li><p class="first">Only for some of these examples is the output included here.</p> +</li> +</ul> +<div class="section" id="a-typical-example"> +<h2><a class="toc-backref" href="#id40">A typical example</a></h2> +<p>In this example the polynomial is square-free.</p> +<pre class="literal-block"> +\poldef f(x) := x^7 - x^6 - 2x + 1; + +\PolToSturm{f}{f} +\PolSturmIsolateZeros{f} +The \PolTypeset{f} polynomial has \PolSturmNbOfIsolatedZeros{f} distinct real +roots which are located in the following intervals: +\PolPrintIntervals{f} +Here is the second root with ten more decimal digits: +\PolRefineInterval[10]{f}{2} +\[\PolSturmIsolatedZeroLeft{f}{2}<Z_2<\PolSturmIsolatedZeroRight{f}{2}\] +And here is the first root with twenty digits after decimal mark: +\PolEnsureIntervalLength{f}{1}{-20} +\[\PolSturmIsolatedZeroLeft{f}{1}<Z_1<\PolSturmIsolatedZeroRight{f}{1}\] +The first element of the Sturm chain has degree $\PolDegree{f_0}$. As +this is the original degreee $\PolDegree{f}$ we know that $f$ is square free. +Its derivative is up to a constant \PolTypeset{f_1} (in this example +it is identical with it). +\PolToSturm{f_1}{f_1}\PolSturmIsolateZeros{f_1}% +The derivative has \PolSturmNbOfIsolatedZeros{f_1} distinct real +roots: +\PolPrintIntervals[W]{f_1} +\PolEnsureIntervalLengths{f_1}{-10}% +Here they are with ten digits after decimal mark: +\PolPrintIntervals[W]{f_1} +\PolDiff{f_1}{f''} +\PolToSturm{f''}{f''} +\PolSturmIsolateZeros{f''} +The second derivative is \PolTypeset{f''}. +It has \PolSturmNbOfIsolatedZeros{f''} distinct real +roots: +\PolPrintIntervals[X]{f''} +Here is the positive one with 20 digits after decimal mark: +\PolEnsureIntervalLength{f''}{2}{-20}% +\[X_2 = \PolSturmIsolatedZeroLeft{f''}{2}\dots\] +The more mathematically advanced among our dear readers will be able +to give the exact value for $X_2$! +</pre> +</div> +<div class="section" id="a-degree-four-polynomial-with-nearby-roots"> +<h2><a class="toc-backref" href="#id41">A degree four polynomial with nearby roots</a></h2> +<p>Notice that this example is a bit outdated as <tt class="docutils literal">0.7</tt> release has +added <tt class="docutils literal"><span class="pre">\PolSturmIsolateZeros**{sturmname}</span></tt> which would find exactly +the roots. The steps here retain their interest when one is interested +in finding isolating intervals for example to prepare some demonstration +of dichotomy method.</p> +<pre class="literal-block"> +\PolDef{Q}{(x-1.050001)(x-1.105001)(x-1.110501)(x-1.111051)} +\PolTypeset{Q} +\PolToSturm{Q}{Q} % it is allowed to use same prefix for Sturm chain +\PolSturmIsolateZeros{Q} +\PolPrintIntervals{Q} +% reports 1.0 < Z_1 < 1.1, 1.10 < Z_2 < 1.11, 1.110 < Z_3 < 1.111, and 1.111 < Z_4 < 1.112 +% but the above bounds do not allow minimizing separation between roots +% so we refine: +\PolRefineInterval*{Q}{1} +\PolRefineInterval*{Q}{2} +\PolRefineInterval*{Q}{3} +\PolRefineInterval*{Q}{4} +\PolPrintIntervals{Q} +% reports 1.05 < Z_1 < 1.06, 1.105 < Z_2 < 1.106, 1.1105 < Z_3 < 1.1106, +% and 1.11105 < Z_4 < 1.11106. +\PolEnsureIntervalLengths{Q}{-6} +\PolPrintIntervals{Q} +% of course finds here all roots exactly +</pre> +</div> +<div class="section" id="the-degree-nine-polynomial-with-0-99-0-999-0-9999-as-triple-roots"> +<h2><a class="toc-backref" href="#id42">The degree nine polynomial with 0.99, 0.999, 0.9999 as triple roots</a></h2> +<pre class="literal-block"> +% define a user command (xinttools is loaded automatically by polexpr) +\newcommand\showmultiplicities[1]{% #1 = "sturmname" +\xintFor* ##1 in {\xintSeq{1}{\PolSturmNbOfIsolatedZeros{#1}}}\do{% + The multiplicity is \PolSturmIsolatedZeroMultiplicity{#1}{##1} + \PolSturmIfZeroExactlyKnown{#1}{##1}% + {at the root $x=\PolSturmIsolatedZeroLeft{#1}{##1}$} + {for the root such that + $\PolSturmIsolatedZeroLeft{#1}{##1}<x<\PolSturmIsolatedZeroRight{#1}{##1}$} + \par +}}% +\PolDef{f}{(x-0.99)^3(x-0.999)^3(x-0.9999)^3} +\renewcommand\PolTypesetOne[1]{\PolDecToString{\xintREZ{#1}}} +\PolTypeset{f}\par +\PolToSturm{f}{f}% it is allowed to use "polname" as "sturmname" too +\PolSturmIsolateZerosAndGetMultiplicities{f}% use the "sturmname" here +% or \PolSturmIsolateZeros*{f} which is exactly the same, but shorter.. + +\showmultiplicities{f} +</pre> +<p>In this example, the output will look like this (but using math mode):</p> +<pre class="literal-block"> +x^9 - 8.9667x^8 + 35.73400293x^7 - 83.070418400109x^6 + 124.143648875193123x^5 +- 123.683070924326075877x^4 + 82.149260397553075617891x^3 +- 35.07602992699900159127007x^2 + 8.7364078733314648368671733x +- 0.967100824643585986488103299 + +The multiplicity is 3 at the root x = 0.99 +The multiplicity is 3 at the root x = 0.999 +The multiplicity is 3 at the root x = 0.9999 +</pre> +<p>On first pass, these rational roots were found (due to their relative +magnitudes, using <tt class="docutils literal">\PolSturmIsolateZeros**</tt> was not needed here). But +multiplicity computation works also with (decimal) roots not yet +identified or with non-decimal or irrational roots.</p> +<p>It is fun to modify only a tiny bit the polynomial and see if polexpr +survives:</p> +<pre class="literal-block"> +\PolDef{g}{f(x)+1e-27} +\PolTypeset{g}\par +\PolToSturm{g}{g} +\PolSturmIsolateZeros*{g} + +\showmultiplicities{g} +</pre> +<p>This produces:</p> +<pre class="literal-block"> +x^9 - 8.9667x^8 + 35.73400293x^7 - 83.070418400109x^6 + 124.143648875193123x^5 +- 123.683070924326075877x^4 + 82.149260397553075617891x^3 +- 35.07602992699900159127007x^2 + 8.7364078733314648368671733x +- 0.967100824643585986488103298 + +The multiplicity is 1 for the root such that 0.98 < x < 0.99 +The multiplicity is 1 for the root such that 0.9991 < x < 0.9992 +The multiplicity is 1 for the root such that 0.9997 < x < 0.9998 +</pre> +<p>Which means that the multiplicity-3 roots each became a real and a pair of +complex ones. Let's see them better:</p> +<pre class="literal-block"> +\PolEnsureIntervalLengths{g}{-10} + +\showmultiplicities{g} +</pre> +<p>which produces:</p> +<pre class="literal-block"> +The multiplicity is 1 for the root such that 0.9899888032 < x < 0.9899888033 +The multiplicity is 1 for the root such that 0.9991447980 < x < 0.9991447981 +The multiplicity is 1 for the root such that 0.9997663986 < x < 0.9997663987 +</pre> +</div> +<div class="section" id="a-degree-five-polynomial-with-three-rational-roots"> +<h2><a class="toc-backref" href="#id43">A degree five polynomial with three rational roots</a></h2> +<pre class="literal-block"> +\poldef Q(x) := 1581755751184441 x^5 + -14907697165025339 x^4 + +48415668972339336 x^3 + -63952057791306264 x^2 + +46833913221154895 x + -49044360626280925; + +\PolToSturm{Q}{Q} +%\begin{flushleft} + \renewcommand\PolTypesetCmdPrefix[1]{\allowbreak\xintiiifSgn{#1}{}{+}{+}}% + $Q_0(x) = \PolTypeset{Q_0}$ +%\end{flushleft} +\PolSturmIsolateZeros**{Q} +\PolPrintIntervals{Q} + +$Q_{norr}(x) = \PolTypeset{Q_norr}$ +</pre> +<p>Here, all real roots are rational:</p> +<pre class="literal-block"> +Z_1 = 833719/265381 +Z_2 = 165707065/52746197 +Z_3 = 355/113 + +Q_norr(x) = x^2 + 1 +</pre> +<p>And let's get their decimal expansion too:</p> +<pre class="literal-block"> +% print decimal expansion of the found roots +\renewcommand\PolPrintIntervalsPrintExactZero + {\xintTrunc{20}{\PolPrintIntervalsTheLeftEndPoint}\dots} +\PolPrintIntervals{Q} + +Z_1 = 3.14159265358107777120... +Z_2 = 3.14159265358979340254... +Z_3 = 3.14159292035398230088... +</pre> +</div> +<div class="section" id="a-mignotte-type-polynomial"> +<h2><a class="toc-backref" href="#id44">A Mignotte type polynomial</a></h2> +<pre class="literal-block"> +\PolDef{P}{x^10 - (10x-1)^2}% +\PolTypeset{P} % prints it in expanded form +\PolToSturm{P}{P} % we can use same prefix for Sturm chain +\PolSturmIsolateZeros{P} % finds 4 real roots +This polynomial has \PolSturmNbOfIsolatedZeros{P} distinct real roots: +\PolPrintIntervals{P}% +% reports -2 < Z_1 < -1, 0.09 < Z_2 < 0.10, 0.1 < Z_3 < 0.2, 1 < Z_4 < 2 +Let us refine the second and third intervals to separate the corresponding +roots: +\PolRefineInterval*{P}{2}% will refine to 0.0999990 < Z_2 < 0.0999991 +\PolRefineInterval*{P}{3}% will refine to 0.100001 < Z_3 < 0.100002 +\PolPrintIntervals{P}% +Let us now get to know all roots with 10 digits after decimal mark: +\PolEnsureIntervalLengths{P}{-10}% +\PolPrintIntervals{P}% now all roots are known 10 decimal digits after mark +Finally, we display 20 digits of the second root: +\PolEnsureIntervalLength{P}{2}{-20}% makes Z_2 known with 20 digits after mark +\[\PolSturmIsolatedZeroLeft{P}{2}<Z_2<\PolSturmIsolatedZeroRight{P}{2}\] +</pre> +<p>The last line produces:</p> +<pre class="literal-block"> +0.09999900004999650028 < Z_2 < 0.09999900004999650029 +</pre> +</div> +<div class="section" id="the-wilkinson-polynomial"> +<h2><a class="toc-backref" href="#id45">The Wilkinson polynomial</a></h2> +<p>See <a class="reference external" href="https://en.wikipedia.org/wiki/Wilkinson%27s_polynomial">Wilkinson polynomial</a>.</p> +<pre class="literal-block"> +\documentclass{article} +\usepackage{polexpr} +\begin{document} +%\xintverbosetrue % for the curious... + +\poldef f(x) := mul((x - i), i = 1..20); + +\renewcommand\PolTypesetCmdPrefix[1]{\allowbreak\xintiiifSgn{#1}{}{+}{+}}% +\renewcommand\PolTypesetOne[1]{\xintDecToString{#1}}% + +\noindent\PolTypeset{f} + +\PolToSturm{f}{f} +\PolSturmIsolateZeros{f} +\PolPrintIntervals{f} + +\clearpage + +\poldef g(x) := f(x) - 2**{-23} x**19; + +% be patient! +\PolToSturm{g}{g} +\noindent\PolTypeset{g_0}% integer coefficient primitive polynomial + +\PolSturmIsolateZeros{g} +\PolEnsureIntervalLengths{g}{-10} + +\renewcommand\PolPrintIntervalsPrintMultiplicity{} +\PolPrintIntervals*{g} + +\end{document} +</pre> +<p>The first polynomial:</p> +<pre class="literal-block"> +f(x) = x**20 +- 210 x**19 ++ 20615 x**18 +- 1256850 x**17 ++ 53327946 x**16 +- 1672280820 x**15 ++ 40171771630 x**14 +- 756111184500 x**13 ++ 11310276995381 x**12 +- 135585182899530 x**11 ++ 1307535010540395 x**10 +- 10142299865511450 x**9 ++ 63030812099294896 x**8 +- 311333643161390640 x**7 ++ 1206647803780373360 x**6 +- 3599979517947607200 x**5 ++ 8037811822645051776 x**4 +- 12870931245150988800 x**3 ++ 13803759753640704000 x**2 +- 8752948036761600000 x ++ 2432902008176640000 +</pre> +<p>is handled fast enough (a few seconds), but the modified one <tt class="docutils literal">f(x) - +<span class="pre">2**-23</span> <span class="pre">x**19</span></tt> takes about 20x longer (the Sturm chain polynomials +have integer coefficients with up to 321 digits, whereas (surprisingly +perhaps) those of the Sturm chain polynomials derived from <tt class="docutils literal">f</tt> never +have more than 21 digits ...).</p> +<p>Once the Sturm chain is computed and the zeros isolated, obtaining their +decimal digits is relatively faster. Here is for the ten real roots of +<tt class="docutils literal">f(x) - <span class="pre">2**-23</span> <span class="pre">x**19</span></tt> as computed by the code above:</p> +<pre class="literal-block"> +Z_1 = 0.9999999999... +Z_2 = 2.0000000000... +Z_3 = 2.9999999999... +Z_4 = 4.0000000002... +Z_5 = 4.9999999275... +Z_6 = 6.0000069439... +Z_7 = 6.9996972339... +Z_8 = 8.0072676034... +Z_9 = 8.9172502485... +Z_10 = 20.8469081014... +</pre> +</div> +<div class="section" id="the-second-wilkinson-polynomial"> +<h2><a class="toc-backref" href="#id46">The second Wilkinson polynomial</a></h2> +<pre class="literal-block"> +\documentclass{article} +\usepackage{polexpr} +\begin{document} +\poldef f(x) := mul(x - 2^-i, i = 1..20); + +%\PolTypeset{f} + +\PolToSturm{f}{f} +\PolSturmIsolateZeros**{f} +\PolPrintIntervals{f} +\end{document} +</pre> +<p>This takes more time than the polynomial with 1, 2, .., 20 as roots but +less than the latter modified by the <tt class="docutils literal"><span class="pre">2**-23</span></tt> change in one +coefficient.</p> +<p>Here is the output (with release 0.7.2):</p> +<pre class="literal-block"> +Z_1 = 0.00000095367431640625 +Z_2 = 0.0000019073486328125 +Z_3 = 0.000003814697265625 +Z_4 = 0.00000762939453125 +Z_5 = 0.0000152587890625 +Z_6 = 0.000030517578125 +Z_7 = 0.00006103515625 +Z_8 = 0.0001220703125 +Z_9 = 1/4096 +Z_10 = 1/2048 +Z_11 = 1/1024 +Z_12 = 1/512 +Z_13 = 1/256 +Z_14 = 1/128 +Z_15 = 0.015625 +Z_16 = 0.03125 +Z_17 = 0.0625 +Z_18 = 0.125 +Z_19 = 0.25 +Z_20 = 0.5 +</pre> +<p>There is some incoherence in output format which has its source in the +fact that some roots are found in branches which can only find decimal +roots, whereas some are found in branches which could find general +fractions and they use <tt class="docutils literal">\xintIrr</tt> before storage of the found root. +This may evolve in future.</p> +</div> +<div class="section" id="the-degree-41-polynomial-with-2-1-9-1-8-0-0-1-1-9-2-as-roots"> +<h2><a class="toc-backref" href="#id47">The degree 41 polynomial with -2, -1.9, -1.8, ..., 0, 0.1, ..., 1.9, 2 as roots</a></h2> +<pre class="literal-block"> +\PolDef{P}{mul((x-i*1e-1), i=-20..20)}% i/10 is same but less efficient +</pre> +<p>In the defining expression we could have used <tt class="docutils literal">i/10</tt> but this gives +less efficient internal form for the coefficients (the <tt class="docutils literal">10</tt>'s end up +in denominators). Using <tt class="docutils literal">\PolToExpr{P}</tt> after having done</p> +<pre class="literal-block"> +\renewcommand\PolToExprCmd[1]{\PolDecToString{\xintREZ{#1}}} +</pre> +<p>we get this expanded form:</p> +<pre class="literal-block"> +x^41 +-28.7*x^39 ++375.7117*x^37 +-2975.11006*x^35 ++15935.28150578*x^33 +-61167.527674162*x^31 ++173944.259366417394*x^29 +-373686.963560544648*x^27 ++613012.0665016658846445*x^25 +-771182.31133138163125495*x^23 ++743263.86672885754888959569*x^21 +-545609.076599482896371978698*x^19 ++301748.325708943677229642930528*x^17 +-123655.8987669450434698869844544*x^15 ++36666.1782054884005855608205864192*x^13 +-7607.85821367459445649518380016128*x^11 ++1053.15135918687298508885950223794176*x^9 +-90.6380005918141132650786081964032*x^7 ++4.33701563847327366842552218288128*x^5 +-0.0944770968420804735498178265088*x^3 ++0.00059190121813899276854174416896*x +</pre> +<p>which shows coefficients with up to 36 significant digits...</p> +<p>Stress test: not a hard challenge to <tt class="docutils literal">xint + polexpr</tt>, but be a bit patient!</p> +<pre class="literal-block"> +\PolDef{P}{mul((x-i*1e-1), i=-20..20)}% +\PolToSturm{P}{S} % dutifully computes S_0, ..., S_{41} +% the [1] optional argument limits the search to interval (-10,10) +\PolSturmIsolateZeros[1]{S} % finds *exactly* (but a bit slowly) all 41 roots! +\PolPrintIntervals{S} % nice, isn't it? +</pre> +<div class="admonition note"> +<p class="first admonition-title">Note</p> +<p>Release <tt class="docutils literal">0.5</tt> has <em>experimental</em> addition of optional argument +<tt class="docutils literal">E</tt> to <tt class="docutils literal">\PolSturmIsolateZeros</tt>. It instructs to search roots only +in interval <tt class="docutils literal"><span class="pre">(-10^E,</span> 10^E)</tt>. Important: the extremities are +<em>assumed to not be roots</em>. In this example, the <tt class="docutils literal">[1]</tt> in +<tt class="docutils literal"><span class="pre">\PolSturmIsolateZeros[1]{S}</span></tt> gives some speed gain; without it, it +turns out in this case that <tt class="docutils literal">polexpr</tt> would have started with +<tt class="docutils literal"><span class="pre">(-10^6,</span> 10^6)</tt> interval.</p> +<p class="last">Please note that this will probably get replaced in future by the +specification of a general interval. Do not rely on meaning of this +optional argument keeping the same.</p> +</div> +</div> +<div class="section" id="roots-of-chebyshev-polynomials"> +<h2><a class="toc-backref" href="#id48">Roots of Chebyshev polynomials</a></h2> +<pre class="literal-block"> +\newcount\mycount +\poldef T_0(x) := 1; +\poldef T_1(x) := x; +\mycount 2 +\xintloop + \poldef T_\the\mycount(x) := + 2x*T_\the\numexpr\mycount-1(x) + - T_\the\numexpr\mycount-2(x); +\ifnum\mycount<15 +\advance\mycount 1 +\repeat + +\[T_{15} = \PolTypeset[X]{T_15}\] +\PolToSturm{T_15}{T_15} +\PolSturmIsolateZeros{T_15} +\PolEnsureIntervalLengths{T_15}{-10} +\PolPrintIntervals{T_15} +</pre> +</div> +</div> +<div class="section" id="non-expandable-macros"> +<h1><a class="toc-backref" href="#id49">Non-expandable macros</a></h1> +<div class="section" id="poldef-polname-letter-expression-in-letter"> +<span id="poldef"></span><h2><a class="toc-backref" href="#id50"><tt class="docutils literal">\poldef <span class="pre">polname(letter):=</span> expression in letter;</tt></a></h2> +<blockquote> +<p>This evaluates the <em>polynomial expression</em> and stores the coefficients +in a private structure accessible later via other package macros, +under the user-chosen <tt class="docutils literal">polname</tt>. Of course the <em>expression</em> can +use other previously defined polynomials. Names must start with a +letter and are constituted of letters, digits, underscores and +(since <tt class="docutils literal">0.5.1</tt>) the right tick <tt class="docutils literal">'</tt>. +The whole <a class="reference external" href="http://www.ctan.org/pkg/xint">xintexpr</a> syntax is authorized:</p> +<pre class="literal-block"> +\poldef sin(z) := add((-1)^i z^(2i+1)/(2i+1)!, i = 0..10); +</pre> +<p>With fractional coefficients, beware the <a class="reference internal" href="#warningtacit">tacit multiplication issue</a>.</p> +<p>As a side effect the function <tt class="docutils literal">polname()</tt> is recognized as a +genuine <tt class="docutils literal"><span class="pre">\xintexpr...\relax</span></tt> function for (exact) numerical +evaluation (or within an <tt class="docutils literal">\xintdefvar</tt> assignment.) It computes +values not according to the original expression but via the Horner +scheme corresponding to the polynomial coefficients.</p> +<div class="admonition attention"> +<p class="first admonition-title">Attention!</p> +<p>Release <tt class="docutils literal">0.3</tt> also did the necessary set-up to let the +polynomial be known to the <tt class="docutils literal">\xintfloatexpr</tt> (or +<tt class="docutils literal">\xintdeffloatvar</tt>) parser.</p> +<p>Since <tt class="docutils literal">0.4</tt> this isn't done automatically. Even more, a +previously existing floating point variant 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 <tt class="docutils literal">\poldef</tt> or <tt class="docutils literal">\PolDef</tt> but as +a product of the other package macros.</p> +<p class="last">See <a class="reference internal" href="#polgenfloatvariant-polname">\PolGenFloatVariant{polname}</a>.</p> +</div> +<p>The original expression is lost after parsing, and in particular +the package provides no way to typeset it. This has to be done +manually, if needed.</p> +</blockquote> +</div> +<div class="section" id="poldef-letter-polname-expression-in-letter"> +<span id="id2"></span><h2><a class="toc-backref" href="#id51"><tt class="docutils literal"><span class="pre">\PolDef[letter]{polname}{expression</span> in letter}</tt></a></h2> +<blockquote> +Does the same as <a class="reference external" href="poldef;">\poldef</a> in an undelimited macro +format (thus avoiding potential problems with the catcode of the +semi-colon in presence of some packages.) In absence of the +<tt class="docutils literal">[letter]</tt> optional argument, the variable is assumed to be <tt class="docutils literal">x</tt>.</blockquote> +</div> +<div class="section" id="polgenfloatvariant-polname"> +<span id="polgenfloatvariant"></span><h2><a class="toc-backref" href="#id52"><tt class="docutils literal">\PolGenFloatVariant{polname}</tt></a></h2> +<blockquote> +<p>Makes the polynomial also usable in the <tt class="docutils literal">\xintfloatexpr</tt> parser. +It will therein evaluates via an Horner scheme with coefficients +already pre-rounded to the float precision.</p> +<p>See also <a class="reference internal" href="#poltofloatexpr-polname">\PolToFloatExpr{polname}</a>.</p> +<div class="admonition attention"> +<p class="first admonition-title">Attention!</p> +<p>Release <tt class="docutils literal">0.3</tt> did this automatically on <tt class="docutils literal">\PolDef</tt> and +<tt class="docutils literal">\poldef</tt> but this was removed at <tt class="docutils literal">0.4</tt> for optimization.</p> +<p class="last">Any operation, for example generating the derivative polynomial, +or dividing two polynomials or using the <tt class="docutils literal">\PolLet</tt>, <strong>must</strong> be +followed by explicit usage of <tt class="docutils literal">\PolGenFloatVariant{polname}</tt> if +the new polynomial is to be used in <tt class="docutils literal">\xintfloatexpr</tt> or alike +context.</p> +</div> +</blockquote> +</div> +<div class="section" id="pollet-polname-2-polname-1"> +<span id="pollet"></span><h2><a class="toc-backref" href="#id53"><tt class="docutils literal"><span class="pre">\PolLet{polname_2}={polname_1}</span></tt></a></h2> +<blockquote> +Makes a copy of the already defined polynomial <tt class="docutils literal">polname_1</tt> to a +new one <tt class="docutils literal">polname_2</tt>. Same effect as +<tt class="docutils literal"><span class="pre">\PolDef{polname_2}{polname_1(x)}</span></tt> but with less overhead. The +<tt class="docutils literal">=</tt> is optional.</blockquote> +</div> +<div class="section" id="polgloballet-polname-2-polname-1"> +<span id="polgloballet"></span><h2><a class="toc-backref" href="#id54"><tt class="docutils literal"><span class="pre">\PolGlobalLet{polname_2}={polname_1}</span></tt></a></h2> +<blockquote> +Acts globally.</blockquote> +</div> +<div class="section" id="polassign-polname-toarray-macro"> +<span id="polassign"></span><h2><a class="toc-backref" href="#id55"><tt class="docutils literal"><span class="pre">\PolAssign{polname}\toarray\macro</span></tt></a></h2> +<blockquote> +<p>Defines a one-argument expandable macro <tt class="docutils literal"><span class="pre">\macro{#1}</span></tt> which expands +to the (raw) #1th polynomial coefficient.</p> +<ul class="simple"> +<li>Attention, coefficients here are indexed starting at 1.</li> +<li>With #1=-1, -2, ..., <tt class="docutils literal"><span class="pre">\macro{#1}</span></tt> returns leading coefficients.</li> +<li>With #1=0, returns the number of coefficients, i.e. <tt class="docutils literal">1 + deg f</tt> +for non-zero polynomials.</li> +<li>Out-of-range #1's return <tt class="docutils literal">0/1[0]</tt>.</li> +</ul> +<p>See also <a class="reference internal" href="#polnthcoeff-polname-number">\PolNthCoeff{polname}{number}</a>. The main difference is that +with <tt class="docutils literal">\PolAssign</tt>, <tt class="docutils literal">\macro</tt> is made a prefix to <tt class="docutils literal">1 + deg f</tt> +already defined (hidden to user) macros holding individually the +coefficients but <a class="reference internal" href="#polnthcoeff-polname-number">\PolNthCoeff{polname}{number}</a> does each time the job +to expandably recover the <tt class="docutils literal">Nth</tt> coefficient, and due to +expandability can not store it in a macro for future usage (of course, +it can be an argument in an <tt class="docutils literal">\edef</tt>.) The other difference +is the shift by one in indexing, mentioned above (negative +indices act the same in both.)</p> +</blockquote> +</div> +<div class="section" id="polget-polname-fromarray-macro"> +<span id="polget"></span><h2><a class="toc-backref" href="#id56"><tt class="docutils literal"><span class="pre">\PolGet{polname}\fromarray\macro</span></tt></a></h2> +<blockquote> +<p>Does the converse operation to +<tt class="docutils literal"><span class="pre">\PolAssign{polname}\toarray\macro</span></tt>. Each individual +<tt class="docutils literal">\macro{number}</tt> gets expanded in an <tt class="docutils literal">\edef</tt> and then normalized +via <a class="reference external" href="http://www.ctan.org/pkg/xint">xintfrac</a>'s macro <tt class="docutils literal">\xintRaw</tt>.</p> +<p>The leading zeros are removed from the polynomial.</p> +<p>(contrived) Example:</p> +<pre class="literal-block"> +\xintAssignArray{1}{-2}{5}{-3}\to\foo +\PolGet{f}\fromarray\foo +</pre> +<p>This will define <tt class="docutils literal">f</tt> as would have <tt class="docutils literal">\poldef <span class="pre">f(x):=1-2x+5x^2-3x^3;</span></tt>.</p> +<div class="admonition note"> +<p class="first admonition-title">Note</p> +<p class="last">Prior to <tt class="docutils literal">0.5</tt>, coefficients were not normalized via +<tt class="docutils literal">\xintRaw</tt> for internal storage.</p> +</div> +</blockquote> +</div> +<div class="section" id="polfromcsv-polname-csv"> +<span id="polfromcsv"></span><h2><a class="toc-backref" href="#id57"><tt class="docutils literal"><span class="pre">\PolFromCSV{polname}{<csv>}</span></tt></a></h2> +<blockquote> +<p>Defines a polynomial directly from the comma separated list of values +(or a macro expanding to such a list) of its coefficients, the <em>first +item</em> gives the constant term, the <em>last item</em> gives the leading +coefficient, except if zero, then it is dropped (iteratively). List +items are each expanded in an <tt class="docutils literal">\edef</tt> and then put into normalized +form via <a class="reference external" href="http://www.ctan.org/pkg/xint">xintfrac</a>'s macro <tt class="docutils literal">\xintRaw</tt>.</p> +<p>As leading zero coefficients are removed:</p> +<pre class="literal-block"> +\PolFromCSV{f}{0, 0, 0, 0, 0, 0, 0, 0, 0, 0} +</pre> +<p>defines the zero polynomial, which holds only one coefficient.</p> +<p>See also expandable macro <a class="reference internal" href="#poltocsv-polname">\PolToCSV</a>.</p> +<div class="admonition note"> +<p class="first admonition-title">Note</p> +<p class="last">Prior to <tt class="docutils literal">0.5</tt>, coefficients were not normalized via +<tt class="docutils literal">\xintRaw</tt> for internal storage.</p> +</div> +</blockquote> +</div> +<div class="section" id="poltypeset-polname"> +<span id="poltypeset"></span><h2><a class="toc-backref" href="#id58"><tt class="docutils literal">\PolTypeset{polname}</tt></a></h2> +<blockquote> +<p>Typesets in descending powers in math mode. It uses letter <tt class="docutils literal">x</tt> but +this can be changed via an optional argument:</p> +<pre class="literal-block"> +\PolTypeset[z]{polname} +</pre> +<p>By default zero coefficients are skipped (issue <tt class="docutils literal">\poltypesetalltrue</tt> +to get all of them in output).</p> +<p>These commands (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.</p> +</blockquote> +<div class="section" id="poltypesetcmd-raw-coeff"> +<span id="poltypesetcmd"></span><h3><a class="toc-backref" href="#id59"><tt class="docutils literal">\PolTypesetCmd{raw_coeff}</tt></a></h3> +<blockquote> +<p>Checks if the coefficient is <tt class="docutils literal">1</tt> or <tt class="docutils literal"><span class="pre">-1</span></tt> and then skips printing +the <tt class="docutils literal">1</tt>, except for the constant term. Also it sets conditional +<a class="reference internal" href="#polifcoeffisplusorminusone-a-b">\PolIfCoeffIsPlusOrMinusOne{A}{B}</a>.</p> +<p>The actual printing of the coefficients, when not equal to plus or +minus one is handled by <a class="reference internal" href="#poltypesetone-raw-coeff">\PolTypesetOne{raw_coeff}</a>.</p> +</blockquote> +</div> +<div class="section" id="poltypesetone-raw-coeff"> +<span id="poltypesetone"></span><h3><a class="toc-backref" href="#id60"><tt class="docutils literal">\PolTypesetOne{raw_coeff}</tt></a></h3> +<blockquote> +<p>The default is <tt class="docutils literal">\xintSignedFrac</tt> but this macro is annoying as it +insists to use a power of ten, and not decimal notation.</p> +<p>One can do things such as for example: <a class="footnote-reference" href="#id5" id="id4">[1]</a></p> +<pre class="literal-block"> +\renewcommand\PolTypesetOne[1]{\num{\xintPFloat[5]{#1}}} +\renewcommand\PolTypesetOne[1]{\num{\xintRound{4}{#1}}} +</pre> +<p>where e.g. we used the <tt class="docutils literal">\num</tt> macro of <tt class="docutils literal">siunitx</tt> as it +understands floating point notation.</p> +<table class="docutils footnote" frame="void" id="id5" rules="none"> +<colgroup><col class="label" /><col /></colgroup> +<tbody valign="top"> +<tr><td class="label"><a class="fn-backref" href="#id4">[1]</a></td><td>the difference in the syntaxes of <tt class="docutils literal">\xintPFloat</tt> and +<tt class="docutils literal">\xintRound</tt> is explained from the fact that +<tt class="docutils literal">\xintPFloat</tt> by default uses the prevailing precision +hence the extra argument like here <tt class="docutils literal">5</tt> is an optional one.</td></tr> +</tbody> +</table> +<p>One can also give a try to using <a class="reference internal" href="#poldectostring-decimal-number">\PolDecToString{decimal number}</a> +which uses decimal notation (at least for the numerator part).</p> +</blockquote> +</div> +<div class="section" id="id6"> +<span id="poltypesetmonomialcmd"></span><h3><a class="toc-backref" href="#id61"><tt class="docutils literal">\PolTypesetMonomialCmd</tt></a></h3> +<blockquote> +This decides how a monomial (in variable <tt class="docutils literal">\PolVar</tt> and with +exponent <tt class="docutils literal">\PolIndex</tt>) is to be printed. The default does nothing +for the constant term, <tt class="docutils literal">\PolVar</tt> for the first degree and +<tt class="docutils literal"><span class="pre">\PolVar^{\PolIndex}</span></tt> for higher degrees monomials. Beware that +<tt class="docutils literal">\PolIndex</tt> expands to digit tokens and needs termination in +<tt class="docutils literal">\ifnum</tt> tests.</blockquote> +</div> +<div class="section" id="poltypesetcmdprefix-raw-coeff"> +<span id="poltypesetcmdprefix"></span><h3><a class="toc-backref" href="#id62"><tt class="docutils literal">\PolTypesetCmdPrefix{raw_coeff}</tt></a></h3> +<blockquote> +Expands to a <tt class="docutils literal">+</tt> if the <tt class="docutils literal">raw_coeff</tt> is zero or positive, and to +nothing if <tt class="docutils literal">raw_coeff</tt> is negative, as in latter case the +<tt class="docutils literal">\xintSignedFrac</tt> used by <a class="reference internal" href="#poltypesetcmd-raw-coeff">\PolTypesetCmd{raw_coeff}</a> will put +the <tt class="docutils literal">-</tt> 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.</blockquote> +</div> +</div> +<div class="section" id="id8"> +<span id="id7"></span><h2><a class="toc-backref" href="#id63"><tt class="docutils literal"><span class="pre">\PolTypeset*{polname}</span></tt></a></h2> +<blockquote> +Typesets in ascending powers. Use e.g. <tt class="docutils literal">[h]</tt> optional argument +(after the <tt class="docutils literal">*</tt>) to use letter <tt class="docutils literal">h</tt> rather than <tt class="docutils literal">x</tt>.</blockquote> +</div> +<div class="section" id="poldiff-polname-1-polname-2"> +<span id="poldiff"></span><h2><a class="toc-backref" href="#id64"><tt class="docutils literal"><span class="pre">\PolDiff{polname_1}{polname_2}</span></tt></a></h2> +<blockquote> +<p>This sets <tt class="docutils literal">polname_2</tt> to the first derivative of <tt class="docutils literal">polname_1</tt>. It +is allowed to issue <tt class="docutils literal"><span class="pre">\PolDiff{f}{f}</span></tt>, effectively replacing <tt class="docutils literal">f</tt> +by <tt class="docutils literal">f'</tt>.</p> +<p>Coefficients of the result <tt class="docutils literal">polname_2</tt> are irreducible fractions +(see <a class="reference internal" href="#technicalities">Technicalities</a> for the whole story.)</p> +</blockquote> +</div> +<div class="section" id="poldiff-n-polname-1-polname-2"> +<span id="poldiff-n"></span><h2><a class="toc-backref" href="#id65"><tt class="docutils literal"><span class="pre">\PolDiff[N]{polname_1}{polname_2}</span></tt></a></h2> +<blockquote> +This sets <tt class="docutils literal">polname_2</tt> to the <tt class="docutils literal">N</tt>-th derivative of <tt class="docutils literal">polname_1</tt>. +Identical arguments is allowed. With <tt class="docutils literal">N=0</tt>, same effect as +<tt class="docutils literal"><span class="pre">\PolLet{polname_2}={polname_1}</span></tt>. With negative <tt class="docutils literal">N</tt>, switches to +using <tt class="docutils literal">\PolAntiDiff</tt>.</blockquote> +</div> +<div class="section" id="polantidiff-polname-1-polname-2"> +<span id="polantidiff"></span><h2><a class="toc-backref" href="#id66"><tt class="docutils literal"><span class="pre">\PolAntiDiff{polname_1}{polname_2}</span></tt></a></h2> +<blockquote> +<p>This sets <tt class="docutils literal">polname_2</tt> to the primitive of <tt class="docutils literal">polname_1</tt> vanishing +at zero.</p> +<p>Coefficients of the result <tt class="docutils literal">polname_2</tt> are irreducible fractions +(see <a class="reference internal" href="#technicalities">Technicalities</a> for the whole story.)</p> +</blockquote> +</div> +<div class="section" id="polantidiff-n-polname-1-polname-2"> +<span id="polantidiff-n"></span><h2><a class="toc-backref" href="#id67"><tt class="docutils literal"><span class="pre">\PolAntiDiff[N]{polname_1}{polname_2}</span></tt></a></h2> +<blockquote> +This sets <tt class="docutils literal">polname_2</tt> to the result of <tt class="docutils literal">N</tt> successive integrations on +<tt class="docutils literal">polname_1</tt>. With negative <tt class="docutils literal">N</tt>, it switches to using <tt class="docutils literal">\PolDiff</tt>.</blockquote> +</div> +<div class="section" id="poldivide-polname-1-polname-2-polname-q-polname-r"> +<span id="poldivide"></span><h2><a class="toc-backref" href="#id68"><tt class="docutils literal"><span class="pre">\PolDivide{polname_1}{polname_2}{polname_Q}{polname_R}</span></tt></a></h2> +<blockquote> +This sets <tt class="docutils literal">polname_Q</tt> and <tt class="docutils literal">polname_R</tt> to be the quotient and +remainder in the Euclidean division of <tt class="docutils literal">polname_1</tt> by +<tt class="docutils literal">polname_2</tt>.</blockquote> +</div> +<div class="section" id="polquo-polname-1-polname-2-polname-q"> +<span id="polquo"></span><h2><a class="toc-backref" href="#id69"><tt class="docutils literal"><span class="pre">\PolQuo{polname_1}{polname_2}{polname_Q}</span></tt></a></h2> +<blockquote> +This sets <tt class="docutils literal">polname_Q</tt> to be the quotient in the Euclidean division +of <tt class="docutils literal">polname_1</tt> by <tt class="docutils literal">polname_2</tt>.</blockquote> +</div> +<div class="section" id="polrem-polname-1-polname-2-polname-r"> +<span id="polrem"></span><h2><a class="toc-backref" href="#id70"><tt class="docutils literal"><span class="pre">\PolRem{polname_1}{polname_2}{polname_R}</span></tt></a></h2> +<blockquote> +This sets <tt class="docutils literal">polname_R</tt> to be the remainder in the Euclidean division +of <tt class="docutils literal">polname_1</tt> by <tt class="docutils literal">polname_2</tt>.</blockquote> +</div> +<div class="section" id="polgcd-polname-1-polname-2-polname-gcd"> +<span id="polgcd"></span><h2><a class="toc-backref" href="#id71"><tt class="docutils literal"><span class="pre">\PolGCD{polname_1}{polname_2}{polname_GCD}</span></tt></a></h2> +<blockquote> +This sets <tt class="docutils literal">polname_GCD</tt> to be the (monic) GCD of the two first +polynomials. It is a unitary polynomial except if both <tt class="docutils literal">polname_1</tt> +and <tt class="docutils literal">polname_2</tt> vanish, then <tt class="docutils literal">polname_GCD</tt> is the zero +polynomial.</blockquote> +<!-- ``\PolIGCD{polname_1}{polname_2}{polname_iGCD}`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + **NOT YET** + + This **assumes** that the two polynomials have integer coefficients. + It then computes the greatest common divisor in the integer + polynomial ring, normalized to have a positive leading coefficient + (if the inputs are not both zero). + +``\PolIContent{polname}`` +~~~~~~~~~~~~~~~~~~~~~~~~~ + + **NOT YET** + + This computes a positive rational number such that dividing the + polynomial with it returns an integer coefficients polynomial with + no common factor among the coefficients. --> +</div> +<div class="section" id="poltosturm-polname-sturmname"> +<span id="poltosturm"></span><h2><a class="toc-backref" href="#id72"><tt class="docutils literal"><span class="pre">\PolToSturm{polname}{sturmname}</span></tt></a></h2> +<blockquote> +<p>With <tt class="docutils literal">polname</tt> being for example <tt class="docutils literal">P</tt>, the macro starts by +computing polynomials <tt class="docutils literal">P</tt> and <tt class="docutils literal">P'</tt>, then computes the (opposite +of the) remainder in euclidean division, iteratively.</p> +<p>The last non-zero remainder <tt class="docutils literal">P_N_</tt> (where <tt class="docutils literal">N</tt> is obtainable as +<a class="reference internal" href="#polsturmchainlength-sturmname">\PolSturmChainLength{sturmname}</a>) is up to a factor +the GCD of <tt class="docutils literal">P</tt> and <tt class="docutils literal">P'</tt> hence it is a constant if and only if +<tt class="docutils literal">P</tt> is square-free.</p> +<div class="admonition note"> +<p class="first admonition-title">Note</p> +<ul class="last simple"> +<li>Since <tt class="docutils literal">0.5</tt> all these polynomials are divided by their rational +content, so they have integer coefficients with no common factor, +and the last one if a constant is either <tt class="docutils literal">1</tt> or <tt class="docutils literal"><span class="pre">-1</span></tt>.</li> +<li>After this normalization to primitive polynomials, they are +stored internally as <tt class="docutils literal">sturmname_k_</tt>, <tt class="docutils literal">k=0,1, ...</tt>.</li> +<li>These polynomials are used internally only. To keep them as +genuine declared polynomials also after the macro call, use the +starred variant <a class="reference internal" href="#id9">PolToSturm*</a>.</li> +</ul> +</div> +<div class="admonition note"> +<p class="first admonition-title">Note</p> +<p class="last">It is perfectly allowed to use the polynomial name as Sturm chain name: +<tt class="docutils literal"><span class="pre">\PolToSturm{f}(f}</span></tt>.</p> +</div> +<p>The macro then declares <tt class="docutils literal">sturmname_0</tt>, <tt class="docutils literal">sturmname_1</tt>, ..., which are +the (non-declared) <tt class="docutils literal">sturmname_k_</tt> divided by the last one. Division is +not done if this last one is the constant <tt class="docutils literal">1</tt> or <tt class="docutils literal"><span class="pre">-1</span></tt>, i.e. if the +original polynomial was square-free. These polynomials are primitive +polynomials too, i.e. with integer coefficients having no common factor.</p> +<p>Thus <tt class="docutils literal">sturmname_0</tt> has exactly the same real and complex roots as +polynomial <tt class="docutils literal">polname</tt>, but with each root now of multiplicity one: +i.e. it is the "square-free part" of original polynomial <tt class="docutils literal">polname</tt>.</p> +<p>Notice that <tt class="docutils literal">sturmname_1</tt> isn't necessarily the derivative of +<tt class="docutils literal">sturmname_0</tt> due to the various normalizations.</p> +<p>The polynomials <tt class="docutils literal">sturmname_k</tt> main utility is for the execution of +<a class="reference internal" href="#polsturmisolatezeros-sturmname">\PolSturmIsolateZeros{sturmname}</a>. Be careful not to use these +names <tt class="docutils literal">sturmname_0</tt>, <tt class="docutils literal">sturmname_1</tt>, etc... for defining other +polynomials after having done <tt class="docutils literal"><span class="pre">\PolToSturm{polname}{sturmname}</span></tt> and +before executing <tt class="docutils literal">\PolSturmIsolateZeros{sturmname}</tt> else the +latter will behave erroneously.</p> +<p><a class="reference internal" href="#polsturmchainlength-sturmname">\PolSturmChainLength{sturmname}</a> gives the index of the last +element of the Sturm chain.</p> +</blockquote> +</div> +<div class="section" id="id10"> +<span id="id9"></span><h2><a class="toc-backref" href="#id73"><tt class="docutils literal"><span class="pre">\PolToSturm*{polname}{sturmname}</span></tt></a></h2> +<blockquote> +<p>Does the same as <a class="reference internal" href="#poltosturm">un-starred version</a> and additionally it +keeps for user usage the memory of the <em>un-normalized</em> Sturm chain +polynomials <tt class="docutils literal">sturmname_k_</tt>, <tt class="docutils literal">k=0,1, <span class="pre">...,</span> N</tt>, with +<tt class="docutils literal">N</tt> being <a class="reference internal" href="#polsturmchainlength-sturmname">\PolSturmChainLength{sturmname}</a>.</p> +<div class="admonition note"> +<p class="first admonition-title">Note</p> +<p class="last">This behaviour was modified at <tt class="docutils literal">0.6</tt>, anyhow the macro was +broken at <tt class="docutils literal">0.5</tt>.</p> +</div> +<div class="admonition hint"> +<p class="first admonition-title">Hint</p> +<p class="last">The square-free part of <tt class="docutils literal">polname</tt> is <tt class="docutils literal">sturmname_0</tt>, and their +quotient is the polynomial with name +<tt class="docutils literal">sturname_\PolSturmChainLength{sturmname}_</tt>. 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 <tt class="docutils literal">f</tt> as +a product <tt class="docutils literal">c f_1 f_2 f_3 ...</tt> of a constant and square-free (primitive) +polynomials, where each <tt class="docutils literal">f_i</tt> divides its predecessor.</p> +</div> +</blockquote> +</div> +<div class="section" id="polsettosturmchainsignchangesat-macro-sturmname-fraction"> +<span id="polsettosturmchainsignchangesat"></span><h2><a class="toc-backref" href="#id74"><tt class="docutils literal"><span class="pre">\PolSetToSturmChainSignChangesAt{\macro}{sturmname}{fraction}</span></tt></a></h2> +<blockquote> +<p>Sets macro <tt class="docutils literal">\macro</tt> to the number of sign changes in the Sturm +chain with name prefix <tt class="docutils literal">sturmname</tt>, at location <tt class="docutils literal">fraction</tt> +(which must be in format as acceptable by the <a class="reference external" href="http://www.ctan.org/pkg/xint">xintfrac</a> macros.)</p> +<div class="admonition note"> +<p class="first admonition-title">Note</p> +<p>The author was lazy and did not provide rather an expandable +variant, where one would do <tt class="docutils literal"><span class="pre">\edef\macro{\PolNbOf...}</span></tt>.</p> +<p>This will presumably get added in a future release.</p> +<p class="last">After some hesitation it was decided the macro would by default +act globally. To make the scope of its macro definition local, +use <tt class="docutils literal">[\empty]</tt> as extra optional argument.</p> +</div> +</blockquote> +</div> +<div class="section" id="polsettonbofzeroswithin-macro-sturmname-value-a-value-b"> +<span id="polsettonbofzeroswithin"></span><h2><a class="toc-backref" href="#id75"><tt class="docutils literal"><span class="pre">\PolSetToNbOfZerosWithin{\macro}{sturmname}{value_a}{value_b}</span></tt></a></h2> +<blockquote> +<p>Applies the <a class="reference external" href="https://en.wikipedia.org/wiki/Sturm%27s_theorem">Sturm Theorem</a> to set <tt class="docutils literal">\macro</tt> to the exact number +of <strong>distinct</strong> roots of <tt class="docutils literal">sturmname_0</tt> in the interval <tt class="docutils literal">(value_a, +value_b]</tt> (the macro first re-orders the value for <tt class="docutils literal">value_a <= +value_b</tt> to hold).</p> +<div class="admonition note"> +<p class="first admonition-title">Note</p> +<p>The author was lazy and did not provide rather an expandable +variant, where one would do <tt class="docutils literal"><span class="pre">\edef\macro{\PolNbOf...}</span></tt>.</p> +<p>This will presumably get added in future.</p> +<p class="last">After some hesitation it was decided the macro would by default +act globally. To make the scope of its macro definition local, +use <tt class="docutils literal">[\empty]</tt> as extra optional argument.</p> +</div> +<p>See also the expandable +<a class="reference internal" href="#polsturmnbofrootsof-sturmname-lessthanorequalto-value">\PolSturmNbOfRootsOf{sturmname}\LessThanOrEqualTo{value}</a>, from +which it is immediate (with <tt class="docutils literal">\numexpr</tt>) to create an expandable +variant of this macro. However the difference is that this macro +requires only <a class="reference internal" href="#poltosturm">\PolToSturm</a> to have been executed, +whereas the expandable variant requires prior execution of +<a class="reference internal" href="#polsturmisolatezeros">\PolSturmIsolateZeros</a>.</p> +<p>See also the expandable +<a class="reference internal" href="#polsturmnbwithmultofrootsof-sturmname-lessthanorequalto-value">\PolSturmNbWithMultOfRootsOf{sturmname}\LessThanOrEqualTo{value}</a> +which requires prior execution of +<a class="reference internal" href="#id11">\PolSturmIsolateZeros*</a>.</p> +</blockquote> +</div> +<div class="section" id="polsturmisolatezeros-sturmname"> +<span id="polsturmisolatezeros"></span><h2><a class="toc-backref" href="#id76"><tt class="docutils literal">\PolSturmIsolateZeros{sturmname}</tt></a></h2> +<blockquote> +<p>The macros locates, using <a class="reference external" href="https://en.wikipedia.org/wiki/Sturm%27s_theorem">Sturm theorem</a>, as many disjoint +intervals as there are (real) roots.</p> +<div class="admonition important"> +<p class="first admonition-title">Important</p> +<p>The Sturm chain must have been produced by an earlier +<a class="reference internal" href="#poltosturm-polname-sturmname">\PolToSturm{polname}{sturmname}</a>.</p> +<p>Why does this macro ask for argument the name of Sturm chain, +rather than the name of a polynomial? well this is mainly for +legacy reason, and because it is accompanied by other macros for +which it is simpler to assume the argument will be the name of an +already computed Sturm chain.</p> +<p>Notice that <tt class="docutils literal"><span class="pre">\PolToSturm{f}{f}</span></tt> is perfectly legal (the +<tt class="docutils literal">sturmname</tt> can be same as the <tt class="docutils literal">polname</tt>): it defines +polynomials <tt class="docutils literal">f_0</tt>, <tt class="docutils literal">f_1</tt>, ... having <tt class="docutils literal">f</tt> has name prefix.</p> +<p class="last">Such a prior call +to <tt class="docutils literal">\PolToSturm</tt> must have been made at any rate for +<tt class="docutils literal">\PolSturmIsolateZeros</tt> to be usable.</p> +</div> +<p>After its execution they are two types of such intervals (stored in +memory and accessible via macros or <a class="reference external" href="http://www.ctan.org/pkg/xint">xintexpr</a> variables, see below):</p> +<ul class="simple"> +<li>singleton <tt class="docutils literal">{a}</tt>: then <tt class="docutils literal">a</tt> is a root, (necessarily a decimal +number, but not all such decimal numbers are exactly identified yet).</li> +<li>open intervals <tt class="docutils literal">(a,b)</tt>: then there is exactly one root <tt class="docutils literal">z</tt> +such that <tt class="docutils literal">a < z < b</tt>, and the end points are guaranteed to not +be roots.</li> +</ul> +<p>The interval boundaries are decimal numbers, originating +in iterated decimal subdivision from initial intervals +<tt class="docutils literal"><span class="pre">(-10^E,</span> 0)</tt> and <tt class="docutils literal">(0, 10^E)</tt> with <tt class="docutils literal">E</tt> 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 <tt class="docutils literal">(a/10^f, <span class="pre">(a+1)/10^f)</span></tt> with <tt class="docutils literal">a</tt> an integer, which is +neither <tt class="docutils literal">0</tt> nor <tt class="docutils literal"><span class="pre">-1</span></tt>. Hence either <tt class="docutils literal">a</tt> and <tt class="docutils literal">a+1</tt> are both positive +or they are both negative.</p> +<p>One does not <em>a priori</em> 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.</p> +<div class="admonition important"> +<p class="first admonition-title">Important</p> +<p>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.</p> +<p class="last">See <a class="reference internal" href="#polrefineinterval-sturmname-index">\PolRefineInterval*{sturmname}{index}</a> which addresses +this issue.</p> +</div> +<!-- This procedure is covariant +with the independent variable ``x`` becoming ``-x``. +Hmm, pas sûr et trop fatigué --> +<p>The interval boundaries (and exactly found roots) are made available +for future computations in <tt class="docutils literal">\xintexpr</tt>-essions or polynomial +definitions as variables <tt class="docutils literal"><sturmname>L_1</tt>, +<tt class="docutils literal"><sturmname>L_2</tt>, etc..., for the left end-points and +<tt class="docutils literal"><sturmname>R_1</tt>, <tt class="docutils literal"><sturmname>R_2</tt>, ..., for the right +end-points.</p> +<p>Thus for example, if <tt class="docutils literal">sturmname</tt> is <tt class="docutils literal">f</tt>, one can use the +<a class="reference external" href="http://www.ctan.org/pkg/xint">xintexpr</a> variables <tt class="docutils literal">fL_1</tt>, <tt class="docutils literal">fL_2</tt>, ... to refer in expressions +to the left end-points (or to the exact root, if left and right end +points coincide). Additionally, <a class="reference external" href="http://www.ctan.org/pkg/xint">xintexpr</a> variable <tt class="docutils literal">fZ_1_isknown</tt> +will have value <tt class="docutils literal">1</tt> if the root in the first interval is known, +and <tt class="docutils literal">0</tt> otherwise. And similarly for the other intervals.</p> +<p>Also, macros <a class="reference internal" href="#polsturmisolatedzeroleft-sturmname-index">\PolSturmIsolatedZeroLeft{sturmname}{index}</a> and +<a class="reference internal" href="#polsturmisolatedzeroright-sturmname-index">\PolSturmIsolatedZeroRight{sturmname}{index}</a> are provided which +expand to these same values, written in decimal notation (i.e. +pre-processed by <a class="reference internal" href="#poldectostring">\PolDecToString</a>.) And there +is also <a class="reference internal" href="#polsturmifzeroexactlyknown-sturmname-index-a-b">\PolSturmIfZeroExactlyKnown{sturmname}{index}{A}{B}</a>.</p> +<div class="admonition important"> +<p class="first admonition-title">Important</p> +<p class="last">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.</p> +</div> +<p>These variables and macros are automatically updated when one next +uses macros such as <a class="reference internal" href="#polrefineinterval-sturmname-index">\PolRefineInterval*{sturmname}{index}</a>.</p> +<p>The start of decimal expansion of a positive <tt class="docutils literal">k</tt>-th root is given +by <a class="reference internal" href="#polsturmisolatedzeroleft">\PolSturmIsolatedZeroLeft{sturmname}{k}</a>, and for a negative root it is given +by <a class="reference internal" href="#polsturmisolatedzeroright">PolSturmIsolatedZeroRight{sturmname}{k}</a>. These two decimal +numbers are either both zero or both of the same sign.</p> +<p>The number of distinct roots is obtainable expandably as +<a class="reference internal" href="#polsturmnbofisolatedzeros-sturmname">\PolSturmNbOfIsolatedZeros{sturmname}</a>.</p> +<p>Furthermore +<a class="reference internal" href="#polsturmnbofrootsof-sturmname-lessthanorequalto-value">\PolSturmNbOfRootsOf{sturmname}\LessThanOrEqualTo{value}</a> and +<a class="reference internal" href="#polsturmnbofrootsof-sturmname-lessthanorequaltoexpr-expression">\PolSturmNbOfRootsOf{sturmname}\LessThanOrEqualToExpr{expression}</a>. +will expandably compute respectively the number of real roots at +most equal to <tt class="docutils literal">value</tt> or <tt class="docutils literal">expression</tt>, and the same but with +multiplicities.</p> +<div class="admonition note"> +<p class="first admonition-title">Note</p> +<p class="last">In the current implementation the <a class="reference external" href="http://www.ctan.org/pkg/xint">xintexpr</a> variables +and <a class="reference external" href="http://www.ctan.org/pkg/xint">xinttools</a> arrays are globally defined. On the +other hand the Sturm sequence polynomials obey the current scope.</p> +</div> +<div class="admonition note"> +<p class="first admonition-title">Note</p> +<p>As all computations are done <em>exactly</em> there can be no errors... +apart those due to bad coding by author. The results are exact +bounds for the mathematically exact real roots.</p> +<p class="last">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.</p> +</div> +</blockquote> +</div> +<div class="section" id="id12"> +<span id="id11"></span><h2><a class="toc-backref" href="#id77"><tt class="docutils literal"><span class="pre">\PolSturmIsolateZeros*{sturmname}</span></tt></a></h2> +<blockquote> +<p>The macro does the same as <a class="reference internal" href="#polsturmisolatezeros-sturmname">\PolSturmIsolateZeros{sturmname}</a> and +then in addition it does the extra work to determine all +multiplicities (of the real roots): +after executing this macro, +<a class="reference internal" href="#polsturmisolatedzeromultiplicity-sturmname-index">\PolSturmIsolatedZeroMultiplicity{sturmname}{index}</a> will expand +to the multiplicity of the root located in the <tt class="docutils literal">index</tt>-th +interval (intervals are enumerated from left to right, with index +starting at <tt class="docutils literal">1</tt>).</p> +<p>Furthermore, if for example the <tt class="docutils literal">sturmname</tt> is <tt class="docutils literal">f</tt>, <a class="reference external" href="http://www.ctan.org/pkg/xint">xintexpr</a> +variables <tt class="docutils literal">fM_1</tt>, <tt class="docutils literal">fM_2</tt>... hold the multiplicities thus +computed.</p> +<div class="admonition note"> +<p class="first admonition-title">Note</p> +<p class="last">It is <strong>not</strong> necessary to have executed the <a class="reference internal" href="#id9">PolToSturm*</a> starred +variant, as the non-starred variant keeps internally the memory of the +original GCD (and even of the full non-normalized original Sturm +chain), even though it does not make the declarations as <em>user-level</em> +genuine polynomials.</p> +</div> +<p>See <a class="reference internal" href="#the-degree-nine-polynomial-with-0-99-0-999-0-9999-as-triple-roots">The degree nine polynomial with 0.99, 0.999, 0.9999 as triple +roots</a> for an example.</p> +</blockquote> +</div> +<div class="section" id="id14"> +<span id="id13"></span><h2><a class="toc-backref" href="#id78"><tt class="docutils literal"><span class="pre">\PolSturmIsolateZeros**{sturmname}</span></tt></a></h2> +<blockquote> +<p>The macro does the same as <a class="reference internal" href="#id12">\PolSturmIsolateZeros*{sturmname}</a> and +in addition it does the extra work to determine all the <em>rational</em> +roots.</p> +<div class="admonition note"> +<p class="first admonition-title">Note</p> +<p class="last">After execution of this macro, a root is "known" if and only if +it is rational.</p> +</div> +<p>Furthermore, primitive polynomial <tt class="docutils literal">sturmname_sqf_norr</tt> is created +to match the (square-free) <tt class="docutils literal">sturmname_0</tt> from which all rational +roots have been removed (see <a class="reference internal" href="#polexprsetup">\polexprsetup</a> for customizing this +name). The number of distinct rational roots is thus the difference +between the degrees of these two polynomials (see also +<a class="reference internal" href="#polsturmnbofrationalroots-sturmname">\PolSturmNbOfRationalRoots{sturmname}</a>).</p> +<p>And <tt class="docutils literal">sturmname_norr</tt> is <tt class="docutils literal">sturmname_0_</tt> from which all rational +roots have been removed (see <a class="reference internal" href="#polexprsetup">\polexprsetup</a>), i.e. it contains +the irrational roots of the original polynomial, with the same +multiplicities.</p> +<p>See <a class="reference internal" href="#a-degree-five-polynomial-with-three-rational-roots">A degree five polynomial with three rational +roots</a> for an example.</p> +</blockquote> +</div> +<div class="section" id="polsturmisolatezerosandgetmultiplicities-sturmname"> +<span id="polsturmisolatezerosandgetmultiplicities"></span><h2><a class="toc-backref" href="#id79"><tt class="docutils literal">\PolSturmIsolateZerosAndGetMultiplicities{sturmname}</tt></a></h2> +<blockquote> +This is another name for <a class="reference internal" href="#id12">\PolSturmIsolateZeros*{sturmname}</a>.</blockquote> +</div> +<div class="section" id="polsturmisolatezerosgetmultiplicitiesandrationalroots-sturmname"> +<span id="polsturmisolatezerosgetmultiplicitiesandrationalroots"></span><h2><a class="toc-backref" href="#id80"><tt class="docutils literal">\PolSturmIsolateZerosGetMultiplicitiesAndRationalRoots{sturmname}</tt></a></h2> +<blockquote> +This is another name for <a class="reference internal" href="#id14">\PolSturmIsolateZeros**{sturmname}</a>.</blockquote> +</div> +<div class="section" id="polsturmisolatezerosandfindrationalroots-sturmname"> +<h2><a class="toc-backref" href="#id81"><tt class="docutils literal">\PolSturmIsolateZerosAndFindRationalRoots{sturmname}</tt></a></h2> +<blockquote> +<p>This works exactly like <a class="reference internal" href="#id14">\PolSturmIsolateZeros**{sturmname}</a> +(inclusive of declaring the polynomials <tt class="docutils literal">sturmname_sqf_norr</tt> and +<tt class="docutils literal">sturmname_norr</tt> with no rational roots) except that it does <em>not</em> +compute the multiplicities of the <em>non-rational</em> roots.</p> +<div class="admonition note"> +<p class="first admonition-title">Note</p> +<p class="last">There is no macro to find the rational roots but not compute +their multiplicities at the same time.</p> +</div> +<div class="admonition attention"> +<p class="first admonition-title">Attention!</p> +<p>This macro does <em>not</em> define <a class="reference external" href="http://www.ctan.org/pkg/xint">xintexpr</a> variables +<tt class="docutils literal">sturmnameM_1</tt>, <tt class="docutils literal">sturmnameM_2</tt>, ... holding the +multiplicities and it leaves the multiplicity array (whose accessor +is <a class="reference internal" href="#polsturmisolatedzeromultiplicity-sturmname-index">\PolSturmIsolatedZeroMultiplicity{sturmname}{index}</a>) into +a broken state, as all non-rational roots will supposedly have +multiplicity one. This means that the output of +<a class="reference internal" href="#id18">\PolPrintIntervals*</a> for example will be +erroneous for the intervals with irrational roots.</p> +<p class="last">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 <em>any</em> +rational root anyhow).</p> +</div> +</blockquote> +</div> +<div class="section" id="polrefineinterval-sturmname-index"> +<span id="polrefineinterval"></span><h2><a class="toc-backref" href="#id82"><tt class="docutils literal"><span class="pre">\PolRefineInterval*{sturmname}{index}</span></tt></a></h2> +<blockquote> +The <tt class="docutils literal">index</tt>-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. This means that the <tt class="docutils literal">k</tt>th root is then +strictly separated from the other roots.</blockquote> +</div> +<div class="section" id="polrefineinterval-n-sturmname-index"> +<span id="polrefineinterval-n"></span><h2><a class="toc-backref" href="#id83"><tt class="docutils literal"><span class="pre">\PolRefineInterval[N]{sturmname}{index}</span></tt></a></h2> +<blockquote> +The <tt class="docutils literal">index</tt>-th interval (starting count at one) is further +subdivided once, reducing its length by a factor of 10. This is done +<tt class="docutils literal">N</tt> times if the optional argument <tt class="docutils literal">[N]</tt> is present.</blockquote> +</div> +<div class="section" id="polensureintervallength-sturmname-index-e"> +<span id="polensureintervallength"></span><h2><a class="toc-backref" href="#id84"><tt class="docutils literal"><span class="pre">\PolEnsureIntervalLength{sturmname}{index}{E}</span></tt></a></h2> +<blockquote> +The <tt class="docutils literal">index</tt>-th interval is subdivided until its length becomes at +most <tt class="docutils literal">10^E</tt>. This means (for <tt class="docutils literal">E<0</tt>) that the first <tt class="docutils literal"><span class="pre">-E</span></tt> digits +after decimal mark of the <tt class="docutils literal">k</tt>th root will then be known exactly.</blockquote> +</div> +<div class="section" id="polensureintervallengths-sturmname-e"> +<span id="polensureintervallengths"></span><h2><a class="toc-backref" href="#id85"><tt class="docutils literal"><span class="pre">\PolEnsureIntervalLengths{sturmname}{E}</span></tt></a></h2> +<blockquote> +<p>The intervals as obtained from <tt class="docutils literal">\PolSturmIsolateZeros</tt> are (if +necessary) subdivided further by (base 10) dichotomy in order for +each of them to have length at most <tt class="docutils literal">10^E</tt> (length will be shorter +than <tt class="docutils literal">10^E</tt> in output only if it did not change or became zero.)</p> +<p>This means that decimal expansions of all roots will be known with +<tt class="docutils literal"><span class="pre">-E</span></tt> digits (for <tt class="docutils literal">E<0</tt>) after decimal mark.</p> +</blockquote> +</div> +<div class="section" id="polprintintervals-varname-sturmname"> +<span id="polprintintervals"></span><h2><a class="toc-backref" href="#id86"><tt class="docutils literal"><span class="pre">\PolPrintIntervals[varname]{sturmname}</span></tt></a></h2> +<blockquote> +<p>This is a convenience macro which prints the bounds for the roots +<tt class="docutils literal">Z_1</tt>, <tt class="docutils literal">Z_2</tt>, ... (the optional argument <tt class="docutils literal">varname</tt> allows to +specify a replacement for the default <tt class="docutils literal">Z</tt>). This will be done (by +default) in a +math mode <tt class="docutils literal">array</tt>, one interval per row, and pattern <tt class="docutils literal">rcccl</tt>, +where the second and fourth column hold the <tt class="docutils literal"><</tt> sign, except when +the interval reduces to a singleton, which means the root is known +exactly.</p> +<div class="admonition attention"> +<p class="first admonition-title">Attention!</p> +<p class="last">This macro was refactored at 0.7, its default output remained +identical but the ways to customize it got completely +modified.</p> +</div> +<p>See next macros which govern its output.</p> +</blockquote> +<div class="section" id="polprintintervalsnorealroots"> +<h3><a class="toc-backref" href="#id87"><tt class="docutils literal">\PolPrintIntervalsNoRealRoots</tt></a></h3> +<blockquote> +<p>Executed in place of an <tt class="docutils literal">array</tt> environment, when there are no +real roots. Default definition:</p> +<pre class="literal-block"> +\newcommand\PolPrintIntervalsNoRealRoots{} +</pre> +</blockquote> +</div> +<div class="section" id="polprintintervalsbeginenv"> +<h3><a class="toc-backref" href="#id88"><tt class="docutils literal">\PolPrintIntervalsBeginEnv</tt></a></h3> +<blockquote> +<p>Default definition:</p> +<pre class="literal-block"> +\newcommand\PolPrintIntervalsBeginEnv{\[\begin{array}{rcccl}} +</pre> +</blockquote> +</div> +<div class="section" id="polprintintervalsendenv"> +<h3><a class="toc-backref" href="#id89"><tt class="docutils literal">\PolPrintIntervalsEndEnv</tt></a></h3> +<blockquote> +<p>Default definition:</p> +<pre class="literal-block"> +\newcommand\PolPrintIntervalsEndEnv{\end{array}\]} +</pre> +</blockquote> +</div> +<div class="section" id="polprintintervalsknownroot"> +<h3><a class="toc-backref" href="#id90"><tt class="docutils literal">\PolPrintIntervalsKnownRoot</tt></a></h3> +<blockquote> +<p>Default definition:</p> +<pre class="literal-block"> +\newcommand\PolPrintIntervalsKnownRoot{% + &&\PolPrintIntervalsTheVar_{\PolPrintIntervalsTheIndex}% + &=&\PolPrintIntervalsPrintExactZero +} +</pre> +</blockquote> +</div> +<div class="section" id="polprintintervalsunknownroot"> +<h3><a class="toc-backref" href="#id91"><tt class="docutils literal">\PolPrintIntervalsUnknownRoot</tt></a></h3> +<blockquote> +<p>Default definition:</p> +<pre class="literal-block"> +\newcommand\PolPrintIntervalsUnknownRoot{% + \PolPrintIntervalsPrintLeftEndPoint&<&% + \PolPrintIntervalsTheVar_{\PolPrintIntervalsTheIndex}&<&% + \PolPrintIntervalsPrintRightEndPoint +} +</pre> +</blockquote> +</div> +<div class="section" id="id15"> +<span id="polprintintervalsprintexactzero"></span><h3><a class="toc-backref" href="#id92"><tt class="docutils literal">\PolPrintIntervalsPrintExactZero</tt></a></h3> +<blockquote> +<p>Default definition:</p> +<pre class="literal-block"> +\newcommand\PolPrintIntervalsPrintExactZero{\PolPrintIntervalsTheLeftEndPoint} +</pre> +</blockquote> +</div> +<div class="section" id="id16"> +<span id="polprintintervalsprintleftendpoint"></span><h3><a class="toc-backref" href="#id93"><tt class="docutils literal">\PolPrintIntervalsPrintLeftEndPoint</tt></a></h3> +<blockquote> +<p>Default definition:</p> +<pre class="literal-block"> +\newcommand\PolPrintIntervalsPrintLeftEndPoint{\PolPrintIntervalsTheLeftEndPoint} +</pre> +</blockquote> +</div> +<div class="section" id="id17"> +<span id="polprintintervalsprintrightendpoint"></span><h3><a class="toc-backref" href="#id94"><tt class="docutils literal">\PolPrintIntervalsPrintRightEndPoint</tt></a></h3> +<blockquote> +<p>Default definition is:</p> +<pre class="literal-block"> +\newcommand\PolPrintIntervalsPrintRightEndPoint{\PolPrintIntervalsTheRightEndPoint} +</pre> +</blockquote> +</div> +</div> +<div class="section" id="id19"> +<span id="id18"></span><h2><a class="toc-backref" href="#id95"><tt class="docutils literal"><span class="pre">\PolPrintIntervals*[varname]{sturmname}</span></tt></a></h2> +<blockquote> +<p>This starred variant produces an alternative output (which +displays the root multiplicity), and is provided as an +example of customization.</p> +<p>As replacement for <a class="reference internal" href="#polprintintervalsknownroot">\PolPrintIntervalsKnownRoot</a>, +<a class="reference internal" href="#polprintintervalsprintexactzero">\PolPrintIntervalsPrintExactZero</a>, +<a class="reference internal" href="#polprintintervalsunknownroot">\PolPrintIntervalsUnknownRoot</a> it uses its own +<tt class="docutils literal"><span class="pre">\POL@@PrintIntervals...</span></tt> macros. We only reproduce here one +definition:</p> +<pre class="literal-block"> +\newcommand\POL@@PrintIntervalsPrintExactZero{% + \displaystyle + \xintSignedFrac{\PolPrintIntervalsTheLeftEndPoint}% +}% +</pre> +<p>Multiplicities are printed using this auxiliary macro:</p> +</blockquote> +<div class="section" id="polprintintervalsprintmultiplicity"> +<h3><a class="toc-backref" href="#id96"><tt class="docutils literal">\PolPrintIntervalsPrintMultiplicity</tt></a></h3> +<blockquote> +<p>whose default definition is:</p> +<pre class="literal-block"> +\newcommand\PolPrintIntervalsPrintMultiplicity{(\mbox{mult. }\PolPrintIntervalsTheMultiplicity)} +</pre> +</blockquote> +</div> +</div> +<div class="section" id="polmapcoeffs-macro-polname"> +<span id="polmapcoeffs"></span><h2><a class="toc-backref" href="#id97"><tt class="docutils literal"><span class="pre">\PolMapCoeffs{\macro}{polname}</span></tt></a></h2> +<blockquote> +<p>It modifies ('in-place': original coefficients get lost) each +coefficient of the defined polynomial via the <em>expandable</em> macro +<tt class="docutils literal">\macro</tt>. The degree is adjusted as necessary if some leading +coefficients vanish after the operation. In replacement text of +<tt class="docutils literal">\macro</tt>, <tt class="docutils literal">\index</tt> expands to the coefficient index (which is +defined to be zero for the constant term).</p> +<p>Notice that <tt class="docutils literal">\macro</tt> will have to handle inputs of the shape +<tt class="docutils literal">A/B[N]</tt> (<a class="reference external" href="http://www.ctan.org/pkg/xint">xintfrac</a> internal notation). This means that it probably +will have to be expressed in terms of macros from <a class="reference external" href="http://www.ctan.org/pkg/xint">xintfrac</a> package.</p> +<p>Example:</p> +<pre class="literal-block"> +\def\foo#1{\xintMul{#1}{\the\numexpr\index*\index\relax}} +</pre> +<p>(or with <tt class="docutils literal"><span class="pre">\xintSqr{\index}</span></tt>) to replace <tt class="docutils literal">n</tt>-th coefficient +<tt class="docutils literal">f_n</tt> by <tt class="docutils literal">f_n*n^2</tt>.</p> +</blockquote> +</div> +<div class="section" id="polreducecoeffs-polname"> +<span id="polreducecoeffs"></span><h2><a class="toc-backref" href="#id98"><tt class="docutils literal">\PolReduceCoeffs{polname}</tt></a></h2> +<blockquote> +About the same as <tt class="docutils literal"><span class="pre">\PolMapCoeffs{\xintIrr}{polname}</span></tt> (but +maintaining a <tt class="docutils literal">[0]</tt> postfix for speedier <a class="reference external" href="http://www.ctan.org/pkg/xint">xintfrac</a> parsing when +polynomial function is used for computations.) This is a +one-argument macro, working 'in-place'.</blockquote> +</div> +<div class="section" id="id21"> +<span id="id20"></span><h2><a class="toc-backref" href="#id99"><tt class="docutils literal"><span class="pre">\PolReduceCoeffs*{polname}</span></tt></a></h2> +<blockquote> +<p>This starred variant leaves un-touched the decimal exponent in the +internal representation of the fractional coefficients, i.e. if a +coefficient is internally <tt class="docutils literal">A/B[N]</tt>, then <tt class="docutils literal">A/B</tt> is reduced to +smallest terms, but the <tt class="docutils literal">10^N</tt> part is kept as is. Note: if the +polynomial is freshly defined directly via <a class="reference internal" href="#polfromcsv">\PolFromCSV</a> its coefficients might still be internally in some +format like <tt class="docutils literal">1.5e7</tt>; the macro will anyhow always first do the +needed conversion to strict format <tt class="docutils literal">A/B[N]</tt>.</p> +<p>Evaluations with polynomials treated by this can be much faster than +with those handled by the non-starred variant +<a class="reference internal" href="#polreducecoeffs-polname">\PolReduceCoeffs{polname}</a>: as the numerators and denominators +remain smaller, this proves very beneficial in favorable cases +(especially when the coefficients are decimal numbers) to the +expansion speed of the <a class="reference external" href="http://www.ctan.org/pkg/xint">xintfrac</a> macros used internally by +<a class="reference internal" href="#polevalat">\PolEval</a>.</p> +</blockquote> +</div> +<div class="section" id="polmakemonic-polname"> +<span id="polmakemonic"></span><h2><a class="toc-backref" href="#id100"><tt class="docutils literal">\PolMakeMonic{polname}</tt></a></h2> +<blockquote> +Divides by the leading coefficient. It is recommended to execute +<a class="reference internal" href="#id21">\PolReduceCoeffs*{polname}</a> immediately afterwards. This is not +done automatically, due to the case the original polynomial had integer +coefficients and we want to keep the leading one as common +denominator.</blockquote> +</div> +<div class="section" id="polmakeprimitive-polname"> +<span id="polmakeprimitive"></span><h2><a class="toc-backref" href="#id101"><tt class="docutils literal">\PolMakePrimitive{polname}</tt></a></h2> +<blockquote> +Divides by the integer content see (<a class="reference internal" href="#policontent">\PolIContent</a>). This thus produces a polynomial with integer +coefficients having no common factor. The sign of the leading +coefficient is not modified.</blockquote> +</div> +</div> +<div class="section" id="expandable-macros"> +<h1><a class="toc-backref" href="#id102">Expandable macros</a></h1> +<p>All these macros expand completely in two steps except <tt class="docutils literal">\PolToExpr</tt> +and <tt class="docutils literal">\PolToFloatExpr</tt> (and their auxiliaries) which need a +<tt class="docutils literal">\write</tt>, <tt class="docutils literal">\edef</tt> or a <tt class="docutils literal"><span class="pre">\csname...\endcsname</span></tt> context.</p> +<div class="section" id="poleval-polname-atexpr-numerical-expression"> +<span id="polevalatexpr"></span><h2><a class="toc-backref" href="#id103"><tt class="docutils literal"><span class="pre">\PolEval{polname}\AtExpr{numerical</span> expression}</tt></a></h2> +<blockquote> +It boils down to +<tt class="docutils literal">\xinttheexpr polname(numerical <span class="pre">expression)\relax</span></tt>.</blockquote> +</div> +<div class="section" id="poleval-polname-at-fraction"> +<span id="polevalat"></span><h2><a class="toc-backref" href="#id104"><tt class="docutils literal"><span class="pre">\PolEval{polname}\At{fraction}</span></tt></a></h2> +<blockquote> +Evaluates the polynomial at value <tt class="docutils literal">fraction</tt> which must be in (or +expand to) a format acceptable to the <a class="reference external" href="http://www.ctan.org/pkg/xint">xintfrac</a> macros.</blockquote> +</div> +<div class="section" id="polevalreduced-polname-atexpr-numerical-expression"> +<span id="polevalreducedatexpr"></span><h2><a class="toc-backref" href="#id105"><tt class="docutils literal"><span class="pre">\PolEvalReduced{polname}\AtExpr{numerical</span> expression}</tt></a></h2> +<blockquote> +Boils down to <tt class="docutils literal">\xinttheexpr reduce(polname(numerical <span class="pre">expression))\relax</span></tt>.</blockquote> +</div> +<div class="section" id="polevalreduced-polname-at-fraction"> +<span id="polevalreducedat"></span><h2><a class="toc-backref" href="#id106"><tt class="docutils literal"><span class="pre">\PolEvalReduced{polname}\At{fraction}</span></tt></a></h2> +<blockquote> +Evaluates the polynomial at value <tt class="docutils literal">fraction</tt> which must be in (or +expand to) a format acceptable to the <a class="reference external" href="http://www.ctan.org/pkg/xint">xintfrac</a> macros, and produce +an irreducible fraction.</blockquote> +</div> +<div class="section" id="polfloateval-polname-atexpr-numerical-expression"> +<span id="polfloatevalatexpr"></span><h2><a class="toc-backref" href="#id107"><tt class="docutils literal"><span class="pre">\PolFloatEval{polname}\AtExpr{numerical</span> expression}</tt></a></h2> +<blockquote> +<p>Boils down to <tt class="docutils literal">\xintthefloatexpr polname(numerical <span class="pre">expression)\relax</span></tt>.</p> +<p>This is done via a Horner Scheme (see <a class="reference internal" href="#poldef">\poldef</a> and +<a class="reference internal" href="#polgenfloatvariant-polname">\PolGenFloatVariant{polname}</a>), with already rounded +coefficients. <a class="footnote-reference" href="#id24" id="id22">[2]</a> To use the <em>exact coefficients</em> with <em>exactly +executed</em> additions and multiplications, just insert it in the float +expression as in this example: <a class="footnote-reference" href="#id25" id="id23">[3]</a></p> +<pre class="literal-block"> +\xintthefloatexpr 3.27*\xintexpr f(2.53)\relax^2\relax +</pre> +<p>The <tt class="docutils literal">f(2.53)</tt> is exactly computed then rounded at the time of +getting raised to the power <tt class="docutils literal">2</tt>. Moving the <tt class="docutils literal">^2</tt> inside, that +operation would also be treated exactly.</p> +<table class="docutils footnote" frame="void" id="id24" rules="none"> +<colgroup><col class="label" /><col /></colgroup> +<tbody valign="top"> +<tr><td class="label"><a class="fn-backref" href="#id22">[2]</a></td><td>Anyway each floating point operation starts by rounding its +operands to the floating point precision.</td></tr> +</tbody> +</table> +<table class="docutils footnote" frame="void" id="id25" rules="none"> +<colgroup><col class="label" /><col /></colgroup> +<tbody valign="top"> +<tr><td class="label"><a class="fn-backref" href="#id23">[3]</a></td><td>The <tt class="docutils literal">\xintexpr</tt> here could be <tt class="docutils literal">\xinttheexpr</tt> but that +would be less efficient. Cf. <a class="reference external" href="http://www.ctan.org/pkg/xint">xintexpr</a> documentation about +nested expressions.</td></tr> +</tbody> +</table> +</blockquote> +</div> +<div class="section" id="polfloateval-polname-at-fraction"> +<span id="polfloatevalat"></span><h2><a class="toc-backref" href="#id108"><tt class="docutils literal"><span class="pre">\PolFloatEval{polname}\At{fraction}</span></tt></a></h2> +<blockquote> +Evaluates the polynomial at value <tt class="docutils literal">fraction</tt> which must be in (or +expand to) a format acceptable to the <a class="reference external" href="http://www.ctan.org/pkg/xint">xintfrac</a> macros, and produces +a floating point number.</blockquote> +</div> +<div class="section" id="polifcoeffisplusorminusone-a-b"> +<span id="polifcoeffisplusorminusone"></span><h2><a class="toc-backref" href="#id109"><tt class="docutils literal"><span class="pre">\PolIfCoeffIsPlusOrMinusOne{A}{B}</span></tt></a></h2> +<blockquote> +<p>This macro is a priori undefined.</p> +<p>It is defined via the default <a class="reference internal" href="#poltypesetcmd-raw-coeff">\PolTypesetCmd{raw_coeff}</a> to be +used if needed in the execution of <a class="reference internal" href="#poltypesetmonomialcmd">\PolTypesetMonomialCmd</a>, +e.g. to insert a <tt class="docutils literal">\cdot</tt> in front of <tt class="docutils literal"><span class="pre">\PolVar^{\PolIndex}</span></tt> if +the coefficient is not plus or minus one.</p> +<p>The macro will execute <tt class="docutils literal">A</tt> if the coefficient has been found to be +plus or minus one, and <tt class="docutils literal">B</tt> if not.</p> +</blockquote> +</div> +<div class="section" id="polleadingcoeff-polname"> +<span id="polleadingcoeff"></span><h2><a class="toc-backref" href="#id110"><tt class="docutils literal">\PolLeadingCoeff{polname}</tt></a></h2> +<blockquote> +Expands to the leading coefficient.</blockquote> +</div> +<div class="section" id="polnthcoeff-polname-number"> +<span id="polnthcoeff"></span><h2><a class="toc-backref" href="#id111"><tt class="docutils literal"><span class="pre">\PolNthCoeff{polname}{number}</span></tt></a></h2> +<blockquote> +It expands to the raw <tt class="docutils literal">N</tt>-th coefficient (<tt class="docutils literal">0/1[0]</tt> if the index +number is out of range). With <tt class="docutils literal"><span class="pre">N=-1</span></tt>, <tt class="docutils literal"><span class="pre">-2</span></tt>, ... expands to the +leading coefficients.</blockquote> +</div> +<div class="section" id="poldegree-polname"> +<span id="poldegree"></span><h2><a class="toc-backref" href="#id112"><tt class="docutils literal">\PolDegree{polname}</tt></a></h2> +<blockquote> +It expands to the degree. This is <tt class="docutils literal"><span class="pre">-1</span></tt> if zero polynomial but this +may change in future. Should it then expand to <tt class="docutils literal"><span class="pre">-\infty</span></tt> ?</blockquote> +</div> +<div class="section" id="policontent-polname"> +<span id="policontent"></span><h2><a class="toc-backref" href="#id113"><tt class="docutils literal">\PolIContent{polname}</tt></a></h2> +<blockquote> +<p>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.</p> +<p>See <a class="reference internal" href="#polmakeprimitive">\PolMakePrimitive</a>.</p> +</blockquote> +</div> +<div class="section" id="poltoexpr-polname"> +<span id="poltoexpr"></span><h2><a class="toc-backref" href="#id114"><tt class="docutils literal">\PolToExpr{polname}</tt></a></h2> +<blockquote> +<p>Expands <a class="footnote-reference" href="#id27" id="id26">[4]</a> to <tt class="docutils literal"><span class="pre">coeff_N*x^N+...</span></tt> (descending powers.)</p> +<table class="docutils footnote" frame="void" id="id27" rules="none"> +<colgroup><col class="label" /><col /></colgroup> +<tbody valign="top"> +<tr><td class="label"><a class="fn-backref" href="#id26">[4]</a></td><td>in a <tt class="docutils literal">\write</tt>, <tt class="docutils literal">\edef</tt>, or <tt class="docutils literal"><span class="pre">\csname...\endcsname</span></tt>, but +not under <tt class="docutils literal"><span class="pre">\romannumeral-`0</span></tt>.</td></tr> +</tbody> +</table> +<p>By default zero coefficients are skipped (issue <tt class="docutils literal">\poltoexpralltrue</tt> to +get all of them in output).</p> +<p>By default, no <tt class="docutils literal">+</tt> sign before negative coefficients, for +compliance with Maple input format (but see +<a class="reference internal" href="#poltoexprtermprefix-raw-coeff">\PolToExprTermPrefix{raw_coeff}</a>.) Also, like the default +behaviour of <a class="reference internal" href="#poltypeset-polname">\PolTypeset{polname}</a>, does not print (for the non +constant terms) coefficients equal to plus or minus one. The degree +one monomial is output as <tt class="docutils literal">x</tt>, not <tt class="docutils literal">x^1</tt>. Complete customization is +possible, see next macros.</p> +<p>Of course <tt class="docutils literal">\PolToExpr{f}</tt> can be inserted in a <tt class="docutils literal">\poldef</tt>, as the +latter expands token by token, hence will force complete expansion +of <tt class="docutils literal">\PolToExpr{f}</tt>, but a simple <tt class="docutils literal">f(x)</tt> is more efficient for +the identical result.</p> +</blockquote> +<div class="section" id="poltoexproneterm-raw-coeff-number"> +<span id="poltoexproneterm"></span><h3><a class="toc-backref" href="#id115"><tt class="docutils literal"><span class="pre">\PolToExprOneTerm{raw_coeff}{number}</span></tt></a></h3> +<blockquote> +<p>This two argument expandable command takes care of the monomial and +its coefficient. The default definition is done in order for +coefficients of absolute value <tt class="docutils literal">1</tt> not be printed explicitely +(except of course for the constant term). Also by default, the +monomial of degree one is <tt class="docutils literal">x</tt> not <tt class="docutils literal">x^1</tt>, and <tt class="docutils literal">x^0</tt> is skipped.</p> +<p>For compatibility with Maple input requirements, by default a <tt class="docutils literal">*</tt> +always precedes the <tt class="docutils literal">x^number</tt>, except if the coefficient is a one +or a minus one. See <a class="reference internal" href="#poltoexprtimes">\PolToExprTimes</a>.</p> +</blockquote> +</div> +<div class="section" id="poltoexpronetermstylea-raw-coeff-number"> +<span id="poltoexpronetermstylea"></span><h3><a class="toc-backref" href="#id116"><tt class="docutils literal"><span class="pre">\PolToExprOneTermStyleA{raw_coeff}{number}</span></tt></a></h3> +<blockquote> +Holds the default package meaning of +<a class="reference internal" href="#poltoexproneterm-raw-coeff-number">\PolToExprOneTerm{raw_coeff}{number}</a>.</blockquote> +</div> +<div class="section" id="poltoexpronetermstyleb-raw-coeff-number"> +<span id="poltoexpronetermstyleb"></span><h3><a class="toc-backref" href="#id117"><tt class="docutils literal"><span class="pre">\PolToExprOneTermStyleB{raw_coeff}{number}</span></tt></a></h3> +<blockquote> +<p>For output in this style:</p> +<pre class="literal-block"> +2*x^11/3+3*x^8/7-x^5-x^4/4-x^3-x^2/2-2*x+1 +</pre> +<p>issue <tt class="docutils literal">\let\PolToExprOneTerm\PolToExprOneTermStyleB</tt> before usage of +<tt class="docutils literal">\PolToExpr</tt>. Note that then <tt class="docutils literal">\PolToExprCmd</tt> isn't used at all. +To revert to package default, issue +<tt class="docutils literal">\let\PolToExprOneTerm\PolToExprOneTermStyleA</tt>.</p> +<p>To suppress the <tt class="docutils literal">*</tt>'s, cf. <a class="reference internal" href="#poltoexprtimes">\PolToExprTimes</a>.</p> +</blockquote> +</div> +<div class="section" id="poltoexprcmd-raw-coeff"> +<span id="poltoexprcmd"></span><h3><a class="toc-backref" href="#id118"><tt class="docutils literal">\PolToExprCmd{raw_coeff}</tt></a></h3> +<blockquote> +It is the one-argument macro used by the package definition of +<tt class="docutils literal">\PolToExprOneTerm</tt> for the coefficients themselves (when not +equal to plus or minus one), and it defaults to +<tt class="docutils literal"><span class="pre">\xintPRaw{\xintRawWithZeros{#1}}</span></tt>. One will have to redefine it +to <tt class="docutils literal"><span class="pre">\xintIrr{#1}</span></tt> or to <tt class="docutils literal"><span class="pre">\xintPRaw{\xintIrr{#1}}</span></tt> to obtain in the +output forcefully reduced coefficients.</blockquote> +</div> +<div class="section" id="poltoexprtermprefix-raw-coeff"> +<span id="poltoexprtermprefix"></span><h3><a class="toc-backref" href="#id119"><tt class="docutils literal">\PolToExprTermPrefix{raw_coeff}</tt></a></h3> +<blockquote> +Defined identically as <a class="reference internal" href="#poltypesetcmdprefix-raw-coeff">\PolTypesetCmdPrefix{raw_coeff}</a>. It +prefixes with a plus sign for non-negative coefficients, because +they don't carry one by themselves.</blockquote> +</div> +<div class="section" id="id28"> +<span id="poltoexprvar"></span><h3><a class="toc-backref" href="#id120"><tt class="docutils literal">\PolToExprVar</tt></a></h3> +<blockquote> +This expands to the variable to use in output (it does not have to +be a single letter, may be an expandable macro.) Initial definition +is <tt class="docutils literal">x</tt>.</blockquote> +</div> +<div class="section" id="id29"> +<span id="poltoexprtimes"></span><h3><a class="toc-backref" href="#id121"><tt class="docutils literal">\PolToExprTimes</tt></a></h3> +<blockquote> +This expands to the symbol used for multiplication of an +<tt class="docutils literal"><span class="pre">x^{number}</span></tt> by the corresponding coefficient. The default is +<tt class="docutils literal">*</tt>. Redefine the macro to expand to nothing to get rid of it (but +this will give output incompatible with some professional computer +algebra software).</blockquote> +</div> +</div> +<div class="section" id="id31"> +<span id="id30"></span><h2><a class="toc-backref" href="#id122"><tt class="docutils literal"><span class="pre">\PolToExpr*{polname}</span></tt></a></h2> +<blockquote> +Expands to <tt class="docutils literal"><span class="pre">coeff_0+coeff_1*x+coeff_2*x^2+...</span></tt> (ascending powers). +Customizable like <a class="reference internal" href="#poltoexpr-polname">\PolToExpr{polname}</a> via the same macros.</blockquote> +</div> +<div class="section" id="poltofloatexpr-polname"> +<span id="poltofloatexpr"></span><h2><a class="toc-backref" href="#id123"><tt class="docutils literal">\PolToFloatExpr{polname}</tt></a></h2> +<blockquote> +<p>Similar to <a class="reference internal" href="#poltoexpr-polname">\PolToExpr{polname}</a> but uses <a class="reference external" href="\PolToFloatExprCmd{raw_coeff}">\PolToFloatExprCmd</a> +which by default rounds and converts the coefficients to floating +point format.</p> +<div class="admonition note"> +<p class="first admonition-title">Note</p> +<p>It is not necessary to have issued +<a class="reference internal" href="#polgenfloatvariant-polname">\PolGenFloatVariant{polname}</a>. The rounded coefficients are +not easily recoverable from the <tt class="docutils literal">\xintfloatexpr</tt> polynomial +function hence <tt class="docutils literal">\PolToFloatExprCmd</tt> operates from the <em>exact</em> +coefficients anew.</p> +<p class="last">Attention that both macros obey the prevailing float precision. +If it is changed between those macro calls, then a mismatch +exists between the coefficients as used in <tt class="docutils literal">\xintfloatexpr</tt> and +those output by <tt class="docutils literal">\PolToFloatExpr{polname}</tt>.</p> +</div> +</blockquote> +<div class="section" id="poltofloatexproneterm-raw-coeff-number"> +<span id="poltofloatexproneterm"></span><h3><a class="toc-backref" href="#id124"><tt class="docutils literal"><span class="pre">\PolToFloatExprOneTerm{raw_coeff}{number}</span></tt></a></h3> +<blockquote> +Similar to <a class="reference external" href="\PolToExprOneTerm{raw_coeff}{number}">\PolToExprOneTerm</a>. But does not treat +especially coefficients equal to plus or minus one.</blockquote> +</div> +<div class="section" id="poltofloatexprcmd-raw-coeff"> +<span id="id33"></span><h3><a class="toc-backref" href="#id125"><tt class="docutils literal">\PolToFloatExprCmd{raw_coeff}</tt></a></h3> +<blockquote> +<p>It is the one-argument macro used by <tt class="docutils literal">\PolToFloatExprOneTerm</tt>. +Its package definition is <tt class="docutils literal"><span class="pre">\xintFloat{#1}</span></tt>.</p> +<div class="admonition caution"> +<p class="first admonition-title">Caution!</p> +<p>Currently (<a class="reference external" href="http://www.ctan.org/pkg/xint">xint</a> <tt class="docutils literal">1.3c</tt>) <tt class="docutils literal">\xintFloat{0}</tt> outputs <tt class="docutils literal">0.e0</tt> +which is perfectly acceptable input for Python, but not for +Maple. Thus, one should better leave the <a class="reference internal" href="#poltoexprallfalse">\poltoexprallfalse</a> +toggle to its default <tt class="docutils literal">\iffalse</tt> state, if one intends to use +the output in a Maple worksheet.</p> +<p>But even then the zero polynomial will cause a problem. Workaround:</p> +<pre class="literal-block"> +\renewcommand\PolToFloatExprCmd[1]{\xintiiifZero{#1}{0.0}{\xintFloat{#1}}} +</pre> +<p class="last">Usage of <tt class="docutils literal">\xintiiifZero</tt> and not <tt class="docutils literal">\xintifZero</tt> is only for +optimization (I can't help it) because <tt class="docutils literal">#1</tt> is known to be +in <tt class="docutils literal">xintfrac</tt> raw format.</p> +</div> +</blockquote> +</div> +</div> +<div class="section" id="id35"> +<span id="id34"></span><h2><a class="toc-backref" href="#id126"><tt class="docutils literal"><span class="pre">\PolToFloatExpr*{polname}</span></tt></a></h2> +<blockquote> +Typesets in ascending powers.</blockquote> +</div> +<div class="section" id="poltolist-polname"> +<span id="poltolist"></span><h2><a class="toc-backref" href="#id127"><tt class="docutils literal">\PolToList{polname}</tt></a></h2> +<blockquote> +Expands to <tt class="docutils literal"><span class="pre">{coeff_0}{coeff_1}...{coeff_N}</span></tt> with <tt class="docutils literal">N</tt> = degree, and +<tt class="docutils literal">coeff_N</tt> the leading coefficient +(the zero polynomial does give <tt class="docutils literal">{0/1[0]}</tt> and not an +empty output.)</blockquote> +</div> +<div class="section" id="poltocsv-polname"> +<span id="poltocsv"></span><h2><a class="toc-backref" href="#id128"><tt class="docutils literal">\PolToCSV{polname}</tt></a></h2> +<blockquote> +Expands to <tt class="docutils literal">coeff_0, coeff_1, coeff_2, <span class="pre">.....,</span> coeff_N</tt>, starting +with constant term and ending with leading coefficient. Converse +to <a class="reference internal" href="#polfromcsv-polname-csv">\PolFromCSV</a>.</blockquote> +</div> +<div class="section" id="polsturmchainlength-sturmname"> +<span id="polsturmchainlength"></span><h2><a class="toc-backref" href="#id129"><tt class="docutils literal">\PolSturmChainLength{sturmname}</tt></a></h2> +<blockquote> +<p>Returns the integer <tt class="docutils literal">N</tt> such that <tt class="docutils literal">sturmname_N</tt> is the last one +in the Sturm chain <tt class="docutils literal">sturmname_0</tt>, <tt class="docutils literal">sturmname_1</tt>, ...</p> +<p>See <a class="reference internal" href="#poltosturm-polname-sturmname">\PolToSturm{polname}{sturmname}</a>.</p> +</blockquote> +</div> +<div class="section" id="polsturmifzeroexactlyknown-sturmname-index-a-b"> +<span id="polsturmifzeroexactlyknown"></span><h2><a class="toc-backref" href="#id130"><tt class="docutils literal"><span class="pre">\PolSturmIfZeroExactlyKnown{sturmname}{index}{A}{B}</span></tt></a></h2> +<blockquote> +<p>Executes <tt class="docutils literal">A</tt> if the <tt class="docutils literal">index</tt>-th interval reduces to a singleton, +i.e. the root is known exactly, else <tt class="docutils literal">B</tt>.</p> +<div class="admonition note"> +<p class="first admonition-title">Note</p> +<p class="last"><tt class="docutils literal">index</tt> is allowed to be something like <tt class="docutils literal">1+2*3</tt> as it is fed +to <tt class="docutils literal"><span class="pre">\the\numexpr...\relax</span></tt>.</p> +</div> +</blockquote> +</div> +<div class="section" id="polsturmisolatedzeroleft-sturmname-index"> +<span id="polsturmisolatedzeroleft"></span><h2><a class="toc-backref" href="#id131"><tt class="docutils literal"><span class="pre">\PolSturmIsolatedZeroLeft{sturmname}{index}</span></tt></a></h2> +<blockquote> +<p>Expands to the left end-point for the <tt class="docutils literal">index</tt>-th interval, as +computed by some earlier <a class="reference internal" href="#polsturmisolatezeros-sturmname">\PolSturmIsolateZeros{sturmname}</a>.</p> +<div class="admonition note"> +<p class="first admonition-title">Note</p> +<p class="last">Of course, this is kept updated by macros such as +<a class="reference internal" href="#polrefineinterval-n">\PolRefineInterval{sturmname}{index}</a>.</p> +</div> +<p>The value is pre-formatted using <a class="reference internal" href="#poldectostring">\PolDecTostring</a>.</p> +</blockquote> +</div> +<div class="section" id="polsturmisolatedzeroright-sturmname-index"> +<span id="polsturmisolatedzeroright"></span><h2><a class="toc-backref" href="#id132"><tt class="docutils literal"><span class="pre">\PolSturmIsolatedZeroRight{sturmname}{index}</span></tt></a></h2> +<blockquote> +<p>Expands to the right end-point for the <tt class="docutils literal">index</tt>-th interval as +computed by some earlier <a class="reference internal" href="#polsturmisolatezeros-sturmname">\PolSturmIsolateZeros{sturmname}</a> and +possibly refined afterwards.</p> +<p>The value is pre-formatted using <a class="reference internal" href="#poldectostring">\PolDecTostring</a>.</p> +</blockquote> +</div> +<div class="section" id="polsturmisolatedzeromultiplicity-sturmname-index"> +<span id="polsturmisolatedzeromultiplicity"></span><h2><a class="toc-backref" href="#id133"><tt class="docutils literal"><span class="pre">\PolSturmIsolatedZeroMultiplicity{sturmname}{index}</span></tt></a></h2> +<blockquote> +<p>Expands to the multiplicity of the unique root contained in the +<tt class="docutils literal">index</tt>-th interval.</p> +<div class="admonition attention"> +<p class="first admonition-title">Attention!</p> +<p class="last">A prior execution of <a class="reference internal" href="#id12">\PolSturmIsolateZeros*{sturmname}</a> is mandatory.</p> +</div> +<p>See <a class="reference internal" href="#the-degree-nine-polynomial-with-0-99-0-999-0-9999-as-triple-roots">The degree nine polynomial with 0.99, 0.999, 0.9999 as triple +roots</a> for an example of use.</p> +</blockquote> +</div> +<div class="section" id="polsturmnbofisolatedzeros-sturmname"> +<span id="polsturmnbofisolatedzeros"></span><h2><a class="toc-backref" href="#id134"><tt class="docutils literal">\PolSturmNbOfIsolatedZeros{sturmname}</tt></a></h2> +<blockquote> +Expands to the number of real roots of the polynomial +<tt class="docutils literal"><sturmname>_0</tt>, i.e. the number of distinct real roots of the +polynomial originally used to create the Sturm chain via +<a class="reference internal" href="#poltosturm-polname-sturmname">\PolToSturm{polname}{sturmname}</a>.</blockquote> +<div class="admonition warning"> +<p class="first admonition-title">Warning</p> +<p class="last">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.</p> +</div> +<div class="section" id="polsturmnbofrootsof-sturmname-lessthanorequalto-value"> +<h3><a class="toc-backref" href="#id135"><tt class="docutils literal"><span class="pre">\PolSturmNbOfRootsOf{sturmname}\LessThanOrEqualTo{value}</span></tt></a></h3> +<blockquote> +<p>Expands to the number of distinct roots (of the polynomial used to +create the Sturm chain) less than or equal to the <tt class="docutils literal">value</tt> (i.e. a +number of fraction recognizable by the <a class="reference external" href="http://www.ctan.org/pkg/xint">xintfrac</a> macros).</p> +<div class="admonition attention"> +<p class="first admonition-title">Attention!</p> +<p><a class="reference internal" href="#polsturmisolatezeros-sturmname">\PolSturmIsolateZeros{sturmname}</a> must have been executed +beforehand.</p> +<p class="last">And the argument is a <tt class="docutils literal">sturmname</tt>, not a <tt class="docutils literal">polname</tt> (this is +why the macro contains Sturm in its name), simply to be reminded +of the above constraint.</p> +</div> +</blockquote> +</div> +<div class="section" id="polsturmnbofrootsof-sturmname-lessthanorequaltoexpr-expression"> +<h3><a class="toc-backref" href="#id136"><tt class="docutils literal"><span class="pre">\PolSturmNbOfRootsOf{sturmname}\LessThanOrEqualToExpr{expression}</span></tt></a></h3> +<blockquote> +<p>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 <tt class="docutils literal">expression</tt>.</p> +<div class="admonition attention"> +<p class="first admonition-title">Attention!</p> +<p class="last"><a class="reference internal" href="#polsturmisolatezeros-sturmname">\PolSturmIsolateZeros{sturmname}</a> must have been executed +beforehand.</p> +</div> +</blockquote> +</div> +<div class="section" id="polsturmnbwithmultofrootsof-sturmname-lessthanorequalto-value"> +<h3><a class="toc-backref" href="#id137"><tt class="docutils literal"><span class="pre">\PolSturmNbWithMultOfRootsOf{sturmname}\LessThanOrEqualTo{value}</span></tt></a></h3> +<blockquote> +<p>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 <tt class="docutils literal">value</tt>.</p> +<div class="admonition attention"> +<p class="first admonition-title">Attention!</p> +<p class="last"><a class="reference internal" href="#id12">\PolSturmIsolateZeros*{sturmname}</a> (or the double starred +variant) must have been executed beforehand.</p> +</div> +</blockquote> +</div> +<div class="section" id="polsturmnbwithmultofrootsof-sturmname-lessthanorequaltoexpr-expression"> +<h3><a class="toc-backref" href="#id138"><tt class="docutils literal"><span class="pre">\PolSturmNbWithMultOfRootsOf{sturmname}\LessThanOrEqualToExpr{expression}</span></tt></a></h3> +<blockquote> +<p>Expands to the total number of roots (counted with multiplicities) +which are less than or equal to the given <tt class="docutils literal">expression</tt>.</p> +<div class="admonition attention"> +<p class="first admonition-title">Attention!</p> +<p class="last"><a class="reference internal" href="#id12">\PolSturmIsolateZeros*{sturmname}</a> (or the double starred +variant) must have been executed beforehand.</p> +</div> +</blockquote> +</div> +</div> +<div class="section" id="polsturmnbofrationalroots-sturmname"> +<h2><a class="toc-backref" href="#id139"><tt class="docutils literal">\PolSturmNbOfRationalRoots{sturmname}</tt></a></h2> +<blockquote> +<p>Expands to the number of rational roots (without multiplicities).</p> +<div class="admonition attention"> +<p class="first admonition-title">Attention!</p> +<p class="last"><a class="reference internal" href="#id14">\PolSturmIsolateZeros**{sturmname}</a> must have been executed +beforehand.</p> +</div> +</blockquote> +</div> +<div class="section" id="polsturmnbofrationalrootswithmultiplicities-sturmname"> +<h2><a class="toc-backref" href="#id140"><tt class="docutils literal">\PolSturmNbOfRationalRootsWithMultiplicities{sturmname}</tt></a></h2> +<blockquote> +<p>Expands to the number of rational roots (counted with multiplicities).</p> +<div class="admonition attention"> +<p class="first admonition-title">Attention!</p> +<p class="last"><a class="reference internal" href="#id14">\PolSturmIsolateZeros**{sturmname}</a> must have been executed +beforehand.</p> +</div> +</blockquote> +</div> +<div class="section" id="polsturmrationalroot-sturmname-k"> +<h2><a class="toc-backref" href="#id141"><tt class="docutils literal"><span class="pre">\PolSturmRationalRoot{sturmname}{k}</span></tt></a></h2> +<blockquote> +<p>Expands to the <tt class="docutils literal">k</tt>th rational root (they are ordered and indexed +starting at 1 for the most negative).</p> +<div class="admonition attention"> +<p class="first admonition-title">Attention!</p> +<p class="last"><a class="reference internal" href="#id14">\PolSturmIsolateZeros**{sturmname}</a> must have been executed +beforehand.</p> +</div> +</blockquote> +</div> +<div class="section" id="polsturmrationalrootindex-sturmname-k"> +<h2><a class="toc-backref" href="#id142"><tt class="docutils literal"><span class="pre">\PolSturmRationalRootIndex{sturmname}{k}</span></tt></a></h2> +<blockquote> +<p>Expands to <tt class="docutils literal">index</tt> of the <tt class="docutils literal">k</tt>th rational root as part of the +ordered real roots (without multiplicities). I.e., above macro +<a class="reference internal" href="#polsturmrationalroot-sturmname-k">\PolSturmRationalRoot{sturmname}{k}</a> is equivalent to this +nested call:</p> +<pre class="literal-block"> +\PolSturmIsolatedZeroLeft{sturmname}{\PolSturmRationalRootIndex{sturmname}{k}} +</pre> +<div class="admonition attention"> +<p class="first admonition-title">Attention!</p> +<p class="last"><a class="reference internal" href="#id14">\PolSturmIsolateZeros**{sturmname}</a> must have been executed +beforehand.</p> +</div> +</blockquote> +</div> +<div class="section" id="polsturmrationalrootmultiplicity-sturmname-k"> +<h2><a class="toc-backref" href="#id143"><tt class="docutils literal"><span class="pre">\PolSturmRationalRootMultiplicity{sturmname}{k}</span></tt></a></h2> +<blockquote> +<p>Expands to the multiplicity of the <tt class="docutils literal">k</tt>th rational root.</p> +<div class="admonition attention"> +<p class="first admonition-title">Attention!</p> +<p class="last"><a class="reference internal" href="#id14">\PolSturmIsolateZeros**{sturmname}</a> must have been executed +beforehand.</p> +</div> +</blockquote> +</div> +<div class="section" id="polintervalwidth-sturmname-index"> +<span id="polintervalwidth"></span><h2><a class="toc-backref" href="#id144"><tt class="docutils literal"><span class="pre">\PolIntervalWidth{sturmname}{index}</span></tt></a></h2> +<blockquote> +The <tt class="docutils literal">10^E</tt> width of the current <tt class="docutils literal">index</tt>-th root localization +interval. Output is in <a class="reference external" href="http://www.ctan.org/pkg/xint">xintfrac</a> raw <tt class="docutils literal">1/1[E]</tt> format (if not zero).</blockquote> +</div> +<div class="section" id="expandable-macros-for-use-within-execution-of-polprintintervals"> +<h2><a class="toc-backref" href="#id145">Expandable macros for use within execution of <tt class="docutils literal">\PolPrintIntervals</tt></a></h2> +<p>These macros are for usage within custom user redefinitions of +<a class="reference internal" href="#polprintintervalsknownroot">\PolPrintIntervalsKnownRoot</a>, <a class="reference internal" href="#polprintintervalsunknownroot">\PolPrintIntervalsUnknownRoot</a>, or +in redefinitions of <a class="reference internal" href="#polprintintervalsprintexactzero">PolPrintIntervalsPrintExactZero</a> (used in the +default for the former) and of <a class="reference internal" href="#polprintintervalsprintleftendpoint">\PolPrintIntervalsPrintLeftEndPoint</a>, +<a class="reference internal" href="#polprintintervalsprintrightendpoint">\PolPrintIntervalsPrintRightEndPoint</a> (used in the default for the +latter).</p> +<div class="admonition attention"> +<p class="first admonition-title">Attention!</p> +<p class="last">Some macros formerly mentioned here got removed at 0.7: +<tt class="docutils literal">\PolPrintIntervalsTheEndPoint</tt>, +<tt class="docutils literal"><span class="pre">\PolIfEndPointIsPositive{A}{B}</span></tt>, +<tt class="docutils literal"><span class="pre">\PolIfEndPointIsNegative{A}{B}</span></tt>, +<tt class="docutils literal"><span class="pre">\PolIfEndPointIsZero{A}{B}</span></tt>.</p> +</div> +<div class="section" id="polprintintervalsthevar"> +<h3><a class="toc-backref" href="#id146"><tt class="docutils literal">\PolPrintIntervalsTheVar</tt></a></h3> +<blockquote> +Expands to the name (default <tt class="docutils literal">Z</tt>) used for representing the roots, +which was passed as optional argument <tt class="docutils literal">varname</tt> to +<a class="reference internal" href="#polprintintervals-varname-sturmname">\PolPrintIntervals[varname]{sturmname}</a>.</blockquote> +</div> +<div class="section" id="polprintintervalstheindex"> +<h3><a class="toc-backref" href="#id147"><tt class="docutils literal">\PolPrintIntervalsTheIndex</tt></a></h3> +<blockquote> +Expands to the index of the considered interval (indexing starting +at 1 for the leftmost interval).</blockquote> +</div> +<div class="section" id="polprintintervalsthesturmname"> +<h3><a class="toc-backref" href="#id148"><tt class="docutils literal">\PolPrintIntervalsTheSturmName</tt></a></h3> +<blockquote> +Expands to the argument which was passed as <tt class="docutils literal">sturmname</tt> to +<a class="reference internal" href="#polprintintervals-varname-sturmname">\PolPrintIntervals[varname]{sturmname}</a>.</blockquote> +</div> +<div class="section" id="polprintintervalstheleftendpoint"> +<h3><a class="toc-backref" href="#id149"><tt class="docutils literal">\PolPrintIntervalsTheLeftEndPoint</tt></a></h3> +<blockquote> +The left end point of the interval, as would be produced by +<a class="reference internal" href="#polsturmisolatedzeroleft">\PolSturmIsolatedZeroLeft</a> if it was +used with arguments the Sturm chain name and interval index returned +by <a class="reference internal" href="#polprintintervalsthesturmname">\PolPrintIntervalsTheSturmName</a> and +<a class="reference internal" href="#polprintintervalstheindex">\PolPrintIntervalsTheIndex</a>.</blockquote> +</div> +<div class="section" id="polprintintervalstherightendpoint"> +<h3><a class="toc-backref" href="#id150"><tt class="docutils literal">\PolPrintIntervalsTheRightEndPoint</tt></a></h3> +<blockquote> +The right end point of the interval, as would be produced by +<a class="reference internal" href="#polsturmisolatedzeroright">\PolSturmIsolatedZeroRight</a> for +this Sturm chain name and index.</blockquote> +</div> +<div class="section" id="polprintintervalsthemultiplicity"> +<h3><a class="toc-backref" href="#id151"><tt class="docutils literal">\PolPrintIntervalsTheMultiplicity</tt></a></h3> +<blockquote> +The multiplicity of the unique root within the interval of index +<a class="reference internal" href="#polprintintervalstheindex">\PolPrintIntervalsTheIndex</a>. Makes sense only if the starred (or +double-starred) variant of <a class="reference internal" href="#polsturmisolatezeros">\PolSturmIsolateZeros</a> was used earlier.</blockquote> +</div> +</div> +<div class="section" id="poldectostring-decimal-number"> +<span id="poldectostring"></span><h2><a class="toc-backref" href="#id152"><tt class="docutils literal">\PolDecToString{decimal number}</tt></a></h2> +<blockquote> +<p>This is a utility macro to print decimal numbers. It has been +backported to <a class="reference external" href="http://www.ctan.org/pkg/xint">xintfrac</a> (release <tt class="docutils literal">1.3</tt> of <tt class="docutils literal">2018/03/01</tt>) under +the name <tt class="docutils literal">\xintDecToString</tt>, and the <tt class="docutils literal">polexpr</tt> macro is simply +now an alias to it.</p> +<p>For example +<tt class="docutils literal"><span class="pre">\PolDecToString{123.456e-8}</span></tt> will expand to <tt class="docutils literal">0.00000123456</tt> +and <tt class="docutils literal"><span class="pre">\PolDecToString{123.450e-8}</span></tt> to <tt class="docutils literal">0.00000123450</tt> which +illustrates that trailing zeros are not trimmed. To trim trailing +zeroes, one can use <tt class="docutils literal"><span class="pre">\PolDecToString{\xintREZ{#1}}</span></tt>.</p> +<p>The precise behaviour of this macro may evolve in future releases of +<a class="reference external" href="http://www.ctan.org/pkg/xint">xint</a>.</p> +</blockquote> +</div> +</div> +<div class="section" id="booleans-with-default-setting-as-indicated"> +<h1><a class="toc-backref" href="#id153">Booleans (with default setting as indicated)</a></h1> +<div class="section" id="xintverbosefalse"> +<h2><a class="toc-backref" href="#id154"><tt class="docutils literal">\xintverbosefalse</tt></a></h2> +<blockquote> +<p>This is actually an <a class="reference external" href="http://www.ctan.org/pkg/xint">xintexpr</a> configuration. Setting it to +<tt class="docutils literal">true</tt> triggers the writing of information to the log when new +polynomials are defined.</p> +<div class="admonition caution"> +<p class="first admonition-title">Caution!</p> +<p class="last">The macro meanings as written to the log are to be considered +unstable and undocumented internal structures.</p> +</div> +</blockquote> +</div> +<div class="section" id="poltypesetallfalse"> +<h2><a class="toc-backref" href="#id155"><tt class="docutils literal">\poltypesetallfalse</tt></a></h2> +<blockquote> +If <tt class="docutils literal">true</tt>, <a class="reference internal" href="#poltypeset-polname">\PolTypeset{polname}</a> will also typeset the vanishing +coefficients.</blockquote> +</div> +<div class="section" id="poltoexprallfalse"> +<h2><a class="toc-backref" href="#id156"><tt class="docutils literal">\poltoexprallfalse</tt></a></h2> +<blockquote> +If <tt class="docutils literal">true</tt>, <a class="reference internal" href="#poltoexpr-polname">\PolToExpr{polname}</a> and <a class="reference internal" href="#poltofloatexpr-polname">\PolToFloatExpr{polname}</a> will +also include the vanishing coefficients in their outputs.</blockquote> +</div> +</div> +<div class="section" id="polexprsetup"> +<h1><a class="toc-backref" href="#id157"><tt class="docutils literal">\polexprsetup</tt></a></h1> +<blockquote> +<p>Serves to customize the package. Currently only two keys are +recognized:</p> +<ul class="simple"> +<li><tt class="docutils literal">norr</tt>: the postfix that <a class="reference internal" href="#id14">\PolSturmIsolateZeros**{sturmname}</a> +should append to <tt class="docutils literal">sturmname</tt> to declare the primitive polynomial +obtained from original one after removal of all rational roots. +The default value is <tt class="docutils literal">_norr</tt> (standing for “no rational roots”).</li> +<li><tt class="docutils literal">sqfnorr</tt>: the postfix that <a class="reference internal" href="#id14">\PolSturmIsolateZeros**{sturmname}</a> +should append to <tt class="docutils literal">sturmname</tt> to declare the primitive polynomial +obtained from original one after removal of all rational roots and +suppression of all multiplicities. +The default value is <tt class="docutils literal">_sqf_norr</tt> (standing for “square-free with +no rational roots”).</li> +</ul> +<p>The package executes <tt class="docutils literal">\polexprsetup{norr=_norr, +sqfnorr=_sqf_norr}</tt> as default.</p> +</blockquote> +</div> +<div class="section" id="technicalities"> +<h1><a class="toc-backref" href="#id158">Technicalities</a></h1> +<ul> +<li><p class="first">The catcode of the semi-colon is reset temporarily by <a class="reference internal" href="#poldef">\poldef</a> 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 <a class="reference internal" href="#id2">\PolDef{f}{P(x)}</a> +rather. The colon in <tt class="docutils literal">:=</tt> may be active with no consequences.</p> +</li> +<li><p class="first">As a consequence of <a class="reference external" href="http://www.ctan.org/pkg/xint">xintfrac</a> addition and subtraction always using +least common multiples for the denominators <a class="footnote-reference" href="#id37" id="id36">[5]</a>, user-chosen common +denominators survive additions and multiplications. For example, this:</p> +<pre class="literal-block"> +\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(x)Q(x); +</pre> +<p>gives internally the polynomial:</p> +<pre class="literal-block"> +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 +</pre> +<p>where all coefficients have the same denominator 6. Notice though that +<tt class="docutils literal">\PolToExpr{PQ}</tt> outputs the <tt class="docutils literal">6/6*x^3</tt> as <tt class="docutils literal">x^3</tt> because (by +default) it recognizes and filters out coefficients equal to one or +minus one (since release <tt class="docutils literal">0.3</tt>). One can use for example +<tt class="docutils literal">\PolToCSV{PQ}</tt> to see the internally stored coefficients.</p> +<table class="docutils footnote" frame="void" id="id37" rules="none"> +<colgroup><col class="label" /><col /></colgroup> +<tbody valign="top"> +<tr><td class="label"><a class="fn-backref" href="#id36">[5]</a></td><td><p class="first last">prior to <tt class="docutils literal">0.4.1</tt>, <tt class="docutils literal">polexpr</tt> used to temporarily patch +during the parsing of polynomials the <a class="reference external" href="http://www.ctan.org/pkg/xint">xintfrac</a> macros. This +patch was backported to <a class="reference external" href="http://www.ctan.org/pkg/xint">xint</a> at release <tt class="docutils literal">1.3</tt>.</p> +</td></tr> +</tbody> +</table> +</li> +<li><p class="first"><a class="reference internal" href="#poldiff-polname-1-polname-2">\PolDiff{polname_1}{polname_2}</a> always applies <tt class="docutils literal">\xintIrr</tt> to the +resulting coefficients, except that the <em>power of ten</em> part <tt class="docutils literal">[N]</tt> +(for example an input in scientific notation such as <tt class="docutils literal">1.23e5</tt> gives +<tt class="docutils literal">123/1[3]</tt> internally in xintfrac) is not taken into account in the +reduction of the fraction. This is tentative and may change.</p> +<p>Same remark for <a class="reference internal" href="#polantidiff-polname-1-polname-2">\PolAntiDiff{polname_1}{polname_2}</a>.</p> +</li> +<li><p class="first">Currently, the package stores all coefficients from index <tt class="docutils literal">0</tt> 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 <tt class="docutils literal">\poldef +<span class="pre">f(x):=x^1000</span> + x^500;</tt> the subsequent definition <tt class="docutils literal">\poldef <span class="pre">g(x):=</span> +<span class="pre">f(x)^2;</span></tt> 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.</p> +</li> +<li><p class="first">As is to be expected internal structures of the package are barely +documented and unstable. Don't use them.</p> +</li> +</ul> +</div> +<div class="section" id="change-log"> +<h1><a class="toc-backref" href="#id159">CHANGE LOG</a></h1> +<ul> +<li><p class="first">v0.1 (2018/01/11): initial release. Features:</p> +<ul class="simple"> +<li>The <a class="reference internal" href="#poldef">\poldef</a> parser itself,</li> +<li>Differentiation and anti-differentiation,</li> +<li>Euclidean division and GCDs,</li> +<li>Various utilities such as <a class="reference internal" href="#polfromcsv">\PolFromCSV</a>, +<a class="reference internal" href="#polmapcoeffs">\PolMapCoeffs</a>, +<a class="reference internal" href="#poltocsv">\PolToCSV</a>, <a class="reference internal" href="#poltoexpr">\PolToExpr</a>, ...</li> +</ul> +<p>Only one-variable polynomials so far.</p> +</li> +<li><p class="first">v0.2 (2018/01/14)</p> +<ul class="simple"> +<li>Fix: <tt class="docutils literal">"README thinks \numexpr recognizes ^ operator"</tt>.</li> +<li>Convert README to reStructuredText markup.</li> +<li>Move main documentation from README to separate <tt class="docutils literal">polexpr.txt</tt> file.</li> +<li>Provide <tt class="docutils literal">polexpr.html</tt> as obtained via <a class="reference external" href="http://docutils.sourceforge.net/docs/index.html">DocUtils</a> <tt class="docutils literal">rst2html.py</tt>.</li> +<li>Convert README to (CTAN compatible) Markdown markup.</li> +</ul> +<p>Due to lack of available time the test suite might not be extensive +enough. Bug reports are very welcome!</p> +</li> +<li><p class="first">v0.3 (2018/01/17)</p> +<ul> +<li><p class="first">bug fixes:</p> +<ul> +<li><p class="first">the <tt class="docutils literal">0.1</tt> <a class="reference internal" href="#polevalat">\PolEval</a> accepted expressions for its second +argument, but this was removed by mistake at <tt class="docutils literal">0.2</tt>. Restored.</p> +<p><strong>Attention</strong>: at <tt class="docutils literal">0.4</tt> this has been reverted again, and +<a class="reference internal" href="#polevalatexpr">\PolEval{P}\AtExpr{foo}</a> syntax is needed for +using expressions in the second argument.</p> +</li> +</ul> +</li> +<li><p class="first">incompatible or breaking changes:</p> +<ul class="simple"> +<li><a class="reference internal" href="#poltoexpr">\PolToExpr</a> now by default uses <em>descending</em> +powers (it also treats differently coefficients equal to 1 or -1.) +Use <a class="reference internal" href="#id30">\PolToExpr*</a> for <em>ascending</em> powers.</li> +<li><a class="reference internal" href="#polevalat">\PolEval</a> reduced the output to smallest terms, +but as this is costly with big fractions and not needed if e.g. +wrapped in an <tt class="docutils literal">\xintRound</tt> or <tt class="docutils literal">\xintFloat</tt>, this step has been +removed; the former meaning is available as <a class="reference internal" href="#polevalreducedat">\PolEvalReduced</a>.</li> +</ul> +</li> +<li><p class="first">new (or newly documented) macros:</p> +<ul class="simple"> +<li><a class="reference internal" href="#poltypesetcmd">\PolTypesetCmd</a></li> +<li><a class="reference internal" href="#poltypesetcmdprefix">\PolTypesetCmdPrefix</a></li> +<li><a class="reference internal" href="#poltypesetmonomialcmd">\PolTypesetMonomialCmd</a></li> +<li><a class="reference internal" href="#polevalreducedat">\PolEvalReducedAt</a></li> +<li><a class="reference internal" href="#poltofloatexpr">\PolToFloatExpr</a></li> +<li><a class="reference internal" href="#poltoexproneterm">\PolToExprOneTerm</a></li> +<li><a class="reference internal" href="#poltofloatexproneterm">\PolToFloatExprOneTerm</a></li> +<li><a class="reference internal" href="#poltoexprcmd">\PolToExprCmd</a></li> +<li><a class="reference internal" href="#id33">\PolToFloatExprCmd</a></li> +<li><a class="reference internal" href="#poltoexprtermprefix">\PolToExprTermPrefix</a></li> +<li><a class="reference internal" href="#poltoexprvar">\PolToExprVar</a></li> +<li><a class="reference internal" href="#poltoexprtimes">\PolToExprTimes</a></li> +</ul> +</li> +<li><p class="first">improvements:</p> +<ul> +<li><p class="first">documentation has a table of contents, internal hyperlinks, +standardized signature notations and added explanations.</p> +</li> +<li><p class="first">one can do <tt class="docutils literal"><span class="pre">\PolLet{g}={f}</span></tt> or <tt class="docutils literal"><span class="pre">\PolLet{g}{f}</span></tt>.</p> +</li> +<li><p class="first"><tt class="docutils literal">\PolToExpr{f}</tt> is highly customizable.</p> +</li> +<li><p class="first"><a class="reference internal" href="#poldef">\poldef</a> and other defining macros prepare the polynomial +functions for usage within <tt class="docutils literal">\xintthefloatexpr</tt> (or +<tt class="docutils literal">\xintdeffloatvar</tt>). 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.</p> +<p><strong>Attention</strong>: this has been reverted at <tt class="docutils literal">0.4</tt>. The macro +<a class="reference internal" href="#polgenfloatvariant">\PolGenFloatVariant</a> must be used for +generation floating point polynomial functions.</p> +</li> +</ul> +</li> +</ul> +</li> +<li><p class="first">v0.3.1 (2018/01/18)</p> +<p>Fixes two typos in example code included in the documentation.</p> +</li> +<li><p class="first">v0.4 (2018/02/16)</p> +<ul> +<li><p class="first">bug fixes:</p> +<ul class="simple"> +<li>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 <a class="reference internal" href="#polmapcoeffs">\PolMapCoeffs</a>.</li> +<li><a class="reference internal" href="#polgcd">\PolGCD</a> was buggy in case of first polynomial being +of lesser degree than the second one.</li> +</ul> +</li> +<li><p class="first">breaking changes:</p> +<ul> +<li><p class="first">formerly <a class="reference internal" href="#polevalat">\PolEval{P}\At{foo}</a> allowed <tt class="docutils literal">foo</tt> to +be an expression, which was transparently handled via +<tt class="docutils literal">\xinttheexpr</tt>. Now, <tt class="docutils literal">foo</tt> must be a fraction (or a macro +expanding to such) in the format acceptable by <tt class="docutils literal">xintfrac.sty</tt> +macros. Use <a class="reference internal" href="#polevalatexpr">\PolEval{P}\AtExpr{foo}</a> for more +general arguments using expression syntax. E.g., if <tt class="docutils literal">foo</tt> is the +name of a variable known to <tt class="docutils literal">\xintexpr</tt>.</p> +<p>The same holds for <a class="reference internal" href="#polevalreducedat">\PolEvalReduced</a> +and <a class="reference internal" href="#polfloatevalat">\PolFloatEval</a>.</p> +</li> +<li><p class="first">the <tt class="docutils literal">3.0</tt> automatic generation of floating point variants has +been reverted. Not only do <em>not</em> the package macros automatically +generate floating point variants of newly created polynomials, +they actually make pre-existing such variant undefined.</p> +<p>See <a class="reference internal" href="#polgenfloatvariant">\PolGenFloatVariant</a>.</p> +</li> +</ul> +</li> +<li><p class="first">new non-expandable macros:</p> +<ul class="simple"> +<li><a class="reference internal" href="#polgenfloatvariant">\PolGenFloatVariant</a></li> +<li><a class="reference internal" href="#polgloballet">\PolGlobalLet</a></li> +<li><a class="reference internal" href="#poltypesetone">\PolTypesetOne</a></li> +<li><a class="reference internal" href="#polquo">\PolQuo</a></li> +<li><a class="reference internal" href="#polrem">\PolRem</a></li> +<li><a class="reference internal" href="#poltosturm">\PolToSturm</a></li> +<li><a class="reference internal" href="#id9">\PolToSturm*</a></li> +<li><a class="reference internal" href="#polsettosturmchainsignchangesat">\PolSetToSturmChainSignChangesAt</a></li> +<li><a class="reference internal" href="#polsettonbofzeroswithin">\PolSetToNbOfZerosWithin</a></li> +<li><a class="reference internal" href="#polsturmisolatezeros">\PolSturmIsolateZeros</a></li> +<li><a class="reference internal" href="#polrefineinterval">\PolRefineInterval*</a></li> +<li><a class="reference internal" href="#polrefineinterval-n">\PolRefineInterval[N]</a></li> +<li><a class="reference internal" href="#polensureintervallength">\PolEnsureIntervalLength</a></li> +<li><a class="reference internal" href="#polensureintervallengths">\PolEnsureIntervalLengths</a></li> +<li><a class="reference internal" href="#polprintintervals">\PolPrintIntervals</a></li> +<li><a class="reference internal" href="#polprintintervalsprintexactzero">\PolPrintIntervalsPrintExactZero</a></li> +<li><a class="reference internal" href="#polprintintervalsprintleftendpoint">\PolPrintIntervalsPrintLeftEndPoint</a></li> +<li><a class="reference internal" href="#polprintintervalsprintrightendpoint">\PolPrintIntervalsPrintRightEndPoint</a></li> +<li><a class="reference internal" href="#id20">\PolReduceCoeffs*</a></li> +<li><a class="reference internal" href="#polmakemonic">\PolMakeMonic</a></li> +</ul> +</li> +<li><p class="first">new expandable macros:</p> +<ul class="simple"> +<li><a class="reference internal" href="#poltoexpronetermstylea">\PolToExprOneTermStyleA</a></li> +<li><a class="reference internal" href="#polifcoeffisplusorminusone">\PolIfCoeffIsPlusOrMinusOne</a></li> +<li><a class="reference internal" href="#polleadingcoeff">\PolLeadingCoeff</a></li> +<li><a class="reference internal" href="#polsturmchainlength">\PolSturmChainLength</a></li> +<li><a class="reference internal" href="#polsturmnbofisolatedzeros">\PolSturmNbOfIsolatedZeros</a></li> +<li><a class="reference internal" href="#polsturmifzeroexactlyknown">\PolSturmIfZeroExactlyKnown</a></li> +<li><a class="reference internal" href="#polsturmisolatedzeroleft">\PolSturmIsolatedZeroLeft</a></li> +<li><a class="reference internal" href="#polsturmisolatedzeroright">\PolSturmIsolatedZeroRight</a></li> +<li><tt class="docutils literal">\PolPrintIntervalsTheEndPoint</tt> (removed at 0.7)</li> +<li><a class="reference internal" href="#polprintintervalstheindex">\PolPrintIntervalsTheIndex</a></li> +<li><tt class="docutils literal">\PolIfEndPointIsPositive</tt> (removed at 0.7)</li> +<li><tt class="docutils literal">\PolIfEndPointIsNegative</tt> (removed at 0.7)</li> +<li><tt class="docutils literal">\PolIfEndPointIsZero</tt> (removed at 0.7)</li> +<li><a class="reference internal" href="#polintervalwidth">\PolIntervalWidth</a></li> +<li><a class="reference internal" href="#poldectostring">\PolDecToString</a></li> +</ul> +</li> +<li><p class="first">improvements:</p> +<p>The main new feature is implementation of the <a class="reference external" href="https://en.wikipedia.org/wiki/Sturm%27s_theorem">Sturm algorithm</a> +for localization of the real roots of polynomials.</p> +</li> +</ul> +</li> +<li><p class="first">v0.4.1 (2018/03/01)</p> +<p>Synced with xint 1.3.</p> +</li> +<li><p class="first">v0.4.2 (2018/03/03)</p> +<p>Documentation fix.</p> +</li> +<li><p class="first">v0.5 (2018/04/08)</p> +<ul class="simple"> +<li>bug fixes:<ul> +<li><a class="reference internal" href="#polget-polname-fromarray-macro">\PolGet{polname}\fromarray\macro</a> crashed when <tt class="docutils literal">\macro</tt> was +an <a class="reference external" href="http://www.ctan.org/pkg/xint">xinttools</a> array macro with no items. It now produces the zero +polynomial.</li> +</ul> +</li> +<li>breaking changes:<ul> +<li><a class="reference internal" href="#poltosturm">\PolToSturm</a> creates primitive integer coefficients polynomials. +This speeds up localization of roots via +<a class="reference internal" href="#polsturmisolatezeros">\PolSturmIsolateZeros</a>. In case of user protests the author +will make available again the code producing the bona fide Sturm +polynomials as used formerly.</li> +<li>polynomials created from <a class="reference internal" href="#polfromcsv">\PolFromCSV</a> or <a class="reference internal" href="#polget">\PolGet</a> +get their coefficients normalized via <a class="reference external" href="http://www.ctan.org/pkg/xint">xintfrac</a>'s <tt class="docutils literal">\xintRaw</tt>.</li> +</ul> +</li> +<li>experimental change:<ul> +<li>optional argument to <a class="reference internal" href="#polsturmisolatezeros">\PolSturmIsolateZeros</a> (see <a class="reference internal" href="#the-degree-41-polynomial-with-2-1-9-1-8-0-0-1-1-9-2-as-roots">The +degree 41 polynomial with -2, -1.9, -1.8, ..., 0, 0.1, ..., 1.9, 2 +as roots</a> for usage). It will presumably be replaced in future by +an interval specification.</li> +</ul> +</li> +<li>new non-expandable macro:<ul> +<li><a class="reference internal" href="#polmakeprimitive">\PolMakePrimitive</a></li> +</ul> +</li> +<li>new expandable macro:<ul> +<li><a class="reference internal" href="#policontent">\PolIContent</a></li> +</ul> +</li> +</ul> +</li> +<li><p class="first">v0.5.1 (2018/04/22)</p> +<ul class="simple"> +<li>new feature:<ul> +<li>the character <tt class="docutils literal">'</tt> can be used in polynomial names.</li> +</ul> +</li> +</ul> +</li> +<li><p class="first">v0.6 (2018/11/20)</p> +<ul class="simple"> +<li>bugfix:<ul> +<li>the starred variant <a class="reference internal" href="#id10">\PolToSturm*{polname}{sturmname}</a> was +broken. On the occasion of the fix, its meaning has been modified, +see its documentation.</li> +<li>using <a class="reference internal" href="#poltosturm">\PolToSturm</a> with a constant polynomial +caused a division by zero error.</li> +</ul> +</li> +<li>new macro:<ul> +<li><a class="reference internal" href="#id11">\PolSturmIsolateZeros*</a> +acts like the <a class="reference internal" href="#polsturmisolatezeros">non-starred variant</a> then computes all the multiplicities.</li> +</ul> +</li> +<li>new expandable macros:<ul> +<li><a class="reference internal" href="#polsturmisolatedzeromultiplicity-sturmname-index">\PolSturmIsolatedZeroMultiplicity{sturmname}{index}</a></li> +<li><a class="reference internal" href="#polsturmnbofrootsof-sturmname-lessthanorequalto-value">\PolSturmNbOfRootsOf{sturmname}\LessThanOrEqualTo{value}</a></li> +<li><a class="reference internal" href="#polsturmnbofrootsof-sturmname-lessthanorequaltoexpr-expression">\PolSturmNbOfRootsOf{sturmname}\LessThanOrEqualToExpr{expression}</a></li> +<li><a class="reference internal" href="#polsturmnbwithmultofrootsof-sturmname-lessthanorequalto-value">\PolSturmNbWithMultOfRootsOf{sturmname}\LessThanOrEqualTo{value}</a></li> +<li><a class="reference internal" href="#polsturmnbwithmultofrootsof-sturmname-lessthanorequaltoexpr-expression">\PolSturmNbWithMultOfRootsOf{sturmname}\LessThanOrEqualToExpr{expression}</a></li> +</ul> +</li> +</ul> +</li> +<li><p class="first">v0.7 (2018/12/08), v0.7.1 (bugfix), v0.7.2 (2nd bugfix) (2018/12/09)</p> +<ul class="simple"> +<li>breaking changes:<ul> +<li>although <a class="reference internal" href="#polprintintervals-varname-sturmname">\PolPrintIntervals[varname]{sturmname}</a> default output +remains the same, some auxiliary macros for user-customization +have been removed: <tt class="docutils literal">\PolPrintIntervalsTheEndPoint</tt>, +<tt class="docutils literal"><span class="pre">\PolIfEndPointIsPositive{A}{B}</span></tt>, +<tt class="docutils literal"><span class="pre">\PolIfEndPointIsNegative{A}{B}</span></tt>, and +<tt class="docutils literal"><span class="pre">\PolIfEndPointIsZero{A}{B}</span></tt>.</li> +</ul> +</li> +<li>bugfix:<ul> +<li>it could happen that, contrarily to documentation, an interval +computed by <a class="reference internal" href="#polsturmisolatezeros-sturmname">\PolSturmIsolateZeros{sturmname}</a> had zero as an +endpoint,</li> +<li><a class="reference internal" href="#polensureintervallength-sturmname-index-e">\PolEnsureIntervalLength{sturmname}{index}{E}</a> could under +certain circumstances erroneously replace a non-zero root by +zero,</li> +<li><a class="reference internal" href="#polensureintervallengths-sturmname-e">\PolEnsureIntervalLengths{sturmname}{E}</a> crashed when used with +a polynomial with no real roots, hence for which no isolation intervals +existed (thanks to Thomas Söll for report).</li> +</ul> +</li> +<li>new macros:<ul> +<li><a class="reference internal" href="#id14">\PolSturmIsolateZeros**{sturmname}</a></li> +<li><a class="reference internal" href="#polsturmisolatezerosgetmultiplicitiesandrationalroots-sturmname">\PolSturmIsolateZerosGetMultiplicitiesAndRationalRoots{sturmname}</a></li> +<li><a class="reference internal" href="#polsturmisolatezerosandfindrationalroots-sturmname">\PolSturmIsolateZerosAndFindRationalRoots{sturmname}</a></li> +<li><a class="reference internal" href="#polexprsetup">\polexprsetup</a></li> +<li><a class="reference internal" href="#id18">\PolPrintIntervals*</a></li> +<li><a class="reference internal" href="#polprintintervalsnorealroots">\PolPrintIntervalsNoRealRoots</a></li> +<li><a class="reference internal" href="#polprintintervalsbeginenv">\PolPrintIntervalsBeginEnv</a></li> +<li><a class="reference internal" href="#polprintintervalsendenv">\PolPrintIntervalsEndEnv</a></li> +<li><a class="reference internal" href="#polprintintervalsknownroot">\PolPrintIntervalsKnownRoot</a></li> +<li><a class="reference internal" href="#polprintintervalsunknownroot">\PolPrintIntervalsUnknownRoot</a></li> +<li><a class="reference internal" href="#polprintintervalsprintmultiplicity">\PolPrintIntervalsPrintMultiplicity</a></li> +</ul> +</li> +<li>new expandable macros:<ul> +<li><a class="reference internal" href="#polsturmnbofrationalroots-sturmname">\PolSturmNbOfRationalRoots{sturmname}</a></li> +<li><a class="reference internal" href="#polsturmnbofrationalrootswithmultiplicities-sturmname">\PolSturmNbOfRationalRootsWithMultiplicities{sturmname}</a></li> +<li><a class="reference internal" href="#polsturmrationalroot-sturmname-k">\PolSturmRationalRoot{sturmname}{k}</a></li> +<li><a class="reference internal" href="#polsturmrationalrootindex-sturmname-k">\PolSturmRationalRootIndex{sturmname}{k}</a></li> +<li><a class="reference internal" href="#polsturmrationalrootmultiplicity-sturmname-k">\PolSturmRationalRootMultiplicity{sturmname}{k}</a></li> +<li><a class="reference internal" href="#polprintintervalsthevar">\PolPrintIntervalsTheVar</a></li> +<li><a class="reference internal" href="#polprintintervalsthesturmname">\PolPrintIntervalsTheSturmName</a></li> +<li><a class="reference internal" href="#polprintintervalsthemultiplicity">\PolPrintIntervalsTheMultiplicity</a></li> +</ul> +</li> +</ul> +</li> +<li><p class="first">v0.7.3 (2019/02/04)</p> +<ul class="simple"> +<li>bugfix:<ul> +<li>Debugging information not destined to user showed in log if root +finding was done under <tt class="docutils literal">\xintverbosetrue</tt> regime.</li> +<li><a class="reference internal" href="#polprintintervalsthevar">\PolPrintIntervalsTheVar</a> remained defined after +<a class="reference internal" href="#polprintintervals">\PolPrintIntervals</a> but was left undefined after +<a class="reference internal" href="#id18">\PolPrintIntervals*</a> (reported by Jürgen Gilg). Now remains +defined in both cases, and <a class="reference internal" href="#polprintintervalsthesturmname">\PolPrintIntervalsTheSturmName</a> +also.</li> +<li>Polynomial names ending in digits caused errors (reported by Thomas +Söll).</li> +</ul> +</li> +</ul> +</li> +<li><p class="first">v0.7.4 (2019/02/12)</p> +<ul class="simple"> +<li>bugfix:<ul> +<li>20000000000 is too big for <tt class="docutils literal">\numexpr</tt>, shouldn't I know that? +Thanks to Jürgen Gilg for report.</li> +</ul> +</li> +</ul> +</li> +</ul> +</div> +<div class="section" id="acknowledgments"> +<h1><a class="toc-backref" href="#id160">Acknowledgments</a></h1> +<p>Thanks to Jürgen Gilg whose question about <a class="reference external" href="http://www.ctan.org/pkg/xint">xint</a> 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.</p> +<p>Renewed thanks to them on occasion of the <tt class="docutils literal">0.6</tt> and <tt class="docutils literal">0.7</tt> releases for their +continued interest.</p> +<p>See README.md for the License.</p> +</div> +</div> +</body> +</html> diff --git a/macros/latex/contrib/polexpr/polexpr.sty b/macros/latex/contrib/polexpr/polexpr.sty new file mode 100644 index 0000000000..e9509d8942 --- /dev/null +++ b/macros/latex/contrib/polexpr/polexpr.sty @@ -0,0 +1,2946 @@ +% author: Jean-François Burnol +% License: LPPL 1.3c (author-maintained) +\ProvidesPackage{polexpr}% + [2019/02/12 v0.7.4 Polynomial expressions with rational coefficients (JFB)]% +\RequirePackage{xintexpr}[2018/06/17]% xint 1.3c for \ifxintglobaldefs boolean +\edef\POL@restorecatcodes + {\catcode`\noexpand\_ \the\catcode`\_ % + \catcode`\noexpand\! \the\catcode`\! % + \catcode`\noexpand\* \the\catcode`\* % + \catcode0 \the\catcode0\relax}% +\catcode`\_ 11 \catcode0 12 \catcode`\* 12 +\long\def\xint_stop_atfirstoftwo #1#2{ #1}% not yet in xint 1.3c +\long\def\xint_stop_atsecondoftwo #1#2{ #2}% + +%% PATCH xintexpr TO AUTHORIZE ' IN NAMES (0.5.1) +\catcode`\! 11 +\def\POL@XINT_expr_scanfunc_b #1% +{% + \ifx !#1\xint_dothis{(_}\fi + \ifcat \relax#1\xint_dothis{(_}\fi + \if (#1\xint_dothis{\xint_firstoftwo{(`}}\fi + \if '#1\xint_dothis \XINT_expr_scanfunc_a \fi + \if @#1\xint_dothis \XINT_expr_scanfunc_a \fi + \if _#1\xint_dothis \XINT_expr_scanfunc_a \fi + \ifnum \xint_c_ix<1\string#1 \xint_dothis \XINT_expr_scanfunc_a \fi + \ifcat a#1\xint_dothis \XINT_expr_scanfunc_a \fi + \xint_orthat {(_}% + #1% +}% + +%% AUXILIARIES +\catcode`! 3 +%% added at 0.7 +\newcommand\polexprsetup[1]{\POL@setup_parsekeys #1,=!,\xint_bye}% +\def\POL@setup_parsekeys #1=#2#3,{% + \ifx!#2\expandafter\xint_bye\fi + \csname POL@setup_setkey_\xint_zapspaces #1 \xint_gobble_i\endcsname + \xint_firstoftwo + {\PackageWarning{polexpr}{The \detokenize{#1} key is unknown! ignoring}}% + {\xintZapLastSpaces{#2#3}}% + \POL@setup_parsekeys +}% +\catcode`! 11 +\def\POL@setup_setkey_norr #1#2{\edef\POL@norr}% +\def\POL@setup_setkey_sqfnorr #1#2{\edef\POL@sqfnorr}% +\polexprsetup{norr=_norr, sqfnorr=_sqf_norr} + +\newcount\POL@count +\newif\ifPOL@pol +\newif\ifxintveryverbose +\newif\ifpoltypesetall +\newif\ifPOL@tosturm@makefirstprimitive +\POL@tosturm@makefirstprimitivetrue +\newif\ifPOL@isolz@nextwillneedrefine +\newif\ifpoltoexprall +%% the main exchange structure (stored in macros \POLuserpol@<name>) +%% is: degree.\empty{coeff0}{coeff1}....{coeffN} +%% (degree=N except zero polynomial recognized from degree set to -1 +%% but it has always the {0/1[0]} coeff0.) +\def\POL@ifZero#1{\expandafter\POL@ifZero@aux#1;}% +\def\POL@ifZero@aux #1#2;{\if-#1\expandafter\xint_firstoftwo + \else\expandafter\xint_secondoftwo + \fi}% +\def\POL@split#1.#2;#3#4% separates degree and list of coefficients +% The \expandafter chain removes the \empty token + {\def#3{#1}\expandafter\def\expandafter#4\expandafter{#2}}% +% +\def\POL@resultfromarray #1{% ATTENTION, **MUST** be executed with +% \count@ set to 1 + degree (\count@ = 0 for zero polynomial) + \edef\POL@result{\ifnum\count@>\z@ + \the\numexpr\count@-\@ne.\noexpand\empty + \xintiloop [1+1]% + \expandafter\POL@braceit\csname POL@array#1\xintiloopindex\endcsname + \ifnum\xintiloopindex<\count@ + \repeat + \else-1.\noexpand\empty{0/1[0]}\fi}% +}% +\def\POL@braceit#1{{#1}}% needed as \xintiloopindex can not "see" through braces + + +\newcommand\PolDef[3][x]{\poldef #2(#1):=#3;}% +\def\poldef{\edef\POL@restoresemicolon{\catcode59=\the\catcode59\relax}% + \catcode59 12 \POL@defpol}% +\def\POL@defpol #1(#2)#3=#4;{% + \POL@restoresemicolon + \edef\POL@tmp{\ifxintverbose1\else0\fi}% + \unless\ifxintveryverbose\xintverbosefalse\fi + \let\POL@originalXINT_expr_scanfunc_b\XINT_expr_scanfunc_b + \let\XINT_expr_scanfunc_b\POL@XINT_expr_scanfunc_b + \xintdeffunc __pol(#2):=0+(#4);% force conversion to raw if a constant + \if1\POL@tmp\xintverbosetrue\fi + \edef\POL@polname{\xint_zapspaces #1 \xint_gobble_i}% + \let\XINT_expr_scanfunc_b\POL@originalXINT_expr_scanfunc_b + \begingroup + \setbox0\hbox{% + \let\xintScalarAdd\xintAdd + \let\xintScalarSub\xintSub + \let\xintScalarMul\xintMul + \let\xintScalarDiv\xintDiv + \let\xintScalarPow\xintPow + \let\xintScalarOpp\xintOpp + \let\xintAdd\POL@add + \let\xintMul\POL@mul + \let\xintDiv\POL@div + \let\xintPow\POL@pow + \let\xintOpp\POL@opp + \def\xintSub ##1##2{\xintAdd{##1}{\xintOpp{##2}}}% + % \xintAdd{0} to get \POL@result defined even if numerical only expression + % I could also test \ifPOL@pol, but this is anyhow small overhead + \xintAdd{0}% + {\csname XINT_expr_userfunc___pol\endcsname + {\global\POL@poltrue\def\POL@result{1.\empty{0/1[0]}{1/1[0]}}}}% + \expandafter}\expandafter + \endgroup\expandafter + \def\csname POLuserpol@\POL@polname\expandafter\endcsname + \expandafter{\POL@result}% + \expandafter\POL@newpol\expandafter{\POL@polname}% +}% +%% +\def\POL@newpol#1{% + \expandafter\POL@ifZero\csname POLuserpol@#1\endcsname + {\@namedef{XINT_expr_userfunc_#1}##1{0/1[0]}}% + {\POL@newpolhorner{#1}}% + \expandafter\XINT_expr_defuserfunc + \csname XINT_expr_func_#1\endcsname{#1}{expr}% + \expandafter\let\csname XINT_flexpr_func_#1\endcsname\@undefined + \ifxintverbose\POL@info{#1}\fi +}% +\def\POL@newfloatpol#1{% + \expandafter\POL@ifZero\csname POLuserpol@#1\endcsname + {\@namedef{XINT_flexpr_userfunc_#1}##1{0[0]}}% + {\POL@newfloatpolhorner{#1}}% + \expandafter\XINT_expr_defuserfunc + \csname XINT_flexpr_func_#1\endcsname{#1}{flexpr}% + \ifxintverbose\POL@floatinfo{#1}\fi +}% +\def\POL@info #1{% + \xintMessage {polexpr}{Info}% + {Function #1 for the \string\xintexpr\space parser is + associated to \string\XINT_expr_userfunc_#1\space + whose meaning uses Horner scheme: + \expandafter\meaning + \csname XINT_expr_userfunc_#1\endcsname}% +}% +\def\POL@floatinfo #1{% + \xintMessage {polexpr}{Info}% + {Function #1 for the \string\xintfloatexpr\space parser is + associated to \string\XINT_flexpr_userfunc_#1\space + whose meaning uses Horner scheme: + \expandafter\meaning + \csname XINT_flexpr_userfunc_#1\endcsname}% +}% +% +\def\POL@newpolhorner#1{% + %% redefine function to expand by Horner scheme. Is this useful? + %% perhaps bad idea for numerical evaluation of thing such as (1+x)^10? +% note: I added {0/1[0]} item to zero polynomial also to facilitate this + \expandafter\expandafter\expandafter\POL@split + \csname POLuserpol@#1\endcsname;\POL@var@deg\POL@var@coeffs + \edef\POL@var@coeffs{\xintRevWithBraces{\POL@var@coeffs}}% + \begingroup + \expandafter\POL@newpol@horner\POL@var@coeffs\relax + \expandafter + \endgroup + \expandafter\def\csname XINT_expr_userfunc_#1\expandafter\endcsname + \expandafter##\expandafter1\expandafter{\POL@tmp{##1}}% +}% +\def\POL@newfloatpolhorner#1{% + %% redefine function to expand by Horner scheme. Is this useful? + %% perhaps bad idea for numerical evaluation of thing such as (1+x)^10? +% note: I added {0/1[0]} item to zero polynomial also to facilitate this + \expandafter\expandafter\expandafter\POL@split + \csname POLuserpol@#1\endcsname;\POL@var@deg\POL@var@coeffs + \edef\POL@var@coeffs{\xintRevWithBraces{\POL@var@coeffs}}% + \begingroup + \expandafter\POL@newpol@floathorner\POL@var@coeffs\relax + \expandafter + \endgroup + \expandafter\def\csname XINT_flexpr_userfunc_#1\expandafter\endcsname + \expandafter##\expandafter1\expandafter{\POL@tmp{##1}}% +}% +\def\POL@newpol@horner#1{\let\xintAdd\relax\let\xintMul\relax + \def\POL@tmp##1{#1}\POL@newpol@horner@loop.}% +\def\POL@newpol@horner@loop.#1{% + \if\relax#1\expandafter\xint_gob_til_dot\fi + \edef\POL@tmp##1{\xintiiifZero{#1} + {\@firstofone}{\xintAdd{#1}}% + {\xintMul{##1}{\POL@tmp{##1}}}}% + \POL@newpol@horner@loop.% +}% +\def\POL@newpol@floathorner#1{\let\XINTinFloatAdd\relax\let\XINTinFloatMul\relax + \def\xintAdd{\XINTinFloatAdd}\def\xintMul{\XINTinFloatMul}% + \edef\POL@tmp##1{\XINTinFloatdigits{#1}}% + \POL@newpol@floathorner@loop.}% +\def\POL@newpol@floathorner@loop.#1{% + \if\relax#1\expandafter\xint_gob_til_dot\fi + \edef\POL@tmp##1{\xintiiifZero{#1} + {\@firstofone}{\xintAdd{\XINTinFloatdigits{#1}}}% + {\xintMul{##1}{\POL@tmp{##1}}}}% + \POL@newpol@floathorner@loop.% +}% + + +\newcommand\PolGenFloatVariant[1]{\POL@newfloatpol{#1}}% + + +\newcommand\PolLet[2]{\if=\noexpand#2\expandafter\xint_firstoftwo + \else\expandafter\xint_secondoftwo\fi + \POL@@let\POL@let{#1}{#2}}% +\def\POL@@let#1#2#3{\POL@let{#1}{#3}}% +\def\POL@let#1#2{% + \expandafter\let\csname POLuserpol@#1\expandafter\endcsname + \csname POLuserpol@#2\endcsname + \expandafter\let\csname XINT_expr_userfunc_#1\expandafter\endcsname + \csname XINT_expr_userfunc_#2\endcsname + \expandafter\XINT_expr_defuserfunc + \csname XINT_expr_func_#1\endcsname{#1}{expr}% + \ifxintverbose\POL@info{#1}\fi +}% +\newcommand\PolGlobalLet[2]{\begingroup + \globaldefs\@ne + \if=\noexpand#2\expandafter\xint_firstoftwo + \else\expandafter\xint_secondoftwo\fi +% do I need to check something here relative to \xintNewExpr? + \POL@@globallet\POL@globallet {#1}{#2}}% +\def\POL@@globallet#1#2#3{\POL@globallet{#1}{#3}}% +\def\POL@globallet#1#2{\POL@let{#1}{#2}\endgroup}% + +\newcommand\PolAssign[1]{\def\POL@polname{#1}\POL@assign}% zap spaces in #1? +\def\POL@assign#1\toarray#2{% + \expandafter\expandafter\expandafter\POL@split + \csname POLuserpol@\POL@polname\endcsname;\POL@var@deg\POL@var@coeffs + \xintAssignArray\POL@var@coeffs\to#2% + % modify \#200 macro to return 0/1[0] for out of range indices + \@namedef{\xint_arrayname00}##1##2##3{% + \@namedef{\xint_arrayname00}####1{% + \ifnum####1>##1 \xint_dothis{ 0/1[0]}\fi + \ifnum####1>\m@ne \xint_dothis + {\expandafter\expandafter\expandafter##3% + \csname##2####1\endcsname}\fi + \unless\ifnum-####1>##1 \xint_dothis + {\expandafter\expandafter\expandafter##3% + \csname##2\the\numexpr##1+####1+\@ne\endcsname}\fi + \xint_orthat{ 0/1[0]}}% space stops a \romannumeral0 + }% + \csname\xint_arrayname00\expandafter\expandafter\expandafter\endcsname + \expandafter\expandafter\expandafter + {\csname\xint_arrayname0\expandafter\endcsname\expandafter}\expandafter + {\xint_arrayname}{ }% +}% + + +\newcommand\PolGet{}% +\def\PolGet#1#2\fromarray#3{% + \begingroup % closed in \POL@getfromarray + \POL@getfromarray{#1}{#3}% + \POL@newpol{#1}% +}% +\def\POL@getfromarray#1#2{% + \count@=#2{0} %<- intentional space + \ifnum\count@=\z@ + \def\POL@result{-1.\empty{0/1[0]}}% 0.5 fix for empty array + \else + \xintloop + \edef\POL@tmp{#2{\count@}}% + \edef\POL@tmp{\xintRaw{\POL@tmp}}% +% sadly xinttools (current 1.3a) arrays have no setters for individual items... + \expandafter\let\csname POL@tmparray\the\count@\endcsname\POL@tmp + \if0\xintiiSgn{\POL@tmp}% + \advance\count@\m@ne + \repeat +% dans le cas particulier d'un array avec que des éléments nuls, \count@ est +% ici devenu 0 et la boucle s'est arrêtée car #2{0} était au moins 1. De plus +% \POL@tmparray1 est bien 0/1[0] donc ok pour polynôme nul dans \POL@result + \count\tw@\count@ + \xintloop +% on mouline tous les coeffs via \xintRaw + \ifnum\count@>\@ne + \advance\count@\m@ne + \edef\POL@tmp{#2{\count@}}% + \edef\POL@tmp{\xintRaw{\POL@tmp}}% + \expandafter\let\csname POL@tmparray\the\count@\endcsname\POL@tmp + \repeat + \count@\count\tw@ + \def\POL@tmp##1.{{\csname POL@tmparray##1\endcsname}}% + \edef\POL@result{\the\numexpr\count@-\@ne.\noexpand\empty + \xintiloop[1+1]% + \expandafter\POL@tmp\xintiloopindex.% + \ifnum\xintiloopindex<\count@ + \repeat}% + \fi + \expandafter + \endgroup + \expandafter + \def\csname POLuserpol@#1\expandafter\endcsname + \expandafter{\POL@result}% +}% + + +\newcommand\PolFromCSV[2]{% + \begingroup % closed in \POL@getfromarray + \xintAssignArray\xintCSVtoList{#2}\to\POL@arrayA + \POL@getfromarray{#1}\POL@arrayA + \POL@newpol{#1}% +% semble un peu indirect et sous-optimal +% mais je veux élaguer les coefficients nuls. Peut-être à revoir. +}% + + +\newcommand\PolTypesetCmdPrefix[1]{\xintiiifSgn{#1}{}{+}{+}}% +\newcommand\PolTypesetCmd[1]{\xintifOne{\xintiiAbs{#1}}% + {\ifnum\PolIndex=\z@\xintiiSgn{#1}\else + \xintiiifSgn{#1}{-}{}{}\fi + \let\PolIfCoeffIsPlusOrMinusOne\@firstoftwo}% + {\PolTypesetOne{#1}% + \let\PolIfCoeffIsPlusOrMinusOne\@secondoftwo}% + }% +\newcommand\PolTypesetOne{\xintSignedFrac}% +\newcommand\PolTypesetMonomialCmd{% + \ifcase\PolIndex\space + % + \or\PolVar + \else\PolVar^{\PolIndex}% + \fi +}% +\newcommand\PolTypeset{\@ifstar + {\def\POL@ts@ascending{1}\POL@Typeset}% + {\def\POL@ts@ascending{0}\POL@Typeset}% +}% +\newcommand\POL@Typeset[2][x]{% LaTeX \newcommand forces optional argument first + \ensuremath{% + \expandafter\expandafter\expandafter\POL@split + \csname POLuserpol@#2\endcsname;\POL@var@deg\POL@var@coeffs + \if\POL@ts@ascending1% + \def\PolIndex{0}% + \let\POL@ts@reverse\@firstofone + \let\POL@@ne@or@m@ne\@ne + \else + \let\PolIndex\POL@var@deg + \ifnum\PolIndex<\z@\def\PolIndex{0}\fi + \let\POL@ts@reverse\xintRevWithBraces + \let\POL@@ne@or@m@ne\m@ne + \fi + \def\PolVar{#1}% + \ifnum\POL@var@deg<\z@ + \PolTypesetCmd{0/1[0]}\PolTypesetMonomialCmd + \else + \ifnum\POL@var@deg=\z@ + \expandafter\PolTypesetCmd\POL@var@coeffs\PolTypesetMonomialCmd + \else + \def\POL@ts@prefix##1{\let\POL@ts@prefix\PolTypesetCmdPrefix}% + \expandafter\POL@ts@loop + \romannumeral-`0\POL@ts@reverse{\POL@var@coeffs}\relax + \fi + \fi + }% +}% +\def\POL@ts@loop{\ifpoltypesetall\expandafter\xint_firstoftwo + \else\expandafter\xint_secondoftwo\fi + {\POL@ts@nocheck}{\POL@ts@check}.% +}% +\def\POL@ts@check.#1{% + \if\relax#1\expandafter\xint_gob_til_dot\fi + \xintiiifZero{#1}% + {}% + {\POL@ts@prefix{#1}\PolTypesetCmd{#1}\PolTypesetMonomialCmd}% + \edef\PolIndex{\the\numexpr\PolIndex+\POL@@ne@or@m@ne}\POL@ts@check.% +}% +\def\POL@ts@nocheck.#1{% + \if\relax#1\expandafter\xint_gob_til_dot\fi + \POL@ts@prefix{#1}\PolTypesetCmd{#1}\PolTypesetMonomialCmd + \edef\PolIndex{\the\numexpr\PolIndex+\POL@@ne@or@m@ne}\POL@ts@nocheck.% +}% + + +\newcommand\PolMapCoeffs[2]{% #1 = macro, #2 = name + \POL@mapcoeffs{#1}{#2}% + \POL@newpol{#2}% +}% +\def\POL@mapcoeffs#1#2{% + \begingroup + \def\POL@mapcoeffs@macro{#1}% + \expandafter\expandafter\expandafter\POL@split + \csname POLuserpol@#2\endcsname;\POL@mapcoeffs@deg\POL@mapcoeffs@coeffs +% ATTENTION à ne pas faire un \expandafter ici, car brace removal si 1 item + \xintAssignArray\POL@mapcoeffs@coeffs\to\POL@arrayA + \def\index{0}% + \count@\z@ + \expandafter\POL@map@loop\expandafter.\POL@mapcoeffs@coeffs\relax + \xintloop +% this abuses that \POL@arrayA0 is never 0. + \xintiiifZero{\csname POL@arrayA\the\count@\endcsname}% + {\iftrue}% + {\iffalse}% + \advance\count@\m@ne + \repeat +% donc en sortie \count@ est 0 ssi pol nul. + \POL@resultfromarray A% + \expandafter + \endgroup + \expandafter + \def\csname POLuserpol@#2\expandafter\endcsname\expandafter{\POL@result}% +}% +\def\POL@map@loop.#1{\if\relax#1\expandafter\xint_gob_til_dot\fi + \advance\count@\@ne + \edef\POL@map@coeff{\POL@mapcoeffs@macro{#1}}% + \expandafter + \let\csname POL@arrayA\the\count@\endcsname\POL@map@coeff + \edef\index{\the\numexpr\index+\@ne}% + \POL@map@loop.}% +\def\POL@xintIrr#1{\xintIrr{#1}[0]}% +\newcommand\PolReduceCoeffs{\@ifstar\POL@sreducecoeffs\POL@reducecoeffs}% +\def\POL@reducecoeffs#1{\PolMapCoeffs{\POL@xintIrr}{#1}}% +\def\POL@sreducecoeffs#1{\PolMapCoeffs{\xintPIrr}{#1}}% + + +%% EUCLIDEAN DIVISION +\newcommand\PolDivide[4]{% #3=quotient, #4=remainder of #1 by #2 + \POL@divide{#1}{#2}% + \expandafter\let\csname POLuserpol@#3\endcsname\POL@Q + \POL@newpol{#3}% + \expandafter\let\csname POLuserpol@#4\endcsname\POL@R + \POL@newpol{#4}% +}% +\newcommand\PolQuo[3]{% #3=quotient of #1 by #2 + \POL@divide{#1}{#2}% + \expandafter\let\csname POLuserpol@#3\endcsname\POL@Q + \POL@newpol{#3}% +}% +\newcommand\PolRem[3]{% #3=remainder of #1 by #2 + \POL@divide{#1}{#2}% + \expandafter\let\csname POLuserpol@#3\endcsname\POL@R + \POL@newpol{#3}% +}% +\newcommand\POL@divide[2]{% + \begingroup + \let\xintScalarSub\xintSub + \let\xintScalarAdd\xintAdd + \let\xintScalarMul\xintMul + \let\xintScalarDiv\xintDiv + \expandafter\let\expandafter\POL@A\csname POLuserpol@#1\endcsname + \expandafter\let\expandafter\POL@B\csname POLuserpol@#2\endcsname + \POL@div@c + \let\POL@Q\POL@result + \ifnum\POL@degQ<\z@ + \let\POL@R\POL@A + \else + \count@\numexpr\POL@degR+\@ne\relax + \POL@resultfromarray R% + \let\POL@R\POL@result + \fi + \expandafter + \endgroup + \expandafter + \def\csname POL@Q\expandafter\expandafter\expandafter\endcsname + \expandafter\expandafter\expandafter{\expandafter\POL@Q\expandafter}% + \expandafter + \def\csname POL@R\expandafter\endcsname\expandafter{\POL@R}% +}% + + +%% GCD +\newcommand\PolGCD[3]{% sets #3 to the (unitary) G.C.D. of #1 and #2 + \POL@GCD{#1}{#2}{#3}% + \POL@newpol{#3}% +}% +\def\POL@GCD #1#2#3{% + \begingroup + \let\xintScalarSub\xintSub + \let\xintScalarAdd\xintAdd + \let\xintScalarMul\xintMul + \let\xintScalarDiv\xintDiv + \expandafter\let\expandafter\POL@A\csname POLuserpol@#1\endcsname + \expandafter\let\expandafter\POL@B\csname POLuserpol@#2\endcsname + \expandafter\POL@split\POL@A;\POL@degA\POL@polA + \expandafter\POL@split\POL@B;\POL@degB\POL@polB + \ifnum\POL@degA<\z@ + \expandafter\xint_firstoftwo\else\expandafter\xint_secondoftwo + \fi + {\ifnum\POL@degB<\z@ + \expandafter\xint_firstoftwo\else\expandafter\xint_secondoftwo + \fi + {\def\POL@result{-1.\empty{0/1[0]}}}% + {\xintAssignArray\POL@polB\to\POL@arrayB + \POL@normalize{B}% + \POL@gcd@exit BA}}% + {\ifnum\POL@degB<\z@ + \expandafter\xint_firstoftwo\else\expandafter\xint_secondoftwo + \fi + {\xintAssignArray\POL@polA\to\POL@arrayA + \POL@normalize{A}% + \POL@gcd@exit AB}% + {\ifnum\POL@degA<\POL@degB\space + \let\POL@tmp\POL@B\let\POL@B\POL@A\let\POL@A\POL@tmp + \let\POL@tmp\POL@degB\let\POL@degB\POL@degA\let\POL@degA\POL@tmp + \let\POL@tmp\POL@polB\let\POL@polB\POL@polA\let\POL@polA\POL@tmp + \fi + \xintAssignArray\POL@polA\to\POL@arrayA + \xintAssignArray\POL@polB\to\POL@arrayB + \POL@gcd AB% + }}% + \expandafter + \endgroup + \expandafter\def\csname POLuserpol@#3\expandafter\endcsname + \expandafter{\POL@result}% +}% +\def\POL@normalize#1{% + \expandafter\def\expandafter\POL@tmp\expandafter + {\csname POL@array#1\csname POL@array#10\endcsname\endcsname}% + \edef\POL@normalize@leading{\POL@tmp}% + \expandafter\def\POL@tmp{1/1[0]}% + \count@\csname POL@deg#1\endcsname\space + \xintloop + \ifnum\count@>\z@ + \expandafter\edef\csname POL@array#1\the\count@\endcsname + {\xintIrr{\xintScalarDiv + {\csname POL@array#1\the\count@\endcsname}% + {\POL@normalize@leading}}[0]}% + \advance\count@\m@ne + \repeat +}% +\def\POL@gcd#1#2{% + \POL@normalize{#2}% + \edef\POL@degQ{\the\numexpr\csname POL@deg#1\endcsname + -\csname POL@deg#2\endcsname}% + \count@\numexpr\csname POL@deg#1\endcsname+\@ne\relax + \count\tw@\numexpr\POL@degQ+\@ne\relax + \xintloop + \POL@gcd@getremainder@loopbody#1#2% + \ifnum\count\tw@>\z@ + \repeat + \expandafter\def\csname POL@array#10\endcsname{1}% + \xintloop + \xintiiifZero{\csname POL@array#1\the\count@\endcsname}% + {\iftrue}% + {\iffalse}% + \advance\count@\m@ne + \repeat + \expandafter\edef\csname POL@deg#1\endcsname{\the\numexpr\count@-\@ne}% + \ifnum\count@<\@ne + \expandafter\POL@gcd@exit + \else + \expandafter\edef\csname POL@array#10\endcsname{\the\count@}% + \expandafter\POL@gcd + \fi{#2}{#1}% +}% +\def\POL@gcd@getremainder@loopbody#1#2{% + \edef\POL@gcd@ratio{\csname POL@array#1\the\count@\endcsname}% + \advance\count@\m@ne + \advance\count\tw@\m@ne + \count4 \count@ + \count6 \csname POL@deg#2\endcsname\space + \xintloop + \ifnum\count6>\z@ + \expandafter\edef\csname POL@array#1\the\count4\endcsname + {\xintScalarSub + {\csname POL@array#1\the\count4\endcsname}% + {\xintScalarMul + {\POL@gcd@ratio}% + {\csname POL@array#2\the\count6\endcsname}}}% + \advance\count4 \m@ne + \advance\count6 \m@ne + \repeat +}% +\def\POL@gcd@exit#1#2{% + \count@\numexpr\csname POL@deg#1\endcsname+\@ne\relax + \POL@resultfromarray #1% +}% + + +%% TODO: BEZOUT + + +%% DIFFERENTIATION +\def\POL@diff@loop@one #1/#2[#3]#4% + {\xintIrr{\xintiiMul{#4}{#1}/#2[0]}[#3]}% +\def\POL@diff#1{\POL@diff@loop1.}% +\def\POL@diff@loop#1.#2{% + \if\relax#2\expandafter\xint_gob_til_dot\fi + {\expandafter\POL@diff@loop@one\romannumeral0\xintraw{#2}{#1}}% + \expandafter\POL@diff@loop\the\numexpr#1+\@ne.% +}% +\newcommand\PolDiff[1][1]{% + % optional parameter is how many times to derivate + % first mandatory arg is name of polynomial function to derivate, + % same name as in \NewPolExpr + % second mandatory arg name of derivative + \edef\POL@iterindex{\the\numexpr#1\relax}% + \ifnum\POL@iterindex<\z@ + \expandafter\@firstoftwo + \else + \expandafter\@secondoftwo + \fi + {\PolAntiDiff[-\POL@iterindex]}{\POL@Diff}% +}% +\def\POL@Diff{% + \ifcase\POL@iterindex\space + \expandafter\POL@Diff@no + \or\expandafter\POL@Diff@one + \else\xint_afterfi{\POL@Iterate\POL@Diff@one}% + \fi +}% +\def\POL@Diff@no #1#2{\POL@let{#2}{#1}}% +\def\POL@Diff@one #1#2{\POL@Diff@@one {#1}{#2}\POL@newpol{#2}}% +\def\POL@Diff@@one#1#2{% + \expandafter\expandafter\expandafter\POL@split + \csname POLuserpol@#1\endcsname;\POL@var@deg\POL@var@coeffs + \ifnum\POL@var@deg<\@ne + \@namedef{POLuserpol@#2}{-1.\empty{0/1[0]}}% + \else + \edef\POL@var@coeffs{\expandafter\POL@diff\POL@var@coeffs\relax}% + \expandafter\edef\csname POLuserpol@#2\endcsname + {\the\numexpr\POL@var@deg-\@ne.\noexpand\empty\POL@var@coeffs}% + \fi +}% +% lazy way but allows to share with AntiDiff +\def\POL@Iterate#1#2#3{% + \begingroup + \xintverbosefalse + #1{#2}{#3}% + \xintloop + \ifnum\POL@iterindex>\tw@ + #1{#3}{#3}% + \edef\POL@iterindex{\the\numexpr\POL@iterindex-\@ne}% + \repeat + \expandafter + \endgroup\expandafter + \def\csname POLuserpol@#3\expandafter\endcsname + \expandafter{\romannumeral`^^@\csname POLuserpol@#3\endcsname}% + #1{#3}{#3}% +}% + + +%% ANTI-DIFFERENTIATION +\def\POL@antidiff@loop@one #1/#2[#3]#4% + {\xintIrr{#1/\xintiiMul{#4}{#2}[0]}[#3]}% +\def\POL@antidiff{\POL@antidiff@loop1.}% +\def\POL@antidiff@loop#1.#2{% + \if\relax#2\expandafter\xint_gob_til_dot\fi + {\expandafter\POL@antidiff@loop@one\romannumeral0\xintraw{#2}{#1}}% + \expandafter\POL@antidiff@loop\the\numexpr#1+\@ne.% +}% +\newcommand\PolAntiDiff[1][1]{% + % optional parameter is how many times to derivate + % first mandatory arg is name of polynomial function to derivate, + % same name as in \NewPolExpr + % second mandatory arg name of derivative + \edef\POL@iterindex{\the\numexpr#1\relax}% + \ifnum\POL@iterindex<\z@ + \expandafter\@firstoftwo + \else + \expandafter\@secondoftwo + \fi + {\PolDiff[-\POL@iterindex]}{\POL@AntiDiff}% +}% +\def\POL@AntiDiff{% + \ifcase\POL@iterindex\space + \expandafter\POL@AntiDiff@no + \or\expandafter\POL@AntiDiff@one + \else\xint_afterfi{\POL@Iterate\POL@AntiDiff@one}% + \fi +}% +\let\POL@AntiDiff@no\POL@Diff@no +\def\POL@AntiDiff@one #1#2{\POL@AntiDiff@@one{#1}{#2}\POL@newpol{#2}}% +\def\POL@AntiDiff@@one#1#2{% + \expandafter\expandafter\expandafter\POL@split + \csname POLuserpol@#1\endcsname;\POL@var@deg\POL@var@coeffs + \ifnum\POL@var@deg<\z@ + \@namedef{POLuserpol@#2}{-1.\empty{0/1[0]}}% + \else + \edef\POL@var@coeffs{\expandafter\POL@antidiff\POL@var@coeffs\relax}% + \expandafter\edef\csname POLuserpol@#2\endcsname + {\the\numexpr\POL@var@deg+\@ne.\noexpand\empty{0/1[0]}\POL@var@coeffs}% + \fi +}% + +%% IContent and \PolMakePrimitive (0.5) +\def\POL@aux@mgcd@loop#1#2{% + \if\relax#2\expandafter\POL@aux@mgcd@exit\fi + \expandafter + \POL@aux@mgcd@loop\romannumeral0\POL@aux@gcd#1.#2.% +}% +\def\POL@aux@mgcd@exit + \expandafter + \POL@aux@mgcd@loop\romannumeral0\POL@aux@gcd#1.\relax.{\xintiiabs{#1}}% +\def\POL@aux@gcd#1.#2.{% + \if0\xintiiSgn{#1}\expandafter\POL@aux@gcd@exit\fi + \expandafter\POL@aux@gcd\romannumeral0\xintmod {#2}{#1}.#1.}% +\def\POL@aux@gcd@exit + \expandafter\POL@aux@gcd\romannumeral0\xintmod #1#2.#3.{{#1}}% + +\def\POL@icontent #1{\romannumeral0\expandafter + \POL@aux@mgcd@loop\romannumeral`^^@#1\relax}% + +\newcommand\PolIContent[1]{\romannumeral0\expandafter + \POL@aux@mgcd@loop\romannumeral`^^@\PolToList{#1}\relax}% + + +\def\POL@makeprim@macro#1% + {\xintREZ{\xintNum{\xintDiv{#1}{\POL@makeprim@icontent}}}}% +\newcommand\PolMakePrimitive[1]{% + % This does not need a full user declared polynomial on input, only + % a \POLuserpol@name macro, but on output it is fully declared + \edef\POL@makeprim@icontent{\PolIContent{#1}}% + \PolMapCoeffs\POL@makeprim@macro{#1}% +}% +\def\POL@makeprimitive#1{% + % Avoids declaring the polynomial, internal usage in \PolToSturm + \edef\POL@makeprim@icontent{\PolIContent{#1}}% + \POL@mapcoeffs\POL@makeprim@macro{#1}% +}% + + +%% Sturm Algorithm (polexpr 0.4) +%% 0.5 uses primitive polynomials for faster evaluations afterwards +%% 0.6 corrects misuse of \@ifstar! (mumble). \PolToSturm* was broken. +%% 0.6's \PolToSturm* defines both normalized and unnormalized, the +%% unnormalized using two underscores, so both are available +%% Sole difference is that \PolToSturm* also declares them as +%% user polynomials, whereas the non-starred only keeps the macros +%% holding the coefficients in memory +%% 0.6 fixes the case of a constant polynomial P which caused division +%% by zero error from P'. +\newcommand\PolToSturm{\@ifstar{\PolToSturm@@}{\PolToSturm@}}% +\def\POL@aux@toint#1{\xintREZ{\xintNum{#1}}}% for polynomials with int. coeffs! +%% Attention that some macros rely upon this one setting \POL@sturmname +%% and \POL@sturm@N as it does +\def\PolToSturm@#1#2{% + \edef\POL@sturmname{#2}% + % 0.6 uses 2 underscores (one before index, one after) to keep in memory + % the unnormalized chain + % This supposes #1 to be a genuine polynomial, not only a name with + % a \POLuserpol@#1 macro + \POL@let{\POL@sturmname _0_}{#1}% + \ifnum\PolDegree{#1}=\z@ + \def\POL@sturm@N{0}% + \POL@count\z@ + % if I applied the same as for positive degree, I should make it -1 + % if constant is negative. I also don't worry if polynomial is zero. + \@namedef{POLuserpol@\POL@sturmname _0}{0.\empty{1/1[0]}}% + \else + \ifPOL@tosturm@makefirstprimitive\POL@makeprimitive{\POL@sturmname _0_}\fi + \POL@tosturm@dosturm + \fi + \expandafter + \let\csname PolSturmChainLength_\POL@sturmname\endcsname\POL@sturm@N + % declare the normalized ones as full-fledged polynomials + % \POL@count\z@ + \xintloop + \POL@newpol{\POL@sturmname _\the\POL@count}% + \unless\ifnum\POL@sturm@N=\POL@count + \advance\POL@count\@ne + \repeat +}% +\def\PolToSturm@@#1#2{\PolToSturm@{#1}{#2}\POL@tosturm@declareunnormalized}% +\def\POL@tosturm@declareunnormalized{% + % optionally declare also the unnormalized ones + \POL@count\z@ + \xintloop + \POL@newpol{\POL@sturmname _\the\POL@count _}% + \unless\ifnum\POL@sturm@N=\POL@count + \advance\POL@count\@ne + \repeat +}% +\def\POL@tosturm@dosturm{% + \POL@Diff@@one{\POL@sturmname _0_}{\POL@sturmname _1_}% + % re-utiliser \POL@varcoeffs directement? + \POL@makeprimitive{\POL@sturmname _1_}% does not do \POL@newpol + \POL@count\@ne + \xintloop + \POL@divide{\POL@sturmname _\the\numexpr\POL@count-\@ne\relax _}% + {\POL@sturmname _\the\POL@count _}% + \expandafter\POL@split\POL@R;\POL@degR\POL@polR + \unless\ifnum\POL@degR=\m@ne + \advance\POL@count\@ne + \expandafter\let + \csname POLuserpol@\POL@sturmname _\the\POL@count _\endcsname\POL@R + \edef\POL@makeprim@icontent{-\POL@icontent\POL@polR}% + % this avoids the \POL@newpol from \PolMapCoeffs + \POL@mapcoeffs\POL@makeprim@macro{\POL@sturmname _\the\POL@count _}% + \repeat + \edef\POL@sturm@N{\the\POL@count}% + % normalize (now always done even by starred variant) + \ifnum\PolDegree{\POL@sturmname _\POL@sturm@N _}>\z@ + % \POL@count\POL@sturm@N\relax + \xintloop + \advance\POL@count\m@ne + \POL@divide{\POL@sturmname _\the\POL@count _}% + {\POL@sturmname _\POL@sturm@N _}% + \expandafter + \let\csname POLuserpol@\POL@sturmname _\the\POL@count\endcsname\POL@Q + % quotient actually belongs to Z[X] and is primitive + \POL@mapcoeffs\POL@aux@toint{\POL@sturmname _\the\POL@count}% + \ifnum\POL@count>\z@ + \repeat + \@namedef{POLuserpol@\POL@sturmname _\POL@sturm@N}{0.\empty{1/1[0]}}% + \else % they are already normalized + \advance\POL@count\@ne % attention to include last one also + \xintloop + \advance\POL@count\m@ne + \expandafter\let + \csname POLuserpol@\POL@sturmname _\the\POL@count\expandafter\endcsname + \csname POLuserpol@\POL@sturmname _\the\POL@count _\endcsname + \ifnum\POL@count>\z@ + \repeat + \fi + % Back to \PolToSturm@, \POL@count holds 0 +}% +\newcommand\PolSturmChainLength[1] + {\romannumeral`^^@\csname PolSturmChainLength_#1\endcsname}% + +\newcommand\PolSetToSturmChainSignChangesAt[4][\global]{% + \edef\POL@sturmchain@X{\xintREZ{#4}}% + \edef\POL@sturmname{#3}% + \edef\POL@sturmlength{\PolSturmChainLength{\POL@sturmname}}% + \POL@sturmchain@getSV@at\POL@sturmchain@X + #1\let#2\POL@sturmchain@SV +}% +\def\POL@sturmchain@getSV@at#1{% ATTENTION USES \POL@count + \def\POL@sturmchain@SV{0}% + \edef\POL@sturmchain@sign{\xintiiSgn{\POL@eval{\POL@sturmname _0}{#1}}}% + \let\POL@isolz@lastsign\POL@sturmchain@sign + \POL@count \z@ + \ifnum\POL@isolz@lastsign=\z@ + \edef\POL@isolz@lastsign + {\xintiiSgn{\POL@eval{\POL@sturmname _1}{#1}}}% + \POL@count \@ne + \fi + \xintloop + \unless\ifnum\POL@sturmlength=\POL@count + \advance\POL@count \@ne + \edef\POL@isolz@newsign + {\xintiiSgn{\POL@eval{\POL@sturmname _\the\POL@count}{#1}}}% + \ifnum\POL@isolz@newsign=\numexpr-\POL@isolz@lastsign\relax + \edef\POL@sturmchain@SV{\the\numexpr\POL@sturmchain@SV+\@ne}% + \let\POL@isolz@lastsign=\POL@isolz@newsign + \fi + \repeat +}% +\newcommand\PolSetToNbOfZerosWithin[5][\global]{% + \edef\POL@tmpA{\xintREZ{#4}}% + \edef\POL@tmpB{\xintREZ{#5}}% + \edef\POL@sturmname{#3}% + \edef\POL@sturmlength{\PolSturmChainLength{\POL@sturmname}}% + \POL@sturmchain@getSV@at\POL@tmpA + \let\POL@SVA\POL@sturmchain@SV + \POL@sturmchain@getSV@at\POL@tmpB + \let\POL@SVB\POL@sturmchain@SV + \ifnum\POL@SVA<\POL@SVB\space + #1\edef#2{\the\numexpr\POL@SVB-\POL@SVA}% + \else + #1\edef#2{\the\numexpr\POL@SVA-\POL@SVB}% + \fi +}% + + +% 0.6 added starred variant to count multiplicities +% 0.7 added double starred variant to locate all rational roots +\newcommand\PolSturmIsolateZeros{\@ifstar + {\PolSturmIsolateZerosAndGetMultiplicities}% + {\PolSturmIsolateZeros@}% +}% +\newcommand\PolSturmIsolateZerosAndGetMultiplicities{\@ifstar + {\PolSturmIsolateZerosGetMultiplicitiesAndRationalRoots}% + {\PolSturmIsolateZerosAndGetMultiplicities@}% +}% +% on aurait besoin de ça dans xint, mais il aurait un \xintRaw{#1} alors +\def\POL@xintfrac@getNDE #1% + {\expandafter\POL@xintfrac@getNDE@i\romannumeral`^^@#1}% +\def\POL@xintfrac@getNDE@i #1/#2[#3]#4#5#6{\def#4{#1}\def#5{#2}\def#6{#3}}% +\newcommand\PolSturmIsolateZerosGetMultiplicitiesAndRationalRoots[2][\empty]{% + \PolSturmIsolateZerosAndFindRationalRoots[#1]{#2}% + \ifnum\POL@isolz@NbOfRoots>\z@ + % get multiplicities of irrational (real) roots, if any + \ifnum\POL@findrat@nbofirrroots>\z@ + \POL@findrat@getirrmult + \fi + \POL@isolzmult@defvar@M + \fi +}% +% added at 0.7 +\newcommand\PolSturmIsolateZerosAndFindRationalRoots[2][\empty]{% + % #1 optional E such that roots are searched in -10^E < x < 10^E + % both -10^E and +10^E must not be roots! + % #2 name of Sturm chain (already pre-computed) + \edef\POL@sturmname{#2}% + \edef\POL@sturm@N{\@nameuse{PolSturmChainLength_\POL@sturmname}}% + % isolate the roots (detects case of constant polynomial) + \PolSturmIsolateZeros@{\POL@sturmname}% + \ifnum\POL@isolz@NbOfRoots=\z@ + % no real roots, define empty arrays nevertheless + \begingroup\globaldefs\@ne + \expandafter\xintAssignArray\expandafter\to\csname POL_ZM\POL@sturmname*\endcsname + \expandafter\xintAssignArray\expandafter\to\csname POL_RI\POL@sturmname*\endcsname + \endgroup + \else + % all we currently know is that multiplicities are at least one + \begingroup\globaldefs\@ne + \expandafter\POL@initarray\csname POL_ZM\POL@sturmname*\endcsname{1}% + \endgroup + % on ne va pas utiliser de Horner, mais des divisions par X - x, et ces + % choses vont évoluer, ainsi que le coefficient dominant entier + % (pour \POL@divide entre autres if faut des noms de user pol) + \expandafter\let + \csname POLuserpol@\POL@sturmname\POL@sqfnorr\expandafter\endcsname + \csname POLuserpol@\POL@sturmname _0\endcsname + \expandafter\let + \csname POLuserpol@\POL@sturmname\POL@norr\expandafter\endcsname + \csname POLuserpol@\POL@sturmname _0_\endcsname + % attention formé avec\xintREZ d'où le \xintAbs pas \xintiiAbs + % D and its exponent E will get updated along the way + \edef\POL@findrat@D{\xintAbs{\PolLeadingCoeff{\POL@sturmname _0}}}% + \POL@xintfrac@getNDE\POL@findrat@D\POL@findrat@Dint\POL@_\POL@findrat@Dexp + \xintiiifOne{\POL@findrat@Dint} + {\let\POL@findrat@E\POL@findrat@Dexp} % aussi ok pour 1[0] + {\edef\POL@findrat@E{\the\numexpr\xintLen{\POL@findrat@Dint}% + +\POL@findrat@Dexp}}% +% ATTENTION QUE LA CONVENTION DE SIGNE POUR \POL@findrat@E EST OPPOSÉE À CELLE +% POUR LE CODE PLUS ANCIEN FAISANT "REFINE" + \POL@initarray\POL@IfMultIsKnown\xint_secondoftwo + \let\POL@findrat@nbofirrroots\POL@isolz@NbOfRoots + % find all rational roots, and their multiplicities, + % factor them out in passing from original (Sturm root) polynomial + \ifnum\POL@findrat@E<7 + \def\POL@findrat@index{1}% + \POL@findrat@loop@secondpass@direct + \else + % we do a first pass scanning for "small" roots p/q (i.e. q < 1000) + \def\POL@findrat@index{1}% + \POL@findrat@loop@firstpass + % and now we do the final pass finding them all + \def\POL@findrat@index{1}% + \POL@findrat@loop@secondpass + \fi + % declare the new polynomials + \POL@newpol{\POL@sturmname\POL@sqfnorr}% without multiplicities + \POL@newpol{\POL@sturmname\POL@norr}% with multiplicities + % declare the array holding the interval indices for the rational roots + \expandafter\POL@findrat@doRRarray\csname POL_RI\POL@sturmname*\endcsname + \fi +}% +\def\POL@findrat@doRRarray#1{% + % il faudrait un \xintAssignArray* qui fasse même expansion que \xintFor* + \edef\POL@temp{% + \xintiloop[1+1] + \romannumeral0\csname POL_ZK\POL@sturmname*\xintiloopindex\endcsname + \xintbracediloopindex % I should have named it \xintiloopbracedindex... + {}% + \ifnum\xintiloopindex<\POL@isolz@NbOfRoots\space + \repeat }% + \begingroup\globaldefs\@ne + % attention de ne surtout pas faire un \expandafter ici, car en cas d'un + % seul item, \xintAssignArray l'unbraces... + \xintAssignArray\POL@temp\to#1% + \endgroup +}% +\def\POL@findrat@loop@firstpass{% + \PolSturmIfZeroExactlyKnown{\POL@sturmname}{\POL@findrat@index}% + \POL@findrat@loop@decimal% get its multiplicity + \POL@findrat@loop@aa % refine interval and check + \edef\POL@findrat@index{\the\numexpr\POL@findrat@index+\@ne}% + \ifnum\POL@findrat@index>\POL@isolz@NbOfRoots + \else + \expandafter\POL@findrat@loop@firstpass + \fi +}% +\def\POL@findrat@loop@aa{% + % we do a first pass to identify roots with denominators < 1000 + \PolEnsureIntervalLength{\POL@sturmname}{\POL@findrat@index}{-6}% + % attention that perhaps now the root is known! + \PolSturmIfZeroExactlyKnown{\POL@sturmname}{\POL@findrat@index}% + \POL@findrat@loop@decimal + \POL@findrat@loop@a +}% +\def\POL@findrat@loop@decimal{% we have an already found decimal root + % we do not go via @storeit, as it is already stored + % j'ai beaucoup hésité néanmoins, car je pourrais faire \xintIrr ici, + % mais attention aussi à l'interaction avec le \PolDecToString. Les racines + % trouvées directement (qui peuvent être des nombres décimaux) sont elles + % stockées comme fraction irréductibles (modulo action additionnelle de + % \PolDecToString). + \POL@xintfrac@getNDE + {\xintIrr{\POL@xintexprGetVar{\POL@sturmname L_\POL@findrat@index}}[0]}% + \POL@findrat@xN\POL@findrat@xD\POl@_ + % we can't move this to updatequotients because other branch will + % need to do the division first anyhow + \edef\POLuserpol@_findrat@oneterm{1.\noexpand\empty + {\xintiiOpp\POL@findrat@xN/1[0]}{\POL@findrat@xD/1[0]}}% + \POL@divide{\POL@sturmname\POL@sqfnorr}{_findrat@oneterm}% the one without mult. + %\expandafter\POL@split\POL@R;\POL@degR\POL@polR + \POL@findrat@loop@updatequotients + \POL@findrat@loop@getmultiplicity +}% +% lacking from xint 1.3c, but \xintSgn has overhead, so we define ii version +\def\xintiiifNeg{\romannumeral0\xintiiifneg }% +\def\xintiiifneg #1% +{% + \ifcase \xintiiSgn{#1} + \expandafter\xint_stop_atsecondoftwo + \or\expandafter\xint_stop_atsecondoftwo + \else\expandafter\xint_stop_atfirstoftwo + \fi +}% +\def\POL@findrat@getE #1/1[#2]{#2}% /1 as it should be there. +% so an error will arise if not but cf \POL@refine@getE where I did not put it +\def\POL@findrat@loop@a{% + % attention that the width may have been already smaller than 10^{-6} + \POL@get@IsoLeft@rawin + \POL@get@IsoRight@rawin + \edef\POL@findrat@localW + {\the\numexpr-\expandafter\POL@findrat@getE + % do I really need the \xintREZ? + \romannumeral0\xintrez + {\xintSub{\POL@IsoRight@rawin}{\POL@IsoLeft@rawin}}% + }% at least 6, maybe larger + \expandafter\POL@get@Int@aux + \POL@IsoLeft@rawin\POL@IsoLeft@Int{-\POL@findrat@localW}% + \expandafter\POL@get@Int@aux + \POL@IsoRight@rawin\POL@IsoRight@Int{-\POL@findrat@localW}% + % in case of odd, some waste here + \edef\POL@findrat@halflocalW{\the\numexpr(\POL@findrat@localW+1)/2-1}% + % Legendre Theorem will be used now but we separate a branch where + % everything can be done with \numexpr + \ifnum\POL@findrat@localW>9 + % not implemented yet by lazyness! + % this root will be handled in second pass only + \else + \POL@findrat@gcdloop + \fi +}% +\def\POL@findrat@gcdloop{% + % we must be careful with sign + % but we are certain no extremity is a root + \let\POL@findrat@ifnegative\xint_secondoftwo + \xintiiifSgn\POL@IsoLeft@Int + \POL@findrat@gcdloop@n + \POL@error@thisisimpossible + \POL@findrat@gcdloop@p +}% +\def\POL@findrat@gcdloop@n{% + \let\POL@findrat@ifnegative\xint_firstoftwo + \let\POL@temp\POL@IsoRight@Int + \edef\POL@IsoRight@Int{\xintiiOpp{\POL@IsoLeft@Int}}% + \edef\POL@IsoLeft@Int{\xintiiOpp{\POL@temp}}% + \POL@findrat@gcdloop@p +}% +\def\POL@findrat@gcdloop@p{% + \edef\POL@findrat@gcdloop@Ap{\xintDec{\xintDouble\POL@IsoRight@Int}}% + \edef\POL@findrat@gcdloop@A + % at most 2e9: this is acceptable to \numexpr + {2\romannumeral\xintreplicate\POL@findrat@localW{0}}% + \xintAssign + \xintiiDivision\POL@findrat@gcdloop@Ap\POL@findrat@gcdloop@A + \to\POL@findrat@gcdloop@B\POL@findrat@gcdloop@An + % on fait de la tambouille pour n'utiliser que \numexpr par la suite + % le reste @An est < 2.10^9 au pire donc ok pour \numexpr + % we will drop integral part in our updating P + \let\POL@findrat@gcdloop@Binitial\POL@findrat@gcdloop@B + \def\POL@findrat@gcdloop@B{0}% do as if B1 = 0 + \def\POL@findrat@gcdloop@Pp{1}% P0 + \def\POL@findrat@gcdloop@P{0}% P1 + \def\POL@findrat@gcdloop@Qp{0}% Q0 + \def\POL@findrat@gcdloop@Q{1}% Q1 + % A2=An can not be zero, as Ap (=A0) is odd and A (=A1=200...000) is even + % first Binitial + P1/Q1 ( = Binitial) can not be root + \let\POL@findrat@gcdloop@Ap\POL@findrat@gcdloop@A % A1 + \let\POL@findrat@gcdloop@A\POL@findrat@gcdloop@An % A2 + \def\next{\POL@findrat@gcdloop@update}% + \def\POL@findrat@gcdloop@done{0}% + \POL@findrat@gcdloop@body +}% +\def\POL@findrat@gcdloop@body{% + % annoying that \numexpr has no divmod... use counts? but groups annoying + \edef\POL@findrat@gcdloop@B + {\the\numexpr(\POL@findrat@gcdloop@Ap+\POL@findrat@gcdloop@A/2)/% + \POL@findrat@gcdloop@A - \@ne}% + \edef\POL@findrat@gcdloop@An + {\the\numexpr\POL@findrat@gcdloop@Ap-% + \POL@findrat@gcdloop@B*\POL@findrat@gcdloop@A}% + \edef\POL@findrat@gcdloop@Pn + {\the\numexpr\POL@findrat@gcdloop@Pp+% + \POL@findrat@gcdloop@B*\POL@findrat@gcdloop@P}% + \edef\POL@findrat@gcdloop@Qn + {\the\numexpr\POL@findrat@gcdloop@Qp+% + \POL@findrat@gcdloop@B*\POL@findrat@gcdloop@Q}% + \ifnum\expandafter\xintLength\expandafter{\POL@findrat@gcdloop@Qn}% + >\POL@findrat@halflocalW\space + \let\next\empty % no solution was found + \else + % with these conditions on denom, only candidates are by Legendre + % theorem among the convergents as computed here + \ifnum\POL@findrat@gcdloop@Qn>\POL@findrat@gcdloop@An\space + % means that P/Q is in interval and is thus a candidate + % it is automatically irreducible + \edef\POL@findrat@x{\xintiiAdd + {\xintiiMul{\POL@findrat@gcdloop@Qn}{\POL@findrat@gcdloop@Binitial}}% + {\POL@findrat@gcdloop@Pn}/\POL@findrat@gcdloop@Qn[0]}% + \POL@findrat@gcdloop@testit + \if1\POL@findrat@gcdloop@done + \let\next\empty % a solution was found + \fi + \fi + \fi + \next +}% +\def\POL@findrat@gcdloop@update{% + \ifnum\POL@findrat@gcdloop@An>\z@ + \let\POL@findrat@gcdloop@Ap\POL@findrat@gcdloop@A + \let\POL@findrat@gcdloop@A\POL@findrat@gcdloop@An + \let\POL@findrat@gcdloop@Pp\POL@findrat@gcdloop@P + \let\POL@findrat@gcdloop@P\POL@findrat@gcdloop@Pn + \let\POL@findrat@gcdloop@Qp\POL@findrat@gcdloop@Q + \let\POL@findrat@gcdloop@Q\POL@findrat@gcdloop@Qn + \expandafter\POL@findrat@gcdloop@body + \fi +}% +\def\POL@findrat@gcdloop@testit{% + % zero should never occur here + \POL@findrat@ifnegative{\edef\POL@findrat@x{-\POL@findrat@x}}{}% + \POL@xintfrac@getNDE\POL@findrat@x\POL@findrat@xN\POL@findrat@xD\POL@_ + \edef\POLuserpol@_findrat@oneterm{1.\noexpand\empty + {\xintiiOpp{\POL@findrat@xN}/1[0]}{\POL@findrat@xD/1[0]}}% + \POL@divide{\POL@sturmname\POL@sqfnorr}{_findrat@oneterm}% the one without mult. + \expandafter\POL@split\POL@R;\POL@degR\POL@polR + \ifnum\POL@degR=\m@ne % found a root + \POL@findrat@loop@storeit + \POL@findrat@loop@updatequotients + \POL@findrat@loop@getmultiplicity % will continue updating the mult. one + \def\POL@findrat@gcdloop@done{1}% + \fi +}% +% This is second phase +\def\POL@findrat@loop@secondpass{% + \PolSturmIfZeroExactlyKnown{\POL@sturmname}{\POL@findrat@index}% + {}% nothing more to be done, already stored + \POL@findrat@loop@bb % refine interval and check + \edef\POL@findrat@index{\the\numexpr\POL@findrat@index+\@ne}% + \ifnum\POL@findrat@index>\POL@isolz@NbOfRoots + \else + \expandafter\POL@findrat@loop@secondpass + \fi +}% +\def\POL@findrat@loop@secondpass@direct{% + \PolSturmIfZeroExactlyKnown{\POL@sturmname}{\POL@findrat@index}% + \POL@findrat@loop@decimal + \POL@findrat@loop@bb + \edef\POL@findrat@index{\the\numexpr\POL@findrat@index+\@ne}% + \ifnum\POL@findrat@index>\POL@isolz@NbOfRoots + \else + \expandafter\POL@findrat@loop@secondpass@direct + \fi +}% +\def\POL@findrat@loop@bb{% + \PolEnsureIntervalLength{\POL@sturmname}{\POL@findrat@index}{-\POL@findrat@E}% + % ATTENTION THAT PERHAPS NOW THE ROOT IS KNOWN! + \PolSturmIfZeroExactlyKnown{\POL@sturmname}{\POL@findrat@index}% + \POL@findrat@loop@decimal + \POL@findrat@loop@b +}% +\def\POL@findrat@loop@b{% + \edef\POL@findrat@Lscaled{\xintMul{\POL@findrat@D}% + {\POL@xintexprGetVar{\POL@sturmname L_\POL@findrat@index}}}% + \edef\POL@findrat@Rscaled{\xintMul{\POL@findrat@D}% + {\POL@xintexprGetVar{\POL@sturmname R_\POL@findrat@index}}}% + \xintiiifNeg{\POL@findrat@Lscaled}% using ii version is an abuse + {% negative interval (right bound possibly zero!) + % truncate towards zero (i.e. to the right) the left bound + \edef\POL@findrat@Num{\xintNum{\POL@findrat@Lscaled}/1[0]}% + % interval boundaries are not root hence in case that was exact + % this will not be found as a root; check if in interval + \xintifLt\POL@findrat@Num\POL@findrat@Rscaled + \POL@findrat@loop@c + {}% iterate + }% + {% positive interval (left bound possibly zero!) + % truncate towards zero (i.e. to the left) the right bound + \edef\POL@findrat@Num{\xintNum{\POL@findrat@Rscaled}/1[0]}% + % check if in interval + \xintifGt\POL@findrat@Num\POL@findrat@Lscaled + \POL@findrat@loop@c + {}% iterate + }% +}% +\def\POL@findrat@loop@c{% + % safer to do the edef as \POL@findrat@x used later in storeit + \edef\POL@findrat@x{\xintIrr{\xintDiv\POL@findrat@Num\POL@findrat@D}[0]}% + \POL@xintfrac@getNDE\POL@findrat@x\POL@findrat@xN\POL@findrat@xD\POL@_ + \edef\POLuserpol@_findrat@oneterm{1.\noexpand\empty + {\xintiiOpp{\POL@findrat@xN}/1[0]}{\POL@findrat@xD/1[0]}}% + \POL@divide{\POL@sturmname\POL@sqfnorr}{_findrat@oneterm}% the one without mult. + \expandafter\POL@split\POL@R;\POL@degR\POL@polR + \ifnum\POL@degR=\m@ne % found a root + \POL@findrat@loop@storeit + \POL@findrat@loop@updatequotients + \POL@findrat@loop@getmultiplicity % will continue updating the mult. one + \fi + % iterate +}% +\def\POL@findrat@loop@storeit{% + % update storage, I can not use storeleftandright here (due to rawout etc...) + \expandafter + \xdef\csname POL_ZL\POL@sturmname*\POL@findrat@index\endcsname + {\PolDecToString{\POL@findrat@x}}% + \global\expandafter + \let\csname POL_ZR\POL@sturmname*\POL@findrat@index\expandafter\endcsname + \csname POL_ZL\POL@sturmname*\POL@findrat@index\endcsname + \global\expandafter + \let\csname POL_ZK\POL@sturmname*\POL@findrat@index\endcsname + \xint_stop_atfirstoftwo + \begingroup\xintglobaldefstrue + % skip some overhead of \xintdefvar... + \XINT_expr_defvar_one{\POL@sturmname L_\POL@findrat@index}% + {\csname .=\POL@findrat@x\endcsname}% + \XINT_expr_defvar_one{\POL@sturmname R_\POL@findrat@index}% + {\csname .=\POL@findrat@x\endcsname}% + \XINT_expr_defvar_one{\POL@sturmname Z_\POL@findrat@index _isknown}% + {\csname .=1\endcsname}% + \endgroup +}% +\def\POL@findrat@loop@updatequotients{% + % attention last division must have been one testing vanishing of\POL@sqfnorr + \expandafter\let\csname POLuserpol@\POL@sturmname\POL@sqfnorr\endcsname\POL@Q + % quotient belongs to Z[X] and is primitive + \POL@mapcoeffs\POL@aux@toint{\POL@sturmname\POL@sqfnorr}% + % update the one with multiplicities + \POL@divide{\POL@sturmname\POL@norr}{_findrat@oneterm}% + \expandafter\let\csname POLuserpol@\POL@sturmname\POL@norr\endcsname\POL@Q + \POL@mapcoeffs\POL@aux@toint{\POL@sturmname\POL@norr} + % updating of \POL@findrat@D at end of execution of getmultiplicity +}% +\def\POL@findrat@loop@getmultiplicity{% + % the one without multiplicity must not be divided again! + % check if we have remaining multiplicity + \POL@divide{\POL@sturmname\POL@norr}{_findrat@oneterm}% + \expandafter\POL@split\POL@R;\POL@degR\POL@polR + \ifnum\POL@degR=\m@ne % yes + \expandafter\let\csname POLuserpol@\POL@sturmname\POL@norr\endcsname\POL@Q + \POL@mapcoeffs\POL@aux@toint{\POL@sturmname\POL@norr}% + \expandafter + \xdef + \csname POL_ZM\POL@sturmname*\POL@findrat@index\endcsname + {\the\numexpr + \csname POL_ZM\POL@sturmname*\POL@findrat@index\endcsname+\@ne}% + \expandafter\POL@findrat@loop@getmultiplicity + \else + % done with multiplicity for this rational root, update stuff + \edef\POL@findrat@nbofirrroots + {\the\numexpr\POL@findrat@nbofirrroots-\@ne}% + \@namedef{POL@IfMultIsKnown\POL@findrat@index}{\xint_firstoftwo}% + \edef\POL@findrat@D{\xintAbs{\PolLeadingCoeff{\POL@sturmname\POL@sqfnorr}}}% + \POL@xintfrac@getNDE\POL@findrat@D\POL@findrat@Dint\POL@_\POL@findrat@Dexp + \xintiiifOne{\POL@findrat@Dint} + {\let\POL@findrat@E\POL@findrat@Dexp} % aussi ok pour 1[0] + {\edef\POL@findrat@E{\the\numexpr\xintLen{\POL@findrat@Dint}% + +\POL@findrat@Dexp}}% + \fi +}% +\def\POL@findrat@getirrmult{% + % first get the GCD of remaining pol with its derivative + \POL@divide{\POL@sturmname\POL@norr}{\POL@sturmname\POL@sqfnorr}% + \expandafter\let + % attention au _ (cf. grosse astuce pour \POL@isolzmult@loop) + \csname POLuserpol@@_1\POL@sturmname _\endcsname\POL@Q + \ifnum\PolDegree{@_1\POL@sturmname _}>\z@ + % il reste des multiplicités (mais peut-être pour des racines complexes) + % (ou pour des racines en-dehors de l'intervalle optionnel) + % attention recyclage ici de \POL@isolzmult@loop qui dépend de + % la grosse astuce avec \@gobble + \POL@makeprimitive{@_1\POL@sturmname _}% + \let\POL@originalsturmname\POL@sturmname + % trick to get isolzmult@loop to define @@lastGCD to @_1sturmname_ + % because it will do \POL@sturmname _\POL@sturm@N _ + \edef\POL@sturmname{@_1\POL@sturmname}% + \let\POL@sturm@N\@gobble% ! + \let\POL@isolz@NbOfRoots@with_unknown_mult\POL@findrat@nbofirrroots + \POL@tosturm@makefirstprimitivefalse + \POL@isolzmult@loop + \POL@tosturm@makefirstprimitivetrue + \let\POL@sturmname\POL@originalsturmname + \fi +}% + + +\newcommand\PolSturmIsolateZerosAndGetMultiplicities@[2][\empty]{% + % #1 optional E such that roots are searched in -10^E < x < 10^E + % both -10^E and +10^E must not be roots! + % #2 name of Sturm chain (already pre-computed) + \edef\POL@sturmname{#2}% + \edef\POL@sturm@N{\@nameuse{PolSturmChainLength_\POL@sturmname}}% + % isolate the roots (detects case of constant polynomial) + \PolSturmIsolateZeros@{\POL@sturmname}% + \ifnum\POL@isolz@NbOfRoots=\z@ + % no roots, define empty array nevertheless + \begingroup\globaldefs\@ne + \expandafter\xintAssignArray\expandafter\to\csname POL_ZM\POL@sturmname*\endcsname + \endgroup + \else + % all we currently know is that multiplicities are at least one + \begingroup\globaldefs\@ne + \expandafter\POL@initarray\csname POL_ZM\POL@sturmname*\endcsname{1}% + \endgroup + % check if GCD had positive degree (hence some roots, maybe complex, have + % multiplicity) + \ifnum\PolDegree{\POL@sturmname _\POL@sturm@N _}>\z@ + % scratch array of flags to signal known multiplicities + \POL@initarray\POL@IfMultIsKnown\xint_secondoftwo + % this count has utility for the case there are other roots + % either complex or outside interval (in case of optional argument) + \let\POL@isolz@NbOfRoots@with_unknown_mult\POL@isolz@NbOfRoots + % store Sturm chain name, it is needed and altered in isolzmult@loop + \let\POL@originalsturmname\POL@sturmname + \POL@tosturm@makefirstprimitivefalse + \POL@isolzmult@loop + \POL@tosturm@makefirstprimitivetrue + \let\POL@sturmname\POL@originalsturmname + \fi + \POL@isolzmult@defvar@M + \fi +}% +\def\POL@isolzmult@defvar@M{% + % Attention that is used not only in ...GetMultiplicities@ but also + % in FindRationalRoots + \begingroup\xintglobaldefstrue + % added at 0.7 + \let\x\POL@isolz@NbOfRoots + \xintloop + % skip some overhead of \xintdefvar... + \XINT_expr_defvar_one{\POL@sturmname M_\x}% + {\csname .=\csname POL_ZM\POL@sturmname*\x\endcsname\endcsname}% + \edef\x{\the\numexpr\x-\@ne}% + \ifnum\x>\z@ + \repeat + \endgroup +}% +\def\POL@isolzmult@loop{% + % we are here only if last iteration gave a new GCD still of degree > 0 + % \POL@sturm@N is the one from last iteration + % Attention to not use \POL@sturmname directly in first arg. of \PolToSturm + % Attention that we need for the case of known roots also to have the last + % GCD (with its multiplicities) known as a genuine polynomial + % - because of usage of \POL@eval in @isknown branch + % - because \PolToSturm@ does a \POL@let which would be anomalous + % if the extended structure is not existing + \edef\POL@isolzmult@lastGCD{\POL@sturmname _\POL@sturm@N _}% + \edef\POL@isolzmult@newsturmname{@_1\POL@sturmname}% + \POL@newpol{\POL@isolzmult@lastGCD}% + \PolToSturm@{\POL@isolzmult@lastGCD}{\POL@isolzmult@newsturmname}% + % now both \POL@sturmname and \POL@sturm@N have changed + \edef\POL@isolzmult@newGCDdegree{\PolDegree{\POL@sturmname _\POL@sturm@N _}}% + \let\POL@isolzmult@index\POL@isolz@NbOfRoots + \xintloop + % ATTENTION that this executes macros which also modifies \POL@sturmname! + % (but not \POL@sturm@N) + \POL@isolzmult@doone + \edef\POL@isolzmult@index{\the\numexpr\POL@isolzmult@index-\@ne}% + \if1\ifnum\POL@isolz@NbOfRoots@with_unknown_mult=\z@ 0\fi + \ifnum\POL@isolzmult@index=\z@ 0\fi 1% + \repeat + \let\POL@sturmname\POL@isolzmult@newsturmname + \if1\ifnum\POL@isolz@NbOfRoots@with_unknown_mult=\z@ 0\fi + % (if new GCD is constant, time to abort) + \ifnum\POL@isolzmult@newGCDdegree=\z@ 0\fi 1% + \expandafter\POL@isolzmult@loop + \fi +}% +\def\POL@isolzmult@doone{% + \csname POL@IfMultIsKnown\POL@isolzmult@index\endcsname + {}% nothing to do + {\POL@SturmIfZeroExactlyKnown{\POL@originalsturmname}% + {\POL@isolzmult@index}% + \POL@isolzmult@loop@isknown + \POL@isolzmult@loop@isnotknown + \POL@isolzmult@loop@sharedbody + }% +}% +\def\POL@isolzmult@loop@isknown{% + \xintifZero + % attention that \POL@eval requires a declared polynomial + {\POL@eval{\POL@isolzmult@lastGCD}% + {\POL@xintexprGetVar{\POL@originalsturmname L_\POL@isolzmult@index}}}% + {\let\POL@isolzmult@haszero\@ne}% + {\let\POL@isolzmult@haszero\z@}% +}% +\def\POL@isolzmult@loop@isnotknown{% + \edef\POL@isolzmult@loop@A + {\POL@xintexprGetVar{\POL@originalsturmname L_\POL@isolzmult@index}} + \edef\POL@isolzmult@loop@B + {\POL@xintexprGetVar{\POL@originalsturmname + R_\POL@isolzmult@index}} + % attention that \PolSetToNbOfZerosWithin sets \POL@sturmname to 2nd argument + \PolSetToNbOfZerosWithin + \POL@isolzmult@haszero % nb of zeros A < x <= B, here 0 or 1 + \POL@isolzmult@newsturmname + \POL@isolzmult@loop@A + \POL@isolzmult@loop@B +}% +\def\POL@isolzmult@loop@sharedbody{% + \ifnum\POL@isolzmult@haszero>\z@ + \expandafter + \xdef + \csname POL_ZM\POL@originalsturmname*\POL@isolzmult@index\endcsname + {\the\numexpr + \csname POL_ZM\POL@originalsturmname + *\POL@isolzmult@index\endcsname+\@ne}% + \else + % multiplicity now known, no need to check this index in future + \@namedef{POL@IfMultIsKnown\POL@isolzmult@index}{\xint_firstoftwo}% + \edef\POL@isolz@NbOfRoots@with_unknown_mult + {\the\numexpr\POL@isolz@NbOfRoots@with_unknown_mult-\@ne}% + \fi +}% + + +\newcommand\PolSturmIsolateZeros@[2][\empty]{% + % #1 optional E such that roots are searched in -10^E < x < 10^E + % both -10^E and +10^E must not be roots! + % #2 name of Sturm chain (already pre-computed from a given polynomial) + % For reasons I have forgotten (no time now) this code **must** be used + % with a *normalized* Sturm chain. + \edef\POL@sturmname{#2}% + \edef\POL@sturmlength{\PolSturmChainLength{#2}}% + % attention to constant polynomial, we must redefine the arrays then + \ifnum\POL@sturmlength>\z@ + \ifx\empty#1\relax + \POL@isolz@getsignchanges@plusinf + \POL@isolz@getsignchanges@minusinf + \else + \edef\POL@isolz@E{\the\numexpr\xint_zapspaces #1 \xint_gobble_i\relax}% + \POL@sturmchain@getSV@at{1[\POL@isolz@E]}% + \let\POL@isolz@plusinf@SV \POL@sturmchain@SV + \let\POL@isolz@plusinf@sign\POL@sturmchain@sign + \POL@sturmchain@getSV@at{-1[\POL@isolz@E]}% + \let\POL@isolz@minusinf@SV \POL@sturmchain@SV + \let\POL@isolz@minusinf@sign\POL@sturmchain@sign + \ifnum\POL@isolz@plusinf@sign=\z@ + \PackageError{polexpr}% +{The polynomial #2 vanishes at set upper bound 10^\POL@isolz@E}% +{Compile again with a bigger exponent in source. (X to abort).}% + \fi + \ifnum\POL@isolz@minusinf@sign=\z@ + \PackageError{polexpr}% +{The polynomial #2 vanishes at set lower bound -10^\POL@isolz@E}% +{Compile again with a bigger exponent in source. (X to abort).}% + \fi + \fi + \edef\POL@isolz@NbOfRoots + {\the\numexpr\POL@isolz@minusinf@SV-\POL@isolz@plusinf@SV}% + \else + % constant polynomial + \def\POL@isolz@NbOfRoots{0}% + \fi + \ifnum\POL@isolz@NbOfRoots=\z@ + \begingroup\globaldefs\@ne + \expandafter\xintAssignArray\expandafter\to\csname POL_ZL#2*\endcsname + \expandafter\xintAssignArray\expandafter\to\csname POL_ZR#2*\endcsname + \expandafter\xintAssignArray\expandafter\to\csname POL_ZK#2*\endcsname + \endgroup + \else + \begingroup\globaldefs\@ne + \expandafter\POL@initarray\csname POL_ZL#2*\endcsname{0}% + \expandafter\POL@initarray\csname POL_ZR#2*\endcsname{0}% + \expandafter\POL@initarray\csname POL_ZK#2*\endcsname + \xint_stop_atsecondoftwo + \endgroup + \ifx\empty#1\relax\expandafter\POL@isolz@getaprioribound\fi + \expandafter\POL@isolz@main + \fi +}% +\def\POL@initarray#1#2{% +% ATTENTION, if only one item, \xintAssignArray UNBRACES IT +% so we use an \empty trick to avoid that. Maybe considered a bug of xinttools? + \expandafter\xintAssignArray\expandafter\empty + \romannumeral\xintreplicate{\POL@isolz@NbOfRoots}{{#2}}\to#1% +}% +\def\POL@isolz@getsignchanges@plusinf{% + % Count number of sign changes at plus infinity in Sturm sequence + \def\POL@isolz@plusinf@SV{0}% + \edef\POL@isolz@lastsign{\xintiiSgn{\PolLeadingCoeff{\POL@sturmname _0}}}% + \let\POL@isolz@plusinf@sign\POL@isolz@lastsign + \POL@count\@ne + \xintloop + \edef\POL@isolz@newsign + {\xintiiSgn{\PolLeadingCoeff{\POL@sturmname _\the\POL@count}}}% + \unless\ifnum\POL@isolz@newsign=\POL@isolz@lastsign + \edef\POL@isolz@plusinf@SV{\the\numexpr\POL@isolz@plusinf@SV+\@ne}% + \fi + \let\POL@isolz@lastsign=\POL@isolz@newsign + \ifnum\POL@sturmlength>\POL@count + \advance\POL@count\@ne + \repeat +}% +\def\POL@isolz@getsignchanges@minusinf{% + % Count number of sign changes at minus infinity in Sturm sequence + \def\POL@isolz@minusinf@SV{0}% + \edef\POL@isolz@lastsign{\xintiiSgn{\PolLeadingCoeff{\POL@sturmname _0}}}% + \ifodd\PolDegree{\POL@sturmname _0} + \edef\POL@isolz@lastsign{\xintiiOpp{\POL@isolz@lastsign}}% + \fi + \let\POL@isolz@minusinf@sign\POL@isolz@lastsign + \POL@count\@ne + \xintloop + \edef\POL@isolz@newsign + {\xintiiSgn{\PolLeadingCoeff{\POL@sturmname _\the\POL@count}}}% + \ifodd\PolDegree{\POL@sturmname _\the\POL@count} + \edef\POL@isolz@newsign{\xintiiOpp{\POL@isolz@newsign}}% + \fi + \unless\ifnum\POL@isolz@newsign=\POL@isolz@lastsign + \edef\POL@isolz@minusinf@SV{\the\numexpr\POL@isolz@minusinf@SV+\@ne}% + \fi + \let\POL@isolz@lastsign=\POL@isolz@newsign + \ifnum\POL@sturmlength>\POL@count + \advance\POL@count\@ne + \repeat +}% +% utility macro for a priori bound on root decimal exponent, via Float Rounding +\def\POL@isolz@updateE #1e#2;% + {\unless\ifnum#2<\POL@isolz@E\space\edef\POL@isolz@E{\the\numexpr#2+\@ne}\fi}% +\def\POL@isolz@getaprioribound{% + \PolAssign{\POL@sturmname _0}\toarray\POL@arrayA + \edef\POL@isolz@leading{\POL@arrayA{\POL@arrayA{0}}}% + \POL@count\z@ + \xintloop + \advance\POL@count\@ne + \ifnum\POL@arrayA{0}>\POL@count + \expandafter\edef\csname POL@arrayA\the\POL@count\endcsname + {\xintDiv{\POL@arrayA\POL@count}\POL@isolz@leading}% + \repeat + \def\POL@isolz@E{1}% WE SEEK SMALLEST E SUCH HAT -10^E < roots < +10^E + \advance\POL@count\m@ne + \xintloop + \ifnum\POL@count>\z@ + \expandafter\POL@isolz@updateE + % use floating point to get decimal exponent + \romannumeral0\xintfloat[4]% should I use with [2] rather? (should work) + {\xintAdd{1/1[0]}{\xintAbs{\POL@arrayA\POL@count}}};% + \advance\POL@count\m@ne + \repeat + % \ifxintverbose\xintMessage{polexpr}{Info}% + % {Roots a priori bounded in absolute value by 10 to the \POL@isolz@E.}% + % \fi +}% +\def\POL@IsoRight@raw{\POL@IsoRight@Int/1[\POL@isolz@E]}% +\def\POL@IsoLeft@raw {\POL@IsoLeft@Int/1[\POL@isolz@E]}% +\def\POL@IsoRight@rawout{% + \ifnum\POL@IsoRightSign=\z@\expandafter\xintREZ\fi\POL@IsoRight@raw +}% +\def\POL@IsoLeft@rawout{% + \ifnum\POL@IsoRightSign=\z@ + \expandafter\xint_firstoftwo\else\expandafter\xint_secondoftwo + \fi{\xintREZ\POL@IsoRight@raw}% + {\POL@IsoLeft@Int/1[\POL@isolz@E]}% +}% +\def\POL@isolz@main {% +% NOTE 2018/02/16. THIS WILL PRESUMABLY BE RE-ORGANIZED IN FUTURE TO DO +% FIRST POSITIVE ROOTS THEN NEGATIVE ROOTS VIA CHANGE OF VARIABLE TO OPPOSITE. + \global\POL@isolz@nextwillneedrefinefalse + \def\POL@IsoRight@Int{0}% + \POL@sturmchain@getSV@at\POL@IsoRight@raw + \let\POL@IsoRightSV \POL@sturmchain@SV + \let\POL@IsoRightSign\POL@sturmchain@sign + \let\POL@IsoAtZeroSV \POL@IsoRightSV + \let\POL@IsoAtZeroSign\POL@IsoRightSign + \ifnum\POL@IsoAtZeroSign=\z@ + \xdef\POL@isolz@IntervalIndex + {\the\numexpr\POL@isolz@minusinf@SV-\POL@IsoRightSV}% + \POL@refine@storeleftandright % store zero root, \POL@IsoRightSign is zero + \edef\POL@IsoRightSV{\the\numexpr\POL@IsoRightSV+\@ne}% +% subtlety here if original polynomial had multiplicities, but ok. I checked! + \edef\POL@IsoRightSign % evaluated twice, but that's not so bad + {\xintiiOpp{\xintiiSgn{\POL@eval{\POL@sturmname _1}{0/1[0]}}}}% + \fi + \def\POL@IsoLeft@Int{-1}% -10^E isn't a root! + \let\POL@IsoLeftSV \POL@isolz@minusinf@SV + \let\POL@IsoLeftSign\POL@isolz@minusinf@sign + % \POL@IsoRight@SV was modified if zero is a root + \edef\POL@isolz@NbOfNegRoots{\the\numexpr\POL@IsoLeftSV-\POL@IsoRightSV}% + \gdef\POL@isolz@IntervalIndex{0}% + \let\POL@isolz@@E\POL@isolz@E + \ifnum\POL@isolz@NbOfNegRoots>\z@ +% refactored at 0.7 to fix cases leading to an intervals with zero as end-point + \POL@isolz@findroots@neg + \fi + \let\POL@isolz@E\POL@isolz@@E + \def\POL@IsoLeft@Int{0}% + \let\POL@IsoLeftSV \POL@IsoAtZeroSV % véritable SV en zéro + \let\POL@IsoLeftSign\POL@IsoAtZeroSign% véritable signe en zéro + \ifnum\POL@IsoLeftSign=\z@ + \xdef\POL@isolz@IntervalIndex{\the\numexpr\POL@isolz@IntervalIndex+\@ne}% + \fi + \let\POL@@IsoRightSV \POL@isolz@plusinf@SV + \let\POL@@IsoRightSign\POL@isolz@plusinf@sign % 10^E not a root! + \edef\POL@isolz@NbOfPosRoots + {\the\numexpr\POL@IsoLeftSV-\POL@@IsoRightSV}% attention @@ + \ifnum\POL@isolz@NbOfPosRoots>\z@ + % always do that to avoid zero as end-point whether it is a root or not + \global\POL@isolz@nextwillneedrefinetrue + \POL@isolz@findroots@pos + \fi +}% +\def\POL@isolz@findroots@neg{% + \def\POL@IsoRight@Int{-1}% + \POL@isolz@findnextzeroboundeddecade@neg + \def\POL@IsoLeft@Int{-10}% + \let\POL@@IsoRightSign\POL@IsoRightSign % a zero there is possible + \let\POL@@IsoRightSV \POL@IsoRightSV + % this will do possibly recursive \POL@isolz@check's + \POL@isolz@explorenexteightsubdecades@neg + \ifnum\POL@isolz@IntervalIndex<\POL@isolz@NbOfNegRoots\space + % above did not explore -2, -1 for this optimization (SV known at Right) + \def\POL@IsoRight@Int{-1}% + \let\POL@IsoRightSign\POL@@IsoRightSign + \let\POL@IsoRightSV \POL@@IsoRightSV + \POL@isolz@check + \ifnum\POL@isolz@IntervalIndex<\POL@isolz@NbOfNegRoots\space + \def\POL@IsoLeft@Int{-1}% + \let\POL@IsoLeftSign\POL@@IsoRightSign + \let\POL@IsoLeftSV \POL@@IsoRightSV + % I don't like being inside TeX conditionals + \expandafter\expandafter\expandafter\POL@isolz@findroots@neg + \fi + \fi +}% +\def\POL@isolz@findnextzeroboundeddecade@neg{% + \xintloop + \edef\POL@isolz@E{\the\numexpr\POL@isolz@E-\@ne}% + \POL@sturmchain@getSV@at\POL@IsoRight@raw + \let\POL@IsoRightSV \POL@sturmchain@SV + \let\POL@IsoRightSign\POL@sturmchain@sign + % would an \ifx test be quicker? (to be checked) + \ifnum\POL@IsoRightSV=\POL@IsoLeftSV\space + % no roots in-between, iterate + \repeat +}% +\def\POL@isolz@explorenexteightsubdecades@neg{% + \xintloop + \edef\POL@IsoRight@Int{\the\numexpr\POL@IsoLeft@Int+\@ne}% + % we could arguably do a more efficient dichotomy here + \POL@sturmchain@getSV@at\POL@IsoRight@raw + \let\POL@IsoRightSV \POL@sturmchain@SV + \let\POL@IsoRightSign\POL@sturmchain@sign + \POL@isolz@check % may recurse if multiple roots are to be found + \ifnum\POL@isolz@IntervalIndex=\POL@isolz@NbOfNegRoots\space + \expandafter\xintbreakloop + \fi + \let\POL@IsoLeft@Int\POL@IsoRight@Int + \let\POL@IsoLeftSign\POL@IsoRightSign + \let\POL@IsoLeftSV\POL@IsoRightSV + \ifnum\POL@IsoRight@Int < -\tw@ + \repeat +}% +\def\POL@isolz@findroots@pos{% + % remark (2018/12/08), this needs some refactoring, I hardly understand + % the logic and it hides most into the recursion done by \POL@isolz@check + % It would probably make more sense to proceed like done for the negative + % but here finding the largest roots first. + \def\POL@IsoRight@Int{1}% + \POL@isolz@findnextzeroboundeddecade@pos + \unless\ifnum\POL@IsoRightSV=\POL@IsoLeftSV\space + % this actually explores the whole of some interval (0, 10^{e-1}] + % in a context where some roots are known to be in (10^{e-1}, 10^{e}] + % and none are larger + \POL@isolz@check % will recurse inside groups if needed with modified E + \fi + % we know get the roots in the last 9 decades from 10^{e-1} to 10^{e} + % we should arguably do a more efficient dichotomy here + \def\POL@IsoLeft@Int{1}% + \let\POL@IsoLeftSV\POL@IsoRightSV + \let\POL@IsoLeftSign\POL@IsoRightSign + \xintloop + \edef\POL@IsoRight@Int{\the\numexpr\POL@IsoLeft@Int+\@ne}% + \POL@sturmchain@getSV@at\POL@IsoRight@raw + \let\POL@IsoRightSV \POL@sturmchain@SV + \let\POL@IsoRightSign\POL@sturmchain@sign + \POL@isolz@check % recurses in needed + \let\POL@IsoLeft@Int\POL@IsoRight@Int + \let\POL@IsoLeftSign\POL@IsoRightSign + \let\POL@IsoLeftSV\POL@IsoRightSV + \ifnum\POL@isolz@IntervalIndex=\POL@isolz@NbOfRoots\space + \expandafter\xintbreakloop + \fi + \ifnum\POL@IsoLeft@Int < \xint_c_ix + \repeat + \ifnum\POL@isolz@IntervalIndex<\POL@isolz@NbOfRoots\space + % get now the last, rightmost, root (or roots) + \def\POL@IsoRight@Int{10}% + \let\POL@IsoRightSign\POL@@IsoRightSign + \let\POL@IsoRightSV\POL@@IsoRightSV + \POL@isolz@check + \fi +}% +\def\POL@isolz@findnextzeroboundeddecade@pos{% + \xintloop + \edef\POL@isolz@E{\the\numexpr\POL@isolz@E-\@ne}% + \POL@sturmchain@getSV@at\POL@IsoRight@raw + \let\POL@IsoRightSV \POL@sturmchain@SV + \let\POL@IsoRightSign\POL@sturmchain@sign + \ifnum\POL@IsoRightSV=\POL@@IsoRightSV\space + \let\POL@@IsoRightSign\POL@IsoRightSign % root here possible! + \repeat +}% +\def\POL@isolz@check{% \POL@IsoRightSign must be ready for use here +% \ifxintverbose +% \xintMessage{polexpr}{Info}% +% {\the\numexpr\POL@IsoLeftSV-\POL@IsoRightSV\relax\space roots +% in (\POL@IsoLeft@raw,\POL@IsoRight@raw] (E = \POL@isolz@E)}% +% \fi + \ifcase\numexpr\POL@IsoLeftSV-\POL@IsoRightSV\relax + % no root in ]left, right] + \global\POL@isolz@nextwillneedrefinefalse + \or + % exactly one root in ]left, right] + \xdef\POL@isolz@IntervalIndex{\the\numexpr\POL@isolz@IntervalIndex+\@ne}% + \ifnum\POL@IsoRightSign=\z@ + % if right boundary is a root, ignore previous flag + \global\POL@isolz@nextwillneedrefinefalse + \fi + % if left boundary is known to have been a root we refine interval + \ifPOL@isolz@nextwillneedrefine + \expandafter\expandafter\expandafter\POL@isolz@refine + \else + % \POL@IsoRightSign is zero iff root now exactly known + \POL@refine@storeleftandright + \ifnum\POL@IsoRightSign=\z@ + \global\POL@isolz@nextwillneedrefinetrue + \fi + \fi + \else + % more than one root, we need to recurse + \expandafter\POL@isolz@recursedeeper + \fi +}% +\def\POL@isolz@recursedeeper{% +% NOTE 2018/02/16. I SHOULD DO A REAL BINARY DICHOTOMY HERE WHICH ON AVERAGE +% SHOULD BRING SOME GAIN (LIKE WHAT IS ALREADY DONE FOR THE "refine" MACROS. +% THUS IN FUTURE THIS MIGHT BE REFACTORED. +\begingroup + \edef\POL@isolz@E{\the\numexpr\POL@isolz@E-\@ne}% + \edef\POL@@IsoRight@Int{\xintDSL{\POL@IsoRight@Int}}% + \let\POL@@IsoRightSign \POL@IsoRightSign + \let\POL@@IsoRightSV \POL@IsoRightSV + \edef\POL@IsoLeft@Int {\xintDSL{\POL@IsoLeft@Int}}% + \xintiloop[1+1] + \edef\POL@IsoRight@Int{\xintInc{\POL@IsoLeft@Int}}% + \POL@sturmchain@getSV@at\POL@IsoRight@raw + \let\POL@IsoRightSV \POL@sturmchain@SV + \let\POL@IsoRightSign\POL@sturmchain@sign + \POL@isolz@check + \let\POL@IsoLeft@Int\POL@IsoRight@Int + \let\POL@IsoLeftSV\POL@IsoRightSV + \let\POL@IsoLeftSign\POL@IsoRightSign% not used, actually + \ifnum\POL@IsoLeftSV=\POL@@IsoRightSV\space + \expandafter\xintbreakiloop + \fi + \ifnum\xintiloopindex < \xint_c_ix + \repeat + \let\POL@IsoRight@Int\POL@@IsoRight@Int + \let\POL@IsoRightSign\POL@@IsoRightSign + \let\POL@IsoRightSV \POL@@IsoRightSV + % if we exited the loop via breakiloop this is superfluous + % but it only costs one \ifnum + \POL@isolz@check +\endgroup +}% +\def\POL@isolz@refine{% + % starting point is first root = left < unique second root < right + % even if we hit exactly via refinement second root, we set flag false as + % processing will continue with original right end-point, which isn't a root + \global\POL@isolz@nextwillneedrefinefalse +\begingroup + \let\POL@@IsoRightSign\POL@IsoRightSign % already evaluated + \xintloop + \edef\POL@isolz@E{\the\numexpr\POL@isolz@E-\@ne}% + \edef\POL@IsoLeft@Int {\xintDSL{\POL@IsoLeft@Int}}% + \edef\POL@IsoRight@Int{\xintInc{\POL@IsoLeft@Int}}% + \edef\POL@IsoRightSign + {\xintiiSgn{\POL@eval{\POL@sturmname _0}{\POL@IsoRight@raw}}}% + \ifnum\POL@IsoRightSign=\POL@@IsoRightSign\space + \repeat + % now second root has been separated from the one at left end point +% we update the storage of the root at left for it to have the same number +% of digits in mantissa. No, I decided not to do that to avoid complications. + % \begingroup + % \let\POL@IsoRight@Int\POL@IsoLeft@Int + % \def\POL@IsoRightSign{0}% + % \edef\POL@isolz@IntervalIndex{\the\numexpr\POL@isolz@IntervalIndex-\@ne}% + % \POL@refine@storeleftandright + % \endgroup + \edef\POL@@IsoRight@Int{\xintDSL{\xintInc{\xintDSR{\POL@IsoLeft@Int}}}}% + \let\POL@IsoLeft@Int\POL@IsoRight@Int + \let\POL@IsoLeftSign\POL@IsoRightSign + \ifnum\POL@IsoRightSign=\z@ % check if new Left is actually a root + \else + \edef\POL@IsoRight@Int{\xintDec{\POL@@IsoRight@Int}}% + \edef\POL@IsoRightSign + {\xintiiSgn{\POL@eval{\POL@sturmname _0}{\POL@IsoRight@raw}}}% + \ifnum\POL@IsoRightSign=\POL@@IsoRightSign\space + \POL@refine@doonce % we need to locate in interval (1, 9) in local scale + \else + \let\POL@IsoLeft@Int\POL@IsoRight@Int + \ifnum\POL@IsoRightSign=\z@ + \def\POL@IsoLeftSign{0}% + \else + \let\POL@IsoRight@Int\POL@@IsoRight@Int + % the IsoRightSign is now wrong but here we don't care + \fi\fi + \fi + % on exit, exact root found iff \POL@IsoRightSign is zero + \POL@refine@storeleftandright +\endgroup +}% +\def\POL@refine@doonce{% if exact root is found, always in IsoRight on exit +% NOTE: FUTURE REFACTORING WILL GET RID OF \xintiiAdd WHICH ARE A BIT COSTLY +% BUT BASICALLY NEEDED TO HANDLE BOTH NEGATIVE AND POSITIVE HERE. +% I WILL RE-ORGANIZE THE WHOLE THING IN FUTURE TO GET ROOTS STARTING FROM +% THE ORIGIN AND SIMPLY RE-LABEL THE NEGATIVE ONE AT THE END. 2018/02/16. + \let\POL@@IsoRight@Int\POL@IsoRight@Int % 9 + \let\POL@@IsoRightSign\POL@IsoRightSign + \edef\POL@IsoRight@Int{\xintiiAdd{4}{\POL@IsoLeft@Int}}% 5 + \edef\POL@IsoRightSign + {\xintiiSgn{\POL@eval{\POL@sturmname _0}{\POL@IsoRight@raw}}}% + \ifnum\POL@IsoRightSign=\POL@IsoLeftSign\space + \let\POL@IsoLeft@Int\POL@IsoRight@Int % 5 + \edef\POL@IsoRight@Int{\xintiiAdd{2}{\POL@IsoLeft@Int}}% + \edef\POL@IsoRightSign + {\xintiiSgn{\POL@eval{\POL@sturmname _0}{\POL@IsoRight@raw}}}% + \ifnum\POL@IsoRightSign=\POL@IsoLeftSign\space + \let\POL@IsoLeft@Int\POL@IsoRight@Int % 7 + \edef\POL@IsoRight@Int{\xintInc{\POL@IsoLeft@Int}}% + \edef\POL@IsoRightSign + {\xintiiSgn{\POL@eval{\POL@sturmname _0}{\POL@IsoRight@raw}}}% + \ifnum\POL@IsoRightSign=\POL@IsoLeftSign\space + \let\POL@IsoLeft@Int\POL@IsoRight@Int % 8 + \let\POL@IsoRight@Int\POL@@IsoRight@Int % 9 + \let\POL@IsoRightSign\POL@@IsoRightSign % opposite of one at left + \fi % else 7, 8 with possible root at 8 + \else + \ifnum\POL@IsoRightSign=\z@ + \let\POL@IsoLeft@Int\POL@IsoRight@Int % root at 7 + \def\POL@IsoLeftSign{0}% + \else + \let\POL@@IsoRight@Int\POL@IsoRight@Int % 7 + \edef\POL@IsoRight@Int{\xintInc{\POL@IsoLeft@Int}}% 6 + \edef\POL@IsoRightSign + {\xintiiSgn{\POL@eval{\POL@sturmname _0}{\POL@IsoRight@raw}}}% + \ifnum\POL@IsoRightSign=\POL@IsoLeftSign\space + \let\POL@IsoLeft@Int\POL@IsoRight@Int % 6 + \let\POL@IsoRight@Int\POL@@IsoRight@Int % 7 + \let\POL@IsoRightSign\POL@@IsoRightSign + \fi % else 5, 6 with possible root at 6 + \fi\fi + \else + \ifnum\POL@IsoRightSign=\z@ + \let\POL@IsoLeft@Int\POL@IsoRight@Int % root at 5 + \def\POL@IsoLeftSign{0}% + \else + \let\POL@@IsoRight@Int\POL@IsoRight@Int % 5 + \edef\POL@IsoRight@Int{\xintiiAdd{2}{\POL@IsoLeft@Int}}% + \edef\POL@IsoRightSign + {\xintiiSgn{\POL@eval{\POL@sturmname _0}{\POL@IsoRight@raw}}}% + \ifnum\POL@IsoRightSign=\POL@IsoLeftSign\space + \let\POL@IsoLeft@Int\POL@IsoRight@Int % 3 + \edef\POL@IsoRight@Int{\xintInc{\POL@IsoLeft@Int}}% 4 + \edef\POL@IsoRightSign + {\xintiiSgn{\POL@eval{\POL@sturmname _0}{\POL@IsoRight@raw}}}% + \ifnum\POL@IsoRightSign=\POL@IsoLeftSign\space + \let\POL@IsoLeft@Int\POL@IsoRight@Int % 4 + \let\POL@IsoRight@Int\POL@@IsoRight@Int % 5 + \let\POL@IsoRightSign\POL@@IsoRightSign + \fi % else 3, 4 with possible root at 4 + \else + \ifnum\POL@IsoRightSign=\z@ + \let\POL@IsoLeft@Int\POL@IsoRight@Int % root at 3 + \def\POL@IsoLeftSign{0}% + \else + \let\POL@@IsoRight@Int\POL@IsoRight@Int % 3 + \edef\POL@IsoRight@Int{\xintInc{\POL@IsoLeft@Int}}% 2 + \edef\POL@IsoRightSign + {\xintiiSgn{\POL@eval{\POL@sturmname _0}{\POL@IsoRight@raw}}}% + \ifnum\POL@IsoRightSign=\POL@IsoLeftSign\space + \let\POL@IsoLeft@Int\POL@IsoRight@Int % 2 + \let\POL@IsoRight@Int\POL@@IsoRight@Int % 3 + \let\POL@IsoRightSign\POL@@IsoRightSign + \fi % else 1, 2 with possible root at 2 + \fi\fi + \fi\fi +}% +\def\POL@refine@storeleftandright{% + \expandafter + \xdef\csname POL_ZL\POL@sturmname*\POL@isolz@IntervalIndex\endcsname + {\PolDecToString{\POL@IsoLeft@rawout}}% + \expandafter + \xdef\csname POL_ZR\POL@sturmname*\POL@isolz@IntervalIndex\endcsname + {\PolDecToString{\POL@IsoRight@rawout}}% + % added at 0.6 + \ifnum\POL@IsoRightSign=\z@ + \global + \expandafter + \let\csname POL_ZK\POL@sturmname*\POL@isolz@IntervalIndex\endcsname + \xint_stop_atfirstoftwo + \fi + \begingroup\xintglobaldefstrue + % skip some overhead of \xintdefvar... + \XINT_expr_defvar_one{\POL@sturmname L_\POL@isolz@IntervalIndex}% + {\csname .=\POL@IsoLeft@rawout\endcsname}% + \XINT_expr_defvar_one{\POL@sturmname R_\POL@isolz@IntervalIndex}% + {\csname .=\POL@IsoRight@rawout\endcsname}% + % added at 0.7 + \XINT_expr_defvar_one{\POL@sturmname Z_\POL@isolz@IntervalIndex _isknown}% + {\csname .=\ifnum\POL@IsoRightSign=\z@ 1\else 0\fi\endcsname}% + \endgroup +}% +%% \PolRefineInterval +\def\POL@xintexprGetVar#1{\expandafter\expandafter\expandafter + \XINT_expr_unlock\csname XINT_expr_var_#1\endcsname}% +% attention, also used by \POL@findrat@loop@a +\def\POL@get@IsoLeft@rawin{% + \edef\POL@IsoLeft@rawin + {\POL@xintexprGetVar{\POL@sturmname L_\POL@isolz@IntervalIndex}}% +}% +% attention, also used by \POL@findrat@loop@a +\def\POL@get@IsoRight@rawin{% + \edef\POL@IsoRight@rawin + {\POL@xintexprGetVar{\POL@sturmname R_\POL@isolz@IntervalIndex}}% +}% +% attention, also used by \POL@findrat@loop@a +\def\POL@get@Int@aux #1/1[#2]#3#4{\edef#3{\xintDSH{#4-#2}{#1}}}% +\def\POL@get@IsoLeft@Int{% + \expandafter\POL@get@Int@aux\POL@IsoLeft@rawin\POL@IsoLeft@Int\POL@isolz@E +}% +\newcommand\PolRefineInterval{\@ifstar\POL@srefine@start\POL@refine@start}% +\newcommand\POL@refine@start[3][1]{% + \edef\POL@isolz@IntervalIndex{\the\numexpr#3}% + \edef\POL@sturmname{#2}% + \expandafter\POL@refine@sharedbody\expandafter + {\expandafter\POL@refine@loop\expandafter{\the\numexpr#1}}% +}% +\def\POL@srefine@start#1#2{% + \edef\POL@isolz@IntervalIndex{\the\numexpr#2}% + \edef\POL@sturmname{#1}% + \POL@refine@sharedbody + {\let\POL@refine@left@next\POL@refine@main % we want to recurse if needed + \let\POL@refine@right@next\POL@refine@main % we want to recurse if needed + \POL@refine@main}% +}% +\def\POL@refine@sharedbody#1{% + \POL@get@IsoLeft@rawin + \edef\POL@IsoLeftSign + {\xintiiSgn{\POL@eval{\POL@sturmname _0}{\POL@IsoLeft@rawin}}}% + \ifnum\POL@IsoLeftSign=\z@ + % do nothing if that interval was already a singleton + \else + % else both end-points are not roots and there is a single one in-between + \POL@get@IsoRight@rawin + \edef\POL@IsoRightSign{\the\numexpr-\POL@IsoLeftSign}% + \edef\POL@isolz@E{\expandafter\POL@refine@getE + % je pense que le xintrez ici est superflu + \romannumeral0\xintrez{\xintSub{\POL@IsoRight@rawin}{\POL@IsoLeft@rawin}}}% + \POL@get@IsoLeft@Int + \edef\POL@IsoRight@Int{\xintInc{\POL@IsoLeft@Int}}% + #1% + \POL@refine@storeleftandright % \POL@IsoRightSign not zero + \fi +}% +\def\POL@refine@loop#1{% + \let\POL@refine@left@next \@empty % no recursion at end sub-intervals + \let\POL@refine@right@next\@empty + \xintiloop[1+1] + \POL@refine@main + \ifnum\POL@IsoRightSign=\z@ + \expandafter\xintbreakiloop + \fi + \ifnum\xintiloopindex<#1 + \repeat +}% +\def\POL@refine@main{% + \edef\POL@isolz@E{\the\numexpr\POL@isolz@E-\@ne}% + \edef\POL@IsoLeft@Int{\xintDSL{\POL@IsoLeft@Int}}% + \edef\POL@IsoRight@Int{\xintDSL{\POL@IsoRight@Int}}% + \let\POL@@IsoRight@Int\POL@IsoRight@Int + \let\POL@@IsoRightSign\POL@IsoRightSign + \edef\POL@IsoRight@Int{\xintInc{\POL@IsoLeft@Int}}% + \edef\POL@IsoRightSign + {\xintiiSgn{\POL@eval{\POL@sturmname _0}{\POL@IsoRight@raw}}}% + \ifnum\POL@IsoRightSign=\z@ + \let\POL@IsoLeft@Int\POL@IsoRight@Int % root at 1 + \def\POL@IsoLeftSign{0}% + \let\POL@next\@empty + \else + \ifnum\POL@IsoRightSign=\POL@@IsoRightSign\space + \let\POL@next\POL@refine@left@next % may be \@empty or \POL@refine@main for recursion + \let\POL@refine@right@next\@empty + \else + \let\POL@IsoLeft@Int\POL@IsoRight@Int + \edef\POL@IsoRight@Int{\xintDec{\POL@@IsoRight@Int}}% + \edef\POL@IsoRightSign + {\xintiiSgn{\POL@eval{\POL@sturmname _0}{\POL@IsoRight@raw}}}% + \ifnum\POL@IsoRightSign=\z@ + \let\POL@IsoLeft@Int\POL@IsoRight@Int % root at 9 + \def\POL@IsoLeftSign{0}% + \let\POL@next\@empty + \else + \ifnum\POL@IsoRightSign=\POL@@IsoRightSign\space + \let\POL@next\POL@refine@doonce + \else + \let\POL@IsoLeft@Int\POL@IsoRight@Int + \let\POL@IsoRight@Int\POL@@IsoRight@Int + \let\POL@IsoRightSign\POL@@IsoRightSign + \let\POL@next\POL@refine@right@next + \let\POL@refine@left@next\@empty + \fi + \fi + \fi\fi + \POL@next +}% +% lacking pre-defined xintfrac macro here (such as an \xintRawExponent) +\def\POL@refine@getE#1[#2]{#2}% \xintREZ already applied, for safety + + +\newcommand\PolIntervalWidth[2]{% +% le \xintRez est à cause des E positifs, car trailing zéros explicites +% si je travaillais à partir des variables xintexpr directement ne devrait +% pas être nécessaire, mais trop fragile par rapport à chgt internes possibles + \romannumeral0\xintrez{\xintSub{\@nameuse{POL_ZR#1*}{#2}}% + {\@nameuse{POL_ZL#1*}{#2}}} +}% + + +\newcommand\PolEnsureIntervalLengths[2]{% #1 = Sturm chain name, + % localize roots in intervals of length at most 10^{#2} + \edef\POL@sturmname{#1}% + \edef\POL@ensure@targetE{\the\numexpr#2}% + \edef\POL@nbofroots{\csname POL_ZL\POL@sturmname*0\endcsname}% + \ifnum\POL@nbofroots>\z@ + \expandafter\POL@ensureintervallengths + \fi +}% +\def\POL@ensureintervallengths{% + \POL@count\z@ + % \POL@count used by \POL@sturmchain@getSV@at but latter not used + \xintloop + \advance\POL@count\@ne + \edef\POL@isolz@IntervalIndex{\the\POL@count}% + \POL@ensure@one + \ifnum\POL@nbofroots>\POL@count + \repeat +}% +\newcommand\PolEnsureIntervalLength[3]{% #1 = Sturm chain name, + % #2 = index of interval + % localize roots in intervals of length at most 10^{#3} + \edef\POL@sturmname{#1}% + \edef\POL@ensure@targetE{\the\numexpr#3}% + \edef\POL@isolz@IntervalIndex{\the\numexpr#2}% +% peut-être autoriser -1, -2, ... ? + \ifnum\POL@isolz@IntervalIndex>\z@ +% 0.7, add this safeguard but attention means this structure must be in place + \ifnum\csname POL_ZL\POL@sturmname*0\endcsname>\z@ +% je ne fais pas les \expandafter mais je préfèrerai ne pas être à l'intérieur + \POL@ensure@one + \fi + \fi +}% +\def\POL@ensure@one{% + \POL@get@IsoLeft@rawin + \POL@get@IsoRight@rawin + \edef\POL@ensure@delta{\xintREZ{\xintSub{\POL@IsoRight@rawin}{\POL@IsoLeft@rawin}}}% + \xintiiifZero{\POL@ensure@delta} + {} + {\edef\POL@isolz@E{\expandafter\POL@refine@getE\POL@ensure@delta}% + \POL@get@IsoLeft@Int + \edef\POL@IsoRight@Int{\xintInc{\POL@IsoLeft@Int}}% + \ifnum\POL@isolz@E>\POL@ensure@targetE\space + \edef\POL@IsoLeftSign + {\xintiiSgn{\POL@eval{\POL@sturmname _0}{\POL@IsoLeft@raw}}}% + % at start left and right are not roots, and values of opposite signs + % \edef\POL@IsoRightSign{\the\numexpr-\POL@IsoLeftSign}% + \xintloop + \POL@ensure@Eloopbody % decreases E by one at each iteration + % if separation level is still too coarse we recurse at deeper level + \ifnum\POL@isolz@E>\POL@ensure@targetE\space + \repeat + % will check if right is at a zero, it needs \POL@IsoRightSign set up + \POL@refine@storeleftandright + \fi + }% +}% +\def\POL@ensure@Eloopbody {% + \edef\POL@isolz@E{\the\numexpr\POL@isolz@E-\@ne}% + \edef\POL@IsoLeft@Int{\xintDSL{\POL@IsoLeft@Int}}% + % this will loop at most ten times + \xintloop + \edef\POL@IsoRight@Int{\xintInc{\POL@IsoLeft@Int}}% + \edef\POL@IsoRightSign + {\xintiiSgn{\POL@eval{\POL@sturmname _0}{\POL@IsoRight@raw}}}% + % if we have found a zero at right boundary the \ifnum test will fail + % and we exit the loop + % else we exit the loop if sign at right boundary is opposite of + % sign at left boundary (the latter is +1 or -1, never 0) + % this is a bit wasteful if we go ten times to the right, because + % we know that there the sign will be opposite, evaluation was superfluous + \ifnum\POL@IsoLeftSign=\POL@IsoRightSign\space + \let\POL@IsoLeft@Int\POL@IsoRight@Int + \repeat + % check for case when we exited the inner loop because we actually + % found a zero, then we force exit from the main (E decreasing) loop + \ifnum\POL@IsoRightSign=\z@ + \expandafter\xintbreakloop + \fi +}% + + +\catcode`_ 8 +\newcommand\PolPrintIntervals + {\@ifstar{\PolPrintIntervals@@}{\PolPrintIntervals@}}% +\newcommand\PolPrintIntervals@@{% + \begingroup + \def\POL@AfterPrintIntervals{\endgroup}% + \def\arraystretch{2}% + \let\PolPrintIntervalsPrintExactZero\POL@@PrintIntervalsPrintExactZero + \let\PolPrintIntervalsUnknownRoot\POL@@PrintIntervalsUnknownRoot + \let\PolPrintIntervalsKnownRoot\POL@@PrintIntervalsKnownRoot + \def\PolPrintIntervalsBeginEnv{\[\begin{array}{cl}}%\] + \def\PolPrintIntervalsEndEnv{\end{array}\]}% + \PolPrintIntervals@ +}% +\newcommand\PolPrintIntervals@[2][Z]{\POL@PrintIntervals{#1}{#2}}% +\newcommand\POL@PrintIntervals[2]{% + \def\PolPrintIntervalsTheVar{#1}% + \def\PolPrintIntervalsTheSturmName{#2}% + \ifnum\@nameuse{POL_ZL#2*}{0}=\z@ + \PolPrintIntervalsNoRealRoots + \else + \gdef\PolPrintIntervalsTheIndex{1}% + \POL@PrintIntervals@DoDefs + \begingroup\edef\POL@tmp{\endgroup + \unexpanded\expandafter{\PolPrintIntervalsBeginEnv}% + \unexpanded\expandafter{\POL@PrintIntervals@Loop}% + \unexpanded\expandafter{\PolPrintIntervalsEndEnv}% + }\POL@tmp + \fi + \POL@AfterPrintIntervals + \def\PolPrintIntervalsTheVar{#1}% + \def\PolPrintIntervalsTheSturmName{#2}% +}% +\let\POL@AfterPrintIntervals\@empty +\newcommand\PolPrintIntervalsNoRealRoots{}% +\newcommand\PolPrintIntervalsBeginEnv{\[\begin{array}{rcccl}}% +\newcommand\PolPrintIntervalsEndEnv{\end{array}\]}% +\newcommand\PolPrintIntervalsKnownRoot{% + &&\PolPrintIntervalsTheVar_{\PolPrintIntervalsTheIndex}% + &=&\PolPrintIntervalsPrintExactZero +}% +\newcommand\PolPrintIntervalsUnknownRoot{% + \PolPrintIntervalsPrintLeftEndPoint&<&% + \PolPrintIntervalsTheVar_{\PolPrintIntervalsTheIndex}&<&% + \PolPrintIntervalsPrintRightEndPoint +}% +\newcommand\PolPrintIntervalsPrintExactZero {\PolPrintIntervalsTheLeftEndPoint}% +\newcommand\PolPrintIntervalsPrintLeftEndPoint {\PolPrintIntervalsTheLeftEndPoint}% +\newcommand\PolPrintIntervalsPrintRightEndPoint{\PolPrintIntervalsTheRightEndPoint}% +\newcommand\PolPrintIntervalsPrintMultiplicity{(\mbox{mult. }\PolPrintIntervalsTheMultiplicity)}% +% +\newcommand\POL@@PrintIntervalsKnownRoot{% + \PolPrintIntervalsPrintMultiplicity&% + \PolPrintIntervalsTheVar_{\PolPrintIntervalsTheIndex}=% + \PolPrintIntervalsPrintExactZero +}% +\newcommand\POL@@PrintIntervalsPrintExactZero{% + \displaystyle + \xintSignedFrac{\PolPrintIntervalsTheLeftEndPoint}% +}% +\newcommand\POL@@PrintIntervalsUnknownRoot{% + \PolPrintIntervalsPrintMultiplicity&% + \xintifSgn{\PolPrintIntervalsTheLeftEndPoint}% + {\xintifSgn{\PolPrintIntervalsTheRightEndPoint} + {\PolPrintIntervalsTheVar_{\PolPrintIntervalsTheIndex}=% + \PolPrintIntervalsPrintRightEndPoint\dots}% + {0>\PolPrintIntervalsTheVar_{\PolPrintIntervalsTheIndex}>% + \PolPrintIntervalsPrintLeftEndPoint}% + {\PolErrorThisShouldNotHappenPleaseReportToAuthorA}}% + {\xintifSgn{\PolPrintIntervalsTheRightEndPoint} + {\PolErrorThisShouldNotHappenPleaseReportToAuthorB}% + {\PolErrorThisShouldNotHappenPleaseReportToAuthorC}% + {0<\PolPrintIntervalsTheVar_{\PolPrintIntervalsTheIndex}<% + \PolPrintIntervalsPrintRightEndPoint}}% + {\xintifSgn{\PolPrintIntervalsTheRightEndPoint} + {\PolErrorThisShouldNotHappenPleaseReportToAuthorD}% + {\PolErrorThisShouldNotHappenPleaseReportToAuthorE}% + {\PolPrintIntervalsTheVar_{\PolPrintIntervalsTheIndex}=% + \PolPrintIntervalsPrintLeftEndPoint\dots}}% +}% +% +\catcode`_ 11 +\def\POL@PrintIntervals@Loop{% + \POL@SturmIfZeroExactlyKnown\PolPrintIntervalsTheSturmName + \PolPrintIntervalsTheIndex + \PolPrintIntervalsKnownRoot + \PolPrintIntervalsUnknownRoot + \xdef\PolPrintIntervalsTheIndex{\the\numexpr\PolPrintIntervalsTheIndex+\@ne}% + \unless\ifnum\PolPrintIntervalsTheIndex> + \@nameuse{POL_ZL\PolPrintIntervalsTheSturmName*0} + \POL@PrintIntervals@DoDefs + \xint_afterfi{\\\POL@PrintIntervals@Loop}% + \fi +}% +\def\POL@PrintIntervals@DoDefs{% + \xdef\PolPrintIntervalsTheLeftEndPoint{% + \csname POL_ZL\PolPrintIntervalsTheSturmName*\PolPrintIntervalsTheIndex + \endcsname + }% + \xdef\PolPrintIntervalsTheRightEndPoint{% + \csname POL_ZR\PolPrintIntervalsTheSturmName*\PolPrintIntervalsTheIndex + \endcsname + }% + \xdef\PolPrintIntervalsTheMultiplicity{% + \ifcsname POL_ZM\PolPrintIntervalsTheSturmName*\PolPrintIntervalsTheIndex + \endcsname + \csname POL_ZM\PolPrintIntervalsTheSturmName*\PolPrintIntervalsTheIndex + \endcsname + \else + ?% or use 0 ? + \fi + }% +}% + + +\newcommand\PolSturmIfZeroExactlyKnown[2]{% #1 = sturmname, #2=index + \romannumeral0\csname POL_ZK#1*\endcsname{#2}% +}% +\newcommand\POL@SturmIfZeroExactlyKnown[2]{% #1 = sturmname, #2=index + \romannumeral0\csname POL_ZK#1*\the\numexpr#2\endcsname +}% +\newcommand\PolSturmIsolatedZeroMultiplicity[2]{% + \romannumeral`^^@\csname POL_ZM#1*\endcsname{#2}% +}% +\newcommand\PolSturmIsolatedZeroLeft[2]{% + \romannumeral`^^@\csname POL_ZL#1*\endcsname{#2}% +}% +\newcommand\PolSturmIsolatedZeroRight[2]{% + \romannumeral`^^@\csname POL_ZR#1*\endcsname{#2}% +}% +\newcommand\PolSturmNbOfIsolatedZeros[1]{% + \romannumeral`^^@\csname POL_ZL#1*0\endcsname +}% +\newcommand\PolSturmRationalRoot[2]{% + \romannumeral`^^@\csname POL_ZL#1*% + \csname POL_RI#1*\endcsname{#2}\endcsname +}% +\newcommand\PolSturmRationalRootIndex[2]{% + \romannumeral`^^@\csname POL_RI#1*\endcsname{#2}% +}% +\newcommand\PolSturmRationalRootMultiplicity[2]{% + \romannumeral`^^@\csname POL_ZM#1% + *\csname POL_RI#1*\endcsname{#2}\endcsname +}% +\newcommand\PolSturmNbOfRationalRoots[1]{% + \romannumeral`^^@\csname POL_RI#1*0\endcsname +}% +\newcommand\PolSturmNbOfRationalRootsWithMultiplicities[1]{% +% means the \POL@norr must not have been changed in-between... + \the\numexpr\PolDegree{#1}-\PolDegree{#1\POL@norr}\relax +}% + + +\let\PolDecToString\xintDecToString + + +\newcommand\PolMakeMonic[1]{% + \edef\POL@leadingcoeff{\PolLeadingCoeff{#1}}% + \edef\POL@leadingcoeff@inverse{\xintDiv{1/1[0]}{\POL@leadingcoeff}}% + \PolMapCoeffs{\xintMul{\POL@leadingcoeff@inverse}}{#1}% +}% + + +%% CORE ALGEBRA MACROS +%% We do this non-expandably, but in a nestable way... this is the whole +%% point because \xintdeffunc as used by \poldef creates a big nested macro. +%% The idea is to execute it with another meaning given to \xintAdd etc.., +%% so that it operates on "polynomials". This is a mixture of expandable +%% and non-expandable techniques. +\def\POL@get#1#2#3{% + \global\POL@polfalse + \begingroup + \def\POL@result{#3}% + #3% + \expandafter + \endgroup + \expandafter\def\expandafter#1\expandafter{\POL@result}% + \unless\ifPOL@pol + % avoid expanding more than twice #3 + \edef#1{#3}% + \xintiiifZero{#1}% + {\def#1{-1.\empty{0/1[0]}}}% + {\edef#1{0.\noexpand\empty{#1}}}% + \fi + #2% +}% +%% ADDITION +\def\POL@add {\POL@get\POL@A\POL@add@b}% +\def\POL@add@b{\POL@get\POL@B\POL@add@c}% +\def\POL@add@c{% + \global\POL@poltrue + \POL@ifZero\POL@A + {\let\POL@result\POL@B}% + {\POL@ifZero\POL@B + {\let\POL@result\POL@A}% + {\POL@@add}}% +}% +\def\POL@@add{% + \expandafter\POL@split\POL@A;\POL@degA\POL@polA + \expandafter\POL@split\POL@B;\POL@degB\POL@polB + \ifnum\POL@degA>\POL@degB\relax + \xintAssignArray\POL@polA\to\POL@arrayA + \xintAssignArray\POL@polB\to\POL@arrayB + \else + \xintAssignArray\POL@polB\to\POL@arrayA + \xintAssignArray\POL@polA\to\POL@arrayB + \let\POL@tmp\POL@degB\let\POL@degB\POL@degA\let\POL@degA\POL@tmp + \fi + \count@\z@ + \xintloop + \advance\count@\@ne + \expandafter\edef\csname POL@arrayA\the\count@\endcsname + {\xintScalarAdd{\@nameuse{POL@arrayA\the\count@}}% + {\@nameuse{POL@arrayB\the\count@}}}% + \unless\ifnum\POL@degB<\count@ + \repeat + \count@\@nameuse{POL@arrayA0} % 1+\POL@degA + % trim zero leading coefficients (we could check for equal degrees, + % but would not bring much as anyhow loop exists immediately if not) + \xintloop + % this abuses that \POL@arrayA0 is never zero + \xintiiifZero{\@nameuse{POL@arrayA\the\count@}}% + {\iftrue}% + {\iffalse}% + \advance\count@\m@ne + \repeat + \POL@resultfromarray A% attention that \POL@arrayA0 not updated +}% + +%% MULTIPLICATION +\def\POL@mul {\POL@get\POL@A\POL@mul@b}% +\def\POL@mul@b{\POL@get\POL@B\POL@mul@c}% +\def\POL@mul@c{% + \global\POL@poltrue + \POL@ifZero\POL@A + {\def\POL@result{-1.\empty{0/1[0]}}}% + {\POL@ifZero\POL@B + {\def\POL@result{-1.\empty{0/1[0]}}}% + {\POL@@mul}}% +}% +\def\POL@@mul{% + \expandafter\POL@split\POL@A;\POL@degA\POL@polA + \expandafter\POL@split\POL@B;\POL@degB\POL@polB + \ifnum\POL@degA>\POL@degB\relax + \xintAssignArray\POL@polA\to\POL@arrayA + \xintAssignArray\POL@polB\to\POL@arrayB + \else + \xintAssignArray\POL@polB\to\POL@arrayA + \xintAssignArray\POL@polA\to\POL@arrayB + \let\POL@tmp\POL@degB + \let\POL@degB\POL@degA + \let\POL@degA\POL@tmp + \fi + \count@\z@ + \xintloop + \POL@@mul@phaseIloopbody + \unless\ifnum\POL@degB<\count@ + \repeat + \xintloop + \unless\ifnum\POL@degA<\count@ % car attention au cas de mêmes degrés + \POL@@mul@phaseIIloopbody + \repeat + \edef\POL@degC{\the\numexpr\POL@degA+\POL@degB}% + \xintloop + \unless\ifnum\POL@degC<\count@ + \POL@@mul@phaseIIIloopbody + \repeat + %\count@\the\numexpr\POL@degC+\@ne\relax % never zero polynomial here + \POL@resultfromarray C% +}% +\def\POL@@mul@phaseIloopbody{% + \advance\count@\@ne + \def\POL@tmp{0[0]}% + \count\tw@\z@ + \xintloop + \advance\count\tw@\@ne + \edef\POL@tmp{% + \xintScalarAdd + {\POL@tmp}% + {\xintScalarMul + {\@nameuse{POL@arrayA\the\count\tw@}}% + {\@nameuse{POL@arrayB\the\numexpr\count@+\@ne-\count\tw@}}% + }% + }% + \ifnum\count\tw@<\count@ + \repeat + \expandafter\let\csname POL@arrayC\the\count@\endcsname\POL@tmp +}% +\def\POL@@mul@phaseIIloopbody{% + \advance\count@\@ne + \def\POL@tmp{0[0]}% + \count\tw@\count@ + \advance\count\tw@-\@nameuse{POL@arrayB0} % + \xintloop + \ifnum\count\tw@<\count@ + \advance\count\tw@\@ne + \edef\POL@tmp{% + \xintScalarAdd + {\POL@tmp}% + {\xintScalarMul + {\@nameuse{POL@arrayA\the\count\tw@}}% + {\@nameuse{POL@arrayB\the\numexpr\count@+\@ne-\count\tw@}}% + }% + }% + \repeat + \expandafter\let\csname POL@arrayC\the\count@\endcsname\POL@tmp +}% +\def\POL@@mul@phaseIIIloopbody{% + \advance\count@\@ne + \def\POL@tmp{0[0]}% + \count\tw@\count@ + \advance\count\tw@-\@nameuse{POL@arrayB0} % + \xintloop + \advance\count\tw@\@ne + \edef\POL@tmp{% + \xintScalarAdd{\POL@tmp}% + {\xintScalarMul + {\@nameuse{POL@arrayA\the\count\tw@}}% + {\@nameuse{POL@arrayB\the\numexpr\count@+\@ne-\count\tw@}}% + }% + }% + \ifnum\@nameuse{POL@arrayA0}>\count\tw@ + \repeat + \expandafter\let\csname POL@arrayC\the\count@\endcsname\POL@tmp +}% + +%% POWERS (SCALAR EXPONENT...) +\def\POL@pow #1#2{% + \global\POL@polfalse + \begingroup + \def\POL@result{#1}% + #1% + \expandafter + \endgroup + \expandafter\def\expandafter\POL@A\expandafter{\POL@result}% + \unless\ifPOL@pol + \edef\POL@A{\xintScalarPow{#1}{#2}}% no error check + \xintiiifZero{\POL@A}% + {\def\POL@result{-1.\empty{0/1[0]}}}% + {\edef\POL@result{0.\noexpand\empty{\POL@A}}}% + \else + \edef\POL@B{\numexpr\xintNum{#2}\relax}% no check on exponent >= 0 + \ifcase\POL@B + \def\POL@result{0.\empty{1/1[0]}}% + \or + \let\POL@result\POL@A + \else + \POL@@pow@check + \fi + \fi + \global\POL@poltrue +}% +\def\POL@@pow@check {% +% no problem here with leftover tokens! +% should I have used that I-don't-care technique more elsewhere? + \ifnum\@ne>\POL@A + % polynomial is a constant, must get rid of dot and \empty + \edef\POL@A{\expandafter\xintScalarPow\romannumeral`^^@% + \expandafter\xint_gob_til_dot\POL@A{\POL@B}}% + \xintiiifZero{\POL@A}% + {\def\POL@result{-1.\empty{0/1[0]}}}% + {\edef\POL@result{0.\noexpand\empty{\POL@A}}}% + \else + \ifnum\@ne=\POL@A + % perhaps a constant times X, check constant term + \xintiiifZero + {\expandafter\xint_firstoftwo\romannumeral`^^@% + \expandafter\xint_gob_til_dot\POL@A} + {\edef\POL@result + {\the\POL@B.% here at least 2. + \noexpand\empty + \romannumeral\xintreplicate{\POL@B}{{0/1[0]}}% + {\xintScalarPow + {\expandafter\xint_secondoftwo\romannumeral`^^@% + \expandafter\xint_gob_til_dot\POL@A}% + {\POL@B}}}}% + {\POL@@pow}% not constant times X, use general recursion + \else + \POL@@pow% general recursion + \fi\fi +}% +\def\POL@@pow@recurse#1#2{% + \begingroup + #1% + \expandafter + \endgroup + \expandafter\def\expandafter\POL@A\expandafter{\POL@result}% + \edef\POL@B{\numexpr\xintNum{#2}\relax}% + \ifcase\POL@B + \POL@thisshouldneverhappen + \or + \let\POL@result\POL@A + \else + \expandafter\POL@@pow + \fi +}% +\def\POL@@pow {% + \let\POL@pow@exp\POL@B + \let\POL@B\POL@A + \POL@@mul + \let\POL@sqA\POL@result + \ifodd\POL@pow@exp\space + \expandafter\POL@@pow@odd + \the\numexpr(\POL@pow@exp+\@ne)/\tw@-\@ne\expandafter.% + \else + \expandafter\POL@@pow@even + \the\numexpr(\POL@pow@exp+\@ne)/\tw@-\@ne\expandafter.% + \fi +}% +\def\POL@@pow@even#1.{% + \expandafter\POL@@pow@recurse\expandafter + {\expandafter\def\expandafter\POL@result\expandafter{\POL@sqA}}% + {#1}% +}% +\def\POL@@pow@odd#1.{% + \expandafter\POL@@pow@odd@i\expandafter{\POL@A}{#1}% +}% +\def\POL@@pow@odd@i #1#2{% + \expandafter\POL@@pow@recurse\expandafter + {\expandafter\def\expandafter\POL@result\expandafter{\POL@sqA}}% + {#2}% + \expandafter\POL@mul\expandafter + {\expandafter\def\expandafter\POL@result\expandafter + {\POL@result}\global\POL@poltrue}% + {\def\POL@result{#1}\global\POL@poltrue}% +}% + +%% DIVISION +%% no check on divisor being non-zero +\def\POL@div {\POL@get\POL@A\POL@div@b}% +\def\POL@div@b{\POL@get\POL@B\POL@div@c}% +\def\POL@div@c{% + \global\POL@poltrue + \expandafter\POL@split\POL@A;\POL@degA\POL@polA + \expandafter\POL@split\POL@B;\POL@degB\POL@polB + \ifnum\POL@degA<\POL@degB\space + \@namedef{POL@arrayQ1}{0/1[0]}% + \def\POL@degQ{-1}% + \else + \xintAssignArray\POL@polA\to\POL@arrayR + \xintAssignArray\POL@polB\to\POL@arrayB + \POL@@div + \fi + \count@\numexpr\POL@degQ+\@ne\relax + \POL@resultfromarray Q% +}% +\def\POL@@div{% + \xintAssignArray\POL@polA\to\POL@arrayR + \xintAssignArray\POL@polB\to\POL@arrayB + \edef\POL@B@leading{\csname POL@arrayB\the\numexpr\POL@degB+\@ne\endcsname}% + \edef\POL@degQ{\the\numexpr\POL@degA-\POL@degB}% + \count@\numexpr\POL@degA+\@ne\relax + \count\tw@\numexpr\POL@degQ+\@ne\relax + \xintloop + \POL@@div@loopbody + \ifnum\count\tw@>\z@ + \repeat + %%\expandafter\def\csname POL@arrayR0\endcsname{1}% + \xintloop + \xintiiifZero{\csname POL@arrayR\the\count@\endcsname}% + {\iftrue}% + {\iffalse}% + \advance\count@\m@ne + \repeat + \edef\POL@degR{\the\numexpr\count@-\@ne}% +}% +\def\POL@@div@loopbody{% + \edef\POL@@div@ratio{% + \xintScalarDiv{\csname POL@arrayR\the\count@\endcsname}% + {\POL@B@leading}}% + \expandafter\let\csname POL@arrayQ\the\count\tw@\endcsname + \POL@@div@ratio + \advance\count@\m@ne + \advance\count\tw@\m@ne + \count4 \count@ + \count6 \POL@degB\space + \xintloop + \ifnum\count6>\z@ + \expandafter\edef\csname POL@arrayR\the\count4\endcsname + {\xintScalarSub + {\csname POL@arrayR\the\count4\endcsname}% + {\xintScalarMul + {\POL@@div@ratio}% + {\csname POL@arrayB\the\count6\endcsname}}}% + \advance\count4 \m@ne + \advance\count6 \m@ne + \repeat +}% + +%% MINUS SIGN AS UNARY OPERATOR +\def\POL@opp #1{% + \global\POL@polfalse + \begingroup + \def\POL@result{#1}% + #1% + \expandafter + \endgroup + \expandafter\def\expandafter\POL@A\expandafter{\POL@result}% + \unless\ifPOL@pol + \edef\POL@A{\xintScalarOpp{#1}}% + \xintiiifZero{\POL@A}% + {\def\POL@result{-1.\empty{0/1[0]}}}% + {\edef\POL@result{0.\noexpand\empty{\POL@A}}}% + \else + \edef\POL@B{0.\noexpand\empty{-1/1[0]}}% + \POL@@mul + \fi + \global\POL@poltrue +}% + + +%% EXPANDABLE MACROS +\def\POL@eval@fork#1\At#2#3\krof{#2}% +\newcommand\PolEval[3]{\romannumeral`^^@\POL@eval@fork + #2\PolEvalAt + \At\PolEvalAtExpr\krof {#1}{#3}% +}% +\newcommand\PolEvalAt[2] + {\xintpraw{\csname XINT_expr_userfunc_#1\endcsname{#2}}}% +\newcommand\POL@eval[2] + {\csname XINT_expr_userfunc_#1\endcsname{#2}}% +\newcommand\PolEvalAtExpr[2]{\xinttheexpr #1(#2)\relax}% +% +\newcommand\PolEvalReduced[3]{\romannumeral`^^@\POL@eval@fork + #2\PolEvalReducedAt + \At\PolEvalReducedAtExpr\krof {#1}{#3}% +}% +\newcommand\PolEvalReducedAt[2]{% + \xintpraw % in order not to print denominator if the latter equals 1 + {\xintIrr{\csname XINT_expr_userfunc_#1\endcsname{#2}}[0]}% +}% +\newcommand\PolEvalReducedAtExpr[2]{% + \xintpraw + {\xintIrr{\romannumeral`^^@\xintthebareeval#1(#2)\relax}[0]}% +}% +% +\newcommand\PolFloatEval[3]{\romannumeral`^^@\POL@eval@fork + #2\PolFloatEvalAt + \At\PolFloatEvalAtExpr\krof {#1}{#3}% +}% +\newcommand\PolFloatEvalAt[2] + {\xintpfloat{\csname XINT_flexpr_userfunc_#1\endcsname{#2}}}% +\newcommand\PolFloatEvalAtExpr[2]{\xintthefloatexpr #1(#2)\relax}% + + +\newcommand\PolSturmIntervalIndex[3]{\the\numexpr\POL@eval@fork + #2\PolSturmIntervalIndexAt + \At\PolSturmIntervalIndexAtExpr\krof {#1}{#3}% +}% +\newcommand\PolSturmIntervalIndexAtExpr[2] + {\PolSturmIntervalIndexAt{#1}{\xinttheexpr#2\relax}}% +\newcommand\PolSturmIntervalIndexAt[2] + {\expandafter\POL@sturm@index@at\romannumeral`^^@#2!{#1}\xint_bye\relax}% +\def\POL@sturm@index@at#1!#2% +{% + \expandafter\POL@sturm@index@at@iloop + \romannumeral`^^@\PolSturmNbOfIsolatedZeros{#2}!{#2}{#1}% +}% +% implementation is sub-optimal as it should use some kind of binary tree +% search rather than comparing to the intervals from right to left as here +\def\POL@sturm@index@at@iloop #1!% +{% + \ifnum #1=\z@ 0\expandafter\xint_bye\fi + \POL@sturm@index@at@iloop@a #1!% +}% +\def\POL@sturm@index@at@iloop@a #1!#2#3% +{% #1 = index, #2 = sturmname, #3 value + \PolSturmIfZeroExactlyKnown{#2}{#1} + {\xintifCmp{#3}{\POL@xintexprGetVar{#2L_#1}}% + {}% + {#1\xint_bye}% + {0\xint_bye}% + }% + {\xintifGt{#3}{\POL@xintexprGetVar{#2L_#1}}% + {\xintifLt{#3}{\POL@xintexprGetVar{#2R_#1}}% + {#1\xint_bye}% + {0\xint_bye}% + }% + {}% + }% + % catcode of ! is 11 in polexpr.sty + \expandafter\POL@sturm@index@at@iloop\the\numexpr#1-\@ne !{#2}{#3}% +}% + + +\def\POL@leq@fork#1\LessThanOrEqualTo#2#3\krof{#2}% +\newcommand\PolSturmNbOfRootsOf[3]{\romannumeral`^^@\POL@leq@fork + #2\PolNbOfRootsLessThanOrEqualTo + \LessThanOrEqualTo\PolNbOfRootsLessThanOrEqualToExpr\krof {#1}{#3}% +}% +\newcommand\PolNbOfRootsLessThanOrEqualToExpr[2] + {\PolNbOfRootsLessThanOrEqualTo{#1}{\xinttheexpr#2\relax}}% +\newcommand\PolNbOfRootsLessThanOrEqualTo[1]{% + \ifnum\PolSturmNbOfIsolatedZeros{#1}=\z@ + \expandafter\xint_firstofthree\expandafter0% + \else + \expandafter\PolNbOfRootsLessThanOrEqualTo@% + \fi {#1}% +}% +\def\PolNbOfRootsLessThanOrEqualTo@ #1#2% +{% + \expandafter\POL@nbofrootsleq@prep\romannumeral`^^@#2!{#1}% +}% +\def\POL@nbofrootsleq@prep#1!#2% +{% + \expandafter\POL@nbofrootsleq@iloop\expandafter 1\expandafter !% + \romannumeral0\xintsgn{\POL@eval{#2_0}{#1}}!% + #1!{#2}% +}% +\def\POL@nbofrootsleq@iloop#1!#2!#3!#4% +{% #1 = index, #2 = sign of evaluation at value, #3 = value, #4 = sturmname + \xintifCmp{#3}{\POL@xintexprGetVar{#4L_#1}}% + {\POL@nbofrootsleq@return #1-\@ne !}% + {\POL@nbofrootsleq@return + \PolSturmIfZeroExactlyKnown{#4}{#1}{#1}{#1-\@ne}!% + }% + % in third branch we are sure that if root is exactly known + % the test \xintifLt will be negative + {\xintifLt{#3}{\POL@xintexprGetVar{#4R_#1}}% + {\POL@nbofrootsleq@return + #1\ifnum#2=\xintSgn{\POL@eval{#4_0}{\POL@xintexprGetVar{#4L_#1}}} + -\@ne\fi !% + }% + {\ifnum#1=\PolSturmNbOfIsolatedZeros{#4} + \expandafter\POL@nbofrootsleq@rightmost + \fi \expandafter\POL@nbofrootsleq@iloop \the\numexpr\@ne+% + }% + }% + #1!#2!#3!{#4}% +}% +\def\POL@nbofrootsleq@return #1!#2!#3!#4!#5{\the\numexpr #1\relax}% +\def\POL@nbofrootsleq@rightmost\expandafter\POL@nbofrootsleq@iloop + \the\numexpr\@ne+#1!#2!#3!#4{#1}% + + +\newcommand\PolSturmNbWithMultOfRootsOf[3] +{\the\numexpr0\POL@leq@fork + #2\PolNbWithMultOfRootsLessThanOrEqualTo + \LessThanOrEqualTo\PolNbWithMultOfRootsLessThanOrEqualToExpr\krof {#1}{#3}% +}% +\newcommand\PolNbWithMultOfRootsLessThanOrEqualToExpr[2] + {\PolNbWithMultOfRootsLessThanOrEqualTo{#1}{\xinttheexpr#2\relax}}% +\newcommand\PolNbWithMultOfRootsLessThanOrEqualTo[1]{% + \ifnum\PolSturmNbOfIsolatedZeros{#1}=\z@ + \expandafter\POL@nbwmofroots@noroots + \else + \expandafter\PolNbWithMultOfRootsLessThanOrEqualTo@% + \fi {#1}% +}% +\def\POL@nbwmofroots@noroots#1#2{\relax}% +\def\PolNbWithMultOfRootsLessThanOrEqualTo@ #1#2% +{% + \expandafter\POL@nbwmofrootsleq@prep\romannumeral`^^@#2!{#1}% +}% +\def\POL@nbwmofrootsleq@prep#1!#2% +{% + \expandafter\POL@nbwmofrootsleq@iloop\expandafter 1\expandafter !% + \romannumeral0\xintsgn{\POL@eval{#2_0}{#1}}!% + #1!{#2}% +}% +\def\POL@nbwmofrootsleq@iloop#1!#2!#3!#4% +{% #1 = index, #2 = sign of evaluation at value, #3 = value, #4 = sturmname + \xintifCmp{#3}{\POL@xintexprGetVar{#4L_#1}}% + {\POL@nbwmofrootsleq@return !}% + {\POL@nbwmofrootsleq@return + \PolSturmIfZeroExactlyKnown{#4}{#1}% + {+\PolSturmIsolatedZeroMultiplicity{#4}{#1}}{}!% + }% + % in third branch we are sure that if root is exactly known + % the test \xintifLt will be negative + {\xintifLt{#3}{\POL@xintexprGetVar{#4R_#1}}% + {\POL@nbwmofrootsleq@return + \unless + \ifnum#2=\xintSgn{\POL@eval{#4_0}{\POL@xintexprGetVar{#4L_#1}}} + +\PolSturmIsolatedZeroMultiplicity{#4}{#1}\fi !% + }% + {+\PolSturmIsolatedZeroMultiplicity{#4}{#1}% + \ifnum#1=\PolSturmNbOfIsolatedZeros{#4} + \expandafter\POL@nbwmofrootsleq@return\expandafter !% + \fi + \expandafter\POL@nbwmofrootsleq@iloop \the\numexpr\@ne+% + }% + }% + #1!#2!#3!{#4}% +}% +\def\POL@nbwmofrootsleq@return #1!#2!#3!#4!#5{#1\relax}% + + +\newcommand\PolLeadingCoeff[1]{% + \romannumeral`^^@\expandafter\expandafter\expandafter\xintlastitem + \expandafter\expandafter\expandafter + {\csname POLuserpol@#1\endcsname}% +}% +% +\newcommand\PolNthCoeff[2]{\romannumeral`^^@% + \expandafter\POL@nthcoeff + \romannumeral0\xintnthelt{\ifnum\numexpr#2<\z@#2\else(#2)+1\fi}% + {\expandafter\expandafter\expandafter + \xint_gob_til_dot\csname POLuserpol@#1\endcsname}@% +}% +\def\POL@nthcoeff#1@{\if @#1@\expandafter\xint_firstoftwo + \else\expandafter\xint_secondoftwo\fi + {0/1[0]}{#1}}% +% +% returns -1 for zero polynomial for context of numerical expression +% should it return -\infty? +\newcommand\PolDegree[1]{\romannumeral`^^@\expandafter\expandafter\expandafter + \POL@degree\csname POLuserpol@#1\endcsname;}% +\def\POL@degree #1.#2;{#1}% +% +\newcommand\PolToList[1]{\romannumeral`^^@\expandafter\expandafter\expandafter + \xint_gob_til_dot\csname POLuserpol@#1\endcsname}% +% +\newcommand\PolToCSV[1]{\romannumeral0\xintlistwithsep{, }{\PolToList{#1}}}% + + +\newcommand\PolToExprCmd[1]{\xintPRaw{\xintRawWithZeros{#1}}}% +\newcommand\PolToFloatExprCmd[1]{\xintFloat{#1}}% +\let\PolToExprTermPrefix\PolTypesetCmdPrefix +\newcommand\PolToExprOneTermStyleA[2]{% + \ifnum#2=\z@ + \PolToExprCmd{#1}% + \else + \xintifOne{\xintiiAbs{#1}} + {\xintiiifSgn{#1}{-}{}{}}% + from \PolToExprTermPrefix + {\PolToExprCmd{#1}\PolToExprTimes}% + \fi + \ifcase\xintiiAbs{#2} %<-- space here mandatory + \or\PolToExprVar + \else\PolToExprVar^\xintiiAbs{#2}% + \fi +}% +\let\PolToExprOneTerm\PolToExprOneTermStyleA +\newcommand\PolToExprOneTermStyleB[2]{% + \ifnum#2=\z@ + \xintNumerator{#1}% + \else + \xintifOne{\xintiiAbs{\xintNumerator{#1}}} + {\xintiiifSgn{#1}{-}{}{}}% + from \PolToExprTermPrefix + {\xintNumerator{#1}\PolToExprTimes}% + \fi + \ifcase\xintiiAbs{#2} %<-- space here mandatory + \or\PolToExprVar + \else\PolToExprVar^\xintiiAbs{#2}% + \fi + \xintiiifOne{\xintDenominator{#1}}{}{/\xintDenominator{#1}}% +}% +\newcommand\PolToFloatExprOneTerm[2]{% + \ifnum#2=\z@ + \PolToFloatExprCmd{#1}% + \else + \PolToFloatExprCmd{#1}\PolToExprTimes + \fi + \ifcase\xintiiAbs{#2} %<-- space here mandatory + \or\PolToExprVar + \else\PolToExprVar^\xintiiAbs{#2}% + \fi +}% +\newcommand\PolToExprTimes{*}% +\newcommand\PolToExprVar{x}% +\newcommand\PolToExpr[1]{% + \if*\noexpand#1\expandafter\xint_firstoftwo\else + \expandafter\xint_secondoftwo\fi + \PolToExprAscending\PolToExprDescending{#1}}% +\newcommand\PolToFloatExpr[1]{% + \if*\noexpand#1\expandafter\xint_firstoftwo\else + \expandafter\xint_secondoftwo\fi + \PolToFloatExprAscending\PolToFloatExprDescending{#1}}% +\newcommand\PolToExprAscending[2]{% + \expandafter\POL@toexpr\csname POLuserpol@#2\endcsname + \PolToExprOneTerm\POL@toexprA}% +\newcommand\PolToFloatExprAscending[2]{% + \expandafter\POL@toexpr\csname POLuserpol@#2\endcsname + \PolToFloatExprOneTerm\POL@toexprA}% +\newcommand\PolToExprDescending[1]{% + \expandafter\POL@toexpr\csname POLuserpol@#1\endcsname + \PolToExprOneTerm\POL@toexprD}% +\newcommand\PolToFloatExprDescending[1]{% + \expandafter\POL@toexpr\csname POLuserpol@#1\endcsname + \PolToFloatExprOneTerm\POL@toexprD}% +% +\def\POL@toexpr#1#2#3{\expandafter\POL@toexpr@ + \expandafter#3\expandafter#2#1\relax}% +\def\POL@toexpr@#1#2#3.{% + \ifnum#3<\z@ + #2{0/1[0]}{0}\expandafter\xint_gobble_v + \else + \expandafter#1% + \fi {#3}#2}% +% +\def\POL@toexprA #1#2\empty#3{% + \ifpoltoexprall\expandafter\POL@toexprall@b + \else\expandafter\POL@toexpr@b + \fi {#3}#2{0}1.% +}% +\def\POL@toexprD #1#2#3\relax{% #3 has \empty to prevent brace removal + \expandafter\POL@toexprD@a\expandafter#2% + \the\numexpr #1\expandafter.\romannumeral0\xintrevwithbraces{#3}\relax +}% +\def\POL@toexprD@a #1#2.#3{% + \ifpoltoexprall\expandafter\POL@toexprall@b + \else\expandafter\POL@toexpr@b + \fi{#3}#1{-#2}\the\numexpr\@ne+-#2.% +}% +\def\POL@toexpr@b #1#2#3{% + \xintiiifZero{#1}% + {\expandafter\POL@toexpr@loop\expandafter\POL@toexpr@b}% + {#2{#1}{#3}% + \expandafter\POL@toexpr@loop\expandafter\POL@toexpr@c}% + \expandafter#2% +}% +\def\POL@toexpr@c #1#2#3{% + \xintiiifZero{#1}% + {}% + {\PolToExprTermPrefix{#1}#2{#1}{#3}}% + \expandafter\POL@toexpr@loop\expandafter\POL@toexpr@c + \expandafter#2% +}% +\def\POL@toexprall@b #1#2#3{% + #2{#1}{#3}% + \expandafter\POL@toexpr@loop\expandafter\POL@toexprall@c + \expandafter#2% +}% +\def\POL@toexprall@c #1#2#3{% + \PolToExprTermPrefix{#1}#2{#1}{#3}% + \expandafter\POL@toexpr@loop\expandafter\POL@toexprall@c + \expandafter#2% +}% +\def\POL@toexpr@loop#1#2#3.#4{% + \if\relax#4\expandafter\xint_gob_til_dot\fi + #1{#4}#2{#3}\the\numexpr\@ne+#3.% +}% + + +\POL@restorecatcodes +\endinput diff --git a/macros/latex/contrib/polexpr/polexpr.txt b/macros/latex/contrib/polexpr/polexpr.txt new file mode 100644 index 0000000000..46ea7e32fa --- /dev/null +++ b/macros/latex/contrib/polexpr/polexpr.txt @@ -0,0 +1,2593 @@ +.. comment: -*- fill-column: 72; mode: rst; -*- + +=============================== + Package polexpr documentation +=============================== + +0.7.4 (2019/02/12) +================== + +.. contents:: + +Basic syntax +------------ + +The syntax is:: + + \poldef polname(x):= expression in variable x; + +where: + +- in place of ``x`` an arbitrary *dummy variable* is authorized, + i.e. per default any of ``[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. + +.. attention:: + + The ``'`` is authorized since ``0.5.1``. As a result some constructs + recognized by the ``\xintexpr`` parser, such as ``var1 'and' var2`` + will get misinterpreted and cause errors. However these constructs + are unlikely to be frequently needed in polynomial expressions, and + the ``\xintexpr`` syntax offers alternatives, so it was deemed a + small evil. Of course the ``\xintexpr`` parser is modified only + temporarily during execution of ``\poldef``. + +One can also issue:: + + \PolDef{polname}{expression in variable x} + +which admits an optional first argument to modify the variable letter +from its default ``x``. + +``\poldef f(x):= 1-x+x^2;`` + defines polynomial ``f``. Polynomial names must start with a + letter and may contain letters, digits, underscores and the right + tick character. The + variable must be a single letter. The colon character is optional. + The semi-colon at end of expression is mandatory. + +``\PolDef{f}{1-x+x^2}`` + does the same as ``\poldef f(x):= 1-x+x^2;`` To use another letter + than ``x`` in the expression, one must pass it as an extra optional + argument to ``\PolDef``. Useful if the semi-colon has been assigned + some non-standard catcode by some package. + +``\PolLet{g}={f}`` + saves a copy of ``f`` under name ``g``. Also usable without ``=``. + +``\poldef f(z):= f(z)^2;`` + redefines ``f`` in terms of itself. + +``\poldef f(T):= f(f(T));`` + again redefines ``f`` in terms of its (new) self. + +``\poldef k(z):= f(z)-g(g(z)^2)^2;`` + should now define the zero polynomial... Let's check: + ``\[ k(z) = \PolTypeset[z]{k} \]`` + +``\PolDiff{f}{f'}`` + sets ``f'`` to the derivative of ``f``. The name doesn't have to be + ``f'`` (in fact the ``'`` is licit only since ``0.5.1``). + +.. 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 defined via ``\PolDiff``: something like + ``T'(x)^2`` will not work without a prior ``\PolDiff{T}{T'}``. + +``\PolDiff{f'}{f''}`` + obtains second derivative. + +``\PolDiff[3]{f}{f'''}`` + computes the third derivative. + +:: + + $f(z) = \PolTypeset[z]{f} $\newline + $f'(z) = \PolTypeset[z]{f'} $\newline + $f''(z) = \PolTypeset[z]{f''} $\newline + $f'''(z)= \PolTypeset[z]{f'''} $\par + +.. important:: + + The package does not currently know rational functions: ``/`` in + a parsed polynomial expression does the Euclidean quotient:: + + (1-x^2)/(1-x) + + does give ``1+x`` but :: + + (1/(1-x))*(1-x^2) + + evaluates to zero. This will work as expected:: + + \poldef k(x):= (x-1)(x-2)(x-3)(x-4)/(x^2-5x+4); + +.. _warningtacit: + +.. attention:: + + ``1/2 x^2`` skips the space and is treated like ``1/(2*x^2)`` because + of the tacit multiplication rules of \xintexpr. But this means 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 + even 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: + xint_ tacit multiplication always "ties more", hence this gets + interpreted as ``1/(2*(x-1)*(x-2))`` which gives zero by polynomial + division. Thus, use one of ``(1/2)(x-1)(x-2)``, ``1/2*(x-1)(x-2)`` or + ``(x-1)(x-2)/2``. + +After:: + + \poldef f_1(x):= 25(x-1)(x^2-2)(x-3)(x-4)(x-5);% + \poldef f_2(x):= 37(x-1)(x^2-2)(x-6)(x-7)(x-8);% + +the macro call ``\PolGCD{f_1}{f_2}{k}`` sets ``k`` to the (unitary) GCD of +``f_1`` and ``f_2`` (hence to the expansion of ``(x-1)(x^2-2)``.) + +``\PolToExpr{k}`` + will (expandably) give in this case ``x^3-x^2-2*x+2``. This is + useful for console or file output (the syntax is Maple- and + PSTricks-compatible; the letter used in output can be + (non-expandably) changed via a redefinition of `\\PolToExprVar`_.) + +``\PolToExpr*{k}`` + gives ascending powers: ``2-2*x-x^2+x^3``. + +Examples of localization of roots +--------------------------------- + +- To make printed decimal numbers more enjoyable than via + ``\xintSignedFrac``:: + + \renewcommand\PolTypesetOne[1]{\PolDecToString{\xintREZ{#1}}}% + + ``\PolDecToString`` will use decimal notation to incorporate the power + of ten part; and the ``\xintREZ`` will have the effect to suppress + trailing zeros if present in raw numerator (if those digits end up + after decimal mark.) Notice that the above are expandable macros and + that one can also do:: + + \renewcommand\PolToExprCmd[1]{\PolDecToString{\xintREZ{#1}}}% + + to modify output of `\\PolToExpr{polname}`_. + +- For extra info in log file use ``\xintverbosetrue``. + +- Only for some of these examples is the output included here. + + +A typical example +~~~~~~~~~~~~~~~~~ + +In this example the polynomial is square-free. + +:: + + \poldef f(x) := x^7 - x^6 - 2x + 1; + + \PolToSturm{f}{f} + \PolSturmIsolateZeros{f} + The \PolTypeset{f} polynomial has \PolSturmNbOfIsolatedZeros{f} distinct real + roots which are located in the following intervals: + \PolPrintIntervals{f} + Here is the second root with ten more decimal digits: + \PolRefineInterval[10]{f}{2} + \[\PolSturmIsolatedZeroLeft{f}{2}<Z_2<\PolSturmIsolatedZeroRight{f}{2}\] + And here is the first root with twenty digits after decimal mark: + \PolEnsureIntervalLength{f}{1}{-20} + \[\PolSturmIsolatedZeroLeft{f}{1}<Z_1<\PolSturmIsolatedZeroRight{f}{1}\] + The first element of the Sturm chain has degree $\PolDegree{f_0}$. As + this is the original degreee $\PolDegree{f}$ we know that $f$ is square free. + Its derivative is up to a constant \PolTypeset{f_1} (in this example + it is identical with it). + \PolToSturm{f_1}{f_1}\PolSturmIsolateZeros{f_1}% + The derivative has \PolSturmNbOfIsolatedZeros{f_1} distinct real + roots: + \PolPrintIntervals[W]{f_1} + \PolEnsureIntervalLengths{f_1}{-10}% + Here they are with ten digits after decimal mark: + \PolPrintIntervals[W]{f_1} + \PolDiff{f_1}{f''} + \PolToSturm{f''}{f''} + \PolSturmIsolateZeros{f''} + The second derivative is \PolTypeset{f''}. + It has \PolSturmNbOfIsolatedZeros{f''} distinct real + roots: + \PolPrintIntervals[X]{f''} + Here is the positive one with 20 digits after decimal mark: + \PolEnsureIntervalLength{f''}{2}{-20}% + \[X_2 = \PolSturmIsolatedZeroLeft{f''}{2}\dots\] + The more mathematically advanced among our dear readers will be able + to give the exact value for $X_2$! + +A degree four polynomial with nearby roots +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Notice that this example is a bit outdated as ``0.7`` release has +added ``\PolSturmIsolateZeros**{sturmname}`` which would find exactly +the roots. The steps here retain their interest when one is interested +in finding isolating intervals for example to prepare some demonstration +of dichotomy method. + + +:: + + \PolDef{Q}{(x-1.050001)(x-1.105001)(x-1.110501)(x-1.111051)} + \PolTypeset{Q} + \PolToSturm{Q}{Q} % it is allowed to use same prefix for Sturm chain + \PolSturmIsolateZeros{Q} + \PolPrintIntervals{Q} + % reports 1.0 < Z_1 < 1.1, 1.10 < Z_2 < 1.11, 1.110 < Z_3 < 1.111, and 1.111 < Z_4 < 1.112 + % but the above bounds do not allow minimizing separation between roots + % so we refine: + \PolRefineInterval*{Q}{1} + \PolRefineInterval*{Q}{2} + \PolRefineInterval*{Q}{3} + \PolRefineInterval*{Q}{4} + \PolPrintIntervals{Q} + % reports 1.05 < Z_1 < 1.06, 1.105 < Z_2 < 1.106, 1.1105 < Z_3 < 1.1106, + % and 1.11105 < Z_4 < 1.11106. + \PolEnsureIntervalLengths{Q}{-6} + \PolPrintIntervals{Q} + % of course finds here all roots exactly + + +The degree nine polynomial with 0.99, 0.999, 0.9999 as triple roots +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +:: + + % define a user command (xinttools is loaded automatically by polexpr) + \newcommand\showmultiplicities[1]{% #1 = "sturmname" + \xintFor* ##1 in {\xintSeq{1}{\PolSturmNbOfIsolatedZeros{#1}}}\do{% + The multiplicity is \PolSturmIsolatedZeroMultiplicity{#1}{##1} + \PolSturmIfZeroExactlyKnown{#1}{##1}% + {at the root $x=\PolSturmIsolatedZeroLeft{#1}{##1}$} + {for the root such that + $\PolSturmIsolatedZeroLeft{#1}{##1}<x<\PolSturmIsolatedZeroRight{#1}{##1}$} + \par + }}% + \PolDef{f}{(x-0.99)^3(x-0.999)^3(x-0.9999)^3} + \renewcommand\PolTypesetOne[1]{\PolDecToString{\xintREZ{#1}}} + \PolTypeset{f}\par + \PolToSturm{f}{f}% it is allowed to use "polname" as "sturmname" too + \PolSturmIsolateZerosAndGetMultiplicities{f}% use the "sturmname" here + % or \PolSturmIsolateZeros*{f} which is exactly the same, but shorter.. + + \showmultiplicities{f} + +In this example, the output will look like this (but using math mode):: + + x^9 - 8.9667x^8 + 35.73400293x^7 - 83.070418400109x^6 + 124.143648875193123x^5 + - 123.683070924326075877x^4 + 82.149260397553075617891x^3 + - 35.07602992699900159127007x^2 + 8.7364078733314648368671733x + - 0.967100824643585986488103299 + + The multiplicity is 3 at the root x = 0.99 + The multiplicity is 3 at the root x = 0.999 + The multiplicity is 3 at the root x = 0.9999 + +On first pass, these rational roots were found (due to their relative +magnitudes, using ``\PolSturmIsolateZeros**`` was not needed here). But +multiplicity computation works also with (decimal) roots not yet +identified or with non-decimal or irrational roots. + +It is fun to modify only a tiny bit the polynomial and see if polexpr +survives:: + + \PolDef{g}{f(x)+1e-27} + \PolTypeset{g}\par + \PolToSturm{g}{g} + \PolSturmIsolateZeros*{g} + + \showmultiplicities{g} + +This produces:: + + x^9 - 8.9667x^8 + 35.73400293x^7 - 83.070418400109x^6 + 124.143648875193123x^5 + - 123.683070924326075877x^4 + 82.149260397553075617891x^3 + - 35.07602992699900159127007x^2 + 8.7364078733314648368671733x + - 0.967100824643585986488103298 + + The multiplicity is 1 for the root such that 0.98 < x < 0.99 + The multiplicity is 1 for the root such that 0.9991 < x < 0.9992 + The multiplicity is 1 for the root such that 0.9997 < x < 0.9998 + +Which means that the multiplicity-3 roots each became a real and a pair of +complex ones. Let's see them better:: + + \PolEnsureIntervalLengths{g}{-10} + + \showmultiplicities{g} + +which produces:: + + The multiplicity is 1 for the root such that 0.9899888032 < x < 0.9899888033 + The multiplicity is 1 for the root such that 0.9991447980 < x < 0.9991447981 + The multiplicity is 1 for the root such that 0.9997663986 < x < 0.9997663987 + +A degree five polynomial with three rational roots +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +:: + + \poldef Q(x) := 1581755751184441 x^5 + -14907697165025339 x^4 + +48415668972339336 x^3 + -63952057791306264 x^2 + +46833913221154895 x + -49044360626280925; + + \PolToSturm{Q}{Q} + %\begin{flushleft} + \renewcommand\PolTypesetCmdPrefix[1]{\allowbreak\xintiiifSgn{#1}{}{+}{+}}% + $Q_0(x) = \PolTypeset{Q_0}$ + %\end{flushleft} + \PolSturmIsolateZeros**{Q} + \PolPrintIntervals{Q} + + $Q_{norr}(x) = \PolTypeset{Q_norr}$ + +Here, all real roots are rational:: + + Z_1 = 833719/265381 + Z_2 = 165707065/52746197 + Z_3 = 355/113 + + Q_norr(x) = x^2 + 1 + +And let's get their decimal expansion too:: + + % print decimal expansion of the found roots + \renewcommand\PolPrintIntervalsPrintExactZero + {\xintTrunc{20}{\PolPrintIntervalsTheLeftEndPoint}\dots} + \PolPrintIntervals{Q} + + Z_1 = 3.14159265358107777120... + Z_2 = 3.14159265358979340254... + Z_3 = 3.14159292035398230088... + + +A Mignotte type polynomial +~~~~~~~~~~~~~~~~~~~~~~~~~~ + +:: + + \PolDef{P}{x^10 - (10x-1)^2}% + \PolTypeset{P} % prints it in expanded form + \PolToSturm{P}{P} % we can use same prefix for Sturm chain + \PolSturmIsolateZeros{P} % finds 4 real roots + This polynomial has \PolSturmNbOfIsolatedZeros{P} distinct real roots: + \PolPrintIntervals{P}% + % reports -2 < Z_1 < -1, 0.09 < Z_2 < 0.10, 0.1 < Z_3 < 0.2, 1 < Z_4 < 2 + Let us refine the second and third intervals to separate the corresponding + roots: + \PolRefineInterval*{P}{2}% will refine to 0.0999990 < Z_2 < 0.0999991 + \PolRefineInterval*{P}{3}% will refine to 0.100001 < Z_3 < 0.100002 + \PolPrintIntervals{P}% + Let us now get to know all roots with 10 digits after decimal mark: + \PolEnsureIntervalLengths{P}{-10}% + \PolPrintIntervals{P}% now all roots are known 10 decimal digits after mark + Finally, we display 20 digits of the second root: + \PolEnsureIntervalLength{P}{2}{-20}% makes Z_2 known with 20 digits after mark + \[\PolSturmIsolatedZeroLeft{P}{2}<Z_2<\PolSturmIsolatedZeroRight{P}{2}\] + +The last line produces:: + + 0.09999900004999650028 < Z_2 < 0.09999900004999650029 + + +The Wilkinson polynomial +~~~~~~~~~~~~~~~~~~~~~~~~ + +See `Wilkinson polynomial`_. + +:: + + \documentclass{article} + \usepackage{polexpr} + \begin{document} + %\xintverbosetrue % for the curious... + + \poldef f(x) := mul((x - i), i = 1..20); + + \renewcommand\PolTypesetCmdPrefix[1]{\allowbreak\xintiiifSgn{#1}{}{+}{+}}% + \renewcommand\PolTypesetOne[1]{\xintDecToString{#1}}% + + \noindent\PolTypeset{f} + + \PolToSturm{f}{f} + \PolSturmIsolateZeros{f} + \PolPrintIntervals{f} + + \clearpage + + \poldef g(x) := f(x) - 2**{-23} x**19; + + % be patient! + \PolToSturm{g}{g} + \noindent\PolTypeset{g_0}% integer coefficient primitive polynomial + + \PolSturmIsolateZeros{g} + \PolEnsureIntervalLengths{g}{-10} + + \renewcommand\PolPrintIntervalsPrintMultiplicity{} + \PolPrintIntervals*{g} + + \end{document} + + +The first polynomial:: + + f(x) = x**20 + - 210 x**19 + + 20615 x**18 + - 1256850 x**17 + + 53327946 x**16 + - 1672280820 x**15 + + 40171771630 x**14 + - 756111184500 x**13 + + 11310276995381 x**12 + - 135585182899530 x**11 + + 1307535010540395 x**10 + - 10142299865511450 x**9 + + 63030812099294896 x**8 + - 311333643161390640 x**7 + + 1206647803780373360 x**6 + - 3599979517947607200 x**5 + + 8037811822645051776 x**4 + - 12870931245150988800 x**3 + + 13803759753640704000 x**2 + - 8752948036761600000 x + + 2432902008176640000 + +is handled fast enough (a few seconds), but the modified one ``f(x) - +2**-23 x**19`` takes about 20x longer (the Sturm chain polynomials +have integer coefficients with up to 321 digits, whereas (surprisingly +perhaps) those of the Sturm chain polynomials derived from ``f`` never +have more than 21 digits ...). + +Once the Sturm chain is computed and the zeros isolated, obtaining their +decimal digits is relatively faster. Here is for the ten real roots of +``f(x) - 2**-23 x**19`` as computed by the code above:: + + Z_1 = 0.9999999999... + Z_2 = 2.0000000000... + Z_3 = 2.9999999999... + Z_4 = 4.0000000002... + Z_5 = 4.9999999275... + Z_6 = 6.0000069439... + Z_7 = 6.9996972339... + Z_8 = 8.0072676034... + Z_9 = 8.9172502485... + Z_10 = 20.8469081014... + +The second Wilkinson polynomial +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +:: + + \documentclass{article} + \usepackage{polexpr} + \begin{document} + \poldef f(x) := mul(x - 2^-i, i = 1..20); + + %\PolTypeset{f} + + \PolToSturm{f}{f} + \PolSturmIsolateZeros**{f} + \PolPrintIntervals{f} + \end{document} + +This takes more time than the polynomial with 1, 2, .., 20 as roots but +less than the latter modified by the ``2**-23`` change in one +coefficient. + +Here is the output (with release 0.7.2):: + + Z_1 = 0.00000095367431640625 + Z_2 = 0.0000019073486328125 + Z_3 = 0.000003814697265625 + Z_4 = 0.00000762939453125 + Z_5 = 0.0000152587890625 + Z_6 = 0.000030517578125 + Z_7 = 0.00006103515625 + Z_8 = 0.0001220703125 + Z_9 = 1/4096 + Z_10 = 1/2048 + Z_11 = 1/1024 + Z_12 = 1/512 + Z_13 = 1/256 + Z_14 = 1/128 + Z_15 = 0.015625 + Z_16 = 0.03125 + Z_17 = 0.0625 + Z_18 = 0.125 + Z_19 = 0.25 + Z_20 = 0.5 + +There is some incoherence in output format which has its source in the +fact that some roots are found in branches which can only find decimal +roots, whereas some are found in branches which could find general +fractions and they use ``\xintIrr`` before storage of the found root. +This may evolve in future. + + +The degree 41 polynomial with -2, -1.9, -1.8, ..., 0, 0.1, ..., 1.9, 2 as roots +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +:: + + \PolDef{P}{mul((x-i*1e-1), i=-20..20)}% i/10 is same but less efficient + +In the defining expression we could have used ``i/10`` but this gives +less efficient internal form for the coefficients (the ``10``'s end up +in denominators). Using ``\PolToExpr{P}`` after having done + +:: + + \renewcommand\PolToExprCmd[1]{\PolDecToString{\xintREZ{#1}}} + +we get this expanded form:: + + x^41 + -28.7*x^39 + +375.7117*x^37 + -2975.11006*x^35 + +15935.28150578*x^33 + -61167.527674162*x^31 + +173944.259366417394*x^29 + -373686.963560544648*x^27 + +613012.0665016658846445*x^25 + -771182.31133138163125495*x^23 + +743263.86672885754888959569*x^21 + -545609.076599482896371978698*x^19 + +301748.325708943677229642930528*x^17 + -123655.8987669450434698869844544*x^15 + +36666.1782054884005855608205864192*x^13 + -7607.85821367459445649518380016128*x^11 + +1053.15135918687298508885950223794176*x^9 + -90.6380005918141132650786081964032*x^7 + +4.33701563847327366842552218288128*x^5 + -0.0944770968420804735498178265088*x^3 + +0.00059190121813899276854174416896*x + +which shows coefficients with up to 36 significant digits... + +Stress test: not a hard challenge to ``xint + polexpr``, but be a bit patient! + +:: + + \PolDef{P}{mul((x-i*1e-1), i=-20..20)}% + \PolToSturm{P}{S} % dutifully computes S_0, ..., S_{41} + % the [1] optional argument limits the search to interval (-10,10) + \PolSturmIsolateZeros[1]{S} % finds *exactly* (but a bit slowly) all 41 roots! + \PolPrintIntervals{S} % nice, isn't it? + +.. note:: + + Release ``0.5`` has *experimental* addition of optional argument + ``E`` to ``\PolSturmIsolateZeros``. It instructs to search roots only + in interval ``(-10^E, 10^E)``. Important: the extremities are + *assumed to not be roots*. In this example, the ``[1]`` in + ``\PolSturmIsolateZeros[1]{S}`` gives some speed gain; without it, it + turns out in this case that ``polexpr`` would have started with + ``(-10^6, 10^6)`` interval. + + Please note that this will probably get replaced in future by the + specification of a general interval. Do not rely on meaning of this + optional argument keeping the same. + +Roots of Chebyshev polynomials +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +:: + + \newcount\mycount + \poldef T_0(x) := 1; + \poldef T_1(x) := x; + \mycount 2 + \xintloop + \poldef T_\the\mycount(x) := + 2x*T_\the\numexpr\mycount-1(x) + - T_\the\numexpr\mycount-2(x); + \ifnum\mycount<15 + \advance\mycount 1 + \repeat + + \[T_{15} = \PolTypeset[X]{T_15}\] + \PolToSturm{T_15}{T_15} + \PolSturmIsolateZeros{T_15} + \PolEnsureIntervalLengths{T_15}{-10} + \PolPrintIntervals{T_15} + + +Non-expandable macros +--------------------- + +.. _poldef;: + +``\poldef polname(letter):= expression in letter;`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + This evaluates the *polynomial expression* and stores the coefficients + in a private structure accessible later via other package macros, + under the user-chosen ``polname``. Of course the *expression* can + use other previously defined polynomials. Names must start with a + letter and are constituted of letters, digits, underscores and + (since ``0.5.1``) the right tick ``'``. + The whole xintexpr_ syntax is authorized:: + + \poldef sin(z) := add((-1)^i z^(2i+1)/(2i+1)!, i = 0..10); + + With fractional coefficients, beware the `tacit multiplication issue + <warningtacit_>`_. + + As a side effect the function ``polname()`` is recognized as a + genuine ``\xintexpr...\relax`` function for (exact) numerical + evaluation (or within an ``\xintdefvar`` assignment.) It computes + values not according to the original expression but via the Horner + scheme corresponding to the polynomial coefficients. + + .. attention:: + + Release ``0.3`` also did the necessary set-up to let the + polynomial be known to the ``\xintfloatexpr`` (or + ``\xintdeffloatvar``) parser. + + Since ``0.4`` this isn't done automatically. Even more, a + previously existing floating point variant 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 + a product of the other package macros. + + See `\\PolGenFloatVariant{polname}`_. + + The original expression is lost after parsing, and in particular + the package provides no way to typeset it. This has to be done + manually, if needed. + +.. _PolDef: + +``\PolDef[letter]{polname}{expression in letter}`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + Does the same as `\\poldef <poldef;>`_ in an undelimited macro + format (thus avoiding potential problems with the catcode of the + semi-colon in presence of some packages.) In absence of the + ``[letter]`` optional argument, the variable is assumed to be ``x``. + +.. _PolGenFloatVariant: + +``\PolGenFloatVariant{polname}`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + Makes the polynomial also usable in the ``\xintfloatexpr`` parser. + It will therein evaluates via an Horner scheme with coefficients + already pre-rounded to the float precision. + + See also `\\PolToFloatExpr{polname}`_. + + .. attention:: + + Release ``0.3`` did this automatically on ``\PolDef`` and + ``\poldef`` but this was removed at ``0.4`` for optimization. + + 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 ``\xintfloatexpr`` or alike + context. + +.. _PolLet: + +``\PolLet{polname_2}={polname_1}`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + Makes a copy of the already defined polynomial ``polname_1`` to a + new one ``polname_2``. Same effect as + ``\PolDef{polname_2}{polname_1(x)}`` but with less overhead. The + ``=`` is optional. + +.. _PolGlobalLet: + +``\PolGlobalLet{polname_2}={polname_1}`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + Acts globally. + +.. _PolAssign: + +``\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. + + - 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}{number}`_. The main difference is that + with ``\PolAssign``, ``\macro`` is made a prefix to ``1 + deg f`` + already defined (hidden to user) macros holding individually the + coefficients but `\\PolNthCoeff{polname}{number}`_ does each time the job + to expandably recover the ``Nth`` coefficient, and due to + expandability can not store it in a macro for future usage (of course, + it can be an argument in an ``\edef``.) The other difference + is the shift by one in indexing, mentioned above (negative + indices act the same in both.) + +.. _PolGet: + +``\PolGet{polname}\fromarray\macro`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + Does the converse operation to + ``\PolAssign{polname}\toarray\macro``. Each individual + ``\macro{number}`` 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;``. + + .. note:: + + Prior to ``0.5``, coefficients were not normalized via + ``\xintRaw`` for internal storage. + +.. _PolFromCSV: + +``\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 <\\PolToCSV{polname}_>`_. + + .. note:: + + Prior to ``0.5``, coefficients were not normalized via + ``\xintRaw`` for internal storage. + +.. _PolTypeset: + +``\PolTypeset{polname}`` +~~~~~~~~~~~~~~~~~~~~~~~~ + + Typesets in descending powers in math mode. It uses letter ``x`` but + this can be changed via an optional argument:: + + \PolTypeset[z]{polname} + + By default zero coefficients are skipped (issue ``\poltypesetalltrue`` + to get all of them in output). + + These commands (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{raw_coeff}`` +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + + Checks if the coefficient is ``1`` or ``-1`` and then skips printing + the ``1``, except for the constant term. Also it sets conditional + `\\PolIfCoeffIsPlusOrMinusOne{A}{B}`_. + + The actual printing of the coefficients, when not equal to plus or + minus one is handled by `\\PolTypesetOne{raw_coeff}`_. + +.. _PolTypesetOne: + +``\PolTypesetOne{raw_coeff}`` +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + + The default is ``\xintSignedFrac`` but this macro is annoying as it + insists to use a power of ten, and not decimal notation. + + One can do things such as for example: [#]_ + + :: + + \renewcommand\PolTypesetOne[1]{\num{\xintPFloat[5]{#1}}} + \renewcommand\PolTypesetOne[1]{\num{\xintRound{4}{#1}}} + + where e.g. we used the ``\num`` macro of ``siunitx`` as it + understands floating point notation. + + .. [#] the difference in the syntaxes of ``\xintPFloat`` and + ``\xintRound`` is explained from the fact that + ``\xintPFloat`` by default uses the prevailing precision + hence the extra argument like here ``5`` is an optional one. + + One can also give a try to using `\\PolDecToString{decimal number}`_ + which uses decimal notation (at least for the numerator part). + +.. _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{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 + ``\xintSignedFrac`` 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*: + +``\PolTypeset*{polname}`` +~~~~~~~~~~~~~~~~~~~~~~~~~ + + Typesets in ascending powers. Use e.g. ``[h]`` optional argument + (after the ``*``) to use letter ``h`` rather than ``x``. + +.. _PolDiff: + +``\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]: + +``\PolDiff[N]{polname_1}{polname_2}`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + This sets ``polname_2`` to the ``N``-th derivative of ``polname_1``. + Identical arguments is allowed. With ``N=0``, same effect as + ``\PolLet{polname_2}={polname_1}``. With negative ``N``, switches to + using ``\PolAntiDiff``. + +.. _PolAntiDiff: + +``\PolAntiDiff{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]: + +``\PolAntiDiff[N]{polname_1}{polname_2}`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + This sets ``polname_2`` to the result of ``N`` successive integrations on + ``polname_1``. With negative ``N``, it switches to using ``\PolDiff``. + +.. _PolDivide: + +``\PolDivide{polname_1}{polname_2}{polname_Q}{polname_R}`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + This sets ``polname_Q`` and ``polname_R`` to be the quotient and + remainder in the Euclidean division of ``polname_1`` by + ``polname_2``. + +.. _PolQuo: + +``\PolQuo{polname_1}{polname_2}{polname_Q}`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + This sets ``polname_Q`` to be the quotient in the Euclidean division + of ``polname_1`` by ``polname_2``. + +.. _PolRem: + +``\PolRem{polname_1}{polname_2}{polname_R}`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + This sets ``polname_R`` to be the remainder in the Euclidean division + of ``polname_1`` by ``polname_2``. + +.. _PolGCD: + +``\PolGCD{polname_1}{polname_2}{polname_GCD}`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + This sets ``polname_GCD`` to be the (monic) GCD of the two first + polynomials. It is a unitary polynomial except if both ``polname_1`` + and ``polname_2`` vanish, then ``polname_GCD`` is the zero + polynomial. + +.. ``\PolIGCD{polname_1}{polname_2}{polname_iGCD}`` + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + **NOT YET** + + This **assumes** that the two polynomials have integer coefficients. + It then computes the greatest common divisor in the integer + polynomial ring, normalized to have a positive leading coefficient + (if the inputs are not both zero). + + ``\PolIContent{polname}`` + ~~~~~~~~~~~~~~~~~~~~~~~~~ + + **NOT YET** + + This computes a positive rational number such that dividing the + polynomial with it returns an integer coefficients polynomial with + no common factor among the coefficients. + +.. _PolToSturm: + +``\PolToSturm{polname}{sturmname}`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + With ``polname`` being for example ``P``, the macro starts by + computing polynomials ``P`` and ``P'``, then computes the (opposite + of the) remainder in euclidean division, iteratively. + + The last non-zero remainder ``P_N_`` (where ``N`` is obtainable as + `\\PolSturmChainLength{sturmname}`_) is up to a factor + the GCD of ``P`` and ``P'`` hence it is a constant if and only if + ``P`` is square-free. + + .. note:: + + - Since ``0.5`` all these polynomials are divided by their rational + content, so they have integer coefficients with no common factor, + and the last one if a constant is either ``1`` or ``-1``. + + - After this normalization to primitive polynomials, they are + stored internally as ``sturmname_k_``, ``k=0,1, ...``. + + - These polynomials are used internally only. To keep them as + genuine declared polynomials also after the macro call, use the + starred variant `PolToSturm*`_. + + .. note:: + + It is perfectly allowed to use the polynomial name as Sturm chain name: + ``\PolToSturm{f}(f}``. + + The macro then declares ``sturmname_0``, ``sturmname_1``, ..., which are + the (non-declared) ``sturmname_k_`` divided by the last one. Division is + not done if this last one is the constant ``1`` or ``-1``, i.e. if the + original polynomial was square-free. These polynomials are primitive + polynomials too, i.e. with integer coefficients having no common factor. + + Thus ``sturmname_0`` has exactly the same real and complex roots as + polynomial ``polname``, but with each root now of multiplicity one: + i.e. it is the "square-free part" of original polynomial ``polname``. + + Notice that ``sturmname_1`` isn't necessarily the derivative of + ``sturmname_0`` due to the various normalizations. + + The polynomials ``sturmname_k`` main utility is for the execution of + `\\PolSturmIsolateZeros{sturmname}`_. Be careful not to use these + names ``sturmname_0``, ``sturmname_1``, etc... for defining other + polynomials after having done ``\PolToSturm{polname}{sturmname}`` and + before executing ``\PolSturmIsolateZeros{sturmname}`` else the + latter will behave erroneously. + + `\\PolSturmChainLength{sturmname}`_ gives the index of the last + element of the Sturm chain. + +.. _PolToSturm*: + +``\PolToSturm*{polname}{sturmname}`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + Does the same as `un-starred version <PolToSturm_>`_ and additionally it + keeps for user usage the memory of the *un-normalized* Sturm chain + polynomials ``sturmname_k_``, ``k=0,1, ..., N``, with + ``N`` being `\\PolSturmChainLength{sturmname}`_. + + .. note:: + + This behaviour was modified at ``0.6``, anyhow the macro was + broken at ``0.5``. + + .. hint:: + + The square-free part of ``polname`` is ``sturmname_0``, and their + quotient is the polynomial with name + ``sturname_\PolSturmChainLength{sturmname}_``. It thus easy to + set-up a loop iteratively computing the latter until the last one + is a constant, thus obtaining the decomposition of an ``f`` as + a product ``c f_1 f_2 f_3 ...`` of a constant and square-free (primitive) + polynomials, where each ``f_i`` divides its predecessor. + +.. _PolSetToSturmChainSignChangesAt: + +``\PolSetToSturmChainSignChangesAt{\macro}{sturmname}{fraction}`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + Sets macro ``\macro`` to the number of sign changes in the Sturm + chain with name prefix ``sturmname``, at location ``fraction`` + (which must be in format as acceptable by the xintfrac_ macros.) + + .. note:: + + The author was lazy and did not provide rather an expandable + variant, where one would do ``\edef\macro{\PolNbOf...}``. + + This will presumably get added in a future release. + + After some hesitation it was decided the macro would by default + act globally. To make the scope of its macro definition local, + use ``[\empty]`` as extra optional argument. + +.. _PolSetToNbOfZerosWithin: + +``\PolSetToNbOfZerosWithin{\macro}{sturmname}{value_a}{value_b}`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + Applies the `Sturm Theorem`_ to set ``\macro`` to the exact number + of **distinct** roots of ``sturmname_0`` in the interval ``(value_a, + value_b]`` (the macro first re-orders the value for ``value_a <= + value_b`` to hold). + + .. note:: + + The author was lazy and did not provide rather an expandable + variant, where one would do ``\edef\macro{\PolNbOf...}``. + + This will presumably get added in future. + + After some hesitation it was decided the macro would by default + act globally. To make the scope of its macro definition local, + use ``[\empty]`` as extra optional argument. + + See also the expandable + `\\PolSturmNbOfRootsOf{sturmname}\\LessThanOrEqualTo{value}`_, from + which it is immediate (with ``\numexpr``) to create an expandable + variant of this macro. However the difference is that this macro + requires only `\\PolToSturm <PolToSturm_>`_ to have been executed, + whereas the expandable variant requires prior execution of + `\\PolSturmIsolateZeros <PolSturmIsolateZeros_>`_. + + See also the expandable + `\\PolSturmNbWithMultOfRootsOf{sturmname}\\LessThanOrEqualTo{value}`_ + which requires prior execution of + `\\PolSturmIsolateZeros* <PolSturmIsolateZeros*_>`_. + + +.. _PolSturmIsolateZeros: + +``\PolSturmIsolateZeros{sturmname}`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + The macros locates, using `Sturm theorem`_, as many disjoint + intervals as there are (real) roots. + + .. important:: + + The Sturm chain must have been produced by an earlier + `\\PolToSturm{polname}{sturmname}`_. + + Why does this macro ask for argument the name of Sturm chain, + rather than the name of a polynomial? well this is mainly for + legacy reason, and because it is accompanied by other macros for + which it is simpler to assume the argument will be the name of an + already computed Sturm chain. + + Notice that ``\PolToSturm{f}{f}`` is perfectly legal (the + ``sturmname`` can be same as the ``polname``): it defines + polynomials ``f_0``, ``f_1``, ... having ``f`` has name prefix. + + Such a prior call + to ``\PolToSturm`` must have been made at any rate for + ``\PolSturmIsolateZeros`` to be usable. + + 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. + + .. This procedure is covariant + with the independent variable ``x`` becoming ``-x``. + Hmm, pas sûr et trop fatigué + + The interval boundaries (and exactly found roots) are made available + for future computations in ``\xintexpr``-essions or polynomial + definitions as variables ``<sturmname>L_1``, + ``<sturmname>L_2``, etc..., for the left end-points and + ``<sturmname>R_1``, ``<sturmname>R_2``, ..., for the right + end-points. + + Thus for example, if ``sturmname`` is ``f``, one can use the + xintexpr_ variables ``fL_1``, ``fL_2``, ... to refer in expressions + to the left end-points (or to the exact root, if left and right end + points coincide). Additionally, xintexpr_ variable ``fZ_1_isknown`` + will have value ``1`` if the root in the first interval is known, + and ``0`` otherwise. And similarly for the other intervals. + + 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 <PolDecToString_>`_.) And there + is also `\\PolSturmIfZeroExactlyKnown{sturmname}{index}{A}{B}`_. + + .. 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. + + These variables and macros are automatically updated when one next + uses macros such as `\\PolRefineInterval*{sturmname}{index}`_. + + The start of decimal expansion of a positive ``k``-th root is given + by `\\PolSturmIsolatedZeroLeft{sturmname}{k} + <PolSturmIsolatedZeroLeft_>`_, and for a negative root it is given + by `\PolSturmIsolatedZeroRight{sturmname}{k} + <PolSturmIsolatedZeroRight_>`_. 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{expression}`_. + will expandably compute respectively the number of real roots at + most equal to ``value`` or ``expression``, and the same but with + multiplicities. + + .. note:: + + In the current implementation the xintexpr_ variables + and xinttools_ arrays are globally defined. On the + other hand the Sturm sequence polynomials obey the current scope. + + .. note:: + + As all computations are done *exactly* there can be no errors... + apart those due to bad coding by author. 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*{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 executing this macro, + `\\PolSturmIsolatedZeroMultiplicity{sturmname}{index}`_ will expand + 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 ``f``, xintexpr_ + variables ``fM_1``, ``fM_2``... hold the multiplicities thus + computed. + + .. note:: + + It is **not** necessary to have executed the `PolToSturm*`_ starred + variant, as the non-starred variant keeps internally the memory of the + original GCD (and even of the full non-normalized original Sturm + chain), even though it does not make the declarations as *user-level* + genuine polynomials. + + See `The degree nine polynomial with 0.99, 0.999, 0.9999 as triple + roots`_ for an example. + +.. _PolSturmIsolateZeros**: + +``\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 (see `\\polexprsetup`_ for customizing this + name). 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 (see `\\polexprsetup`_), i.e. it contains + the irrational roots of the original polynomial, with the same + multiplicities. + + See `A degree five polynomial with three rational + roots`_ for an example. + +.. _PolSturmIsolateZerosAndGetMultiplicities: + +``\PolSturmIsolateZerosAndGetMultiplicities{sturmname}`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + This is another name for `\\PolSturmIsolateZeros*{sturmname}`_. + +.. _PolSturmIsolateZerosGetMultiplicitiesAndRationalRoots: + +``\PolSturmIsolateZerosGetMultiplicitiesAndRationalRoots{sturmname}`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + This is another name for `\\PolSturmIsolateZeros**{sturmname}`_. + + +``\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* <PolPrintIntervals*_>`_ for example will be + erroneous for the intervals with 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*{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. This means that the ``k``\ th root is then + strictly separated from the other roots. + +.. _PolRefineInterval[N]: + +``\PolRefineInterval[N]{sturmname}{index}`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + The ``index``\ -th interval (starting count at one) is further + subdivided once, reducing its length by a factor of 10. This is done + ``N`` times if the optional argument ``[N]`` is present. + +.. _PolEnsureIntervalLength: + +``\PolEnsureIntervalLength{sturmname}{index}{E}`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + 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{sturmname}{E}`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + 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`` (length will be shorter + than ``10^E`` in output only if it did not change or became zero.) + + This means that decimal expansions of all roots will be known with + ``-E`` digits (for ``E<0``) after decimal mark. + +.. _PolPrintIntervals: + +``\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. + + .. attention:: + + This macro was refactored at 0.7, its default output remained + identical but the ways to customize it got completely + modified. + + See 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:: + + \newcommand\PolPrintIntervalsBeginEnv{\[\begin{array}{rcccl}} + +``\PolPrintIntervalsEndEnv`` +^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + + Default definition:: + + \newcommand\PolPrintIntervalsEndEnv{\end{array}\]} + +``\PolPrintIntervalsKnownRoot`` +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + + Default definition:: + + \newcommand\PolPrintIntervalsKnownRoot{% + &&\PolPrintIntervalsTheVar_{\PolPrintIntervalsTheIndex}% + &=&\PolPrintIntervalsPrintExactZero + } + +``\PolPrintIntervalsUnknownRoot`` +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + + Default definition:: + + \newcommand\PolPrintIntervalsUnknownRoot{% + \PolPrintIntervalsPrintLeftEndPoint&<&% + \PolPrintIntervalsTheVar_{\PolPrintIntervalsTheIndex}&<&% + \PolPrintIntervalsPrintRightEndPoint + } + + +.. _PolPrintIntervalsPrintExactZero: + +``\PolPrintIntervalsPrintExactZero`` +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + + Default definition:: + + \newcommand\PolPrintIntervalsPrintExactZero{\PolPrintIntervalsTheLeftEndPoint} + + +.. _PolPrintIntervalsPrintLeftEndPoint: + +``\PolPrintIntervalsPrintLeftEndPoint`` +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + + Default definition:: + + \newcommand\PolPrintIntervalsPrintLeftEndPoint{\PolPrintIntervalsTheLeftEndPoint} + +.. _PolPrintIntervalsPrintRightEndPoint: + +``\PolPrintIntervalsPrintRightEndPoint`` +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + + Default definition is:: + + \newcommand\PolPrintIntervalsPrintRightEndPoint{\PolPrintIntervalsTheRightEndPoint} + +.. _PolPrintIntervals*: + +``\PolPrintIntervals*[varname]{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 + \xintSignedFrac{\PolPrintIntervalsTheLeftEndPoint}% + }% + + Multiplicities are printed using this auxiliary macro: + +``\PolPrintIntervalsPrintMultiplicity`` +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + + whose default definition is:: + + \newcommand\PolPrintIntervalsPrintMultiplicity{(\mbox{mult. }\PolPrintIntervalsTheMultiplicity)} + + +.. _PolMapCoeffs: + +``\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 replacement text of + ``\macro``, ``\index`` expands to the coefficient index (which is + defined to be zero for the constant term). + + Notice that ``\macro`` will have to handle inputs of the shape + ``A/B[N]`` (xintfrac_ internal notation). This means that it probably + will have to be expressed in terms of macros from 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{polname}`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + About the same as ``\PolMapCoeffs{\xintIrr}{polname}`` (but + maintaining a ``[0]`` postfix for speedier xintfrac_ parsing when + polynomial function is used for computations.) This is a + one-argument macro, working 'in-place'. + +.. _PolReduceCoeffs*: + +``\PolReduceCoeffs*{polname}`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + This starred variant leaves un-touched the decimal exponent in the + internal representation of the fractional coefficients, i.e. if a + coefficient is internally ``A/B[N]``, then ``A/B`` is reduced to + smallest terms, but the ``10^N`` part is kept as is. Note: if the + polynomial is freshly defined directly via `\\PolFromCSV + <PolFromCSV_>`_ its coefficients might still be internally in some + format like ``1.5e7``; the macro will anyhow always first do the + needed conversion to strict format ``A/B[N]``. + + 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 smaller, this proves very beneficial in favorable cases + (especially when the coefficients are decimal numbers) to the + expansion speed of the xintfrac_ macros used internally by + `\\PolEval <PolEvalAt_>`_. + +.. _PolMakeMonic: + +``\PolMakeMonic{polname}`` +~~~~~~~~~~~~~~~~~~~~~~~~~~ + + Divides by the leading coefficient. It is recommended to execute + `\\PolReduceCoeffs*{polname}`_ immediately afterwards. This is not + done automatically, due to the case the original polynomial had integer + coefficients and we want to keep the leading one as common + denominator. + +.. _PolMakePrimitive: + +``\PolMakePrimitive{polname}`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + Divides by the integer content see (`\\PolIContent + <PolIContent_>`_). This thus produces a polynomial with integer + coefficients having no common factor. The sign of the leading + coefficient is not modified. + +Expandable macros +----------------- + +All these macros expand completely in two steps except ``\PolToExpr`` +and ``\PolToFloatExpr`` (and their auxiliaries) which need a +``\write``, ``\edef`` or a ``\csname...\endcsname`` context. + +.. _PolEvalAtExpr: + +``\PolEval{polname}\AtExpr{numerical expression}`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + It boils down to + ``\xinttheexpr polname(numerical expression)\relax``. + +.. _PolEvalAt: + +``\PolEval{polname}\At{fraction}`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + Evaluates the polynomial at value ``fraction`` which must be in (or + expand to) a format acceptable to the xintfrac_ macros. + +.. _PolEvalReducedAtExpr: + +``\PolEvalReduced{polname}\AtExpr{numerical expression}`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + Boils down to ``\xinttheexpr reduce(polname(numerical expression))\relax``. + +.. _PolEvalReducedAt: + +``\PolEvalReduced{polname}\At{fraction}`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + Evaluates the polynomial at value ``fraction`` which must be in (or + expand to) a format acceptable to the xintfrac_ macros, and produce + an irreducible fraction. + +.. _PolFloatEvalAtExpr: + +``\PolFloatEval{polname}\AtExpr{numerical expression}`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + Boils down to ``\xintthefloatexpr polname(numerical expression)\relax``. + + This is done via a Horner Scheme (see `\\poldef <poldef;_>`_ and + `\\PolGenFloatVariant{polname}`_), with already rounded + coefficients. [#]_ To use the *exact coefficients* with *exactly + executed* additions and multiplications, just insert it in the float + expression as in this example: [#]_ + + :: + + \xintthefloatexpr 3.27*\xintexpr f(2.53)\relax^2\relax + + The ``f(2.53)`` is exactly computed then rounded at the time of + getting raised to the power ``2``. Moving the ``^2`` inside, that + operation would also be treated exactly. + + + .. [#] Anyway each floating point operation starts by rounding its + operands to the floating point precision. + + .. [#] The ``\xintexpr`` here could be ``\xinttheexpr`` but that + would be less efficient. Cf. xintexpr_ documentation about + nested expressions. + +.. _PolFloatEvalAt: + +``\PolFloatEval{polname}\At{fraction}`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + Evaluates the polynomial at value ``fraction`` which must be in (or + expand to) a format acceptable to the xintfrac_ macros, and produces + a floating point number. + +.. _PolIfCoeffIsPlusOrMinusOne: + +``\PolIfCoeffIsPlusOrMinusOne{A}{B}`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + 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 ``A`` if the coefficient has been found to be + plus or minus one, and ``B`` if not. + +.. _PolLeadingCoeff: + +``\PolLeadingCoeff{polname}`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + Expands to the leading coefficient. + +.. _PolNthCoeff: + +``\PolNthCoeff{polname}{number}`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + It expands to the raw ``N``-th coefficient (``0/1[0]`` if the index + number is out of range). With ``N=-1``, ``-2``, ... expands to the + leading coefficients. + +.. _PolDegree: + +``\PolDegree{polname}`` +~~~~~~~~~~~~~~~~~~~~~~~ + + It expands to the degree. This is ``-1`` if zero polynomial but this + may change in future. Should it then expand to ``-\infty`` ? + +.. _PolIContent: + +``\PolIContent{polname}`` +~~~~~~~~~~~~~~~~~~~~~~~~~ + + It expands to the contents of the polynomial, i.e. to the positive + fraction such that dividing by this fraction produces a polynomial + with integer coefficients having no common prime divisor. + + See `\\PolMakePrimitive <PolMakePrimitive_>`_. + +.. _PolToExpr: + +``\PolToExpr{polname}`` +~~~~~~~~~~~~~~~~~~~~~~~ + + Expands [#]_ to ``coeff_N*x^N+...`` (descending powers.) + + .. [#] in a ``\write``, ``\edef``, or ``\csname...\endcsname``, but + not under ``\romannumeral-`0``. + + By default zero coefficients are skipped (issue ``\poltoexpralltrue`` to + get all of them in output). + + By default, no ``+`` sign before negative coefficients, for + compliance with Maple input format (but see + `\\PolToExprTermPrefix{raw_coeff}`_.) Also, like the default + behaviour of `\\PolTypeset{polname}`_, does not print (for the non + constant terms) coefficients equal to plus or minus one. The degree + one monomial is output as ``x``, not ``x^1``. Complete customization is + possible, see next macros. + + Of course ``\PolToExpr{f}`` can be inserted in a ``\poldef``, as the + latter expands token by token, hence will force complete expansion + of ``\PolToExpr{f}``, but a simple ``f(x)`` is more efficient for + the identical result. + +.. _PolToExprOneTerm: + +``\PolToExprOneTerm{raw_coeff}{number}`` +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + + This two argument expandable command takes care of the monomial and + its coefficient. The default definition is done in order for + coefficients of absolute value ``1`` not be printed explicitely + (except of course for the constant term). Also by default, the + monomial of degree one is ``x`` not ``x^1``, and ``x^0`` is skipped. + + For compatibility with Maple input requirements, by default a ``*`` + always precedes the ``x^number``, except if the coefficient is a one + or a minus one. See `\\PolToExprTimes`_. + +.. _PolToExprOneTermStyleA: + +``\PolToExprOneTermStyleA{raw_coeff}{number}`` +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + + Holds the default package meaning of + `\\PolToExprOneTerm{raw_coeff}{number}`_. + +.. _PolToExprOneTermStyleB: + +``\PolToExprOneTermStyleB{raw_coeff}{number}`` +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + + For output in this style:: + + 2*x^11/3+3*x^8/7-x^5-x^4/4-x^3-x^2/2-2*x+1 + + issue ``\let\PolToExprOneTerm\PolToExprOneTermStyleB`` before usage of + ``\PolToExpr``. Note that then ``\PolToExprCmd`` isn't used at all. + To revert to package default, issue + ``\let\PolToExprOneTerm\PolToExprOneTermStyleA``. + + To suppress the ``*``'s, cf. `\\PolToExprTimes`_. + +.. _PolToExprCmd: + +``\PolToExprCmd{raw_coeff}`` +^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + + It is the one-argument macro used by the package definition of + ``\PolToExprOneTerm`` for the coefficients themselves (when not + equal to plus or minus one), and it defaults to + ``\xintPRaw{\xintRawWithZeros{#1}}``. One will have to redefine it + to ``\xintIrr{#1}`` or to ``\xintPRaw{\xintIrr{#1}}`` to obtain in the + output forcefully reduced coefficients. + +.. _PolToExprTermPrefix: + +``\PolToExprTermPrefix{raw_coeff}`` +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + + Defined identically as `\\PolTypesetCmdPrefix{raw_coeff}`_. It + prefixes with a plus sign for non-negative coefficients, because + they don't carry one by themselves. + +.. _PolToExprVar: + +``\PolToExprVar`` +^^^^^^^^^^^^^^^^^ + + This expands to the variable to use in output (it does not have to + be a single letter, may be an expandable macro.) Initial definition + is ``x``. + +.. _PolToExprTimes: + +``\PolToExprTimes`` +^^^^^^^^^^^^^^^^^^^ + + This expands to the symbol used for multiplication of an + ``x^{number}`` by the corresponding coefficient. The default is + ``*``. Redefine the macro to expand to nothing to get rid of it (but + this will give output incompatible with some professional computer + algebra software). + +.. _PolToExpr*: + +``\PolToExpr*{polname}`` +~~~~~~~~~~~~~~~~~~~~~~~~ + + Expands to ``coeff_0+coeff_1*x+coeff_2*x^2+...`` (ascending powers). + Customizable like `\\PolToExpr{polname}`_ via the same macros. + +.. _PolToFloatExpr: + +``\PolToFloatExpr{polname}`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + Similar to `\\PolToExpr{polname}`_ but uses `\\PolToFloatExprCmd + <\\PolToFloatExprCmd{raw_coeff}>`_ + which by default rounds and converts the coefficients to floating + point format. + + .. note:: + + It is not necessary to have issued + `\\PolGenFloatVariant{polname}`_. The rounded coefficients are + not easily recoverable from the ``\xintfloatexpr`` polynomial + function hence ``\PolToFloatExprCmd`` operates from the *exact* + coefficients anew. + + Attention that both macros obey the prevailing float precision. + If it is changed between those macro calls, then a mismatch + exists between the coefficients as used in ``\xintfloatexpr`` and + those output by ``\PolToFloatExpr{polname}``. + +.. _PolToFloatExprOneTerm: + +``\PolToFloatExprOneTerm{raw_coeff}{number}`` +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + + Similar to `\\PolToExprOneTerm + <\\PolToExprOneTerm{raw_coeff}{number}>`_. But does not treat + especially coefficients equal to plus or minus one. + +.. _PolToFloatExprCmd: + +``\PolToFloatExprCmd{raw_coeff}`` +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + + It is the one-argument macro used by ``\PolToFloatExprOneTerm``. + Its package definition is ``\xintFloat{#1}``. + + .. caution:: + + Currently (xint_ ``1.3c``) ``\xintFloat{0}`` outputs ``0.e0`` + which is perfectly acceptable input for Python, but not for + Maple. Thus, one should better leave the `\\poltoexprallfalse`_ + toggle to its default ``\iffalse`` state, if one intends to use + the output in a Maple worksheet. + + But even then the zero polynomial will cause a problem. Workaround:: + + \renewcommand\PolToFloatExprCmd[1]{\xintiiifZero{#1}{0.0}{\xintFloat{#1}}} + + Usage of ``\xintiiifZero`` and not ``\xintifZero`` is only for + optimization (I can't help it) because ``#1`` is known to be + in ``xintfrac`` raw format. + +.. _PolToFloatExpr*: + +``\PolToFloatExpr*{polname}`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + Typesets in ascending powers. + +.. _PolToList: + +``\PolToList{polname}`` +~~~~~~~~~~~~~~~~~~~~~~~ + + Expands to ``{coeff_0}{coeff_1}...{coeff_N}`` with ``N`` = degree, and + ``coeff_N`` the leading coefficient + (the zero polynomial does give ``{0/1[0]}`` and not an + empty output.) + +.. _PolToCSV: + +``\PolToCSV{polname}`` +~~~~~~~~~~~~~~~~~~~~~~ + + Expands to ``coeff_0, coeff_1, coeff_2, ....., coeff_N``, starting + with constant term and ending with leading coefficient. Converse + to `\\PolFromCSV <\\PolFromCSV{polname}{\<csv\>}_>`_. + +.. _PolSturmChainLength: + +``\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: + +``\PolSturmIfZeroExactlyKnown{sturmname}{index}{A}{B}`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + Executes ``A`` if the ``index``\ -th interval reduces to a singleton, + i.e. the root is known exactly, else ``B``. + + .. note:: + + ``index`` is allowed to be something like ``1+2*3`` as it is fed + to ``\the\numexpr...\relax``. + +.. _PolSturmIsolatedZeroLeft: + +``\PolSturmIsolatedZeroLeft{sturmname}{index}`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + Expands to the left end-point for the ``index``\ -th interval, as + computed by some earlier `\\PolSturmIsolateZeros{sturmname}`_. + + .. note:: + + Of course, this is kept updated by macros such as + `\\PolRefineInterval{sturmname}{index} <PolRefineInterval[N]_>`_. + + The value is pre-formatted using `\\PolDecTostring + <PolDecToString_>`_. + +.. _PolSturmIsolatedZeroRight: + +``\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 + <PolDecToString_>`_. + +.. _PolSturmIsolatedZeroMultiplicity: + +``\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`_ for an example of use. + +.. _PolSturmNbOfIsolatedZeros: + +``\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{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{sturmname}\LessThanOrEqualToExpr{expression}`` +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + + 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 ``expression``. + + .. attention:: + + `\\PolSturmIsolateZeros{sturmname}`_ must have been executed + beforehand. + +``\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{sturmname}\LessThanOrEqualToExpr{expression}`` +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + + 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{sturmname}`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + Expands to the number of rational roots (without multiplicities). + + .. attention:: + + `\\PolSturmIsolateZeros**{sturmname}`_ must have been executed + beforehand. + +``\PolSturmNbOfRationalRootsWithMultiplicities{sturmname}`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + Expands to the number of rational roots (counted with multiplicities). + + .. attention:: + + `\\PolSturmIsolateZeros**{sturmname}`_ must have been executed + beforehand. + +``\PolSturmRationalRoot{sturmname}{k}`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + Expands to the ``k``\ th rational root (they are ordered and indexed + starting at 1 for the most negative). + + .. attention:: + + `\\PolSturmIsolateZeros**{sturmname}`_ must have been executed + beforehand. + +``\PolSturmRationalRootIndex{sturmname}{k}`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + Expands to ``index`` of the ``k``\ th rational root as part of the + ordered real roots (without multiplicities). I.e., above macro + `\\PolSturmRationalRoot{sturmname}{k}`_ is equivalent to this + nested call:: + + \PolSturmIsolatedZeroLeft{sturmname}{\PolSturmRationalRootIndex{sturmname}{k}} + + .. attention:: + + `\\PolSturmIsolateZeros**{sturmname}`_ must have been executed + beforehand. + +``\PolSturmRationalRootMultiplicity{sturmname}{k}`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + Expands to the multiplicity of the ``k``\ th rational root. + + .. attention:: + + `\\PolSturmIsolateZeros**{sturmname}`_ must have been executed + beforehand. + +.. _PolIntervalWidth: + +``\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). + +.. attention:: + + Some macros formerly mentioned here got removed at 0.7: + ``\PolPrintIntervalsTheEndPoint``, + ``\PolIfEndPointIsPositive{A}{B}``, + ``\PolIfEndPointIsNegative{A}{B}``, + ``\PolIfEndPointIsZero{A}{B}``. + +``\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 <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 <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 + <PolSturmIsolateZeros_>`_ was used earlier. + +.. _PolDecToString: + +``\PolDecToString{decimal number}`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + This is a utility macro to print decimal numbers. 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}}``. + + The precise behaviour of this macro may evolve in future releases of + xint_. + +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 + polynomials are defined. + + .. caution:: + + The macro meanings as written to the log are to be considered + unstable and undocumented internal structures. + +``\poltypesetallfalse`` +~~~~~~~~~~~~~~~~~~~~~~~ + + If ``true``, `\\PolTypeset{polname}`_ will also typeset the vanishing + coefficients. + + +``\poltoexprallfalse`` +~~~~~~~~~~~~~~~~~~~~~~ + + If ``true``, `\\PolToExpr{polname}`_ and `\\PolToFloatExpr{polname}`_ will + also include the vanishing coefficients in their outputs. + +``\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 + <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{f}{P(x)} <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(x)Q(x); + + 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 (since release ``0.3``). One can use for example + ``\PolToCSV{PQ}`` to see the internally stored coefficients. + + .. [#] prior to ``0.4.1``, ``polexpr`` used to temporarily patch + during the parsing of polynomials the xintfrac_ macros. This + patch was backported to xint_ at release ``1.3``. + +- `\\PolDiff{polname_1}{polname_2}`_ always applies ``\xintIrr`` to the + resulting coefficients, except that the *power of ten* part ``[N]`` + (for example an input in scientific notation such as ``1.23e5`` gives + ``123/1[3]`` internally in xintfrac) is not taken into account in the + reduction of the fraction. 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 +---------- + +- v0.1 (2018/01/11): initial release. Features: + + * The `\\poldef <poldef;_>`_ parser itself, + * Differentiation and anti-differentiation, + * Euclidean division and GCDs, + * Various utilities such as `\\PolFromCSV <PolFromCSV_>`_, + `\\PolMapCoeffs <PolMapCoeffs_>`_, + `\\PolToCSV <PolToCSV_>`_, `\\PolToExpr <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`` `\\PolEval <PolEvalAt_>`_ 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} <PolEvalAtExpr_>`_ syntax is needed for + using expressions in the second argument. + * incompatible or breaking changes: + + - `\\PolToExpr <PolToExpr_>`_ now by default uses *descending* + powers (it also treats differently coefficients equal to 1 or -1.) + Use `\\PolToExpr* <PolToExpr*_>`_ for *ascending* powers. + - `\\PolEval <PolEvalAt_>`_ 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 + <PolEvalReducedAt_>`_. + * new (or newly documented) macros: + + - `\\PolTypesetCmd <PolTypesetCmd_>`_ + - `\\PolTypesetCmdPrefix <PolTypesetCmdPrefix_>`_ + - `\\PolTypesetMonomialCmd <PolTypesetMonomialCmd_>`_ + - `\\PolEvalReducedAt <PolEvalReducedAt_>`_ + - `\\PolToFloatExpr <PolToFloatExpr_>`_ + - `\\PolToExprOneTerm <PolToExprOneTerm_>`_ + - `\\PolToFloatExprOneTerm <PolToFloatExprOneTerm_>`_ + - `\\PolToExprCmd <PolToExprCmd_>`_ + - `\\PolToFloatExprCmd <PolToFloatExprCmd_>`_ + - `\\PolToExprTermPrefix <PolToExprTermPrefix_>`_ + - `\\PolToExprVar <PolToExprVar_>`_ + - `\\PolToExprTimes <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. + - `\\poldef <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 <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 `\\PolMapCoeffs <PolMapCoeffs_>`_. + - `\\PolGCD <PolGCD_>`_ was buggy in case of first polynomial being + of lesser degree than the second one. + * breaking changes: + + - formerly `\\PolEval{P}\\At{foo} <PolEvalAt_>`_ 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 `\\PolEval{P}\\AtExpr{foo} <PolEvalAtExpr_>`_ for more + general arguments using expression syntax. E.g., if ``foo`` is the + name of a variable known to ``\xintexpr``. + + The same holds for `\\PolEvalReduced <PolEvalReducedAt_>`_ + and `\\PolFloatEval <PolFloatEvalAt_>`_. + - 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 `\\PolGenFloatVariant <PolGenFloatVariant_>`_. + * new non-expandable macros: + + - `\\PolGenFloatVariant <PolGenFloatVariant_>`_ + - `\\PolGlobalLet <PolGlobalLet_>`_ + - `\\PolTypesetOne <PolTypesetOne_>`_ + - `\\PolQuo <PolQuo_>`_ + - `\\PolRem <PolRem_>`_ + - `\\PolToSturm <PolToSturm_>`_ + - `\\PolToSturm\* <PolToSturm*_>`_ + - `\\PolSetToSturmChainSignChangesAt <PolSetToSturmChainSignChangesAt_>`_ + - `\\PolSetToNbOfZerosWithin <PolSetToNbOfZerosWithin_>`_ + - `\\PolSturmIsolateZeros <PolSturmIsolateZeros_>`_ + - `\\PolRefineInterval* <PolRefineInterval*_>`_ + - `\\PolRefineInterval[N] <PolRefineInterval[N]_>`_ + - `\\PolEnsureIntervalLength <PolEnsureIntervalLength_>`_ + - `\\PolEnsureIntervalLengths <PolEnsureIntervalLengths_>`_ + - `\\PolPrintIntervals <PolPrintIntervals_>`_ + - `\\PolPrintIntervalsPrintExactZero <PolPrintIntervalsPrintExactZero_>`_ + - `\\PolPrintIntervalsPrintLeftEndPoint <PolPrintIntervalsPrintLeftEndPoint_>`_ + - `\\PolPrintIntervalsPrintRightEndPoint <PolPrintIntervalsPrintRightEndPoint_>`_ + - `\\PolReduceCoeffs* <PolReduceCoeffs*_>`_ + - `\\PolMakeMonic <PolMakeMonic_>`_ + * new expandable macros: + + - `\\PolToExprOneTermStyleA <PolToExprOneTermStyleA_>`_ + - `\\PolIfCoeffIsPlusOrMinusOne <PolIfCoeffIsPlusOrMinusOne_>`_ + - `\\PolLeadingCoeff <PolLeadingCoeff_>`_ + - `\\PolSturmChainLength <PolSturmChainLength_>`_ + - `\\PolSturmNbOfIsolatedZeros <PolSturmNbOfIsolatedZeros_>`_ + - `\\PolSturmIfZeroExactlyKnown <PolSturmIfZeroExactlyKnown_>`_ + - `\\PolSturmIsolatedZeroLeft <PolSturmIsolatedZeroLeft_>`_ + - `\\PolSturmIsolatedZeroRight <PolSturmIsolatedZeroRight_>`_ + - ``\PolPrintIntervalsTheEndPoint`` (removed at 0.7) + - `\\PolPrintIntervalsTheIndex`_ + - ``\PolIfEndPointIsPositive`` (removed at 0.7) + - ``\PolIfEndPointIsNegative`` (removed at 0.7) + - ``\PolIfEndPointIsZero`` (removed at 0.7) + - `\\PolIntervalWidth <PolIntervalWidth_>`_ + - `\\PolDecToString <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: + + - `\\PolGet{polname}\\fromarray\\macro`_ crashed when ``\macro`` was + an xinttools_ array macro with no items. It now produces the zero + polynomial. + * 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 <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`_ for usage). It will presumably be replaced in future by + an interval specification. + * new non-expandable macro: + + - `\\PolMakePrimitive`_ + * new expandable macro: + + - `\\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 `\\PolToSturm*{polname}{sturmname}`_ was + broken. On the occasion of the fix, its meaning has been modified, + see its documentation. + + - using `\\PolToSturm <PolToSturm_>`_ with a constant polynomial + caused a division by zero error. + + * new macro: + + - `\\PolSturmIsolateZeros* <PolSturmIsolateZeros*_>`_ + acts like the `non-starred variant + <PolSturmIsolateZeros_>`_ then computes all the multiplicities. + + * new expandable macros: + + - `\\PolSturmIsolatedZeroMultiplicity{sturmname}{index}`_ + - `\\PolSturmNbOfRootsOf{sturmname}\\LessThanOrEqualTo{value}`_ + - `\\PolSturmNbOfRootsOf{sturmname}\\LessThanOrEqualToExpr{expression}`_ + - `\\PolSturmNbWithMultOfRootsOf{sturmname}\\LessThanOrEqualTo{value}`_ + - `\\PolSturmNbWithMultOfRootsOf{sturmname}\\LessThanOrEqualToExpr{expression}`_ + +- v0.7 (2018/12/08), v0.7.1 (bugfix), v0.7.2 (2nd bugfix) (2018/12/09) + + * breaking changes: + + - although `\\PolPrintIntervals[varname]{sturmname}`_ default output + remains the same, some auxiliary macros for user-customization + have been removed: ``\PolPrintIntervalsTheEndPoint``, + ``\PolIfEndPointIsPositive{A}{B}``, + ``\PolIfEndPointIsNegative{A}{B}``, and + ``\PolIfEndPointIsZero{A}{B}``. + + * bugfix: + + - it could happen that, contrarily to documentation, an interval + computed by `\\PolSturmIsolateZeros{sturmname}`_ had zero as an + endpoint, + - `\\PolEnsureIntervalLength{sturmname}{index}{E}`_ could under + certain circumstances erroneously replace a non-zero root by + zero, + - `\\PolEnsureIntervalLengths{sturmname}{E}`_ 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: + + - `\\PolSturmIsolateZeros**{sturmname}`_ + - `\\PolSturmIsolateZerosGetMultiplicitiesAndRationalRoots{sturmname}`_ + - `\\PolSturmIsolateZerosAndFindRationalRoots{sturmname}`_ + - `\\polexprsetup`_ + - `\\PolPrintIntervals* <PolPrintIntervals*_>`_ + - `\\PolPrintIntervalsNoRealRoots`_ + - `\\PolPrintIntervalsBeginEnv`_ + - `\\PolPrintIntervalsEndEnv`_ + - `\\PolPrintIntervalsKnownRoot`_ + - `\\PolPrintIntervalsUnknownRoot`_ + - `\\PolPrintIntervalsPrintMultiplicity`_ + + * new expandable macros: + + - `\\PolSturmNbOfRationalRoots{sturmname}`_ + - `\\PolSturmNbOfRationalRootsWithMultiplicities{sturmname}`_ + - `\\PolSturmRationalRoot{sturmname}{k}`_ + - `\\PolSturmRationalRootIndex{sturmname}{k}`_ + - `\\PolSturmRationalRootMultiplicity{sturmname}{k}`_ + - `\\PolPrintIntervalsTheVar`_ + - `\\PolPrintIntervalsTheSturmName`_ + - `\\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. + - `\\PolPrintIntervalsTheVar`_ remained defined after + `\\PolPrintIntervals`_ but was left undefined after + `\\PolPrintIntervals*`_ (reported by Jürgen Gilg). Now remains + defined in both cases, and `\\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. + +Acknowledgments +--------------- + +Thanks to Jürgen Gilg whose question about 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. + +Renewed thanks to them on occasion of the ``0.6`` and ``0.7`` releases for their +continued interest. + +See README.md for the License. + +.. _xinttools: +.. _xintfrac: +.. _xintexpr: +.. _xint: http://www.ctan.org/pkg/xint + +.. _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 |