├── .clj-kondo ├── babashka │ ├── fs │ │ └── config.edn │ └── sci │ │ ├── config.edn │ │ └── sci │ │ └── core.clj ├── config.edn ├── nextjournal │ └── clerk │ │ ├── config.edn │ │ └── nextjournal │ │ └── clerk │ │ └── viewer.clj_kondo ├── org.mentat │ ├── clerk-utils │ │ ├── config.edn │ │ └── hooks │ │ │ └── mentat │ │ │ └── clerk_utils │ │ │ └── viewers.clj_kondo │ ├── emmy │ │ ├── config.edn │ │ └── hooks │ │ │ └── emmy │ │ │ ├── abstract │ │ │ └── function.clj │ │ │ ├── calculus │ │ │ └── coordinate.clj │ │ │ ├── env.clj │ │ │ ├── pattern │ │ │ └── rule.clj │ │ │ └── util │ │ │ └── def.clj │ └── mathbox.cljs │ │ ├── config.edn │ │ └── hooks │ │ └── mathbox │ │ └── macros.clj_kondo ├── rewrite-clj │ └── rewrite-clj │ │ └── config.edn └── taoensso │ └── encore │ ├── config.edn │ └── taoensso │ └── encore.clj ├── .dir-locals.el ├── .github ├── FUNDING.yml └── workflows │ ├── gh-pages.yml │ └── kondo.yml ├── .gitignore ├── CHANGELOG.md ├── DEVELOPING.md ├── LICENSE ├── README.md ├── bb.edn ├── deps.edn ├── dev └── user.clj ├── essays └── reality │ ├── faq.md │ ├── index.clj │ ├── introduction.md │ ├── references.md │ └── tools.md ├── package-lock.json ├── package.json └── src └── reality ├── custom.cljs ├── mathbox.cljs ├── sci_extensions.cljs ├── toroid.clj └── viewer.clj /.clj-kondo/babashka/fs/config.edn: -------------------------------------------------------------------------------- 1 | {:lint-as {babashka.fs/with-temp-dir clojure.core/let}} 2 | -------------------------------------------------------------------------------- /.clj-kondo/babashka/sci/config.edn: -------------------------------------------------------------------------------- 1 | {:hooks {:macroexpand {sci.core/copy-ns sci.core/copy-ns}}} 2 | -------------------------------------------------------------------------------- /.clj-kondo/babashka/sci/sci/core.clj: -------------------------------------------------------------------------------- 1 | (ns sci.core) 2 | 3 | (defmacro copy-ns 4 | ([ns-sym sci-ns] 5 | `(copy-ns ~ns-sym ~sci-ns nil)) 6 | ([ns-sym sci-ns opts] 7 | `[(quote ~ns-sym) 8 | ~sci-ns 9 | (quote ~opts)])) 10 | -------------------------------------------------------------------------------- /.clj-kondo/config.edn: -------------------------------------------------------------------------------- 1 | {:lint-as 2 | {reagent.core/with-let clojure.core/let} 3 | 4 | :linters {:refer-all {:exclude [emmy.env]}}} 5 | -------------------------------------------------------------------------------- /.clj-kondo/nextjournal/clerk/config.edn: -------------------------------------------------------------------------------- 1 | {:config-in-call {nextjournal.clerk.viewer/->viewer-fn {:linters {:unresolved-symbol {:exclude [clj->js]} 2 | :unresolved-namespace {:exclude [nextjournal.clerk.render 3 | nextjournal.clerk.render.code 4 | nextjournal.clerk.render.hooks 5 | js]}}} 6 | nextjournal.clerk.viewer/->viewer-eval {:linters {:unresolved-symbol {:exclude [clj->js]} 7 | :unresolved-namespace {:exclude [nextjournal.clerk.render 8 | nextjournal.clerk.render.code 9 | nextjournal.clerk.render.hooks 10 | js]}}}} 11 | :hooks {:analyze-call {nextjournal.clerk.viewer/->viewer-fn nextjournal.clerk.viewer/->viewer-fn 12 | nextjournal.clerk.viewer/->viewer-eval nextjournal.clerk.viewer/->viewer-fn}} 13 | :lint-as {nextjournal.clerk/defcached clojure.core/def}} 14 | -------------------------------------------------------------------------------- /.clj-kondo/nextjournal/clerk/nextjournal/clerk/viewer.clj_kondo: -------------------------------------------------------------------------------- 1 | (ns nextjournal.clerk.viewer 2 | (:require [clj-kondo.hooks-api :as api] 3 | [clojure.string :as str])) 4 | 5 | (defn ->viewer-fn [{:keys [node]}] 6 | (let [[name-node quoted-node] (:children node) 7 | quoted-tag (api/tag quoted-node)] 8 | (when (= :quote quoted-tag) 9 | (let [quoted-node {:tag :syntax-quote 10 | :children (:children quoted-node)} 11 | fn-node (first (:children quoted-node))] 12 | {:node fn-node})))) 13 | -------------------------------------------------------------------------------- /.clj-kondo/org.mentat/clerk-utils/config.edn: -------------------------------------------------------------------------------- 1 | {:lint-as 2 | {mentat.clerk-utils/->clerk clojure.test/do 3 | mentat.clerk-utils/->clerk-only clojure.test/do} 4 | 5 | :hooks 6 | {:analyze-call 7 | {mentat.clerk-utils.viewers/q hooks.mentat.clerk-utils.viewers/q}} 8 | 9 | :config-in-call 10 | {mentat.clerk-utils.show/show-sci 11 | {:linters 12 | {:unresolved-symbol {:level :off} 13 | :unresolved-namespace {:level :off}}} 14 | mentat.clerk-utils.show/show-cljs 15 | {:linters 16 | {:unresolved-symbol {:level :off} 17 | :unresolved-namespace {:level :off}}}}} 18 | -------------------------------------------------------------------------------- /.clj-kondo/org.mentat/clerk-utils/hooks/mentat/clerk_utils/viewers.clj_kondo: -------------------------------------------------------------------------------- 1 | (ns hooks.mentat.clerk-utils.viewers 2 | (:require [clj-kondo.hooks-api :as api])) 3 | 4 | (defn set-node? 5 | "This is missing from `hooks-api`, so we hack it here." 6 | [n] 7 | (= :set (api/tag n))) 8 | 9 | ;; Lint the argument of `q` by treating everything as quoted, except anything 10 | ;; inside an [[unquote?]] or [[unquote-splice?]] form. 11 | 12 | (defn unquote? 13 | "Returns true if the supplied `node` is an `:unquote` node, false otherwise." 14 | [node] 15 | (= :unquote (:tag node))) 16 | 17 | (defn unquote-splice? 18 | "Returns true if the supplied `node` is an `:unquote-splicing` node, false 19 | otherwise." 20 | [node] 21 | (= :unquote-splicing (:tag node))) 22 | 23 | (def any-unquote? 24 | "Returns true if the supplied `node` is either of the unquote 25 | forms (`:unquote` or `:unquote-splicing`, false otherwise.)" 26 | (some-fn unquote? unquote-splice?)) 27 | 28 | (def coll-node? 29 | "Returns true if the supplied `node` is a collection, ie, a list, 30 | vector or map, false otherwise." 31 | (some-fn api/list-node? api/vector-node? api/map-node? set-node?)) 32 | 33 | (defn walk-node 34 | "Given a function `f` of a node and some `node`, returns a vector of all nodes 35 | in the syntax tree represented by `node` for which `(f sub-node)` returns a 36 | non-nil result. 37 | 38 | NOTE: The result is an eagerly-evaluated vector, so `f` is permitted to have 39 | side effects." 40 | [f node] 41 | (let [tree (tree-seq coll-node? :children node) 42 | xform (mapcat (fn [x] 43 | (when-let [result (f x)] 44 | [result])))] 45 | (into [] xform tree))) 46 | 47 | (defn unquotes 48 | "If the supplied node is an [[any-unquote?]], acts as identity. Else, returns 49 | `nil`." 50 | [node] 51 | (when (any-unquote? node) 52 | node)) 53 | 54 | (defn q 55 | "Converts a node representing an invocation of 56 | the [[mentat.clerk-utils.viewers/q]] macro into a vector-node of all lintable 57 | forms." 58 | [{:keys [node]}] 59 | (let [[_ form] (:children node)] 60 | {:node 61 | (api/vector-node 62 | (walk-node unquotes form))})) 63 | -------------------------------------------------------------------------------- /.clj-kondo/org.mentat/emmy/config.edn: -------------------------------------------------------------------------------- 1 | {:linters 2 | {:emmy.pattern/binding-sym {:level :error} 3 | :emmy.pattern/consequence-restriction {:level :error} 4 | :emmy.pattern/ruleset-args {:level :error} 5 | :emmy.abstract.function/invalid-binding {:level :error} 6 | :emmy.calculus.coordinate/invalid-binding {:level :error}} 7 | 8 | :lint-as 9 | {emmy.numerical.quadrature.common/defintegrator clojure.core/def 10 | emmy.util.def/import-vars potemkin/import-vars 11 | emmy.util.def/defgeneric clojure.core/defmulti} 12 | 13 | :hooks 14 | {:analyze-call 15 | {emmy.abstract.function/with-literal-functions 16 | hooks.emmy.abstract.function/with-literal-functions 17 | 18 | emmy.calculus.coordinate/define-coordinates 19 | hooks.emmy.calculus.coordinate/define-coordinates 20 | 21 | emmy.calculus.coordinate/let-coordinates 22 | hooks.emmy.calculus.coordinate/let-coordinates 23 | 24 | emmy.calculus.coordinate/using-coordinates 25 | hooks.emmy.calculus.coordinate/using-coordinates 26 | 27 | emmy.env/define-coordinates 28 | hooks.emmy.calculus.coordinate/define-coordinates 29 | 30 | emmy.env/let-coordinates 31 | hooks.emmy.calculus.coordinate/let-coordinates 32 | 33 | emmy.env/using-coordinates 34 | hooks.emmy.calculus.coordinate/using-coordinates 35 | 36 | emmy.env/bootstrap-repl! 37 | hooks.emmy.env/bootstrap-repl! 38 | 39 | emmy.env/literal-function 40 | hooks.emmy.abstract.function/literal-function 41 | 42 | emmy.env/with-literal-functions 43 | hooks.emmy.abstract.function/with-literal-functions 44 | 45 | emmy.util.def/import-def hooks.emmy.util.def/import-def 46 | emmy.util.def/import-macro hooks.emmy.util.def/import-def 47 | 48 | emmy.pattern.rule/consequence hooks.emmy.pattern.rule/consequence 49 | emmy.pattern.rule/pattern hooks.emmy.pattern.rule/pattern 50 | emmy.pattern.rule/rule hooks.emmy.pattern.rule/rule 51 | emmy.pattern.rule/ruleset hooks.emmy.pattern.rule/ruleset 52 | emmy.pattern.rule/template hooks.emmy.pattern.rule/template}}} 53 | -------------------------------------------------------------------------------- /.clj-kondo/org.mentat/emmy/hooks/emmy/abstract/function.clj: -------------------------------------------------------------------------------- 1 | (ns hooks.emmy.abstract.function 2 | (:require [clj-kondo.hooks-api :as api])) 3 | 4 | (defn- arrow-form? 5 | "Returns true if the supplied node is a list node of the form `(-> ...)`, false 6 | otherwise." 7 | [signature] 8 | (and (api/list-node? signature) 9 | (= '-> (:value 10 | (first 11 | (:children signature)))))) 12 | 13 | (defn literal-function 14 | "Lints the macro version of `literal-function`, living in `emmy.env`. 15 | 16 | If the signature consists of a list-node starting with `->` it's treated as 17 | quoted. Else, it's emitted in a vector-node with the `f` entry." 18 | [{:keys [node]}] 19 | (let [[_ f sig-or-domain range] (:children node) 20 | new-node (cond range 21 | (api/vector-node [f sig-or-domain range]) 22 | 23 | (arrow-form? sig-or-domain) 24 | (api/vector-node [f]) 25 | 26 | :else (api/vector-node [f sig-or-domain]))] 27 | {:node new-node})) 28 | 29 | (defn binding-pair 30 | "Given an entry in the binding vector of a call to `with-literal-functions`, 31 | returns a 2-vector pair of lintable entries in a `let` form. 32 | 33 | Invalid entries return an empty vector after triggering a linter error." 34 | [entry] 35 | (cond (and (api/token-node? entry) 36 | (simple-symbol? (:value entry))) 37 | (let [v (api/list-node 38 | [(api/token-node 'quote) entry])] 39 | [entry v]) 40 | 41 | (and (or (api/list-node? entry) 42 | (api/vector-node? entry)) 43 | (= (count (:children entry)) 3)) 44 | (let [[sym domain range] (:children entry)] 45 | [sym (api/vector-node [domain range])]) 46 | 47 | :else 48 | (do (api/reg-finding! 49 | (assoc (meta entry) 50 | :message (str "Bindings must be either bare symbols or " 51 | "3-vectors of the form [sym domain range]. " 52 | "Received: " 53 | (pr-str (api/sexpr entry))) 54 | :type :emmy.abstract.function/invalid-binding)) 55 | []))) 56 | 57 | (defn with-literal-functions 58 | "Converts a node representing an invocation of 59 | the [[emmy.abstract.function/with-literal-functions]] macro into a 60 | let-style representation of the requested bindings." 61 | [{:keys [node]}] 62 | (let [[_ binding-vec & body] (:children node) 63 | bindings (into [] 64 | (mapcat binding-pair) 65 | (:children binding-vec))] 66 | {:node 67 | (api/list-node 68 | (list* 69 | (api/token-node 'let) 70 | (api/vector-node bindings) 71 | body))})) 72 | -------------------------------------------------------------------------------- /.clj-kondo/org.mentat/emmy/hooks/emmy/calculus/coordinate.clj: -------------------------------------------------------------------------------- 1 | (ns hooks.emmy.calculus.coordinate 2 | (:require [clj-kondo.hooks-api :as api])) 3 | 4 | (defn symbols-from-prototype 5 | "Generates a list of lintable symbols from the supplied argument prototype. The 6 | prototype is allowed to be a vector, a list like `(up x y)` or a bare symbol. 7 | Anything else causes an exception. 8 | 9 | Nested structures are fine! The return value is a flat sequence." 10 | [p] 11 | (cond (and (api/list-node? p) 12 | ('#{up down} (:value (first (:children p))))) 13 | (mapcat symbols-from-prototype (rest (:children p))) 14 | 15 | (api/vector-node? p) 16 | (mapcat symbols-from-prototype (:children p)) 17 | 18 | (and (api/token-node? p) (symbol? (:value p))) 19 | [p] 20 | 21 | :else 22 | (do (api/reg-finding! 23 | (assoc (meta p) 24 | :message (str "Bindings must be either a vector or list " 25 | "(optionally beginning with `up` or `down`) " 26 | "or a bare symbol. Received: " 27 | (pr-str (api/sexpr p))) 28 | :type :emmy.calculus.coordinate/invalid-binding)) 29 | []))) 30 | 31 | (defn coordinate-name->vf-name 32 | "Given a token-node of coordinate symbolic name, returns a token-node containing 33 | the symbolic name of the associated coordinate basis vector field." 34 | [n] 35 | (api/token-node 36 | (symbol (str "d:d" (:value n))))) 37 | 38 | (defn coordinate-name->ff-name 39 | "Given a token-node of coordinate symbolic name, returns a token-node containing 40 | the symbolic name of the associated coordinate basis one-form vector field." 41 | [n] 42 | (api/token-node 43 | (symbol (str \d (:value n))))) 44 | 45 | (defn quotify 46 | "Given some node, returns a 2-vector representing a pair of entries in a 47 | let-style binding vector. The value is a quoted node `n`." 48 | [n] 49 | [n (api/list-node [(api/token-node 'quote) n])]) 50 | 51 | (defn let-coordinates 52 | "Converts a node representing an invocation of 53 | the [[emmy.calculus.coordinate/let-coordinates]] macro into a let-style 54 | representation of the requested bindings." 55 | [{:keys [node]}] 56 | (let [[_ binding-vec & body] (:children node)] 57 | (when-not (even? (count (:children binding-vec))) 58 | (throw 59 | (ex-info "let-coordinates requires an even number of bindings." {}))) 60 | 61 | (let [pairs (partition 2 (:children binding-vec)) 62 | prototypes (map first pairs) 63 | c-systems (map second pairs) 64 | system-names (map (comp api/token-node symbol name :value) c-systems) 65 | coord-names (mapcat symbols-from-prototype prototypes) 66 | vf-names (map coordinate-name->vf-name coord-names) 67 | ff-names (map coordinate-name->ff-name coord-names) 68 | new-node (api/list-node 69 | (list* 70 | (api/token-node 'let) 71 | (api/vector-node 72 | (concat 73 | (interleave system-names c-systems) 74 | (mapcat quotify coord-names) 75 | (mapcat quotify vf-names) 76 | (mapcat quotify ff-names))) 77 | (api/vector-node 78 | (concat system-names coord-names vf-names ff-names)) 79 | body))] 80 | {:node new-node}))) 81 | 82 | (defn using-coordinates 83 | "Converts a node representing an invocation of 84 | the [[emmy.calculus.coordinate/using-coordinates]] macro into a let-style 85 | representation of the requested bindings." 86 | [{:keys [node]}] 87 | (let [[sym prototype system & body] (:children node)] 88 | (let-coordinates 89 | {:node (api/list-node 90 | (list* sym 91 | (api/vector-node [prototype system]) 92 | body))}))) 93 | 94 | (defn ->declare 95 | "Given some token-node, returns a 2-vector representing a pair of entries in a 96 | let-style binding vector. The value is a quoted node `n`." 97 | [n] 98 | (api/list-node 99 | [(api/token-node 'declare) 100 | n])) 101 | 102 | (defn define-coordinates 103 | "Converts a node representing an invocation of 104 | the [[emmy.calculus.coordinate/define-coordinates]] macro into a series 105 | of declarations for all generated `def` forms, plus a final vector of all 106 | entries. 107 | 108 | This last vector will silence any 'not used' warnings." 109 | [{:keys [node]}] 110 | (let [[_ prototype system] (:children node) 111 | sys-name (api/token-node (symbol (name (:value system)))) 112 | coord-names (symbols-from-prototype prototype) 113 | vf-names (map coordinate-name->vf-name coord-names) 114 | ff-names (map coordinate-name->ff-name coord-names) 115 | syms (concat [sys-name] coord-names vf-names ff-names) 116 | new-node (api/list-node 117 | (concat 118 | [(api/token-node 'do) 119 | (->declare sys-name)] 120 | (map ->declare coord-names) 121 | (map ->declare vf-names) 122 | (map ->declare ff-names) 123 | [(api/vector-node syms)]))] 124 | {:node new-node})) 125 | -------------------------------------------------------------------------------- /.clj-kondo/org.mentat/emmy/hooks/emmy/env.clj: -------------------------------------------------------------------------------- 1 | (ns hooks.emmy.env 2 | (:require [clj-kondo.hooks-api :as api] 3 | [hooks.emmy.calculus.coordinate :as coord])) 4 | 5 | (defn bootstrap-repl! 6 | "Generates a form that looks like 7 | 8 | ```clj 9 | (do (declare 'x) (declare 'y) ,,,) 10 | ``` 11 | 12 | For all vars exported by the `emmy.env` namespace." 13 | [{:keys [_node]}] 14 | (let [analysis (api/ns-analysis 'emmy.env) 15 | entries (into (:clj analysis) (:cljs analysis)) 16 | xform (comp (filter 17 | (comp #{'emmy.env} :ns val)) 18 | (map (comp coord/->declare api/token-node key))) 19 | declares (into [] xform entries) 20 | new-node (api/list-node 21 | (list* 22 | (api/token-node 'do) 23 | declares))] 24 | {:node new-node})) 25 | -------------------------------------------------------------------------------- /.clj-kondo/org.mentat/emmy/hooks/emmy/pattern/rule.clj: -------------------------------------------------------------------------------- 1 | (ns hooks.emmy.pattern.rule 2 | (:require [clj-kondo.hooks-api :as api])) 3 | 4 | ;; ## Pattern Linting 5 | ;; 6 | ;; Lint the first argument of the `pattern` and macros by treating everything as 7 | ;; quoted, EXCEPT: 8 | ;; 9 | ;; - anything inside an [[unquote?]] or [[unquote-splice?]]form 10 | ;; - restrictions, which appear in the third-and-further position of `(? sym 11 | ;; ..)` or `(?? sym ...)` forms 12 | ;; 13 | ;; Additionally, check that: 14 | ;; 15 | ;; - `($$ ...)` forms contain only a single symbol, nothing else 16 | ;; - `(?? ...)` and `(? ...)` begin with a bare symbol, nothing else. 17 | 18 | (defn unquote? 19 | "Returns true if the supplied `node` is an `:unquote` node, false otherwise." 20 | [node] 21 | (= :unquote (:tag node))) 22 | 23 | (defn unquote-splice? 24 | "Returns true if the supplied `node` is an `:unquote-splicing` node, false 25 | otherwise." 26 | [node] 27 | (= :unquote-splicing (:tag node))) 28 | 29 | (def any-unquote? 30 | "Returns true if the supplied `node` is either of the unquote 31 | forms (`:unquote` or `:unquote-splicing`, false otherwise.)" 32 | (some-fn unquote? unquote-splice?)) 33 | 34 | (def coll-node? 35 | "Returns true if the supplied `node` is a collection, i.e., a list, 36 | vector or map, false otherwise." 37 | (some-fn api/list-node? api/vector-node? api/map-node?)) 38 | 39 | (defn binding-form? 40 | "Returns true if the node references a list of the form `(? ...)`, `(?? ...)` 41 | or `($$ ...)`, false otherwise." 42 | [node] 43 | (and (api/list-node? node) 44 | (#{'? '?? '$$} 45 | (:value 46 | (first (:children node)))))) 47 | 48 | (defn segment-marker? 49 | "Returns true if the supplied node begins a segment binding, false otherwise." 50 | [sym] 51 | (contains? #{'?? '$$} (:value sym))) 52 | 53 | (def match-first 54 | "Given any number of nil-or-result producing functions, returns a 55 | new function (of a single `node`) that will 56 | 57 | - try all functions from left to right on the `node` 58 | - return the first non-nil result encountered." 59 | some-fn) 60 | 61 | (defn match-any 62 | "Given any number of nil-or-result producing functions, returns a new function 63 | of `node` that will produce a nested series of `api/vector-node`s containing 64 | all non-nil results from applying any of the supplied functions to `node`." 65 | ([] (constantly nil)) 66 | ([l] l) 67 | ([l r] 68 | (fn [node] 69 | (let [l' (l node) 70 | r' (r node)] 71 | (if (and l' r') 72 | (api/vector-node [l' r']) 73 | (or l' r'))))) 74 | ([l r & more] 75 | (reduce match-any l (cons r more)))) 76 | 77 | (defn walk-node 78 | "Given a function `f` of a node and some `node`, returns a vector of all nodes 79 | in the syntax tree represented by `node` for which `(f sub-node)` returns a 80 | non-nil result. 81 | 82 | NOTE: The result is an eagerly-evaluated vector, so `f` is permitted to have 83 | side effects. 84 | 85 | NOTE: Use [[match-any]] and [[match-first]] to build up more sophisticated 86 | values of `f`." 87 | [f node] 88 | (let [tree (tree-seq coll-node? :children node) 89 | xform (mapcat (fn [x] 90 | (when-let [result (f x)] 91 | [result])))] 92 | (into [] xform tree))) 93 | 94 | (defn restrictions 95 | "If the supplied node is a [[binding-form?]], emits an `api/vector-node` 96 | containing the restrictions. Else, returns `nil`." 97 | [node] 98 | (when (binding-form? node) 99 | (let [[_ _ & restrictions] (:children node)] 100 | (when (seq restrictions) 101 | (api/vector-node restrictions))))) 102 | 103 | (defn unquotes 104 | "If the supplied node is an [[any-unquote?]], acts as identity. Else, returns 105 | `nil`." 106 | [node] 107 | (when (any-unquote? node) 108 | node)) 109 | 110 | (defn- reg-binding-sym! 111 | "This function is shared between binding and consequence checkers, with 112 | different guards in each case." 113 | [binding] 114 | (api/reg-finding! 115 | (assoc (meta binding) 116 | :message 117 | (str "Binding variable " 118 | (pr-str (api/sexpr binding)) 119 | " must be a non-namespaced symbol or non-symbol form.") 120 | :type :emmy.pattern/binding-sym))) 121 | 122 | (defn lint-binding-form! 123 | "If the supplied `node` is a [[binding-form?]], registers findings for invalid 124 | syntax. 125 | 126 | [[lint-binding-form!]] returns nil for any input." 127 | [node] 128 | (when (binding-form? node) 129 | (let [[_ binding] (:children node)] 130 | (when-not (or (simple-symbol? (:value binding)) 131 | (any-unquote? binding)) 132 | (reg-binding-sym! binding))))) 133 | 134 | (defn pattern-vec 135 | "Given a node representing a pattern form, (and, optionally, a node representing 136 | a predicate function `pred`), returns a vector of all checkable entries in the 137 | pattern. 138 | 139 | These are 140 | 141 | - all unquoted forms 142 | - all restrictions on binding forms 143 | 144 | During the syntax tree walk, [[pattern-vec]] will trigger a side effect of 145 | linting all binding forms it sees using [[lint-binding-form!]]" 146 | ([node] (pattern-vec node nil)) 147 | ([node pred] 148 | (let [f (match-first lint-binding-form! restrictions unquotes) 149 | to-check (walk-node f node)] 150 | (if pred 151 | (conj to-check pred) 152 | to-check)))) 153 | 154 | (defn pattern 155 | "Converts a node representing an invocation of the [[emmy.pattern.rule/pattern]] 156 | macro into a vector-node of all lintable forms. 157 | 158 | As a side effect, registers any issue with binding forms encountered in the 159 | pattern using [[lint-binding-form!]]" 160 | [{:keys [node]}] 161 | (let [[_ form pred] (:children node)] 162 | {:node 163 | (api/vector-node 164 | (pattern-vec form pred))})) 165 | 166 | ;; ### Consequences 167 | ;; 168 | ;; Consequence forms also use `(? ..)` and `(?? ...)` as a way to splice in 169 | ;; matched bindings. Unlike the pattern uses of these, restrictions are NOT 170 | ;; allowed. 171 | 172 | (defn binding-field 173 | "If the supplied node is a [[binding-form?]] and the binding entry is NOT 174 | symbolic, emits the binding node. 175 | 176 | Else, returns `nil`." 177 | [node] 178 | (when (binding-form? node) 179 | (let [[_ binding] (:children node)] 180 | (when-not (symbol? (:value binding)) 181 | binding)))) 182 | 183 | (defn lint-consequence! 184 | "If the supplied `node` is a [[binding-form?]], registers findings for invalid 185 | syntax (interpreting the binding forms as consequence matchers, not patterns). 186 | 187 | [[lint-consequence!]] returns nil for any input." 188 | [node] 189 | (when (binding-form? node) 190 | (let [[_ binding & restrictions] (:children node)] 191 | (when (qualified-symbol? (:value binding)) 192 | (reg-binding-sym! binding)) 193 | (doseq [r restrictions] 194 | (api/reg-finding! 195 | (assoc (meta r) 196 | :message 197 | (str (str "Restrictions are not allowed in consequence bindings: " 198 | (pr-str (api/sexpr r)))) 199 | :type :emmy.pattern/consequence-restriction)))))) 200 | 201 | (defn consequence-vec 202 | "Given a node representing a consequence form, (the right side of a rule), 203 | returns a vector of all checkable entries in the consequence. 204 | 205 | These are 206 | 207 | - all unquoted forms 208 | - any non-symbolic binding field 209 | - any restrictions on binding forms (which are invalid to use here, but still 210 | deserve linting if they are ALSO non-existent or something!) 211 | 212 | During the syntax tree walk, [[consequence-vec]] will trigger a side effect of 213 | linting all binding forms it sees using [[lint-consequence!]]" 214 | [form] 215 | (let [f (match-first 216 | lint-consequence! 217 | (match-any binding-field restrictions) 218 | unquotes)] 219 | (walk-node f form))) 220 | 221 | (defn consequence 222 | "Converts a node representing an invocation of the [[emmy.pattern.rule/consequence]] 223 | macro into a vector-node of all lintable forms. 224 | 225 | As a side effect, registers any issue with binding forms encountered in the 226 | pattern using [[lint-consequence!]]" 227 | [{:keys [node]}] 228 | (let [[_ form] (:children node)] 229 | {:node 230 | (api/vector-node 231 | (consequence-vec form))})) 232 | 233 | (defn template 234 | "Converts a node representing an invocation of the [[emmy.pattern.rule/template]] 235 | macro into a vector-node of all lintable forms. 236 | 237 | These include the optional first argument `m` and anything returned 238 | by `([[consequence-vec]] )`." 239 | [{:keys [node]}] 240 | (let [[_ m-or-form form-or-nil] (:children node)] 241 | {:node 242 | (if form-or-nil 243 | (api/vector-node 244 | (conj (consequence-vec form-or-nil) m-or-form)) 245 | (api/vector-node 246 | (consequence-vec m-or-form)))})) 247 | 248 | (defn- process-rule 249 | "Given the 2- or 3- arguments supplied to the [[emmy.pattern.rule/rule]] macro, 250 | returns an `api/vector-node` of all lintable forms. 251 | 252 | The `pattern` argument is processed using [[pattern-vec]], while the 253 | `skeleton` argument is processed using [[consequence-vec]]. 254 | 255 | The `pred` or `consequent-fn` arguments are presented as fn invocation forms 256 | like `(fn {})` to prevent 'unused fn' warnings." 257 | [args] 258 | (condp = (count args) 259 | 2 (let [[pattern consequent-fn] args] 260 | (api/vector-node 261 | (conj (pattern-vec pattern) 262 | (api/list-node 263 | [consequent-fn (api/map-node {})])))) 264 | 265 | 3 (let [[pattern pred skel] args] 266 | (api/vector-node 267 | (concat 268 | [(api/list-node 269 | [pred (api/map-node {})])] 270 | (pattern-vec pattern) 271 | (consequence-vec skel)))) 272 | 273 | ;; This should never happen. 274 | (throw (ex-info "wrong number of arguments for rule" {})))) 275 | 276 | (defn rule 277 | "Converts a node representing an invocation of the [[emmy.pattern.rule/rule]] macro 278 | into a vector-node of all lintable forms." 279 | [{:keys [node]}] 280 | {:node (process-rule 281 | (rest (:children node)))}) 282 | 283 | (defn ruleset 284 | "Converts a node representing an invocation of the [[emmy.pattern.rule/ruleset]] 285 | macro into a vector-node of all lintable forms." 286 | [{:keys [node]}] 287 | (let [binding-count (dec (count (:children node)))] 288 | (when-not (zero? (mod binding-count 3)) 289 | (api/reg-finding! 290 | (assoc (meta (first (:children node))) 291 | :message 292 | (str "ruleset requires bindings in groups of 3. Received " 293 | binding-count " bindings.") 294 | :type :emmy.emmy.pattern.ruleset-args)))) 295 | (let [inputs (partition 3 (rest (:children node))) 296 | rules (map process-rule inputs)] 297 | {:node (api/vector-node rules)})) 298 | -------------------------------------------------------------------------------- /.clj-kondo/org.mentat/emmy/hooks/emmy/util/def.clj: -------------------------------------------------------------------------------- 1 | (ns hooks.emmy.util.def 2 | (:require [clj-kondo.hooks-api :as api])) 3 | 4 | (defn import-def 5 | "Converts a node representing an invocation of 6 | the [[emmy.util.def/import-def]] macro into a matching `def` call." 7 | [{:keys [node]}] 8 | (let [[_ v sym] (:children node) 9 | sym (or sym (api/token-node 10 | (symbol (name (:value v))))) 11 | new-node (api/list-node 12 | [(api/token-node 'def) 13 | sym v])] 14 | {:node new-node})) 15 | -------------------------------------------------------------------------------- /.clj-kondo/org.mentat/mathbox.cljs/config.edn: -------------------------------------------------------------------------------- 1 | {:hooks 2 | {:analyze-call 3 | {mathbox.macros/defprim 4 | hooks.mathbox.macros/defprim}}} 5 | -------------------------------------------------------------------------------- /.clj-kondo/org.mentat/mathbox.cljs/hooks/mathbox/macros.clj_kondo: -------------------------------------------------------------------------------- 1 | (ns hooks.mathbox.macros 2 | (:require [clj-kondo.hooks-api :as api])) 3 | 4 | (defn ->sym [node] 5 | (update node :value (comp symbol name))) 6 | 7 | (defn defprim 8 | "Converts a node representing an invocation of the [[mathbox.macros/defprim]] 9 | macro into a matching `defn` call." 10 | [{:keys [node]}] 11 | (let [[_ var-to-alias & body] (:children node) 12 | [docstring body] (if (api/string-node? (first body)) 13 | [(first body) (rest body)] 14 | [nil body]) 15 | attrs (when (api/map-node? (first body)) 16 | (first body))] 17 | {:node 18 | (api/list-node 19 | (concat [(api/token-node 'defn) 20 | (->sym var-to-alias)] 21 | (when docstring [docstring]) 22 | (when attrs [attrs]) 23 | [(api/vector-node []) 24 | var-to-alias]))})) 25 | -------------------------------------------------------------------------------- /.clj-kondo/rewrite-clj/rewrite-clj/config.edn: -------------------------------------------------------------------------------- 1 | {:lint-as 2 | {rewrite-clj.zip/subedit-> clojure.core/-> 3 | rewrite-clj.zip/subedit->> clojure.core/->> 4 | rewrite-clj.zip/edit-> clojure.core/-> 5 | rewrite-clj.zip/edit->> clojure.core/->>}} 6 | -------------------------------------------------------------------------------- /.clj-kondo/taoensso/encore/config.edn: -------------------------------------------------------------------------------- 1 | {:hooks {:analyze-call {taoensso.encore/defalias taoensso.encore/defalias}}} 2 | -------------------------------------------------------------------------------- /.clj-kondo/taoensso/encore/taoensso/encore.clj: -------------------------------------------------------------------------------- 1 | (ns taoensso.encore 2 | (:require 3 | [clj-kondo.hooks-api :as hooks])) 4 | 5 | (defn defalias [{:keys [node]}] 6 | (let [[sym-raw src-raw] (rest (:children node)) 7 | src (if src-raw src-raw sym-raw) 8 | sym (if src-raw 9 | sym-raw 10 | (symbol (name (hooks/sexpr src))))] 11 | {:node (with-meta 12 | (hooks/list-node 13 | [(hooks/token-node 'def) 14 | (hooks/token-node (hooks/sexpr sym)) 15 | (hooks/token-node (hooks/sexpr src))]) 16 | (meta src))})) 17 | -------------------------------------------------------------------------------- /.dir-locals.el: -------------------------------------------------------------------------------- 1 | ((nil 2 | . ((cider-default-cljs-repl . node))) 3 | (clojurescript-mode 4 | . ((cider-clojure-cli-aliases . ":nextjournal/clerk"))) 5 | (clojurec-mode 6 | . ((cider-preferred-build-tool . clojure-cli) 7 | (cider-clojure-cli-aliases . ":nextjournal/clerk"))) 8 | (clojure-mode 9 | . ((cider-preferred-build-tool . clojure-cli) 10 | (cider-clojure-cli-aliases . ":nextjournal/clerk")))) 11 | -------------------------------------------------------------------------------- /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | # These are supported funding model platforms 2 | 3 | github: sritchie 4 | -------------------------------------------------------------------------------- /.github/workflows/gh-pages.yml: -------------------------------------------------------------------------------- 1 | name: GitHub Pages 2 | 3 | on: 4 | push: 5 | branches: 6 | - main # Set a branch name to trigger deployment 7 | jobs: 8 | publish: 9 | runs-on: ubuntu-20.04 10 | steps: 11 | - name: Cache Maven packages 12 | uses: actions/cache@v3 13 | with: 14 | path: | 15 | .cpcache 16 | .shadow-cljs 17 | ~/.m2 18 | key: ${{ runner.os }}-m2-${{ hashFiles('**/deps.edn') }} 19 | restore-keys: ${{ runner.os }}-m2 20 | 21 | - name: Checkout 22 | uses: actions/checkout@v3 23 | 24 | - name: Install clojure tools 25 | uses: DeLaGuardo/setup-clojure@master 26 | with: 27 | cli: latest 28 | bb: latest 29 | github-token: ${{ secrets.GITHUB_TOKEN }} 30 | 31 | - name: Build static site 32 | run: bb build-static 33 | 34 | - name: Deploy 35 | uses: peaceiris/actions-gh-pages@v3 36 | if: ${{ github.ref == 'refs/heads/main' }} 37 | with: 38 | github_token: ${{ secrets.GITHUB_TOKEN }} 39 | publish_dir: ./public/build 40 | -------------------------------------------------------------------------------- /.github/workflows/kondo.yml: -------------------------------------------------------------------------------- 1 | name: Linter 2 | 3 | on: 4 | pull_request: 5 | push: 6 | branches: [main] 7 | 8 | jobs: 9 | lint: 10 | runs-on: ubuntu-latest 11 | steps: 12 | - name: Checkout 13 | uses: actions/checkout@v2 14 | 15 | - name: Install Babashka 16 | uses: DeLaGuardo/setup-clojure@10.2 17 | with: 18 | bb: latest 19 | 20 | - name: Cache kondo directory 21 | uses: actions/cache@v2 22 | with: 23 | path: ~/.clj-kondo/.cache 24 | key: ${{ runner.os }}-kondo 25 | restore-keys: ${{ runner.os }}-kondo 26 | 27 | - name: Lint dependencies 28 | run: bb lint-deps 29 | 30 | - name: Lint project files 31 | run: bb lint --config '{:output {:pattern "::{{level}} file={{filename}},line={{row}},col={{col}}::{{message}}"}}' 32 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .calva/output-window/ 2 | .classpath 3 | .clj-kondo/.cache 4 | .clj-kondo/.lock 5 | .clj-kondo/inline-configs 6 | .cpcache 7 | .eastwood 8 | .factorypath 9 | .hg/ 10 | .hgignore 11 | .java-version 12 | .lein-* 13 | .lsp/.cache 14 | .lsp/sqlite.db 15 | .nrepl-history 16 | .nrepl-port 17 | .project 18 | .rebel_readline_history 19 | .settings 20 | .socket-repl-port 21 | .sw* 22 | .vscode 23 | *.class 24 | *.jar 25 | *.swp 26 | *~ 27 | /checkouts 28 | /classes 29 | /target 30 | 31 | pom.xml 32 | !template/pom.xml 33 | pom.xml.asc 34 | *.iml 35 | *.jar 36 | *.log 37 | .shadow-cljs 38 | .idea 39 | .lein-* 40 | .nrepl-* 41 | .DS_Store 42 | 43 | node_modules/ 44 | public/js 45 | .hgignore 46 | .hg/ 47 | .clerk/ 48 | .cache/ 49 | public 50 | ltximg 51 | presentations/reveal.js/examples -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Change Log 2 | 3 | Follow along here for any changes or updates to the essays. 4 | 5 | ## [unreleased] 6 | 7 | - #5 adds the introduction essay and follows up with edits to the tools, FAQ, 8 | index and project README pages. 9 | -------------------------------------------------------------------------------- /DEVELOPING.md: -------------------------------------------------------------------------------- 1 | ## Dev Dependencies 2 | 3 | - [node.js](https://nodejs.org/en/) 4 | - The [Clojure command line tool](https://clojure.org/guides/install_clojure) 5 | - [Babashka](https://github.com/babashka/babashka#installation) 6 | 7 | ## Github Pages, Docs Notebook 8 | 9 | The project's [Github Pages site](https://reality.mentat.org) hosts all essays 10 | in the form of interactive [Clerk](https://github.com/nextjournal/clerk) 11 | notebooks. 12 | 13 | ### Local Development 14 | 15 | Start a Clojure process however you like, and run `(user/serve!)` to run the 16 | Clerk server. This command should open up `localhost:7777`. 17 | 18 | Alternatively, run 19 | 20 | ```sh 21 | bb clerk-watch 22 | ``` 23 | 24 | ### Static Build 25 | 26 | To test the static build locally: 27 | 28 | ``` 29 | bb publish-local 30 | ``` 31 | 32 | This will generate the static site in `public/build`, start a development http 33 | server and open up a browser window (http://127.0.0.1:8080/) with the production 34 | build of the essays 35 | 36 | ### GitHub Pages 37 | 38 | To build and release to Github Pages: 39 | 40 | ``` 41 | bb release-gh-pages 42 | ``` 43 | 44 | This will ship the site to https://reality.mentat.org. 45 | 46 | ## Linting 47 | 48 | Essays and supporting code are linted with 49 | [`clj-kondo`](https://github.com/clj-kondo/clj-kondo): 50 | 51 | ``` 52 | bb lint 53 | ``` 54 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2022-2023 Sam Ritchie 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | [![Substack][substack]][substack-url] 2 | [![Discord Shield][discord]][discord-url] 3 | [![License][license]][license-url] 4 | 5 | # Road to Reality Essays 6 | 7 | Welcome to the Road to Reality! 8 | 9 | The Road to Reality is an essay series by me, [Sam 10 | Ritchie](https://samritchie.io). Starting with the basics of Lisp (the 11 | [Clojure](https://clojure.org) programming language, specifically), we'll build 12 | a modern computer algebra system and use that system to explore and simulate 13 | gems of modern physics like variational mechanics and general relativity. 14 | 15 | The only way to really learn how a machine works is to build one yourself. By 16 | the time we're through, you'll understand modern physics with the intuitive ease 17 | of a mechanic debugging the drivetrain of a familiar car. You will have _built 18 | the car_, and will be able to drive the car with confidence into the strange 19 | country of quantum mechanics, general relativity, chaos theory and phase space. 20 | 21 | The essays live at https://reality.mentat.org. Get started reading at the 22 | [Introduction](https://reality.mentat.org/essays/reality/introduction). 23 | 24 | I publish updates on the essays in the ["Road to Reality" Substack 25 | newsletter][substack-url]. Please subscribe at 26 | https://roadtoreality.substack.com. 27 | 28 | ## How can I help? 29 | 30 | The Road to Reality essays are part of my larger attempt to build a system for 31 | writing and publishing [executable 32 | textbooks](https://roadtoreality.substack.com/p/the-dynamic-notebook). If you 33 | find any of this inspiring or interesting, you can: 34 | 35 | - Subscribe to the newsletter: [![Substack][substack]][substack-url] 36 | - Join the Discord community: [![Discord Shield][discord]][discord-url] 37 | - Send me a note at [sam@mentat.org](mailto:sam@mentat.org). 38 | 39 | Please consider sponsoring the effort via [Github 40 | Sponsors](https://github.com/sponsors/sritchie), or by signing up for a paid 41 | subscription to the ["Road to Reality" Substack][substack-url]. 42 | 43 | The _best_ thing you can do is riff on and share the essays, and to the extent 44 | that you find them inspiring, use them to teach someone else. 45 | 46 | ## How do I read the essays? 47 | 48 | There are currently two ways to read the essays: 49 | 50 | - Read the static output at https://reality.mentat.org 51 | - Run them as a program, and edit and play along as you read! 52 | 53 | I strongly believe that work like this should be read in the same environment 54 | that I used while writing. You can read a paper book with pen in hand, mark it 55 | up and take margin notes; why not do the same with these executable essays? 56 | 57 | Each essay is backed by a source code file written in the Clojure programming 58 | language. I hope you'll pay the small up-front cost of setting up your computer 59 | and downloading the essays (described in the ["Running the 60 | Essays"](#running--editing-the-essays) section). 61 | 62 | The environment has the beautiful property that if you (you!!) change the source 63 | code, the entire essay will re-render and incorporate your changes. 64 | 65 | So as you read, if you become curious about what a simulation would look like 66 | with different initial conditions, or how a satellite might behave if you change 67 | its orbit... or if you want to hijack an essay completely and turn it into a 68 | programmable calculator, you can do that! 69 | 70 | These essays are successful only to the extent that you feel empowered to edit 71 | and fiddle with them, and maybe even use the tools to explore and learn on your 72 | own. 73 | 74 | ## Why are you writing these? 75 | 76 | My work on this project stemmed from my own frustration at the one-way nature of 77 | the way I was studying math and physics. When I read books like Sussman and 78 | Wisdom's ["Structure and Interpretation of Classical Mechanics"][sicm-book-url], 79 | I felt like I was building new machinery inside my head that let me see new 80 | patterns in the world that I hadn't been able to see before. 81 | 82 | I wanted to share what I'd learned, but the only language available was 83 | symbol-heavy and inscrutable to my friends. I couldn't show anyone what I could 84 | now see in my head. 85 | 86 | My work on the [Emmy computer algebra system](https://emmy.mentat.org) and the 87 | other projects [described on the "Tools" 88 | page](https://reality.mentat.org/essays/reality/tools) is my attempt to make 89 | tangible and accessible some of the discoveries and progression that humans have 90 | achieved in math and physics over the last 2,000 years in a way that feels less 91 | like torture and more like exploring a beautiful, strange series of simulations 92 | and video games. 93 | 94 | Put more simply: An executable Wikipedia / Digital Museum full of interactive 95 | simulations demonstrating our best understanding of the rules reality follows 96 | _should exist_. No one else seemed to be building it, so I decided to start 97 | poking around. 98 | 99 | # Running / Editing the Essays 100 | 101 | To run the essays, you'll need to complete the following steps: 102 | 103 | - Download the essays to your computer 104 | - Set up your computer to run the essays 105 | - Choose a programming "text editor" that you'll use to edit the files 106 | - Run the program that builds the essays.... 107 | - Play! 108 | 109 | if you get stuck at any point, [write up where you're stuck on this 110 | form](https://github.com/mentat-collective/road-to-reality/issues/new) and I'll 111 | help you get going. 112 | 113 | > **Note** 114 | > 115 | > I know that this is a fairly annoying sequence of steps! I will simplify this 116 | > process over time. Eventually you'll be able to read and edit the essays fully 117 | > in the browser at https://reality.mentat.org. This is where we are now, not 118 | > where we'll end up. 119 | 120 | ## Download the Essays 121 | 122 | Open your terminal and run the following commands: 123 | 124 | ```sh 125 | cd ~/Documents # or pick your location 126 | git clone git@github.com:mentat-collective/road-to-reality.git 127 | cd road-to-reality 128 | ``` 129 | 130 | The essays live inside of the `essays` folder. 131 | 132 | > If you don't know what this means, install [GitHub 133 | > Desktop](https://desktop.github.com/), create an account or sign in, and 134 | > choose "Clone a Repository from the Internet". Type the phrase "mentat road", 135 | > select the first item in the list and click "Clone". 136 | 137 | ## Dependencies 138 | 139 | Install the following dependencies (follow the hyperlinks for install 140 | instructions): 141 | 142 | - [Java](https://practical.li/clojure/install/java/) 143 | - [Clojure CLI tools](https://clojure.org/guides/install_clojure) 144 | - [`babashka`](https://github.com/babashka/babashka#installation) 145 | 146 | You'll also need `node` installed, preferably via 147 | [`nvm`](https://github.com/nvm-sh/nvm#installing-and-updating). 148 | 149 | Now, in the `road-to-reality` directory you entered above, run the following 150 | command to check your installation and see all of the [Babashka 151 | Tasks](https://book.babashka.org/#tasks) declared in the `bb.edn` file: 152 | 153 | ```sh 154 | bb tasks 155 | ``` 156 | 157 | ## Choosing an Editor 158 | 159 | The essays are rendered using the [Clerk][clerk-url] notebook system. 160 | 161 | [Clerk][clerk-url] is a program that watches Clojure source code files and 162 | renders them in a browser window. To use this workflow you'll need to choose 163 | your own text editor to edit these source files. 164 | 165 | Here are links to guides for the most popular editors and Clojure plugins: 166 | 167 | - [Calva](https://calva.io/jack-in-guide/) for [Visual Studio 168 | Code](https://code.visualstudio.com/) (use this if you're not sure!) 169 | - [Cider](https://docs.cider.mx/cider/basics/up_and_running.html#launch-an-nrepl-server-from-emacs) for [Emacs](https://www.gnu.org/software/emacs/) 170 | - [Cursive](https://cursive-ide.com/userguide/repl.html) for [Intellij IDEA](https://www.jetbrains.com/idea/download/#section=mac) 171 | - [Clojure-Vim](https://github.com/clojure-vim/vim-jack-in) for [Vim](https://www.vim.org/) and [Neovim](https://neovim.io/) 172 | 173 | > If this is your first time using Clojure, I recommend 174 | > [Calva](https://calva.io/jack-in-guide/) for [Visual Studio 175 | > Code](https://code.visualstudio.com/). 176 | 177 | Once you've chosen an editor, open the `road-to-reality` project in the editor 178 | and navigate to the `essays/reality/introduction.clj` file. 179 | 180 | ## Editing the Essays 181 | 182 | Back at your terminal, run the following command: 183 | 184 | ``` 185 | bb clerk-watch 186 | ``` 187 | 188 | Eventually a browser window will appear, pointing to http://localhost:7777. If 189 | you close the window by accident this link will get you back to the essay view. 190 | 191 | Now edit any line in `introduction.clj` -- maybe add an exclamation point 192 | somewhere? -- and save the file. If the browser display updates to the 193 | introduction essay with your change, you're now in business! Read in the browser 194 | pane, and edit any example you find in the essays. A simple edit-and-save should 195 | cause everything to update. 196 | 197 | ## REPL-Based Exploration 198 | 199 | Alternatively, instead of `bb clerk-watch` follow your editor's instructions 200 | (see ["Choosing an Editor"](#choosing-an-editor) above) to start a Clojure REPL, 201 | and then run `(user/serve!)`. 202 | 203 | Running the essays this way will let you use the Clojure REPL to explore. 204 | 205 | To show or reload a particular notebook, call `nextjournal.clerk/show!` with the 206 | file's path as argument. The [Book of Clerk](https://book.clerk.vision) has 207 | [good instructions on how to configure your editor for 208 | this](https://book.clerk.vision/#editor-integration). 209 | 210 | You can try this without any editor support by starting a REPL from the command 211 | line: 212 | 213 | ```sh 214 | bb repl 215 | ``` 216 | 217 | Then start the server: 218 | 219 | ```clj 220 | (user/serve!) 221 | ``` 222 | 223 | To show a file, pass it to `clerk/show!`: 224 | 225 | ```clj 226 | (nextjournal.clerk/show! "essays/reality/introduction.md") 227 | ``` 228 | 229 | ## License 230 | 231 | Copyright © 2022-2023 Sam Ritchie. 232 | 233 | Distributed under the [MIT License](LICENSE). See [LICENSE](LICENSE). 234 | 235 | [clerk-url]: https://clerk.vision 236 | [discord-url]: https://discord.gg/hsRBqGEeQ4 237 | [discord]: https://img.shields.io/discord/731131562002743336?style=flat&colorA=000000&colorB=000000&label=&logo=discord 238 | [emmy-slack-url]: https://clojurians.slack.com/archives/C01ECA9AA74 239 | [fdg-book-url]: https://mitpress.mit.edu/9780262019347/functional-differential-geometry/ 240 | [license-url]: LICENSE 241 | [license]: https://img.shields.io/badge/license-MIT-brightgreen.svg 242 | [physics-in-clj-talk-url]: https://www.youtube.com/watch?v=7PoajCqNKpg 243 | [refman-url]: https://cljdoc.org/d/org.mentat/emmy/CURRENT/doc/reference-manual 244 | [substack-url]: https://roadtoreality.substack.com 245 | [substack]: https://img.shields.io/badge/Substack-%23006f5c.svg?style=flat&logo=substack&logoColor=FF6719 246 | [scmutils-refman-url]: https://groups.csail.mit.edu/mac/users/gjs/6946/refman.txt 247 | [sicm-book-url]: https://mitpress.mit.edu/9780262028967/structure-and-interpretation-of-classical-mechanics 248 | [sicp-book-url]: https://mitpress.mit.edu/9780262510875/structure-and-interpretation-of-computer-programs 249 | -------------------------------------------------------------------------------- /bb.edn: -------------------------------------------------------------------------------- 1 | {:deps {org.babashka/http-server {:mvn/version "0.1.11"} 2 | org.babashka/cli {:mvn/version "0.2.23"} 3 | io.github.clj-kondo/clj-kondo-bb 4 | {:git/tag "v2023.01.20" :git/sha "adfc7df"}} 5 | :tasks 6 | {:requires ([babashka.cli :as cli]) 7 | :init 8 | (do (def cli-opts 9 | (cli/parse-opts *command-line-args* {:coerce {:port :int}})) 10 | 11 | (defn X [cmd] 12 | (let [args *command-line-args*] 13 | (if (even? (count args)) 14 | (apply shell cmd args) 15 | (do (println "Please supply an even number of arguments!") 16 | (System/exit 1)))))) 17 | 18 | repl 19 | {:doc "Start a repl with the `emmy.env` (or the supplied namespace) loaded." 20 | :task (let [namespace (or (first *command-line-args*) "emmy.env") 21 | init (str "(do" 22 | (format "(require '%s) (in-ns '%s)" 23 | namespace namespace) 24 | "(println \"Clojure\" (clojure-version))" 25 | ")")] 26 | (shell "clj -M:nextjournal/clerk" "-e" init "-r"))} 27 | 28 | clerk-watch 29 | {:doc "Runs `user/serve!` with a watcher process generating custom JS." 30 | :task (X "clojure -X:nextjournal/clerk user/serve!")} 31 | 32 | build-static 33 | {:doc "Generate a fresh static build." 34 | :task 35 | (apply shell 36 | "clojure -X:nextjournal/clerk" 37 | *command-line-args*)} 38 | 39 | serve 40 | {:doc "Serve static assets" 41 | :requires ([babashka.http-server :as server]) 42 | :task (server/exec 43 | (merge {:port 8080 44 | :dir "public/build"} 45 | cli-opts))} 46 | 47 | release-gh-pages 48 | {:doc "Generate a fresh static build and release it to Github Pages." 49 | :task 50 | (do (shell "rm -rf public/build") 51 | (run 'build-static) 52 | (shell "npm run gh-pages"))} 53 | 54 | publish-local 55 | {:doc "Generate a fresh static build and start a local webserver." 56 | :task 57 | (do (run 'build-static) 58 | (run 'serve))} 59 | 60 | lint-deps 61 | {:requires ([clj-kondo.core :as kondo]) 62 | :doc "Lint dependencies." 63 | :task (kondo/run! 64 | {:lint [(with-out-str 65 | (babashka.tasks/clojure 66 | "-Spath -A:nextjournal/clerk"))] 67 | :dependencies true})} 68 | 69 | lint 70 | {:doc "Lint with clj-kondo." 71 | :task (exec 'clj-kondo.core/exec) 72 | :exec-args {:lint ["src" "dev" "essays"]}}}} 73 | -------------------------------------------------------------------------------- /deps.edn: -------------------------------------------------------------------------------- 1 | {:paths ["src" "dev" "essays"] 2 | :deps {org.clojure/clojure {:mvn/version "1.11.1"} 3 | io.github.nextjournal/clerk 4 | {:git/sha "4329fa31b75bf26c04bdcc803a52fe642baec56e"} 5 | 6 | io.github.mentat-collective/emmy-viewers 7 | {:git/sha "0ae1d00133cc49fcd6a32363abaf3cf0c7a71f06" 8 | ;; This is required because Clerk specifies SCI using a 9 | ;; git dependency and `clojure` can't resolve the 10 | ;; conflict. 11 | :exclusions [org.babashka/sci org.mentat/emmy]} 12 | 13 | org.mentat/emmy {:mvn/version "0.31.0-SNAPSHOT" 14 | :exclusions [org.babashka/sci]} 15 | 16 | io.github.mentat-collective/clerk-utils 17 | {:git/sha "a508ab01d0fb04a44c0a6a1dd510207b2ca7135e"}} 18 | 19 | :aliases 20 | {:nextjournal/clerk 21 | {:extra-deps 22 | {io.github.nextjournal/clerk.render 23 | {:git/url "https://github.com/nextjournal/clerk" 24 | ;; make sure this sha matches the one in `:deps` above. 25 | :git/sha "4329fa31b75bf26c04bdcc803a52fe642baec56e" 26 | :deps/root "render"}} 27 | :exec-fn user/build!} 28 | 29 | :repl 30 | {:main-opts 31 | ["-e" 32 | "(do (require 'emmy.env) (in-ns 'emmy.env) (println \"Clojure\" (clojure-version)))" 33 | "-r"]}}} 34 | -------------------------------------------------------------------------------- /dev/user.clj: -------------------------------------------------------------------------------- 1 | (ns user 2 | (:require [mentat.clerk-utils.build :as b] 3 | [mentat.clerk-utils.css :as css] 4 | [nextjournal.clerk.config :as cc])) 5 | 6 | (try (requiring-resolve 'cljs.analyzer.api/ns-resolve) (catch Exception _ nil)) 7 | (require '[emmy.env]) 8 | (require '[emmy.expression.render :as xr]) 9 | 10 | (alter-var-root 11 | #'xr/*TeX-vertical-down-tuples* 12 | (constantly true)) 13 | 14 | (alter-var-root 15 | #'cc/*bounded-count-limit* 16 | (constantly 2)) 17 | 18 | (css/set-css! 19 | ;; mafs 20 | "https://unpkg.com/computer-modern@0.1.2/cmu-serif.css" 21 | "https://unpkg.com/mafs@0.15.2/core.css" 22 | "https://unpkg.com/mafs@0.15.2/font.css" 23 | 24 | ;; JSXGraph 25 | "https://cdn.jsdelivr.net/npm/jsxgraph@1.5.0/distrib/jsxgraph.css" 26 | 27 | ;; mathbox 28 | "https://unpkg.com/mathbox@2.3.1/build/mathbox.css" 29 | 30 | ;; mathlive 31 | "https://unpkg.com/mathlive@0.85.1/dist/mathlive-static.css" 32 | "https://unpkg.com/mathlive@0.85.1/dist/mathlive-fonts.css") 33 | 34 | (def index 35 | "essays/reality/index.clj") 36 | 37 | (def defaults 38 | {:index index 39 | :cljs-namespaces '[reality.sci-extensions]}) 40 | 41 | (def serve-defaults 42 | (assoc defaults 43 | :port 7777 44 | :watch-paths ["essays"] 45 | :browse? true)) 46 | 47 | (def static-defaults 48 | (assoc defaults 49 | :browse? false 50 | :paths ["essays/**.clj" "essays/**.cljc" "essays/**.md"] 51 | :cname "reality.mentat.org" 52 | :git/url "https://github.com/mentat-collective/road-to-reality")) 53 | 54 | (defn serve! 55 | "Alias of [[mentat.clerk-utils.build/serve!]] with [[defaults]] supplied as 56 | default arguments. 57 | 58 | Any supplied `opts` overrides the defaults." 59 | ([] (serve! {})) 60 | ([opts] 61 | (b/serve! 62 | (merge serve-defaults opts)))) 63 | 64 | (def ^{:doc "Alias for [[mentat.clerk-utils.build/halt!]]."} 65 | halt! 66 | b/halt!) 67 | 68 | (defn build! 69 | "Alias of [[mentat.clerk-utils.build/build!]] with [[static-defaults]] supplied 70 | as default arguments. 71 | 72 | Any supplied `opts` overrides the defaults." 73 | [opts] 74 | (b/build! 75 | (merge static-defaults opts))) 76 | -------------------------------------------------------------------------------- /essays/reality/faq.md: -------------------------------------------------------------------------------- 1 | 2 | # Road to Reality FAQ 3 | 4 | - [How can I help?](#how-can-i-help) 5 | - [How do I read the essays?](#how-do-i-read-the-essays) 6 | - [Why are you writing these?](#why-are-you-writing-these) 7 | 8 | 9 | 10 | ## How can I help? 11 | 12 | The Road to Reality essays are part of my larger attempt to build a system for 13 | writing and publishing [executable 14 | textbooks](https://roadtoreality.substack.com/p/the-dynamic-notebook). If you 15 | find any of this inspiring or interesting, you can: 16 | 17 | - Subscribe to the newsletter: [![Substack][substack]][substack-url] 18 | - Join the Discord community: [![Discord Shield][discord]][discord-url] 19 | - Send me a note at [sam@mentat.org](mailto:sam@mentat.org). 20 | 21 | Please consider sponsoring the effort via [Github 22 | Sponsors](https://github.com/sponsors/sritchie), or by signing up for a paid 23 | subscription to the ["Road to Reality" Substack][substack-url]. 24 | 25 | The _best_ thing you can do is riff on and share the essays, and to the extent 26 | that you find them inspiring, use them to teach someone else. 27 | 28 | ## How do I read the essays? 29 | 30 | There are currently two ways to read the essays: 31 | 32 | - Read the static output at https://reality.mentat.org 33 | - Run them as a program, and edit and play along as you read! 34 | 35 | The instructions for running the essays live at the [project's GitHub 36 | page][edit-essays-url]. 37 | 38 | I strongly believe that work like this should be read in the same environment 39 | that I used while writing. You can read a paper book with pen in hand, mark it 40 | up and take margin notes; why not do the same with these executable essays? 41 | 42 | Each essay is backed by a source code file written in the Clojure programming 43 | language. I hope you'll pay the small up-front cost of setting up your computer 44 | and downloading the essays (described in the ["Running the 45 | Essays"][edit-essays-url] section). 46 | 47 | The environment has the beautiful property that if you (you!!) change the source 48 | code, the entire essay will re-render and incorporate your changes. 49 | 50 | So as you read, if you become curious about what a simulation would look like 51 | with different initial conditions, or how a satellite might behave if you change 52 | its orbit... or if you want to hijack an essay completely and turn it into a 53 | programmable calculator, you can do that! 54 | 55 | These essays are successful only to the extent that you feel empowered to edit 56 | and fiddle with them, and maybe even use the tools to explore and learn on your 57 | own. 58 | 59 | ## Why are you writing these? 60 | 61 | My work on this project stemmed from my own frustration at the one-way nature of 62 | the way I was studying math and physics. When I read books like Sussman and 63 | Wisdom's ["Structure and Interpretation of Classical Mechanics"][sicm-book-url], 64 | I felt like I was building new machinery inside my head that let me see new 65 | patterns in the world that I hadn't been able to see before. 66 | 67 | I wanted to share what I'd learned, but the only language available was 68 | symbol-heavy and inscrutable to my friends. I couldn't show anyone what I could 69 | now see in my head. 70 | 71 | My work on the [Emmy computer algebra system](https://emmy.mentat.org) and the 72 | other projects [described on the "Tools" 73 | page](https://reality.mentat.org/essays/reality/tools) is my attempt to make 74 | tangible and accessible some of the discoveries and progression that humans have 75 | achieved in math and physics over the last 2,000 years in a way that feels less 76 | like torture and more like exploring a beautiful, strange series of simulations 77 | and video games. 78 | 79 | Put more simply: An executable Wikipedia / Digital Museum full of interactive 80 | simulations demonstrating our best understanding of the rules reality follows 81 | _should exist_. No one else seemed to be building it, so I decided to start 82 | poking around. 83 | 84 | [clerk-url]: https://clerk.vision 85 | [edit-essays-url]: https://github.com/mentat-collective/road-to-reality#running--editing-the-essays 86 | [discord-url]: https://discord.gg/hsRBqGEeQ4 87 | [discord]: https://img.shields.io/discord/731131562002743336?style=flat&colorA=000000&colorB=000000&label=&logo=discord 88 | [substack-url]: https://roadtoreality.substack.com 89 | [substack]: https://img.shields.io/badge/Substack-%23006f5c.svg?style=flat&logo=substack&logoColor=FF6719 90 | [sicm-book-url]: https://mitpress.mit.edu/9780262028967/structure-and-interpretation-of-classical-mechanics 91 | -------------------------------------------------------------------------------- /essays/reality/index.clj: -------------------------------------------------------------------------------- 1 | ^{:nextjournal.clerk/visibility 2 | {:code :hide}} 3 | (ns reality.index 4 | {:nextjournal.clerk/toc true} 5 | (:require [reality.viewer :as rv] 6 | [nextjournal.clerk :as clerk])) 7 | 8 | ;; # Road to Reality Essays 9 | 10 | ;; Welcome to the Road to Reality! 11 | 12 | ;; The Road to Reality is an essay series by me, [Sam 13 | ;; Ritchie](https://samritchie.io). The essays live at 14 | ;; [reality.mentat.org](https://reality.mentat.org). 15 | 16 | ;; Get started reading at the [Introduction](essays/reality/introduction). 17 | 18 | ;; Over the course of the series, you are going to build a workshop full of the 19 | ;; tools required to create and explore simulated worlds that behave like our 20 | ;; most advanced models of reality. 21 | 22 | ;; Each tool in the workshop will take the form of a program written in the Lisp 23 | ;; programming language[^clojure]. 24 | 25 | ;; [^clojure]: More precisely, in a dialect of Lisp called 26 | ;; [Clojure](https://clojure.org/). 27 | 28 | ;; The only way to really learn how a machine works is to build one yourself. By 29 | ;; the time we're through, you'll understand modern physics with the intuitive ease 30 | ;; of a mechanic debugging the drivetrain of a familiar car. You will have _built 31 | ;; the car_, and will be able to drive the car with confidence into the strange 32 | ;; country of quantum mechanics, general relativity, chaos theory and phase space. 33 | ;; 34 | 35 | 36 | ;; I publish updates on the essays at the ["Road to Reality" Substack 37 | ;; newsletter](https://roadtoreality.substack.com). Please subscribe: 38 | 39 | ^{::clerk/visibility {:code :hide}} 40 | (rv/substack) 41 | ;; 42 | ;; ## Essay Index 43 | ;; 44 | ;; 1. [Introduction](essays/reality/introduction) 45 | ;; 46 | ;; ## Appendices 47 | ;; 48 | ;; - [FAQ](essays/reality/faq) 49 | ;; - [Tools](essays/reality/tools) 50 | 51 | ;; ## License 52 | 53 | ;; Copyright © 2023 Sam Ritchie. 54 | 55 | ;; Distributed under the [MIT 56 | ;; License](https://github.com/mentat-collective/road-to-reality/LICENSE). 57 | ;; See [LICENSE](https://github.com/mentat-collective/road-to-reality/LICENSE). 58 | -------------------------------------------------------------------------------- /essays/reality/introduction.md: -------------------------------------------------------------------------------- 1 | ```clojure 2 | ^{:nextjournal.clerk/visibility {:code :hide}} 3 | (ns reality.introduction 4 | "The first essay in the Road to Reality series." 5 | {:nextjournal.clerk/toc true} 6 | (:refer-clojure 7 | :exclude [+ - * / zero? compare divide numerator denominator 8 | infinite? abs ref partial =]) 9 | (:require [emmy.env :refer :all] 10 | [emmy.mafs :as plot] 11 | [emmy.viewer :as ev :refer [with-let]] 12 | [mentat.clerk-utils.viewers :refer [q]] 13 | [nextjournal.clerk :as clerk] 14 | [reality.toroid :as toroid] 15 | [reality.viewer :as rv])) 16 | 17 | ^{::clerk/visibility {:code :hide :result :hide}} 18 | (rv/install!) 19 | ``` 20 | 21 | ```clojure 22 | #_" If you're reading this, you've figured out how to run and read this essay 23 | from its source code. Welcome! 24 | 25 | Clerk supports files written in Markdown format (ending in `.md`) or Clojure 26 | format (ending in `.clj`.) 27 | 28 | This particular essay is written in Markdown. If you want to add new code forms 29 | for Clerk to evaluate, you'll need to surround them in a code fence of triple 30 | backticks like the one surrounding this string. 31 | 32 | I did this because this particular essay is so prose-heavy! In `.clj` essays you 33 | can drop code anywhere you like and Clerk will evaluate it and splice in 34 | results. 35 | " 36 | ``` 37 | 38 | # Introduction 39 | 40 | ## Welcome to the Road to Reality! 41 | 42 | Over the course of this essay series, you are going to build a workshop full of 43 | the tools required to create and explore simulated worlds that behave like our 44 | most advanced models of reality. 45 | 46 | Each tool in the workshop will take the form of a program written in the Lisp 47 | programming language[^clojure]; accordingly, you will learn how to read and 48 | write Lisp code as a side-effect of our journey together. Lisp is one of our 49 | oldest programming languages. The entire language definition fits on half a 50 | sheet of paper[^lisp]. Out of this small set of fundamentals you will learn to 51 | describe our universe. 52 | 53 | The only way to really learn how a machine works is to build one yourself. By 54 | the time we're through, you'll understand modern physics with the intuitive ease 55 | of a mechanic debugging the drivetrain of a familiar car. You will have _built 56 | the car_, and will be able to drive the car with confidence into the strange 57 | country of quantum mechanics, general relativity, chaos theory and phase space. 58 | 59 | [^clojure]: More precisely, in a dialect of Lisp called 60 | [Clojure](https://clojure.org/). 61 | 62 | [^lisp]: See Michael Nielsen's lovely essay [_Lisp as the Maxwell’s equations of 63 | software_](https://michaelnielsen.org/ddi/lisp-as-the-maxwells-equations-of-software/). 64 | 65 | ## Physics as Discovery 66 | 67 | The tools you'll build are the tools of modern physics, and the story of their 68 | design is the story of thousands of years of difficult, creative, intense work 69 | by some of the most visionary humans that have lived. The idea that the points 70 | of light we see in the night sky move according to some predictable pattern 71 | — or that these are the same patterns that describe the planets' motion 72 | around the sun, or a lobbed baseball's arc — is outrageous. But it seems 73 | to be true! 74 | 75 | In fact there doesn't seem to be anything going on in the universe that 76 | _doesn't_ follow some predictable pattern, or law. The tooth-and-nail fight to 77 | figure out these patterns led to the invention of mathematics and science. Of 78 | course, once humans figured out that nature acted according to patterns, we 79 | began to figure out ways to control nature, bringing the disciplines of 80 | engineering into the story. 81 | 82 | Our knowledge of how reality unfolds is written in the language of mathematics, 83 | in equations like this one[^euler]: 84 | 85 | $$D\left(\partial_{2} L \circ \Gamma[q]\right)- \partial_{1} L \circ \Gamma[q] = 0$$ 86 | 87 | [^euler]: The [Euler-Lagrange 88 | equations](https://tgvaughan.github.io/sicm/chapter001.html#h1-6), written 89 | in functional notation. 90 | 91 | This line of text expresses a profound statement about the thrifty way that 92 | physical systems evolve, spending as little as possible of the difference 93 | between the system's kinetic and potential energy as time ticks forward.[^action] 94 | 95 | [^action]: This idea is called the "Principle of Least Action". 96 | 97 | Most of us (myself included) look at this line of text and can't visualize 98 | anything at all! If you're not one of the tiny number of people that have 99 | learned to interpret these symbols, this barrier deprives you of the ability to 100 | understand the details of this grand human story, let alone contribute to its 101 | next chapters. 102 | 103 | We can do better. Take an example of a system that's easy to visualize[^irons]: 104 | a particle attached to the surface of a donut, moving along and pulled into a 105 | bending path by the donut's curves. You might imagine some pattern like this: 106 | 107 | [^irons]: Image from [_"Geodesics of the 108 | Torus"_](http://www.rdrop.com/~half/math/torus/geodesics.xhtml), by Mark 109 | Irons. 110 | 111 | ```clojure 112 | ^{::clerk/visibility {:code :hide}} 113 | (clerk/image 114 | "http://www.rdrop.com/~half/math/torus/period.1.unbounded.5-loop.geodesic.png") 115 | ``` 116 | 117 | Here are the system's equations of motion. To describe the actual path the 118 | particle will take, when you plug in the various distances and angles, both of 119 | these equations must come out to zero at every moment in time: 120 | 121 | ```clojure 122 | ^{::clerk/visibility {:code :fold} 123 | ::clerk/width :full} 124 | 125 | (let [L (toroid/L-toroidal 'R 'r) 126 | theta (literal-function 'theta) 127 | phi (literal-function 'phi)] 128 | (simplify 129 | (((Lagrange-equations L) (up theta phi)) 130 | 't))) 131 | ``` 132 | 133 | I don't see anything in my head when I look at these equations. But! I generated 134 | the equations using a program, and your computer will happily use them to 135 | animate a little microworld. This simulation shows the bead rolling around with 136 | its future path projected ahead of it: 137 | 138 | ```clojure 139 | ^{::clerk/viewer toroid/geodesic-viewer 140 | ::clerk/width :full 141 | ::clerk/visibility {:code :hide}} 142 | (let [R 2 143 | r 0.5] 144 | ;; If you're reading the source code, forgive me... I only recently figured 145 | ;; out how to write_simulations like this in a nice-to-edit way! I'm cheating 146 | ;; to get this first essay out. I'll come back and turn this into a foldable 147 | ;; code block, so that it's easy to play around and explore. 148 | {:params {:R R :r r} 149 | :schema 150 | {:R {:min 0.5 :max 2 :step 0.01} 151 | :r {:min 0.5 :max 2 :step 0.01}} 152 | :keys [:R :r] 153 | :state->xyz toroid/toroidal->rect 154 | :L toroid/L-toroidal 155 | :initial-state [0 [0 0] [6 1]] 156 | :cartesian 157 | {:range [[-10 10] 158 | [-10 10] 159 | [-10 10]] 160 | :scale [3 3 3]}}) 161 | ``` 162 | 163 | Now we have something tangible to play with[^future]. In a future essay we'll 164 | add controls for modifying the shape of the torus and firing the bead off at 165 | different starting angles. There are wild patterns lurking in simple systems. 166 | 167 | [^future]: Drag the camera around with your mouse or finger and zoom in and out. 168 | You'll see this example again in more interactive style. 169 | 170 | ## Executing the Essays 171 | 172 | To build the tools covered in the series, you'll need to set up your computer 173 | with the same environment that I used to write the essays. 174 | 175 | To do this, follow the instructions at the [Road to Reality GitHub 176 | repository](https://github.com/mentat-collective/road-to-reality#running--editing-the-essays). 177 | As I say in that guide, if you get stuck at any point, [write up where you're 178 | stuck using this 179 | form](https://github.com/mentat-collective/road-to-reality/issues/new) and I'll 180 | help you get going. 181 | 182 | Each of the essays is a _program_, written as a mix of prose and Clojure 183 | code[^code] forms. 184 | 185 | [^code]: This essay's source code [lives 186 | here](https://github.com/mentat-collective/road-to-reality/blob/main/essays/reality/introduction.md). 187 | 188 | Another program called [Clerk](https://clerk.vision/) executes this 189 | essay-program each time I save the file and renders the changes to the 190 | http://localhost:7777 in my browser. 191 | 192 | Clerk treats prose and comments as 193 | [Markdown](https://www.markdownguide.org/basic-syntax) and formats output 194 | accordingly. 195 | 196 | When Clerk encounters a Clojure expression, it evaluates the expression and 197 | displays the result below the expression that produced it. For example, this 198 | expression should evaluate to 6[^evaluate]: 199 | 200 | [^evaluate]: See the [Tools](/essays/reality/tools#clojure) page to understand 201 | why. 202 | 203 | ```clojure 204 | (+ 1 2 3) 205 | ``` 206 | 207 | Clerk's superpower is that it is _moldable_. We can teach Clerk to render 208 | different kinds of expressions using any visualization that the browser can 209 | handle. 210 | 211 | ### Emmy 212 | 213 | Every notebook has access to the powerful 214 | [Emmy](https://github.com/mentat-collective/emmy) computer algebra system. Emmy 215 | extends Clojure with all of the abilities and tools required to run advanced 216 | physics simulations. 217 | 218 | I can write math by adding together Clojure's symbols instead of numbers, and 219 | Clerk will print the result as beautiful $\LaTeX$: 220 | 221 | ```clojure 222 | (+ 'x 'y) 223 | ``` 224 | 225 | In a more advanced example, I can add new functions, or programmer's verbs, to 226 | the environment: 227 | 228 | ```clojure 229 | (defn f [x] 230 | (+ (* 1/120 (expt x 5)) 231 | (* -1/6 (expt x 3)) 232 | x)) 233 | ``` 234 | 235 | Here is the result of calling `f` with symbol `'x`, rendered in mathematical 236 | notation: 237 | 238 | ```clojure 239 | (f 'x) 240 | ``` 241 | 242 | I can also pass `f` to the `plot/of-x` function, producing a result that Clerk 243 | renders as an in-line, scrollable mathematical plot[^viewers]: 244 | 245 | [^viewers]: Using code from the 246 | [emmy-viewers](https://github.com/mentat-collective/emmy-viewers) library. 247 | 248 | ```clojure 249 | (plot/of-x f {:color (:blue plot/Theme)}) 250 | ``` 251 | 252 | You'll become comfortable with the plotting system as we proceed, so I won't say 253 | more now. But I can't resist showing off the ability to compose detailed, 254 | scrollable visualizations: 255 | 256 | ```clojure 257 | (plot/mafs 258 | {:height 400} 259 | (plot/cartesian) 260 | (plot/of-x f {:color (:blue plot/Theme)}) 261 | (plot/of-x (D f) {:color (:green plot/Theme)}) 262 | (plot/of-x ((square D) f) {:color (:violet plot/Theme)})) 263 | ``` 264 | 265 | or interactive scenes, with glowing pink points that invite manipulation: 266 | 267 | ```clojure 268 | ^{::clerk/visibility {:code :fold}} 269 | (with-let [!c [0 2]] 270 | (let [a [2 0] 271 | b [-2 0]] 272 | (plot/mafs 273 | {:height 300} 274 | (plot/cartesian) 275 | (plot/polygon 276 | {:stroke-style "dashed" 277 | :points 278 | (q (let [[cx cy] @~!c] 279 | [[cx (- cy)] ~a ~b]))}) 280 | (plot/polygon 281 | {:points [(q @~!c) a b] 282 | :color (:blue plot/Theme)}) 283 | (plot/movable-point {:atom !c})))) 284 | ``` 285 | 286 | In the next essay I'll discuss what it means to model reality, and how we can 287 | use these models to make predictions about the future. 288 | 289 | ## What you need to know 290 | 291 | At the end of this series, you will: 292 | 293 | - have built your own workshop full of software that you can use to simulate 294 | reality and explore the leading edge of mathematical physics; 295 | 296 | - understand the ideas behind these tools in a deep, intuitive way; 297 | 298 | - have become a proficient programmer, comfortable with a text editor and a 299 | means for running and exploring code. 300 | 301 | I will have been successful if you head off in directions that I've never 302 | imagined, and use what you've learned to teach or excite someone else in your 303 | life. 304 | 305 | For a final dose of motivation, here's Richard Feynman on the enriching effect 306 | that his study of physics has had on his appreciation for the beauty and 307 | structure that animates our world: 308 | 309 | > Poets say science takes away from the beauty of the stars—mere globs of gas 310 | > atoms. Nothing is “mere.” I too can see the stars on a desert night, and feel 311 | > them. But do I see less or more? The vastness of the heavens stretches my 312 | > imagination — stuck on this carousel my little eye can catch 313 | > one-million-year-old light. A vast pattern — of which I am a part 314 | > — perhaps my stuff was belched from some forgotten star, as one is 315 | > belching there. Or see them with the greater eye of Palomar, rushing all apart 316 | > from some common starting point when they were perhaps all together. 317 | > 318 | > What is the pattern, or the meaning, or the why? It does not do harm to the 319 | > mystery to know a little about it. For far more marvelous is the truth than 320 | > any artists of the past imagined! Why do the poets of the present not speak of 321 | > it? What men are poets who can speak of Jupiter if he were like a man, but if 322 | > he is an immense spinning sphere of methane and ammonia must be 323 | > silent?[^feynman] 324 | 325 | [^feynman]: From lecture 3 of [_"The Feynman Lectures on 326 | Physics"_](https://www.feynmanlectures.caltech.edu/I_03.html), by Richard 327 | Feynman. 328 | 329 | For updates on the project and notifications about new essays, please subscribe 330 | to the Road to Reality newsletter: 331 | 332 | ``` 333 | ^{::clerk/visibility {:code :hide}} 334 | (rv/substack) 335 | ``` 336 | 337 | ## Exercises 338 | 339 | 1. Follow the instructions at the [Road to Reality GitHub 340 | repository](https://github.com/mentat-collective/road-to-reality#running--editing-the-essays), 341 | and get to the point where you have this essay open in your text editor and a 342 | Clerk process watching the essays for updates. 343 | 2. Edit the definition of `f` above and save the file. Notice that any 344 | expression that depends on `f` refreshes automatically. 345 | 3. Play around in the scratchpad below, saving after each edit and noticing the 346 | results that Clerk renders. This won't work in the browser, so you'll have to 347 | complete exercise 1 and edit the block in your text editor. 348 | 349 | ```clojure 350 | (str "edit me on your local computer!") 351 | ``` 352 | -------------------------------------------------------------------------------- /essays/reality/references.md: -------------------------------------------------------------------------------- 1 | ```clojure 2 | ^{:nextjournal.clerk/visibility {:code :hide}} 3 | (ns reality.references 4 | {:nextjournal.clerk/toc true}) 5 | ``` 6 | 7 | # Road to Reality References 8 | 9 | This page contains an in-progress directory of books, links and articles that 10 | have helped readers get comfortable with the concepts in the essays. If you have 11 | something great, please [suggest it 12 | here](https://github.com/mentat-collective/road-to-reality/issues/new) and I'll 13 | add it to the list. 14 | 15 | ## Sussman and Wisdom's SICM, Notation etc 16 | 17 | - [Structure and Interpretation of Classical 18 | Mechanics](https://amzn.to/3b4fMG5), by Sussman and Wisdom. 19 | 20 | - A beautiful [HTML version of the 2nd edition lives 21 | here](https://tgvaughan.github.io/sicm/). 22 | 23 | - Here's an [open access PDF version of the 1st 24 | edition](https://library.oapen.org/viewer/web/viewer.html?file=/bitstream/handle/20.500.12657/26048/0103d4acb9fdde999d4c94fbbf711b99a2a7.pdf), 25 | if you've gotta have a free PDF. 26 | 27 | - [Sam's Roam Notes from Chapter 1: Lagrangian Mechanics](https://roamresearch.com/#/app/sritchie/page/3eV9kOrBm). These are a nice summary of what the chapter is aiming at. I recommend reading this for the high level overview before attempting the first chapter. 28 | 29 | - [Errata for the 2nd edition of SICM](http://groups.csail.mit.edu/mac/users/gjs/6946/errata.pdf). I've found some more, which I'll add to this page as I go. 30 | 31 | - The [course website](https://groups.csail.mit.edu/mac/users/gjs/6946/) for MIT's 6.946, ["Classical Mechanics: A Computational Approach"](https://groups.csail.mit.edu/mac/users/gjs/6946/). This is a graduate level course in classical mechanics that uses this textbook. The course page has excellent materials, links to errata, all the goods. 32 | 33 | - [MIT OpenCourseware page for the Fall 2008 version of the course](https://ocw.mit.edu/courses/earth-atmospheric-and-planetary-sciences/12-620j-classical-mechanics-a-computational-approach-fall-2008/index.htm). This uses the first edition of the textbook. I haven't gone through this page in any detail. 34 | 35 | - [Emmy Reference 36 | Manual](https://cljdoc.org/d/org.mentat/emmy/CURRENT/doc/reference-manual) in 37 | Clojure. This is a port of the original 38 | [refman.txt](https://groups.csail.mit.edu/mac/users/gjs/6946/refman.txt) that 39 | Sussman and Wisdom supply to students of [MIT's 6.946 40 | course](http://groups.csail.mit.edu/mac/users/gjs/6946/) 41 | 42 | - [Talk: Programming for the Expression of Ideas](https://www.infoq.com/presentations/Expression-of-Ideas/), by Gerald Sussman. This is a wild talk that goes through examples from SICM and FDG in an attempt to hammer home the idea that code is a more expressive, self-contained vehicle for many of our mathematical ideas than traditional, "impressionistic" mathematical notation. 43 | 44 | - [Paper: The Role of Programming in the Formulation of Ideas](https://dspace.mit.edu/handle/1721.1/6707), by Sussman and Wisdom ([direct PDF link here](https://dspace.mit.edu/bitstream/handle/1721.1/6707/AIM-2002-018.pdf?sequence=2&isAllowed=y)). This paper gives an overview of the whole pedagogical theory behind the approach in SICM and FDG. This is quite close to the first chapter of FDG. 45 | 46 | - a large collection of [worked SICM exercises on Nextjournal](https://nextjournal.com/sicm). 47 | 48 | These each have URLs like https://nextjournal.com/sicm/ch-9-our-notation. Insert 49 | `try` before `sicm`, like https://nextjournal.com/try/sicm/ch-9-our-notation, 50 | and the page will become editable. Play with Emmy here! 51 | 52 | - [Procedural approach to classical mechanics](http://fmnt.info/blog/20180228_sicm/index.html), by [Francesco Montanari](http://fmnt.info). Another great overview of the functional notation that Sussman and Wisdom adopted from Spivak's [Calculus on Manifolds](https://amzn.to/2ZTfPy1), with examples from the Scheme scmutils library. 53 | 54 | ### Functional Differential Geometry 55 | 56 | - [Functional Differential Geometry](https://amzn.to/2ZVHVsl), by Sussman and Wisdom. The [PDF lives here](http://xahlee.info/math/i/functional_geometry_2013_sussman_14322.pdf). This is a "sequel" to SICM, and builds up the mathematical toolkit used in general relativity using the same "Code as Communication" approach from SICM. 57 | 58 | ## Community Talks 59 | 60 | - 31 Mar 2017 » [Video: Physics in Clojure](https://www.youtube.com/watch?v=7PoajCqNKpg), by Colin Smith 61 | 62 | - 2 Dec 2020 » [Video: Scicloj SICMUtils meetup with Sam Ritchie, Colin Smith and Jordan Miller](https://www.youtube.com/watch?v=GyUSh0AAloA&feature=youtu.be) 63 | 64 | - 4 Dec 2020 » [Video: re:Clojure 2020 - Functional Physics & the Preservation of Society](https://www.youtube.com/watch?v=8AxMp0nfN7s), by Sam Ritchie ([slides](https://speakerdeck.com/sritchie/functional-physics-and-the-preservation-of-society)) 65 | 66 | - 26 Jan 2021 » Video: London Clojurians Meetup: [Dynamic Notebooks and Literate Programming](https://www.youtube.com/watch?v=UCEzBNh9ufs&feature=emb_title), by Sam Ritchie ([slides](https://speakerdeck.com/sritchie/dynamic-notebooks-and-literate-programming)) 67 | 68 | ## The Full Journey 69 | 70 | - [Teach Yourself Physics](https://amzn.to/3sxEVie), by [Jakob Schwichtenberg](http://jakobschwichtenberg.com) 71 | 72 | - [The Feynman Lectures on Physics](https://www.feynmanlectures.caltech.edu), by [Richard Feynman](https://en.wikipedia.org/wiki/Richard_Feynman) 73 | 74 | ## Classical Mechanics 75 | 76 | - [The Theoretical Minimum: What You Need to Know to Start Doing Physics](https://amzn.to/3r1wV8N), by [Leonard Susskind](https://en.wikipedia.org/wiki/Leonard_Susskind) 77 | - [associated lectures from Lenny](https://theoreticalminimum.com/courses/classical-mechanics/2011/fall) 78 | 79 | - [No Nonsense Classical Mechanics](https://amzn.to/3bNRWxl), by [Jakob Schwichtenberg](http://jakobschwichtenberg.com) 80 | 81 | ## Least Action & more specific texts 82 | 83 | - [Optics: The Principle of Least Time](https://www.feynmanlectures.caltech.edu/I_26.html); this is lecture 26 from the Feynman Lectures on Physics. 84 | 85 | - [Energy: The Subtle Concept](https://amzn.to/3bNSymD), by [Jennifer Coopersmith](https://jennifercoopersmith.com) 86 | 87 | - [The Lazy Universe: An Introduction to the Principle of Least Action](https://amzn.to/3kvL4IF), by [Jennifer Coopersmith](https://jennifercoopersmith.com) 88 | 89 | - [The Variational Principles of Mechanics](https://amzn.to/37RdKqy), by [Cornelius Lanczos](https://en.wikipedia.org/wiki/Cornelius_Lanczos) 90 | 91 | ## Calculus 92 | 93 | - [The Essence of Calculus](https://www.youtube.com/playlist?list=PLZHQObOWTQDMsr9K-rj53DwVRMYO3t5Yr), from [3blue1brown](https://www.3blue1brown.com) 94 | 95 | - 3blue1brown's [Differential Equations](https://www.youtube.com/playlist?list=PLZHQObOWTQDNPOjrT6KVlfJuKtYTftqH6) series 96 | 97 | - [Calculus On Manifolds](https://amzn.to/2ZTfPy1), by [Michael Spivak](https://en.wikipedia.org/wiki/Michael_Spivak). This is Gerald Sussman's _favorite book_ on Calculus, and the book that introduced the calculus notation that Sussman and Wisdom implemented in SICM. 98 | 99 | ## History 100 | 101 | - [A History of Vector Analysis: The Evolution of the Idea of a Vectorial System](https://amzn.to/2ZSNTtY), by [Michael J Crowe](https://www3.nd.edu/~mcrowe1/) 102 | 103 | - This was a fascinating read; dealing with rotations in 3D space was, it 104 | turns out, an API design problem that's lasted for centuries now. Vectors 105 | won the day, but they probably aren't the final say. 106 | 107 | ## Numerical Methods 108 | 109 | - [Abstraction in Numerical 110 | Methods](https://dspace.mit.edu/bitstream/handle/1721.1/6060/AIM-997.pdf?sequence=2), 111 | by Matthew Halfant and Gerald Sussman. 112 | 113 | ## Data Visualization 114 | 115 | - [Vega Lite: A Grammar of Interactive Graphics](https://www.youtube.com/watch?v=9uaHRWj04D4); a talk from 2017 that goes over the wonderful library we're exploring as a data visualization layer for Emmy. 116 | -------------------------------------------------------------------------------- /essays/reality/tools.md: -------------------------------------------------------------------------------- 1 | ```clojure 2 | ^{:nextjournal.clerk/visibility {:code :hide}} 3 | (ns reality.tools 4 | {:nextjournal.clerk/toc true} 5 | (:require [nextjournal.clerk :as clerk])) 6 | ``` 7 | 8 | # Tools 9 | 10 | I'm writing The [Road to Reality essays](https://reality.mentat.org) using a 11 | stack of tools that I've designed and built (with plenty of help!) to make it 12 | easy and joyful to write documents with embedded code and interactive 13 | simulations. 14 | 15 | I'm writing these essays using the [Clerk][clerk-url] notebook engine and the 16 | [Emmy](https://github.com/mentat-collective/emmy) computer algebra system. Each 17 | essay contains interactive, executable code that you're meant to explore! I'll 18 | add as much interactivity as I can to each essay, but for the full experience I 19 | want you to read them using the same tools and environment that I used to write 20 | the essays. 21 | 22 | ## Clojure 23 | 24 | The essays consist of a mixture of prose and code in the [Clojure programming 25 | language](https://en.wikipedia.org/wiki/Clojure). Clojure is a dialect of 26 | [Lisp](https://en.wikipedia.org/wiki/Lisp_(programming_language)), one of the 27 | oldest programming languages we have. 28 | 29 | Lisp stands for Li(st) P(rocessing). Clojure code looks like a nest of lists. 30 | The language takes forms like this: 31 | 32 | ```clojure 33 | (+ 1 (* 2 3)) 34 | ``` 35 | 36 | And evaluates them by 37 | 38 | - Parsing a parenthesized list as `( ...)` 39 | - Evaluating each argument using these rules 40 | - Passing the evaluated arguments to `procedure`, and replacing the whole list 41 | with the result. 42 | 43 | Try doing this by hand on the above form, and you should get the following 44 | intermediate steps: 45 | 46 | (+ 1 (* 2 3)) ;; 1 evaluates to itself, (* 2 3) needs evaluation! 47 | (+ 1 (* 2 3)) ;; 2 and 3 evaluate to themselves. Pass them to *... 48 | (+ 1 6) ;; 1 and 6 are fully evaluated, pass them to +... 49 | 7 ;; done! 50 | 51 | There is not much more to it, and you'll be doing this process in your head 52 | before long with much more complex code. 53 | 54 | The wild truth is that we can use simple tools like this to build up powerful 55 | environments to simulate ideas at the leading edge of modern computational 56 | physics. 57 | 58 | ## Emmy 59 | 60 | [Emmy](https://github.com/mentat-collective/emmy) is a [computer algebra 61 | system](https://en.wikipedia.org/wiki/Computer_algebra_system) based on Gerald 62 | Jay Sussman's powerful-yet-obscure 63 | [`scmutils`](https://groups.csail.mit.edu/mac/users/gjs/6946/installation.html) 64 | project. 65 | 66 | Emmy is the computational engine behind the essays. The essays are really a tour 67 | of the construction of this library, of advanced programming techniques, and of 68 | the historical origin of scmutils and Sussman's work in Scheme and Lisp. 69 | 70 | ## Clerk 71 | 72 | [Clerk][clerk-url] is a [computational 73 | notebook](https://en.wikipedia.org/wiki/Notebook_interface) library for 74 | [Clojure](#clojure). I write each essay in a Clojure source file and 75 | [Clerk][clerk-url] converts the contents of the file into a beautifully rendered 76 | HTML document like the one you're reading. 77 | 78 | Clerk is "extensible", which means that I can teach it how to display different 79 | mathematical objects. 80 | 81 | Clerk renders this string as itself by default: 82 | 83 | ``` 84 | "{\\rm e}^{i\\pi} = -1" 85 | ``` 86 | 87 | If I tell Clerk to use the `clerk/tex` viewer to render the string, it will 88 | instead generate beautifully typeset $\TeX$ output: 89 | 90 | ```clojure 91 | (clerk/with-viewer clerk/tex 92 | "{\\rm e}^{i\\pi} = -1") 93 | ``` 94 | 95 | I've used this extensibility to implement a number of powerful Clerk viewers for 96 | showing off interactive math and physics on 2D (via [Mafs.cljs](#mafs.cljs) and 97 | [JSXGraph.cljs](#jsxgraph.cljs)) and 3D (via [MathBox.cljs](#mathbox.cljs)) 98 | rendering canvases. These appear throughout the essays! 99 | 100 | To learn more about Clerk, visit: 101 | 102 | - the [Book of Clerk](https://book.clerk.vision/) 103 | - [The Clerk-Demo index](https://github.clerk.garden/nextjournal/clerk-demo) 104 | - My [awesome-clerk](https://github.com/mentat-collective/awesome-clerk) 105 | directory of cool work I've found in the Clerk community. 106 | 107 | ## MathBox.cljs 108 | 109 | [MathBox](https://github.com/unconed/mathbox) is a JavaScript library designed 110 | for rendering complex mathematical scenes in 2D and 3D from a declarative 111 | description of the scene. The brilliant [Steven Wittens](https://acko.net/) 112 | wrote MathBox, and allowed me to adopt the project and take over as its 113 | maintainer. 114 | 115 | MathBox sits on top of [ThreeJS](https://threejs.org/), which in turn sits on 116 | top of [WebGL](https://developer.mozilla.org/en-US/docs/Web/API/WebGL_API). See 117 | https://mathbox.org/ for many examples of what MathBox can do. 118 | 119 | I've wrapped MathBox in a Clojure-friendly package and published it as 120 | [MathBox.cljs](https://mathbox.mentat.org/); this is the layer used by the 121 | essays for any interactive 3D scene. I'll link to examples as they come online. 122 | 123 | ## Mafs.cljs 124 | 125 | [Mafs](https://mafs.dev/) is a [React](https://react.dev/)-based JavaScript 126 | library for writing declarative 2D mathematical scenes that are more interactive 127 | than what MathBox allows out of the box. 128 | 129 | See my [ClojureScript wrapper, Mafs.cljs](https://mafs.mentat.org/), for many 130 | examples and more detail. 131 | 132 | ## JSXGraph.cljs 133 | 134 | [JSXGraph](https://jsxgraph.org/) is a powerful JavaScript library for defining 135 | complex, interactive geometric scenes, full of dependencies and relationships. 136 | 137 | This toolkit is more powerful at displaying geometric constructions than [Mafs.cljs](#mafs.cljs), and I expect that I'll use heavily more when building up visual proofs in the style of books like Tristan Needham's [Visual Complex Analysis](https://global.oup.com/academic/product/visual-complex-analysis-9780192868923?cc=us&lang=en). 138 | 139 | See my [ClojureScript wrapper, JSXGraph.cljs](https://jsxgraph.mentat.org/), for 140 | many examples and more detail. 141 | 142 | ## Leva.cljs 143 | 144 | [Leva](https://github.com/pmndrs/leva/) is a JavaScript library for writing 145 | declarative GUIs with sliders, toggles, realtime charts and more. 146 | 147 | [Leva.cljs](https://leva.mentat.org) wraps Leva and allows an author to build up 148 | custom control panels for various simulations or interactive pieces of an 149 | executable essay or textbook section. 150 | 151 | ## MathLive.cljs 152 | 153 | [MathLive](https://mathlive.mentat.org/) provides an equation editor that 154 | renders math as beautiful $\TeX$ inside of a form that lets a reader _edit_ the 155 | rendered math. 156 | 157 | [MathLive.cljs](https://mathlive.mentat.org/) extends MathLive with the ability 158 | to extract the equations not just as text, but as a piece of Clojure source code 159 | that [Emmy](#emmy) and the other tools discussed here can use to power 160 | simulations and visuals. 161 | 162 | Imagine a textbook where any equation is editable, and editing it updates any 163 | figure that depends on that math. 164 | 165 | [clerk-url]: https://clerk.vision 166 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "devDependencies": { 3 | "gh-pages": "^3.2.3" 4 | }, 5 | "scripts": { 6 | "gh-pages": "gh-pages -d public/build --dotfiles true" 7 | }, 8 | "dependencies": { 9 | "@codemirror/autocomplete": "6.5.1", 10 | "@codemirror/commands": "6.2.3", 11 | "@codemirror/lang-markdown": "6.0.0", 12 | "@codemirror/language": "6.6.0", 13 | "@codemirror/lint": "6.2.1", 14 | "@codemirror/search": "6.3.0", 15 | "@codemirror/state": "6.2.0", 16 | "@codemirror/view": "6.9.6", 17 | "@cortex-js/compute-engine": "0.12.2", 18 | "@lezer/common": "1.0.2", 19 | "@lezer/generator": "1.2.2", 20 | "@lezer/highlight": "1.1.4", 21 | "@lezer/lr": "1.3.3", 22 | "@lezer/markdown": "1.0.2", 23 | "@nextjournal/lang-clojure": "1.0.0", 24 | "@nextjournal/lezer-clojure": "1.0.0", 25 | "complex.js": "2.1.1", 26 | "d3-require": "1.3.0", 27 | "fraction.js": "4.2.0", 28 | "framer-motion": "6.5.1", 29 | "jsxgraph": "1.5.0", 30 | "katex": "0.12.0", 31 | "leva": "0.9.34", 32 | "mafs": "0.15.2", 33 | "markdown-it": "12.3.2", 34 | "markdown-it-block-image": "0.0.3", 35 | "markdown-it-footnote": "3.0.3", 36 | "markdown-it-texmath": "0.9.7", 37 | "markdown-it-toc-done-right": "4.2.0", 38 | "mathbox": "2.3.1", 39 | "mathbox-react": "0.0.14", 40 | "mathlive": "0.86.1", 41 | "odex": "3.0.0-rc.4", 42 | "punycode": "2.1.1", 43 | "react": "18.2.0", 44 | "react-dom": "18.2.0", 45 | "shadow-cljs": "2.22.7", 46 | "three": "0.151.3", 47 | "threestrap": "0.5.1", 48 | "use-sync-external-store": "1.2.0", 49 | "vh-sticky-table-header": "1.2.1", 50 | "w3c-keyname": "2.2.6" 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /src/reality/custom.cljs: -------------------------------------------------------------------------------- 1 | (ns reality.custom) 2 | 3 | ;; ## Custom ClojureScript 4 | ;; 5 | ;; This namespace contains custom ClojureScript definitions used by the 6 | ;; `road-to-reality` project. 7 | -------------------------------------------------------------------------------- /src/reality/mathbox.cljs: -------------------------------------------------------------------------------- 1 | (ns reality.mathbox 2 | (:require [demo.mathbox :as dm] 3 | [leva.core] 4 | [mathbox.core] 5 | [mathbox.primitives :as mb] 6 | [nextjournal.clerk.render] 7 | [reagent.core :as r])) 8 | 9 | (defn ToroidPoint 10 | [{state :initial-state 11 | state->xyz :state->xyz 12 | :as opts}] 13 | (reagent.core/with-let 14 | [render-fn (apply js/Function state->xyz) 15 | !state (reagent.core/atom {:time 0 :state state}) 16 | !arr (reagent.core/atom (js/Array. 2.0 0.5))] 17 | [:<> 18 | [:div.hidden 19 | [nextjournal.clerk.render/inspect @!arr] 20 | [nextjournal.clerk.render/inspect @!state]] 21 | [dm/Evolve 22 | {:L (:L opts) 23 | :params !arr 24 | :atom !state}] 25 | [mathbox.core/MathBox 26 | {:container {:style {:height "400px" :width "100%"}} 27 | :renderer {:background-color 0xffffff}} 28 | [mb/Cartesian (:cartesian opts) 29 | [mb/Axis {:axis 1 :width 3}] 30 | [mb/Axis {:axis 2 :width 3}] 31 | [mb/Axis {:axis 3 :width 3}] 32 | [demo.mathbox/Curve 33 | {:state-derivative (apply js/Function (:L opts)) 34 | :state->xyz render-fn 35 | :initial-state-fn 36 | (fn [] 37 | (let [s (:state (.-state !state))] 38 | (if (array? s) 39 | s 40 | (clj->js (flatten s))))) 41 | :steps 200 42 | :params !arr}] 43 | [dm/Comet 44 | {:dimensions 3 45 | :length 20 46 | :color 0xa0d0ff 47 | :size 10 48 | :opacity 0.99 49 | :path 50 | (let [out #js [0 0 0]] 51 | (fn [emit _ _] 52 | (render-fn (:state (.-state !state)) 53 | out 54 | (.-state !arr)) 55 | (emit (aget out 0) 56 | (aget out 2) 57 | (aget out 1))))}] 58 | [dm/Torus render-fn !arr]]]])) 59 | -------------------------------------------------------------------------------- /src/reality/sci_extensions.cljs: -------------------------------------------------------------------------------- 1 | (ns reality.sci-extensions 2 | (:require [emmy-viewers.sci] 3 | [reality.custom] 4 | [reality.mathbox] 5 | [sci.ctx-store] 6 | [sci.core :as sci])) 7 | 8 | ;; ## SCI Environment Extension 9 | ;; 10 | ;; This namespace extends the SCI environment used by Clerk, making available 11 | ;; any custom ClojureScript we use while [writing 12 | ;; viewers](https://book.clerk.vision/#writing-viewers) for the essays. 13 | 14 | ;; ## SCI Environment Extension 15 | 16 | ;; First, install the `emmy-viewers` environment extensions: 17 | 18 | (emmy-viewers.sci/install!) 19 | 20 | (def custom-namespace 21 | (sci/copy-ns reality.custom (sci/create-ns 'reality.custom))) 22 | 23 | (def mathbox-namespace 24 | (sci/copy-ns reality.mathbox (sci/create-ns 'reality.mathbox))) 25 | 26 | (def custom-namespaces 27 | {'reality.custom custom-namespace 28 | 'reality.mathbox mathbox-namespace}) 29 | 30 | (sci.ctx-store/swap-ctx! 31 | sci/merge-opts 32 | {:classes {'Math js/Math} 33 | :namespaces custom-namespaces}) 34 | -------------------------------------------------------------------------------- /src/reality/toroid.clj: -------------------------------------------------------------------------------- 1 | (ns reality.toroid 2 | (:refer-clojure 3 | :exclude [+ - * / = zero? compare 4 | numerator denominator ref partial 5 | infinite? abs]) 6 | (:require [emmy.env :as e :refer :all] 7 | [emmy.mechanics.rotation :as rot] 8 | [emmy.expression.compile :as xc] 9 | [emmy.structure :as s] 10 | [nextjournal.clerk :as clerk])) 11 | 12 | (defn toroidal->rect [R r] 13 | (fn [[_ [theta phi] _]] 14 | (* 15 | (rot/rotate-z-matrix phi) 16 | (s/up (+ R (* r (cos theta))) 17 | 0 18 | (* r (sin theta)))))) 19 | 20 | (defn T-free-particle 21 | [[_ _ v]] 22 | (* 1/2 (square v))) 23 | 24 | (defn V-free-particle 25 | [[_ _ _]] 26 | 0) 27 | 28 | (defn L-toroidal [R r] 29 | (comp 30 | (- T-free-particle 31 | V-free-particle) 32 | (F->C 33 | (toroidal->rect R r)))) 34 | 35 | ^{::clerk/visibility {:code :hide :result :hide}} 36 | (def geodesic-viewer 37 | {:transform-fn 38 | (comp clerk/mark-presented 39 | (clerk/update-val 40 | (fn [{:keys [L params initial-state state->xyz 41 | keys] :as m}] 42 | (assoc m 43 | :L 44 | (xc/compile-state-fn 45 | (compose e/Lagrangian->state-derivative L) 46 | (mapv params keys) 47 | initial-state 48 | {:mode :js 49 | :calling-convention :primitive 50 | :generic-params? true}) 51 | 52 | :state->xyz 53 | (xc/compile-state-fn 54 | state->xyz 55 | (mapv params keys) 56 | initial-state 57 | {:mode :js 58 | :calling-convention :primitive 59 | :generic-params? true}))))) 60 | :render-fn 'reality.mathbox/ToroidPoint}) 61 | -------------------------------------------------------------------------------- /src/reality/viewer.clj: -------------------------------------------------------------------------------- 1 | (ns reality.viewer 2 | (:require [emmy.env :as e] 3 | [emmy.expression :as x] 4 | [emmy.structure :as s] 5 | [emmy.viewer :as ev] 6 | [nextjournal.clerk :as clerk])) 7 | 8 | (defn install! [] 9 | (clerk/add-viewers! 10 | [ev/meta-viewer 11 | {:pred (some-fn x/literal? s/structure?) 12 | :transform-fn 13 | (clerk/update-val 14 | (comp clerk/tex e/->TeX))}])) 15 | 16 | (defn substack 17 | ([] (substack 100)) 18 | ([height] 19 | (clerk/html 20 | [:center 21 | [:iframe 22 | {:src "https://roadtoreality.substack.com/embed" 23 | :width "100%" :height height 24 | :style 25 | {:border "1px solid #EEE" 26 | :background "white" 27 | :frameborder 0 28 | :scrolling "no"}}]]))) 29 | --------------------------------------------------------------------------------