Skip to content

Commit

Permalink
Improve SCI environment, add sci-macro (#145)
Browse files Browse the repository at this point in the history
Co-authored-by: Matthew Huebert <[email protected]>
  • Loading branch information
sritchie and mhuebert authored Aug 4, 2023
1 parent f6c3e9c commit e16b569
Show file tree
Hide file tree
Showing 26 changed files with 485 additions and 545 deletions.
14 changes: 7 additions & 7 deletions .dir-locals.el
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
((nil
. ((cider-print-fn . "emmy.expression/expression->stream")
(cider-default-cljs-repl . node)))
(clojurec-mode
. ((cider-preferred-build-tool . clojure-cli)
(cider-clojure-cli-aliases . ":test:cljs:nextjournal/clerk:dev")))
(clojure-mode
. ((cider-preferred-build-tool . clojure-cli)
(cider-clojure-cli-aliases . ":test:cljs:nextjournal/clerk:dev"))))
(cider-default-cljs-repl . node)
(cider-preferred-build-tool . clojure-cli)
(cider-clojure-cli-aliases . ":test:cljs:nextjournal/clerk:dev")

;; Custom indentation:
(eval . (put-clojure-indent 'sci-macro :defn))
(eval . (put-clojure-indent 'careful-def 1)))))
3 changes: 3 additions & 0 deletions .github/workflows/kondo.yml
Original file line number Diff line number Diff line change
Expand Up @@ -24,5 +24,8 @@ jobs:
key: ${{ runner.os }}-kondo
restore-keys: ${{ runner.os }}-kondo

- name: Lint dependencies
run: bb lint-deps

- name: Run clj-kondo
run: bb lint --config '{:output {:pattern "::{{level}} file={{filename}},line={{row}},col={{col}}::{{message}}"}}'
23 changes: 23 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,29 @@

## [unreleased]

- #145 (thank you to @mhuebert for amazing work here!!):

- Adds `emmy.util/sci-macro` for defining macros meant to be exposed via SCI,
without requiring redefinition as a `fn`.

- Modifies `emmy.sci` so that SCI has access to all of the metadata we need
for a great experience on https://2.maria.cloud and other platforms that use
SCI.

- Removes some unused `kondo/ignore` metadata and upgrades `clj-kondo` to
2023.07.13, which caught a couple more errors like a test with no assertion
and a block of tests accidentally included in another test block.

- Upgrades `emmy.calculus.coordinate/define-coordinates` and
`emmy.util.def/{import-vars,careful-def}` to play nicely with SCI.

- Resolves the ambiguous `simplify` implementation for subvectors.

- Adds docstrings to the aliased macros in `emmy.env`.

- Exposes `emmy.calculus.coordinate/coordinate-functions` as
`emmy.env/coordinate-functions`.

- #143:

- Replace the implementation of common subexpression elimination with
Expand Down
11 changes: 10 additions & 1 deletion bb.edn
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{:deps {org.babashka/http-server {:mvn/version "0.1.11"}
org.babashka/cli {:mvn/version "0.2.23"}
io.github.clj-kondo/clj-kondo-bb
{:git/tag "v2023.01.20" :git/sha "adfc7df"}}
{:git/sha "178b027e827172da0d63122a754bb4d765a6faeb"}}
:tasks
{:requires ([babashka.cli :as cli])
:init
Expand Down Expand Up @@ -63,6 +63,15 @@
{:doc "Release the library to Clojars."
:task (shell "clojure -T:build publish")}

lint-deps
{:requires ([clj-kondo.core :as kondo])
:doc "Lint dependencies."
:task (kondo/run!
{:lint [(with-out-str
(babashka.tasks/clojure
"-Spath -A:nextjournal/clerk"))]
:dependencies true})}

lint
{:doc "Lint with clj-kondo."
:task (exec 'clj-kondo.core/exec)
Expand Down
2 changes: 1 addition & 1 deletion deps.edn
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
com.taoensso/timbre {:mvn/version "6.0.4"}
dm3/stopwatch {:mvn/version "0.1.1" :exclusions [org.clojure/clojurescript]}
org.apache.commons/commons-math3 {:mvn/version "3.6.1"}
org.babashka/sci {:mvn/version "0.7.39"}
org.babashka/sci {:mvn/version "0.8.40"}
org.mentat/clerk-utils {:mvn/version "0.6.0"}}

:aliases
Expand Down
3 changes: 3 additions & 0 deletions resources/clj-kondo.exports/org.mentat/emmy/config.edn
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@

:lint-as
{emmy.numerical.quadrature.common/defintegrator clojure.core/def
emmy.util/sci-macro clojure.core/defmacro
emmy.util.def/import-vars potemkin/import-vars
emmy.util.def/defgeneric clojure.core/defmulti}

Expand Down Expand Up @@ -42,6 +43,8 @@
emmy.env/with-literal-functions
hooks.emmy.abstract.function/with-literal-functions

emmy.util/copy-ns hooks.emmy.util/copy-ns

emmy.util.def/import-def hooks.emmy.util.def/import-def
emmy.util.def/import-macro hooks.emmy.util.def/import-def

Expand Down
13 changes: 13 additions & 0 deletions resources/clj-kondo.exports/org.mentat/emmy/hooks/emmy/util.clj
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
(ns hooks.emmy.util
(:require [clj-kondo.hooks-api :as api]))

(defn copy-ns
"Converts a node representing an invocation of the [[emmy.util/copy-ns]] macro
into a vector node that quotes the `ns-sym` and `opts` entries."
[{:keys [node]}]
(let [[_ ns-sym sci-ns opts] (:children node)]
{:node
(api/vector-node
[(api/list-node [(api/token-node 'quote) ns-sym])
sci-ns
(api/list-node [(api/token-node 'quote) opts])])}))
2 changes: 1 addition & 1 deletion src/emmy/abstract/function.cljc
Original file line number Diff line number Diff line change
Expand Up @@ -229,7 +229,7 @@
(entry->fn entry)])
litfns)))

(defmacro with-literal-functions [litfns & body]
(u/sci-macro with-literal-functions [litfns & body]
(let [pairs (binding-pairs litfns)
bindings (into [] cat pairs)]
`(let ~bindings ~@body)))
Expand Down
3 changes: 2 additions & 1 deletion src/emmy/algebra/fold.cljc
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
(:refer-clojure :exclude [min max count])
(:require [clojure.core :as core]
[emmy.generic :as g]
[emmy.util :as u]
[emmy.util.def :as ud]
[mentat.clerk-utils :refer [->clerk ->clerk-only]])
#?(:cljs
Expand Down Expand Up @@ -483,7 +484,7 @@
(let [~@(mapcat #(klein-term % delta) prefix)]
[~@prefix (+ ~final ~delta)]))]))

(defmacro kbk-n
(u/sci-macro kbk-n
"Given some order `n`, returns a fold implementing `n`-th order
Kahan-Babushka-Klein summation.
Expand Down
48 changes: 28 additions & 20 deletions src/emmy/calculus/coordinate.cljc
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@
(symbol? p) [p]
:else (u/illegal (str "Invalid coordinate prototype: " p))))

(defmacro let-coordinates
(u/sci-macro let-coordinates
"similar to a `let` binding that holds pairs of
<coordinate-structure-prototype>, <coordinate-system>
Expand Down Expand Up @@ -124,7 +124,7 @@
(map ff/coordinate-system->oneform-basis c-systems#))]
~@body)))

(defmacro using-coordinates
(u/sci-macro using-coordinates
"[[using-coordinates]] wraps [[let-coordinates]] and allows you to supply a
single coordinate prototype and a single coordinate system.
See [[let-coordinates]] for details about what symbols are bound inside the
Expand All @@ -140,7 +140,7 @@
`(let-coordinates [~coordinate-prototype ~coordinate-system]
~@body))

(defmacro define-coordinates
(u/sci-macro define-coordinates
"Give some `coordinate-system` like `R2-rect` and a `coordinate-prototype` like
`[x y]` or `(up x y), `binds the following definitions into the namespace
where [[define-coordinates]] is invoked:
Expand All @@ -156,22 +156,30 @@
- `dx` and `dy` bind to 1-forms for each coordinate."
[coordinate-prototype coordinate-system]
(let [sys-name (symbol (name coordinate-system))
value-sym (gensym (str sys-name "-values"))
coord-names (symbols-from-prototype coordinate-prototype)
vector-field-names (map vf/coordinate-name->vf-name coord-names)
form-field-names (map ff/coordinate-name->ff-name coord-names)
sys-sym (gensym)
value-sym (gensym)
bind (ud/careful-def *ns*)]
`(let [~sys-sym (m/with-coordinate-prototype
~coordinate-system
~(quotify-coordinate-prototype coordinate-prototype))]
~(bind sys-name sys-sym)
(let [~value-sym
(into [] (flatten
[(coordinate-functions ~sys-sym)
(vf/coordinate-system->vector-basis ~sys-sym)
(ff/coordinate-system->oneform-basis ~sys-sym)]))]
~@(map-indexed
(fn [i sym]
(bind sym `(nth ~value-sym ~i)))
(concat coord-names vector-field-names form-field-names))))))
form-field-names (map ff/coordinate-name->ff-name coord-names)]
`(do
(ud/careful-def ~sys-name
(m/with-coordinate-prototype
~coordinate-system
~(quotify-coordinate-prototype coordinate-prototype)))

(def ~value-sym
(into [] (flatten
[(coordinate-functions ~sys-name)
(vf/coordinate-system->vector-basis ~sys-name)
(ff/coordinate-system->oneform-basis ~sys-name)])))

~@(map-indexed
(fn [i sym]
`(ud/careful-def ~sym (nth ~value-sym ~i)))
(concat coord-names vector-field-names form-field-names))

#_{:clj-kondo/ignore [:unresolved-symbol]}
~(if (or (:sci? &env) #?(:clj (not (:ns &env))))
`(ns-unmap *ns* '~value-sym)
`(set! ~value-sym nil))

(var ~sys-name))))
4 changes: 4 additions & 0 deletions src/emmy/collection.cljc
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,10 @@
(defmethod g/simplify [PersistentVector] [v]
(mapv g/simplify v))

#?(:clj
(defmethod g/simplify [clojure.lang.APersistentVector$SubVector] [v]
(mapv g/simplify v)))

(extend-type #?(:clj IPersistentVector :cljs PersistentVector)
v/Value
(zero? [v] (every? v/zero? v))
Expand Down
77 changes: 68 additions & 9 deletions src/emmy/env.cljc
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@
[emmy.sr.boost]
[emmy.sr.frames]
[emmy.structure :as structure]
[emmy.util]
[emmy.util :as u]
[emmy.util.aggregate]
[emmy.util.def :refer [import-def import-vars]]
[emmy.util.permute]
Expand All @@ -97,7 +97,7 @@
:refer
(into [] (keys (ns-publics 'emmy.env)))]))

(defmacro literal-function
(u/sci-macro literal-function
([f] `(af/literal-function ~f))
([f sicm-signature]
(if (and (list? sicm-signature)
Expand All @@ -107,17 +107,74 @@
([f domain range]
`(af/literal-function ~f ~domain ~range)))

(defmacro with-literal-functions [& args]
(u/sci-macro with-literal-functions [& args]
`(af/with-literal-functions ~@args))

(defmacro let-coordinates [& args]
`(cc/let-coordinates ~@args))
(u/sci-macro let-coordinates
"similar to a `let` binding that holds pairs of
(defmacro using-coordinates [& args]
`(cc/using-coordinates ~@args))
<coordinate-structure-prototype>, <coordinate-system>
(defmacro define-coordinates [& args]
`(cc/define-coordinates ~@args))
And internally binds, for each pair: (take `[x y]` and `m/R2-rect` as
examples):
- The coordinate system symbol `R2-rect` to a new version of the coordinate
system with its `coordinate-prototype` replaced by the one you supplied.
That's `(up x y)` in this example.
- the entries `x` and `y` to coordinate functions, i.e., functions from manifold
point to this particular coordinate
- `d:dx` and `d:dy` vector field procedures (I'm fuzzy here!)
- `dx` and `dy` 1-forms for each coordinate (fuzzy here too!)
Example:
```clojure
(let-coordinates [[x y] R2-rect
[r theta] R2-polar]
;; bindings:
;; R2-rect, x, y, d:dx, d:dy, dx, dy
;; R2-polar, r, theta, d:dr, d:dtheta, dr, dtheta
body...)
```"
[bindings & body]
`(cc/let-coordinates ~bindings ~@body))

(u/sci-macro using-coordinates
"[[using-coordinates]] wraps [[let-coordinates]] and allows you to supply a
single coordinate prototype and a single coordinate system.
See [[let-coordinates]] for details about what symbols are bound inside the
body.
Example:
```clojure
(using-coordinates (up x y) R2-rect
body...)
```"
[coordinate-prototype coordinate-system & body]
`(cc/using-coordinates ~coordinate-prototype
~coordinate-system
~@body))

(u/sci-macro define-coordinates
"Given some `coordinate-system` like `R2-rect` and a `coordinate-prototype` like
`[x y]` or `(up x y), `binds the following definitions into the namespace
where [[define-coordinates]] is invoked:
- `R2-rect` binds to a new version of the coordinate system with its
`coordinate-prototype` replaced by the supplied prototype
- `x` and `y` bind to coordinate functions, i.e., functions from manifold point
to that particular coordinate
- `d:dx` and `d:dy` bind to the corresponding vector field procedures
- `dx` and `dy` bind to 1-forms for each coordinate."
[coordinate-prototype coordinate-system]
`(cc/define-coordinates ~coordinate-prototype ~coordinate-system))

(defn ref
"A shim so that ref can act like nth in SICM contexts, as clojure core ref
Expand Down Expand Up @@ -307,6 +364,8 @@
make-constant-vector-field
Jacobian]

[emmy.calculus.coordinate coordinate-functions]

[emmy.calculus.connection
make-Christoffel-1
metric->Christoffel-1 metric->Christoffel-2
Expand Down
9 changes: 5 additions & 4 deletions src/emmy/numerical/quadrature/common.cljc
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,8 @@
- code to wrap a sequence of progressively better estimates in a common `integrator` interface
- data structures implementing various integration intervals."
(:refer-clojure :exclude [infinite?])
(:require [emmy.util.stream :as us]
(:require [emmy.util :as u]
[emmy.util.stream :as us]
[taoensso.timbre :as log])
#?(:cljs
(:require-macros [emmy.numerical.quadrature.common])))
Expand Down Expand Up @@ -166,11 +167,11 @@
attr)]
[(with-meta name attr) body])))

(defmacro defintegrator
(u/sci-macro defintegrator
"Helper macro for defining integrators."
[sym & body]
(let [meta {:arglists (list 'quote '([f a b] [f a b opts]))}
[sym body] (name-with-attributes sym body meta)
(let [meta {:arglists (list 'quote '([f a b] [f a b opts]))}
[sym body] (name-with-attributes sym body meta)
{:keys [area-fn seq-fn]} (apply hash-map body)]
(assert seq-fn (str "defintegrator " sym ": seq-fn cannot be nil"))
(assert area-fn (str "defintegrator " sym ": area-fn cannot be nil"))
Expand Down
Loading

0 comments on commit e16b569

Please sign in to comment.