0.15.0: Autodiff, Rendering, SCI, oh my!
0.15.0
(If you have any questions about how to use any of the following, please ask us at our Github Discussions page!)
This release was focused on a small number of themes:
Automatic differentiation:
The goal for this cycle's automatic differentiation (AD) work was to expand the
set of functions and types that can play with AD. AD now works on functions that
return all Clojure sequences, maps, and vectors, in addition to SICMUtils types
like Operator
, Series
, PowerSeries
and Structure
. The system is now
fully extensible, so if you want to differentiate functions that return custom
records or Java collections, it's now no problem.
SICMUtils can now differentiate functions in Clojurescript that use comparison
operations like <
, =
, <=
and friends. Clojure can't quite do this yet, but
you can differentiate through v/compare
and v/=
calls.
We can also differentiate functions that return other functions with no trouble;
only a few libraries can do this, and the behavior is subtle. Hold tight for
comprehensive docs describing this behavior.
New Div
, Grad
, Curl
and Lap
operators build on this foundation.
SCI Integration
To support safe execution inside of a browser-based Notebook or REPL
environment, SICMUtils now has full support for @borkdude's
SCI, the Small Clojure Interpreter, via the
sicmutils.sci
namespace. Every function and macro in the library now works in SCI. (Thanks for
@borkdude and @mk for your help and contributions.
Rendering
@hcarvalhoalves made a number of contributions to the LaTeX and infix renderers;
PowerSeries
and Series
now render beautifully, as well as =
and the
various inequality symbols. Expect a lot more action here as we move into more
browser-based notebook environments.
There's a lot more that went into this release; give the detailed notes below a
look for more details.
What's coming next?
The next release will focus on getting SICMUtils integrated with 2D and 3D
rendering libraries like three.js,
babylon.js and
Quil. The long-term goal is for SICMUtils to
support the sort of workflow I described in "The Dynamic
Notebook". This will
require a big push on generic, pluggable representations for the various types
and expressions in the library.
Thanks again to @hcarvalhoalves and @mk for their contributions, and to @borkdude for
his help with SCI!
On to the detailed release notes:
Automatic Differentiation
-
New, literate
Differential
implementation lives at at
sicmutils.differential
(#221) (see this
page for a
readable version.) Notable changes to the original impl at
sicmutils.calculus.derivative
include:-
We've changed our terminology from GJS's
finite-part
,
infinitesimal-part
,make-x+dx
to the more modernprimal-part
,
tangent-part
,bundle-element
that the Automatic Differentiation
community has adopted. His comment is that he doesn't take terms from
mathematics unless he's sure that he's using it in the correct way; the
safer way is to stick with his terms, but we go boldly forth with the
masses. -
A new
sicmutils.differential.IPerturbed
protocol makes it possible to
extend the Automatic Differentiation (AD) system to be able to handle
different Functor-shaped return values, like Java or JS lists and objects.
See the cljdoc page on Automatic
Differentiation
for more detail.-
#222 implements
d/IPerturbed
for Clojure maps, vectors and sequences;
all are now valid return types for functions you pass toD
. -
#222 also implements
d/IPerturbed
for SICMUtilsMatrix
,Structure
,
Series
,PowerSeries
andOperator
. -
#223 implements
d/IPerturbed
for Clojure functions and multimethods,
handling the attendant subtlety that fixes "Alexey's Amazing Bug".
-
-
sicmutils.differential/{lift-1,lift-2,lift-n}
allow you to make custom
operations differentiable, provided you can supply a derivative. -
Differential
implementssicmutils.function/arity
,IFn
, and can be
applied to arguments if its coefficients are function values.Differential
instances alsov/freeze
andg/simplify
properly (by pushing these
actions into their coefficients). -
New
compare
andequiv
implementations allowDifferential
instances to
compare themselves with other objects using only their primal parts; this
makes it possible to use functions like<=
,>
,=
to do control flow
during automatic differentiation. (Usecompare-full
andeq
if you want
to do full equality comparisons on primal and tangent components.) -
related,
g/abs
is now implemented forDifferential
instances, making
this function available in functions passed toD
. -
proper
numerical?
,one?
andidentity?
implementations. The latter two
only respondtrue
if there are NO tangent components; This means that
one?
and(= % 1)
will not agree. -
The new implementation fixes a subtle bug with nested, higher order
automatic differentiation - it's too subtle for the CHANGELOG, so please the
"amazing" bug sections insicmutils.calculus.derivative-test
for proper
exposition.
-
-
#223 converts the implementation of
sicmutils.calculus.derivative/D
to use
the newDifferential
type; this fixes "Alexey's Amazing Bug" and allowsD
to operate on higher order functions. For some functionf
that returns
another function,((D f) x)
will return a function that keepsx
"alive"
for the purposes of differentiation inside its body. See
sicmutils.calculus.derivative-test/amazing-bug
for an extended example. -
sicmutils.generic/partial-derivative
gains aKeyword
extension, so it can
respond properly to:name
and:arity
calls (#221). -
D
(orsicmutils.generic/partial-derivative
) applied to a matrix of
functions now takes the elementwise partials of every function in the matrix.
(#218) -
#253 moves the derivative implementations (where relevant) onto the metadata
of generic functions. You can access these by calling(<generic-function> :dfdx)
or(<generic-function> :dfdy)
, depending on whether the generic is
unary or binary. #253 also changes the name of macro
sicmutils.generic/def-generic-function
tosicmutils.generic/defgeneric
.
Rendering
-
sicmutils.expression/Literal
instances now usepr-str
to generate a string
representation; this allows this type to wrap lazy-sequence expressions such
as those returned fromg/simplify
(#259) -
sicmutils.expression.render/->infix
andsicmutils.expression.render/->TeX
now handle equality/inequality symbols (=
,>=
,>
, ...) as infix (#257). -
sicmutils.expression.render/*TeX-sans-serif-symbols*
binding to control if
symbols longer than 1 char should have\mathsf
applied (#258). -
->infix
,->TeX
and->JavaScript
insicmutils.expression.render
can now
accept unfrozen and unsimplifiedExpression
instances (#241). This makes it
a bit more convenient to use->infix
and->TeX
at the REPL, or in a
Notebook environment. Additionally, the return values of renderers are always
coerced to strings. (Previously,(->infix 10)
would return a number
directly.) -
up
anddown
tuples fromsicmutils.structure
gain a properprint-method
implementation (#229); these now render as(up 1 2 3)
and(down 1 2 3)
,
instead of the former more verbose representation (when usingpr
.) -
sicmutils.render/->infix
andsicmutils.render/->TeX
will renderSeries
andPowerSeries
as an infinite sum (showing the first four terms).
In the case of unnapliedPowerSeries
, it will represent the unbound
variable as_
(#260).
Performance Improvements
sicmutils.modint
gains more efficient implementations forinverse
,
quotient
,exact-divide
andexpt
on the JVM (#251).
Comparison / Native Type Integration
-
beefed up the Javascript numeric tower to allow objects like
sicmutils.differential/Differential
,sicmutils.expression/Expression
and
friends that WRAP numbers to compare properly using cljs-native<
,<=
,
=
,>=
and>
(#236) -
new
sicmutils.value/compare
function exposed insicmutils.env
returns a
valid comparison bit between native numbers and numbers wrapped in
Differential
orExpression
in both JVM Clojure and Clojurescript (#236).
The behavior matchesclojure.core/compare
for all reals on the JVM; it
doesn't in Clojurescript because nativecompare
can't handle
goog.math.{Long,Integer}
orjs/BigInt
.
Operator
-
#219 introduces a number of changes to
Operator
's behavior:-
Operator
is now adeftype
(not adefrecord
); the keyword lookup for
its:name
,:arity
,:context
and:o
fields have been replaced by,
respectively,o/name
,sicmutils.function/arity
,o/context
and
o/procedure
functions. This change happened to allowOperator
to
implement protocols likeILookup
. -
Native
get
andget-in
now act onOperator
. Given an operator function
f
,get
andget-in
compose#(get % k)
, or similar withf
. This
deferred action matches the effect of all sicmutils generics on functions. -
Combining an operator and a non-operator via
+
and-
, the non-operator
was previously lifted into an operator that multiplied itself by the new
operator's argument. As of #219, this "multiplication" uses the operator
definition of multiplication - meaning, the new operator composes the
non-operator with its argument. Where does this matter?Previously adding the non-operator
sicmutils.function/I
to the identity
operatorI
would act like this:(((g/+ o/identity f/I) f/I) 10) ;; => 110 == (+ 10 (* 10 10))
Because
f/I
multiplied itself by its argument... resulting in(* f/I f/I) == g/square
.After the change, you see this:
(((g/+ o/identity f/I) f/I) 10) ;; => 20
because
f/I
composes with its argument. -
sicmutils.operator/identity-operator
has been renamed to
sicmutils.operator/identity
-
o/make-operator
now takes an explicitcontext
map, instead of a
multi-arity implementation with key-value pairs. -
Operator
now implementsg/negate
. -
g/cross-product
is no longer implemented forOperator
. operators were
introduced by GJS to act like "differential operators", can only add, negate
and multiply (defined as composition). We will probably relax this in the
future, and add more functions likeg/cross-product
that compose with the
operator's output; but for now we're cleaning house, since this function
isn't used anywhere. -
In this same spirit,
Operator
instances can now only be divided by scalars
(not functions anymore), reflecting the ring structure of a differential
operator.
-
Additions
-
#224 adds new
Div
,Grad
,Curl
andLap
operators in
sicmutils.calculus.derivative
and installs them intosicmutils.env
. #224
also removes theg/transpose
implementation forOperator
instances, and
exposessicmutils.calculus.derivative/taylor-series
tosicmutils.env
. -
#222 adds
v/Value
implementations for Clojure sequences and maps. Maps and
vectors implementf/Arity
and return[:between 1 2].
zero?and
zero-likework on sequence entries and map values. Maps can specify their
v/kindreturn value with a
:typekey, and some of the calculus implementations do already make use of this feature.
g/partial-derivative` on
a Clojure Map passes through to its values. -
As of #232,
sicmutils.expression.compile/compile-univariate-fn
is now
compile-fn
(same change for the non-cachedcompile-fn*
in the same
namespace). The new implementation can compile arguments of any arity, not
just arity == 1. The new version takes an arity parametern
that defaults to
(sicmutils.function/arity f)
. -
sicmutils.function/arity
is now a protocol method, under the
sicmutils.function/IArity
protocol (#218). In addition to functions,arity
now correctly responds to:sicmutils.matrix/Matrix
: callingarity
on a matrix assumes that the
matrix has function elements; the returned arity is the most general arity
that all functions will respond to.sicmutils.operator/Operator
: returns the arity of the operator's wrapped
function.sicmutils.series/Series
:arity
on aSeries
assumes that the series
contains functions as entries, and returns, conservatively, the arity of
the first element of the series.sicmutils.series/PowerSeries
:arity
returns[:exactly 1]
, since
PowerSeries
are currently single variable.- vectors, and
sicmutils.structure/Structure
:arity
on these collections
assumes that the collection contains functions as entries, and returns the
most general arity that is compatible with all of the function elements.
-
New single-arity case for
sicmutils.structure/opposite
returns an identical
structure with flipped orientation (#220). acts asidentity
for
non-structures. -
Added missing
identity?
,identity-like
for complex and rational numbers
(#236) -
sicmutils.env/ref
now accepts function and operators (#219).(ref f 0 1)
,
as an example, returns a new functiong
that acts likef
but calls(ref result 0 1)
on the result. -
The slightly more general
sicmutils.env/component
replaces
sicmutils.structure/component
in thesicmutils.env
namespace (#219).
((component 0 1) x) == (ref x 0 1)
. -
New functions
sicmutils.function/{get,get-in}
added that act like the
clojure.core
versions; but given a functionf
, they compose#(get % k)
,
or similar withf
. This deferred action matches the effect of all sicmutils
generics on functions. (#218) -
sicmutils.function/I
aliasesclojure.core/identity
(#218). #219 exposes
I
insicmutils.env
. -
sicmutils.env.sci
contains an SCI context and namespace mapping sufficient
to evaluate all of sicmutils, macros and all, inside of an
SCI environment (#216). Huge thanks to
@borkdude for support and @mk for implementing this! -
sicmutils.numerical.elliptic
gains a full complement of elliptic integral
utilities (#211):- Carlson symmetric forms of the elliptic integrals:
carlson-rd
,
carlson-rc
,carlson-rj
(carlson-rf
was already present) - Legendre elliptic integrals of the second and third forms, as the two-arity
forms ofelliptic-e
andelliptic-pi
(elliptic-f
already existed) - the complete elliptic integrals via
elliptic-k
(first kind) and the
single-arity forms ofelliptic-e
andelliptic-pi
k-and-deriv
returns a pair of the complete elliptical integral of the first form,
elliptic-k
, and its derivative with respect tok
.jacobi-elliptic-functions
ported fromscmutils
and Press's Numerical
Recipes
- Carlson symmetric forms of the elliptic integrals:
Fixes / Misc
-
The operator returned by
sicmutils.calculus.derivative/partial
now has a
proper name field like(partial 0)
, instead of:partial-derivative
(#223). -
#223 fixes a problem where
(operator * structure)
would return a structure
of operators instead of an operator that closed over the multiplication.
::s/structure
is now properly a::o/co-operator
, matching its status as a
::f/cofunction
. -
Fix a bug where
f/arity
would throw an exception with multiple-arity
functions on the JVM (#240). It now responds properly with[:between min-arity max-arity]
, or[:at-least n]
if there is a variadic case too. -
#238 converts
sicmutils.abstract.function/Function
from adefrecord
to a
deftype
, fixing a subtle bug where (empty f) was getting called in a nested
derivative test. -
fixed bug with
g/dimension
for row and column matrices (#214). previously
they returned1
in both cases; now they return the total number of entries. -
#253 adds proper
:arglists
metadata for all generic functions.