8000 Upgrade polynomial + rational function representation, gcd namespace by sritchie · Pull Request #341 · sicmutils/sicmutils · GitHub
[go: up one dir, main page]
More Web Proxy on the site http://driver.im/
Skip to content
This repository was archived by the owner on Jun 18, 2025. It is now read-only.

Upgrade polynomial + rational function representation, gcd namespace #341

Merged
merged 110 commits into from
May 27, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
110 commits
Select commit Hold shift + click to select a range
55054e2
got it
sritchie May 3, 2021
8dba95a
more tidying that doesn'tnquite work
sritchie May 5, 2021
8abc35a
more stuff moved over
sritchie May 11, 2021
384c87e
more gcd
sritchie May 11, 2021
b4712b1
arg scale
sritchie May 11, 2021
e7e6053
stop
sritchie May 12, 2021
5194171
getting closer...
sritchie May 12, 2021
< 8000 code class="float-right">24ed20b
tidy
sritchie May 12, 2021
7cdfc03
push
sritchie May 13, 2021
73474a1
checkpoint
sritchie May 13, 2021
7e9d746
working
sritchie May 13, 2021
b87f87c
working
sritchie May 13, 2021
ef5ef47
more fixes
sritchie May 13, 2021
f8a025d
tests are passing
sritchie May 13, 2021
cecc619
boom, now it all works
sritchie May 13, 2021
4a59894
fix cljs warnings
sritchie May 13, 2021
6c3da1d
unlock some more tests
sritchie May 13, 2021
a194acc
poly merge
sritchie May 14, 2021
1770ecb
add bianchi testing
sritchie May 14, 2021
2f105f8
bianchi timing
sritchie May 14, 2021
b106431
share assume
sritchie May 14, 2021
4739cf3
sorted map conversion
sritchie May 14, 2021
c79b91c
got it
sritchie May 14, 2021
3d23249
new bianchi timing
sritchie May 14, 2021
e7eb7d7
turn on more tests
sritchie May 15, 2021
11118fd
got it
sritchie May 16, 2021
3b7b612
test fix
sritchie May 16, 2021
175d390
tidy
sritchie May 17, 2021
17d4bfa
test fix
sritchie May 17, 2021
6e8e863
faster gcd...
sritchie May 17, 2021
2fd693a
accumulation
sritchie May 17, 2021
9c158ca
solid aggregator
sritchie May 17, 2021
0efb8aa
various bug and test fixes
sritchie May 17, 2021
8a32177
typo
sritchie May 17, 2021
47a40af
lcm impl
sritchie May 17, 2021
58bedad
monoid
sritchie May 17, 2021
90fff4d
arg-shift, arg-scale tests
sritchie May 17, 2021
719b3d1
series tests
sritchie May 17, 2021
e8230e9
start to remove coeff
sritchie May 17, 2021
b6ef678
share merge fn
sritchie May 17, 2021
e5be69b
removing cruft
sritchie May 17, 2021
bdeea87
conversion continues
sritchie May 18, 2021
f42756d
more progress
sritchie May 18, 2021
88fbd1e
more progress
sritchie May 18, 2021
276115d
life is still good
sritchie May 18, 2021
2ccb5b7
huge work, all good
sritchie May 18, 2021
85b98b4
fix gcd issues
sritchie May 18, 2021
42072b5
more fixes, tidying
sritchie May 18, 2021
9c476ae
one more fix
sritchie May 18, 2021
a72bdc1
typo
sritchie May 18, 2021
588c19b
tidying
sritchie May 18, 2021
8000
99c5da4
fix
sritchie May 18, 2021
289d6f8
pull expt out
sritchie May 19, 2021
2c0381c
pause
sritchie May 19, 2021
f09fd77
start doing rf
sritchie May 19, 2021
ff45840
start working on rf
sritchie May 19, 2021
e0eefc6
get some
sritchie May 19, 2021
be40baa
faster multiplication
sritchie May 19, 2021
23d4556
remove tabs
sritchie May 20, 2021
77abd09
pause again
sritchie May 20, 2021
09d5bdf
divide through
sritchie May 20, 2021
0414717
tidy analyzer
sritchie May 20, 2021
fcefe89
numerator protocol
sritchie May 20, 2021
e59ca79
add lcm
sritchie May 20, 2021
6d9464d
in a good place
sritchie May 20, 2021
682f3de
fix
sritchie May 20, 2021
70621b9
remove
sritchie May 20, 2021
ddd7725
more checks removed
sritchie May 20, 2021
680737f
remove drop at one
sritchie May 20, 2021
0688848
tidy
sritchie May 20, 2021
5e401a7
toss in abs
sritchie May 20, 2021
d2610a7
reduced
sritchie May 20, 2021
279126d
add more operations
sritchie May 20, 2021
15c1881
tidy generic fns
sritchie May 20, 2021
c14fa71
working
sritchie May 21, 2021
1856bf5
done
sritchie May 21, 2021
72e1e67
get D working
sritchie May 22, 2021
c78587d
partial D
sritchie May 22, 2021
5a8c033
docs etc
sritchie May 24, 2021
cc2f230
reverse lex
sritchie May 24, 2021
7e39c24
fast again
sritchie May 24, 2021
6a83a74
exponent docs
sritchie May 24, 2021
516e613
fix
sritchie May 24, 2021
b0c8b1c
poly impl
sritchie May 24, 2021
4c45f72
more notes
sritchie May 24, 2021
b148cd6
tidy analyzer
sritchie May 24, 2021
2bf4e47
more docstrings
sritchie May 24, 2021
1af667e
more docs
sritchie May 24, 2021
588212d
poly docs
sritchie May 25, 2021
e617a4b
more gcd docs
sritchie May 25, 2021
05d5ea8
pause
sritchie May 25, 2021
1593ae6
more notes
sritchie May 25, 2021
ad31a98
more efficient gcd
sritchie May 25, 2021
19ab251
more writing
sritchie May 25, 2021
cb00c81
fix cljs build
sritchie May 25, 2021
5482d6c
fix tests again
sritchie May 25, 2021
5065e79
start the docs
sritchie May 26, 2021
501ec83
finish rf docs
sritchie May 26, 2021
ba26f5b
almost done
sritchie May 26, 2021
d328770
more comments
sritchie May 26, 2021
df7b942
first docs pass
sritchie May 26, 2021
2a802d8
more tests
sritchie May 26, 2021
4cda4b7
more tests
sritchie May 27, 2021
3e53e15
make identity 0-indexed
sritchie May 27, 2021
8bed446
more tests
sritchie May 27, 2021
cd94576
fix tests
sritchie May 27, 2021
d2998de
tidy again
sritchie May 27, 2021
6ded9da
fix gcd
sritchie May 27, 2021
9bd288c
fix palindromic tests
sritchie May 27, 2021
389a111
final test push
sritchie May 27, 2021
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
177 changes: 177 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,183 @@

## [unreleased]

- #341 takes on a large rewrite of the rational function and polynomial
simplfiers. One goal of this project was to improve the performance of the
Bianchi Identities in `sicmutils.fdg.bianchi-test`, and I'm happy to say that
they are now a good bit faster than the original scmutils implementation.

`sicmutils.polynomial` and `sicmutils.rational-function` are now solid data
F438 structures of their own, with many operations installed into the generic
system. These are now valuable and useful outside of their role in the
simplifier.

This was a large project, and many small improvements and bugfixes snuck in.
Here is the full list:

- `v/kind` now works for `sorted-map` instances.

- GCD in Clojurescript is now fast and efficient between all combinations of
`js/BigInt` and `js/Number`, and in Clojure between all combinations of
`clojure.lang.BigInt`, `BigInteger`, `Long` and `Integer`.

- on the JVM, GCD now works properly with rational numbers. Previously
anything non-integral would return `1`; now `(gcd 1/2 1/3)` properly returns
`1/6`.

- `g/exact-divide` now succeeds for all non-exact `::v/scalar` types (symbols,
floats, etc) either if the denominator is zero, or if the two arguments are
equal. Else, it throws, just like before.

- A multi-arity call to `sicmutils.generic/*` now stops if it encounters a
0, rather than attempting to multiply all remaining items by 0.

- The default function for `sicmutils.generic/lcm` protects against overflow
by dividing only a single one of its arguments `a` and `b` by `(gcd a b)`.

- `(g/lcm 0 0)` now properly returns 0.

- New `sicmutils.util.aggregate/{monoid,group}` functions let you build
multi-arity aggregations out of binary combination functions, with an option
to bail early at "annihilator" values, like 0 for multiplication.

- New multi-arity `lcm` and `gcd` implementations for symbolic expressions
appropriately handle `0` and `1` on either side, as well as the case where
both arguments are equal.

- In the `sicmutils.numsymb` namespace, thanks to `monoid` and `group`, the
`'*`, `'/`, `'-`, `'+`, `'or`, `'and`, `'gcd`, `'lcm` and `'=` operations
now have efficient multi-arity implementations that stop computing when they
receive an annihilator, like `0` for multiplication or `true` for `or`.
Access these via `(sicmutils.numsymb/symbolic-operator <symbol>)`.

- `sicmutils.series/PowerSeries` gains `arg-scale` and `arg-shift` functions;
these are identical to `sicmutils.function/arg-{scale,shift}`, but preserve
the `PowerSeries` type. (#367 proposes making these functions generic.)

- New `sicmutils.ratio/IRational` protocol, with `numerator` and `denominator`
functions implemented for ratios and for the `RationalFunction` data type.
These two are now exposed in `sicmutils.env`.

- `sicmutils.simplify.rules/*divide-numbers-through-simplify?*` is now `true`
by default; numbers in the denominator will now automatically pull up into
the numerator. All tests now reflect this setting.

- Any analyzer generated from `sicmutils.expression.analyze` can now act on
both bare, unwrapped expressions (raw lists etc) and on
`sicmutils.expression.Literal` instances. This means that you can now call
`sicmutils.simplify/{*rf-simplify*,*poly-simplify*}` as functions and
canonicalize some form with either simplifier without triggering a full
simplification. A small win, but ice.

- `sicmutils.polynomial.factor` got a major rewrite, and now exposes a few
functions like `poly->factored-expression`, `factor-expression` and
`factor`.

- `factor` is _tremendously useful_! Call `factor` (it's aliased into
`sicmutils.env`) on any expression to factor out all possible terms.
This makes it much easier to see where there is some cancellation
lurking, in, say, some expression you know should equal zero (a
residual).

- bugfix: `sicmutils.expression.Literal` instances now compare their contained
expression via `sicmutils.value/=`.

- `sicmutils.rules/constant-elimination` can now eliminate constants from
expressions with any arity, not just binary forms.


Now, the three big namespaces... `sicmutils.polynomial`,
`sicmutils.rational-function` and `sicmutils.polynomial.gcd` all got a big
overhaul.

- `sicmutils.polynomial` notes:

- `Polynomial` uses a new sparse representation for its "power product"
term; this, plus an arithmetic rewrite, makes the whole system much faster
for larger numbers of variables (for all #s, really).

- `Polynomial` instances implement many more Clojure(script) protocols. They
can hold metadata; they can be evaluated as functions of their
indeterminates, and `seq` now returns a sequence of terms.

- `Polynomial` extends `sicmutils.function/IArity` and
`differential/IPerturbed`, so you can use `sicmutils.function/arity`, and
take derivatives of functions that return polynomials.

- In their arithmetic, `Polynomial` instances will drop down to bare
coefficients whenever some multiplication or addition removes all
indeterminates. All binary arithmetic exposed in the namespace can handle
non-`Polynomial` instances on either or both sides, so this is fine.
Coefficients are treated as constant polynomials.

- The namespace holds many new functions. Some choice ones are:

- constructors: `make`, `constant`, `linear`, `c*xn`, `identity`, and
`new-variables`

- accessor functions: `arity`, `degree`, `coefficients`, `leading-term`,
`leading-coefficient`, `leading-exponents`, `leading-base-coefficient`,
`trailing-coefficient`, `lowest-degree`

- predicates: `monomial?`, `monic?`, `univariate?`, `multivariate?`,
`negative?`

- functions to generate new polynomials: `map-coefficients`,
`map-exponents`, `scale`, `scale-l`, `normalize`, `reciprocal`,
`drop-leading-term`, `contract` and `extend` alongside `contractible?`,
`lower-arity`, `raise-arity`, `with-lower-arity`, `arg-scale`,
`arg-shift`

- arithmetic: `negate`, `abs`, `add`, `sub`, `mul`, `square`, `cube`,
`expt`, `divide` along with `divisible?`, `evenly-divide`,
`pseudo-remainder`, and _lots_ of functions installed into the generic
arithmetic system.

- different ways to evaluate polynomials: `evaluate`, `horner-with-error`

- calculus! `partial-derivative` and `partial-derivatives` are alive and
well, and work with the `D` operator.

- Functions to get in and out of polynomials from other types:
`univariate->dense`, `->power-series`, `expression->`, `->expression`

- `sicmutils.polynomial.gcd` also got a rewrite; it's fairly clear to read
now, and prepared for the eventual addition of the sparse multivariate GCD
routine that scmutils uses. There are some efficiency gains here too that
let us turn a number of tests back on, or demote them from `:long` markers.

- `sicmutils.rational-function` notes:

- `RationalFunction` instances implement many more Clojure(script)
protocols. They can hold metadata; they can be evaluated as functions of
their indeterminates, and `seq` now returns a pair of `numerator`,
`denominator`.

- `RationalFunction` extends `sicmutils.function/IArity` and
`sicmutils.ratio/IRational`, so our generic `arity`, `numerator` and
`denominator` work on these instances.

- Here are some new functions from the `RationalFunction` namespace:

- constructor: `make`, drops to polynomial or coefficient where needed
just like `Polynomial` functions

- functions to generate new rational functions: `arg-scale`, `arg-shift`

- predicates: `negative?`

- arithmetic: `negate`, `abs`, `add`, `sub`, `mul`, `square`, `cube`,
`expt`, `invert`, `div`, `gcd`, and many functions installed into the
generic arithmetic system.

- evaluation via `evaluate`

- calculus! `partial-derivative` and `partial-derivatives` are alive and
well, and work with the `D` operator.

- Functions to get in and out of rational functions from symbolic
expressions: `expression->`, `->expression`.

- #360 introduces a number of performance improvements to the
`sicmutils.differential.Differential` implementation, primarily in `terms:+`
and `terms:*`. thanks again to @ptaoussanis and the
Expand Down
5 changes: 1 addition & 4 deletions src/sicmutils/abstract/number.cljc
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,6 @@
[sicmutils.expression :as x]
[sicmutils.generic :as g]
[sicmutils.numsymb :as sym]
[sicmutils.simplify :as s]
[sicmutils.util :as u]
[sicmutils.value :as v])
#?(:clj
Expand Down Expand Up @@ -217,8 +216,6 @@
(defunary g/conjugate 'conjugate)

(defbinary g/gcd 'gcd)
(defbinary g/lcm 'lcm)

(defmethod g BEA9 /simplify [Symbol] [a] a)
(defmethod g/simplify [::x/numeric] [a]
(literal-number
(s/simplify-expression (v/freeze a))))
3 changes: 2 additions & 1 deletion src/sicmutils/calculus/manifold.cljc
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@
[sicmutils.function :as f]
[sicmutils.generic :as g]
[sicmutils.matrix :as matrix]
[sicmutils.simplify :refer [simplify-numerical-expression]]
[sicmutils.structure :as s]
[sicmutils.util :as u]
[sicmutils.value :as v]
Expand Down Expand Up @@ -297,7 +298,7 @@
[manifold-point coordinate-system thunk]
(let [reps (:coordinate-representations manifold-point)]
(or (@reps coordinate-system)
(let [rep (g/simplify (thunk))]
(let [rep (s/mapr simplify-numerical-expression (thunk))]
(swap! reps assoc coordinate-system rep)
rep))))

Expand Down
4 changes: 3 additions & 1 deletion src/sicmutils/collection.cljc
Original file line number Diff line number Diff line change
Expand Up @@ -186,7 +186,9 @@
(identity-like [m] (u/unsupported (str "identity-like: " m)))
(exact? [m] (every? v/exact? (vals m)))
(freeze [m] (u/map-vals v/freeze m))
(kind [m] (:type m (type m)))
(kind [m] (if (sorted? m)
(type m)
(:type m (type m))))

f/IArity
(arity [_] [:between 1 2])
Expand Down
47 changes: 7 additions & 40 deletions src/sicmutils/differential.cljc
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
(:require [clojure.string :refer [join]]
[sicmutils.generic :as g]
[sicmutils.util :as u]
[sicmutils.util.aggregate :as ua]
[sicmutils.util.stream :as us]
[sicmutils.util.vector-set :as uv]
[sicmutils.value :as v]))
Expand Down Expand Up @@ -254,7 +255,7 @@
;; al. (2019).
;;
;; The solution is to introduce a new $\varepsilon$ for every level, and allow
;; different $\varepsilon$ instances to multiply without annihalating. Each
;; different $\varepsilon$ instances to multiply without annihilating. Each
;; $\varepsilon$ is called a "tag". [[Differential]] (implemented below) is a
;; generalized dual number that can track many tags at once, allowing nested
;; derivatives like the one described above to work.
Expand Down Expand Up @@ -475,48 +476,14 @@
;; NOTE: Clojure vectors already implement this ordering properly, so we can
;; use [[clojure.core/compare]] to determine an ordering on a tag list.

(defn- terms:+
"Returns the sum of the two supplied sequences of differential terms; any terms
(def ^{:private true
:doc "Returns the sum of the two supplied sequences of differential terms; any terms
in the result with a zero coefficient will be removed.

Each input must be sequence of `[tag-set, coefficient]` pairs, sorted by
`tag-set`.

NOTE that this function recurs on increasing indices internally instead of
walking through the lists directly. This method of traversing vectors is more
efficient, and this function is called so often that the performance gain is
worth it, and reads almost like the explicit sequence traversal."
([] [])
([xs] xs)
([xs ys]
(loop [i (long 0)
j (long 0)
result (transient [])]
(let [x (nth xs i nil)
y (nth ys j nil)]
(cond (not x) (into (persistent! result) (subvec ys j))
(not y) (into (persistent! result) (subvec xs i))
:else (let [[x-tags x-coef] x
[y-tags y-coef] y
compare-flag (core-compare x-tags y-tags)]
(cond
;; If the terms have the same tag set, add the coefficients
;; together. Include the term in the result only if the new
;; coefficient is non-zero.
(zero? compare-flag)
(let [sum (g/add x-coef y-coef)]
(recur (inc i)
(inc j)
(if (v/zero? sum)
result
(conj! result (make-term x-tags sum)))))

;; Else, pass the smaller term on unchanged and proceed.
(neg? compare-flag)
(recur (inc i) j (conj! result x))

:else
(recur i (inc j) (conj! result y)))))))))
`tag-set`."}
terms:+
(ua/merge-fn core-compare g/add v/zero? make-term))

;; Because we've decided to store terms as a vector, we can multiply two vectors
;; of terms by:
Expand Down
9 changes: 6 additions & 3 deletions src/sicmutils/env.cljc
10000
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,9 @@
partial core-partial
compare core-compare
= core=}
:exclude [+ - * / zero? compare divide #?@(:cljs [= partial])])
:exclude [+ - * / zero? compare divide
numerator denominator
#?@(:cljs [= partial])])
(:require #?(:clj [potemkin :refer [import-def import-vars]])
#?(:clj [nrepl.middleware.print])
[sicmutils.abstract.function :as af #?@(:cljs [:include-macros true])]
Expand All @@ -53,6 +55,7 @@
[sicmutils.generic :as g]
[sicmutils.modint]
[sicmutils.operator :as o]
[sicmutils.polynomial.factor :as pf]
[sicmutils.ratio]
[sicmutils.simplify]
[sicmutils.structure :as structure]
Expand Down Expand Up @@ -244,8 +247,8 @@ constant [Pi](https://en.wikipedia.org/wiki/Pi)."}
[sicmutils.function arity compose arg-shift arg-scale I]
[sicmutils.modint chinese-remainder]
[sicmutils.operator commutator anticommutator]
#?(:cljs [sicmutils.ratio
ratio? rationalize numerator denominator])
[sicmutils.polynomial.factor factor]
[sicmutils.ratio numerator denominator #?@(:cljs [ratio? rationalize])]
[sicmutils.series binomial-series partial-sums]
[sicmutils.util bigint? #?@(:cljs [bigint])]

Expand Down
10 changes: 7 additions & 3 deletions src/sicmutils/expression.cljc
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,7 @@
(if (instance? Literal b)
(let [b ^Literal b]
(and (= type (.-type b))
(= expression (.-expression b))
(v/= expression (.-expression b))
(= m (.-m b))))
(v/= expression b))))

Expand All @@ -114,7 +114,7 @@
(if (instance? Literal b)
(let [b ^Literal b]
(and (= type (.-type b))
(= expression (.-expression b))
(v/= expression (.-expression b))
(= m (.-m b))))
(v/= expression b)))

Expand Down Expand Up @@ -221,7 +221,11 @@
(sequential? node)
(let [[f-sym & args] node]
(if-let [f (sym->f f-sym)]
(apply f (map walk args))
;; NOTE: I'm not sure why this `doall` is required.
;; Without it, we were getting heisenbugs in the rational
;; function simplifier, and `mismatched-arity` notes.
(apply f (doall
(map walk args)))
(u/illegal (str "Missing fn for symbol - " f-sym))))
:else node))]
(walk
Expand Down
Loading
0