$30 off During Our Annual Pro Sale. View Details »

Building SICMUtils, the Atelier of Abstractions

Building SICMUtils, the Atelier of Abstractions

These slides are from my second talk at the 2022 European Lisp Symposium in Porto, Portugal: https://european-lisp-symposium.org/2022/index.html

The source code for these slides and the demos in the talk live at https://github.com/sritchie/programming-2022.

Abstract:
SICMUtils is a Clojure library designed for interactive exploration of mathematical physics. It is simultaneously a work of persuasive writing, a collection of essays on functional pearls and computational ideas, a stable of workhorse functional abstractions, and a practical place to work and visualize algorithms and physical systems, on a server or in the browser.

How do you build a library like this? This talk will go through the architecture of SICMUtils, based on many of the ideas of "additive programming" from Gerald Sussman and Chris Hanson's latest book, Software Design for Flexibility. We'll look at surprising examples of the system becoming easier to extend over time. Clojure's embrace of its host platform lets us use the best modern work in Javascript for visualization, while keeping the horsepower of our servers for real work. Lisp's particular elegance will shine throughout.

Sam Ritchie

March 23, 2022
Tweet

More Decks by Sam Ritchie

Other Decks in Programming

Transcript

  1. BUILDING SICMUTILS
    The Atelier of Abstractions
    , Mentat
    Collective
    Sam Ritchie
    2

    View Slide

  2. SICMUTILS
    4

    View Slide

  3. ❤️
    OPEN SOURCE ❤️
    https://github.com/sicmutils/sicmutils
    5

    View Slide

  4. AGENDA
    Overview of SICMUtils
    Programming Techniques
    Issues
    Demos
    7

    View Slide

  5. THANKS TO GJS
    (and many others!)

    View Slide



  6. 9

    View Slide

  7. SICMUTILS PROJECT GOALS
    11

    View Slide

  8. LIBRARY AS WORKSHOP / TEXTBOOK

    View Slide

  9. 12

    View Slide

  10. MANY ENVIRONMENTS
    REPL
    Nextjournal
    org-mode, these slides
    Clojure, Clojurescript
    Zeugma, any Java environment
    Roam Research or Obsidian, etc
    TexMacs
    13

    View Slide

  11. WHAT'S IN THE LIBRARY?
    15

    View Slide

  12. 16

    View Slide

  13. 17

    View Slide

  14. NUMERICS
    full numeric tower in JavaScript, up to Complex
    dual numbers
    modular arithmetic types
    Quaternions, beyond
    18

    View Slide

  15. EXTENSIBLE GENERICS
    ((square +) 'x 'y)

    (expt (+ x y) 2)

    ((square +) 1 2)

    9

    19

    View Slide

  16. EXAMPLES OF GENERICS
    [sicmutils.generic
    * + - / divide
    negate
    negative? infinite?
    invert
    abs
    sqrt
    quotient remainder modulo
    floor ceiling
    integer-part fractional-part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    expt
    11
    exp exp2 exp10
    12
    log log2 log10
    13
    gcd lcm
    14
    exact-divide
    15
    square cube
    16
    20

    View Slide

  17. EXAMPLES OF GENERICS
    [sicmutils.generic
    * + - / divide
    negate
    negative? infinite?
    invert
    abs
    sqrt
    quotient remainder modulo
    floor ceiling
    integer-part fractional-part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    expt
    11
    exp exp2 exp10
    12
    log log2 log10
    13
    gcd lcm
    14
    exact-divide
    15
    square cube
    16
    make-rectangular make-polar
    real-part imag-part
    magnitude angle conjugate
    transpose trace determinant dimension
    dot-product inner-product outer-product cross-product
    partial-derivative Lie-derivative
    solve-linear solve-linear-left solve-linear-right
    simplify]
    square cube
    16
    cos sin tan
    17
    cot sec csc
    18
    atan
    19
    acos asin acot asec acsc
    20
    cosh sinh tanh coth sech csch
    21
    acosh asinh atanh acoth asech acsch
    22
    sinc tanc sinhc tanhc
    23
    24
    25
    26
    27
    28
    29
    30
    31
    20

    View Slide

  18. SYMBOLIC COMPUTATION
    (+ (square (sin 'x))

    (square (cos 'x)))

    (+ (expt (sin x) 2) (expt (cos x) 2))

    (simplify

    (+ (square (sin 'x))

    (square (cos 'x))))

    1

    21

    View Slide

  19. "COMPOUND" DATA TYPES
    vector, matrix, up, down structures
    polynomial, rational function
    power series
    quaternions
    22

    View Slide

  20. "LITERALS", IE, SYMBOLIC-LIKE THINGS:
    literal numbers
    literal functions
    symbols, or literal-number
    literal vectors, matrices
    quantum states, bra, ket
    23

    View Slide

  21. PATTERN MATCHING DSL
    (rule (/ (* ??u ?x ??v) (sqrt ?x))

    =>

    (* ??u (sqrt ?x) ??v))

    24

    View Slide

  22. PATTERN COMBINATORS
    (let [r (while (fn [l _] (< l 100))

    (rule ?x => (? #(inc (% '?x)))))]

    (= 101 (r 12)))

    25

    View Slide

  23. PATTERN COMBINATORS
    (let [r (while (fn [l _] (< l 100))

    (rule ?x => (? #(inc (% '?x)))))]

    (= 101 (r 12)))

    Literal Derivative:
    (choice

    (rule (D ?f) => ((expt D 2) ?f))

    (rule ((expt D ?n) ?f) => ((expt D (? #(inc (% '?n)))) ?f))

    (rule ?f => (D ?f)))

    25

    View Slide

  24. RENDERERS
    Infix:
    TeX:
    (->infix

    (+ (square (sin 'eta))

    (cube (tan 'phi_2))))
    sin²(η) + (tan(φ₂))³

    (->TeX

    (+ (square (sin 'eta))

    (cube (tan 'phi_2))))
    {\sin}^{2}\left(\eta\right) + {\left(\tan\left({\phi}_2\right)\right)}^
    26

    View Slide

  25. RENDERERS
    JavaScript Source Renderer
    (println

    (->JavaScript

    (+ (square (sin 'eta))

    (cube (tan 'phi-2)))))

    function(eta, phi_2) {

    return Math.pow(Math.sin(eta), 2) + Math.pow(Math.tan(phi_2), 3);

    }

    27

    View Slide

  26. FUNCTION COMPILATION
    (defn my-fn [x y]

    (+ x

    (sin y)

    (square (cos 'x))

    (square (sin 'x))

    (cube (sin y))))

    (binding [*mode* :source]
    (compile-fn my-fn))

    (clojure.core/fn [x45929 x45930]

    (clojure.core/let [G0000000000000000 (Math/sin x45930)]

    (clojure.core/+ (clojure.core/*

    -1.0

    G0000000000000000

    (Math/pow (Math/cos x45930) 2.0))

    x45929

    (clojure.core/* 2.0 G0000000000000000)

    1.0)))

    28

    View Slide

  27. FUNCTIONAL NUMERICAL METHODS
    Univariate and multivariate minimization
    Polynomial and RF interpolation
    Richardson Extrapolation
    (FUNCTIONAL!) Numerical quadrature
    numeric derivatives
    Native ODE solvers

    29

    View Slide

  28. AUTOMATIC DIFFERENTIATION
    Forward mode,
    immutable reverse mode!
    30

    View Slide

  29. PHYSICS
    Hamiltonian and Lagrangian mechanics
    Differential Geometry
    Manifolds, Coordinate Systems
    Tensor Calculus
    Geometric Algebra
    31

    View Slide

  30. ANIMATIONS
    Mathbox
    JSXGraph
    extensible from Clojure, not JS!
    32

    View Slide

  31. SICMUTILS PROGRAMMING TECHNIQUES
    Extensible Generics
    Clojure is Opinionated!
    Combinators
    DSLs, Pattern Matching
    34

    View Slide

  32. TYPE VS KIND
    (map kind [(make-rectangular 1 2) 10 {:k "v"}])

    (:sicmutils.complex/complex

    java.lang.Long

    clojure.lang.PersistentArrayMap)

    35

    View Slide

  33. CONSTRAINED EXTENSIBILITY
    (derive ::square-matrix ::matrix)

    (derive ::column-matrix ::matrix)

    (derive ::row-matrix ::matrix)

    (derive ::matrix ::f/cofunction)

    (defmethod g/mul [::matrix ::matrix] [a b]

    (mul a b))

    (defmethod g/mul [::v/scalar ::matrix] [n a]

    (scalar*matrix n a))

    (defmethod g/mul [::matrix ::v/scalar] [a n]

    (matrix*scalar a n))

    36

    View Slide

  34. STICK WITH CLOJURE
    Different Environments, CLJS
    Small # of core data structures
    ~Everything is Immutable
    37

    View Slide

  35. PRAGMATIC CORE
    [] {} #{} () :keyword 'sym

    #quaternion [1 2 3 4]

    #complex [2 3]

    38

    View Slide

  36. COMBINATORS
    pattern matching combinators
    numerical method combinators: infinite
    Aggregation functions
    39

    View Slide

  37. DSL, PATTERN MATCHING:
    (defn unary-elimination [& ops]
    (let [op-set (into #{} ops)]
    (ruleset
    ((? _ op-set) ?x) => ?x)))
    (require '[pattern.rule :as r :refer [ruleset =>]])
    1
    2
    3
    4
    5
    6
    7
    (defn constant-elimination [op constant]
    8
    (letfn [(filter-constants [{xs '??xs}]
    9
    (remove #{constant} xs))]
    10
    (ruleset
    11
    (~op ??xs) => (~op (?? ~filter-constants)))))
    12
    13
    (defn constant-promotion [op constant]
    14
    (ruleset
    15
    (~op ~constant) => ~constant
    16
    40

    View Slide

  38. DSL, PATTERN MATCHING:
    (defn unary-elimination [& ops]
    (let [op-set (into #{} ops)]
    (ruleset
    ((? _ op-set) ?x) => ?x)))
    (require '[pattern.rule :as r :refer [ruleset =>]])
    1
    2
    3
    4
    5
    6
    7
    (defn constant-elimination [op constant]
    8
    (letfn [(filter-constants [{xs '??xs}]
    9
    (remove #{constant} xs))]
    10
    (ruleset
    11
    (~op ??xs) => (~op (?? ~filter-constants)))))
    12
    13
    (defn constant-promotion [op constant]
    14
    (ruleset
    15
    (~op ~constant) => ~constant
    16
    (defn constant-elimination [op constant]
    (letfn [(filter-constants [{xs '??xs}]
    (remove #{constant} xs))]
    (ruleset
    (~op ??xs) => (~op (?? ~filter-constants)))))
    (let [op set (into #{} ops)]
    4
    (ruleset
    5
    ((? _ op-set) ?x) => ?x)))
    6
    7
    8
    9
    10
    11
    12
    13
    (defn constant-promotion [op constant]
    14
    (ruleset
    15
    (~op _ ~constant) => ~constant
    16
    (~op ~constant _) => ~constant))
    17
    18
    (def my-simplify
    19
    (r/rule-simplifier
    20
    40

    View Slide

  39. DSL, PATTERN MATCHING:
    (defn unary-elimination [& ops]
    (let [op-set (into #{} ops)]
    (ruleset
    ((? _ op-set) ?x) => ?x)))
    (require '[pattern.rule :as r :refer [ruleset =>]])
    1
    2
    3
    4
    5
    6
    7
    (defn constant-elimination [op constant]
    8
    (letfn [(filter-constants [{xs '??xs}]
    9
    (remove #{constant} xs))]
    10
    (ruleset
    11
    (~op ??xs) => (~op (?? ~filter-constants)))))
    12
    13
    (defn constant-promotion [op constant]
    14
    (ruleset
    15
    (~op ~constant) => ~constant
    16
    (defn constant-elimination [op constant]
    (letfn [(filter-constants [{xs '??xs}]
    (remove #{constant} xs))]
    (ruleset
    (~op ??xs) => (~op (?? ~filter-constants)))))
    (require '[pattern.rule :as r :refer [ruleset =>]])
    1
    2
    (defn unary-elimination [& ops]
    3
    (let [op-set (into #{} ops)]
    4
    (ruleset
    5
    ((? _ op-set) ?x) => ?x)))
    6
    7
    8
    9
    10
    11
    12
    13
    (defn constant-promotion [op constant]
    14
    (ruleset
    15
    (~op ~constant) => ~constant
    16
    (defn constant-promotion [op constant]
    (ruleset
    (~op _ ~constant) => ~constant
    (~op ~constant _) => ~constant))
    (letfn [(filter constants [{xs ??xs}]
    9
    (remove #{constant} xs))]
    10
    (ruleset
    11
    (~op ??xs) => (~op (?? ~filter-constants)))))
    12
    13
    14
    15
    16
    17
    18
    (def my-simplify
    19
    (r/rule-simplifier
    20
    (unary-elimination '+ '*)
    21
    (constant-elimination '+ 0)
    22
    (constant-elimination '* 1)
    23
    (constant-promotion '* 0)))
    24
    40

    View Slide

  40. DSL, PATTERN MATCHING:
    (defn unary-elimination [& ops]
    (let [op-set (into #{} ops)]
    (ruleset
    ((? _ op-set) ?x) => ?x)))
    (require '[pattern.rule :as r :refer [ruleset =>]])
    1
    2
    3
    4
    5
    6
    7
    (defn constant-elimination [op constant]
    8
    (letfn [(filter-constants [{xs '??xs}]
    9
    (remove #{constant} xs))]
    10
    (ruleset
    11
    (~op ??xs) => (~op (?? ~filter-constants)))))
    12
    13
    (defn constant-promotion [op constant]
    14
    (ruleset
    15
    (~op ~constant) => ~constant
    16
    (defn constant-elimination [op constant]
    (letfn [(filter-constants [{xs '??xs}]
    (remove #{constant} xs))]
    (ruleset
    (~op ??xs) => (~op (?? ~filter-constants)))))
    (require '[pattern.rule :as r :refer [ruleset =>]])
    1
    2
    (defn unary-elimination [& ops]
    3
    (let [op-set (into #{} ops)]
    4
    (ruleset
    5
    ((? _ op-set) ?x) => ?x)))
    6
    7
    8
    9
    10
    11
    12
    13
    (defn constant-promotion [op constant]
    14
    (ruleset
    15
    (~op ~constant) => ~constant
    16
    (defn constant-promotion [op constant]
    (ruleset
    (~op ~constant) => ~constant
    (require '[pattern.rule :as r :refer [ruleset =>]])
    1
    2
    (defn unary-elimination [& ops]
    3
    (let [op-set (into #{} ops)]
    4
    (ruleset
    5
    ((? _ op-set) ?x) => ?x)))
    6
    7
    (defn constant-elimination [op constant]
    8
    (letfn [(filter-constants [{xs '??xs}]
    9
    (remove #{constant} xs))]
    10
    (ruleset
    11
    (~op ??xs) => (~op (?? ~filter-constants)))))
    12
    13
    14
    15
    16
    (def my-simplify
    (r/rule-simplifier
    (unary-elimination '+ '*)
    (constant-elimination '+ 0)
    (constant-elimination '* 1)
    (constant-promotion '* 0)))
    (letfn [(filter constants [{xs ??xs}]
    9
    (remove #{constant} xs))]
    10
    (ruleset
    11
    (~op ??xs) => (~op (?? ~filter-constants)))))
    12
    13
    (defn constant-promotion [op constant]
    14
    (ruleset
    15
    (~op _ ~constant) => ~constant
    16
    (~op ~constant _) => ~constant))
    17
    18
    19
    20
    21
    22
    23
    24
    40

    View Slide

  41. (my-simplify

    '(cos (+ 0 (+ 0 12 0) (* 1 x))))

    (cos (+ 12 x))

    41

    View Slide

  42. OPERATOR SIMPLIFICATION
    (def simplify-operator-name

    (rule-simplifier

    (rules/associative '+ '*)

    rules/exponent-contract

    (rules/unary-elimination '+ '*)))

    42

    View Slide

  43. MULTI-STAGE PROGRAMMING
    (defn my-fn [x y]

    (+ x

    (sin y)

    (square (cos 'x))

    (square (sin 'x))

    (cube (sin y))))

    (binding [*mode* :source]
    (compile-fn my-fn))

    (clojure.core/fn [x45929 x45930]

    (clojure.core/let [G0000000000000000 (Math/sin x45930)]

    (clojure.core/+ (clojure.core/*

    -1.0

    G0000000000000000

    (Math/pow (Math/cos x45930) 2.0))

    x45929

    (clojure.core/* 2.0 G0000000000000000)

    1.0)))

    43

    View Slide

  44. CLOJURE COMMUNITY
    Sussman et. al.
    Colin Smith
    Clerk: Martin Kavalar, Jack Rusher, Nextjournal
    team
    maria.cloud
    SCI, CLJ-Kondo: Michiel Borkent (@borkdude)
    44

    View Slide

  45. HARD?
    No types so far
    what's the right way to introspect the library?
    Context
    46

    View Slide

  46. DEMOS
    48

    View Slide

  47. THANKS!
    Sam Ritchie, Mentat Collective
    Slides, Demos live at
    @sritchie
    https://github.com/sritchie/programming-2022
    50

    View Slide