Upgrade to Pro — share decks privately, control downloads, hide ads and more …

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 full-size slide

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

    View full-size slide

  3. AGENDA
    Overview of SICMUtils
    Programming Techniques
    Issues
    Demos
    7

    View full-size slide

  4. THANKS TO GJS
    (and many others!)

    View full-size slide

  5. SICMUTILS PROJECT GOALS
    11

    View full-size slide

  6. LIBRARY AS WORKSHOP / TEXTBOOK

    View full-size slide

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

    View full-size slide

  8. WHAT'S IN THE LIBRARY?
    15

    View full-size slide

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

    View full-size slide

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

    (expt (+ x y) 2)

    ((square +) 1 2)

    9

    19

    View full-size slide

  11. 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 full-size slide

  12. 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 full-size slide

  13. 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 full-size slide

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

    View full-size slide

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

    View full-size slide

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

    =>

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

    24

    View full-size slide

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

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

    (= 101 (r 12)))

    25

    View full-size slide

  18. 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 full-size slide

  19. 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 full-size slide

  20. 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 full-size slide

  21. 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 full-size slide

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

    29

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    (:sicmutils.complex/complex

    java.lang.Long

    clojure.lang.PersistentArrayMap)

    35

    View full-size slide

  28. 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 full-size slide

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

    View full-size slide

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

    #quaternion [1 2 3 4]

    #complex [2 3]

    38

    View full-size slide

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

    View full-size slide

  32. 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 full-size slide

  33. 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 full-size slide

  34. 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 full-size slide

  35. 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 full-size slide

  36. (my-simplify

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

    (cos (+ 12 x))

    41

    View full-size slide

  37. OPERATOR SIMPLIFICATION
    (def simplify-operator-name

    (rule-simplifier

    (rules/associative '+ '*)

    rules/exponent-contract

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

    42

    View full-size slide

  38. 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 full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide