-
-
Notifications
You must be signed in to change notification settings - Fork 69
warm diggety: a first crack at geometric algebra ('hestenic.cljc') #347
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Conversation
Codecov Report
@@ Coverage Diff @@
## master #347 +/- ##
=======================================
Coverage 83.04% 83.04%
=======================================
Files 92 92
Lines 10932 10932
Branches 526 526
=======================================
Hits 9078 9078
Misses 1328 1328
Partials 526 526
Continue to review full report at Codecov.
|
@@ -47,6 +47,7 @@ | |||
[sicmutils.abstract.function :as af #?@(:cljs [:include-macros true])] | |||
[sicmutils.abstract.number :as an] | |||
[sicmutils.complex] | |||
;; [sicmutils.hestenic :as h] ;; well, this sure doesn't work... |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Interesting if the file compiles... What was the error? I'll give it a test too.
src/sicmutils/hestenic.cljc
Outdated
;; | ||
;; | ||
|
||
(ns sicmutils.hestenic |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
first pass, I'll just make notes about the code, not high level design, as I go through! Design next.
src/sicmutils/hestenic.cljc
Outdated
;; | ||
;; note that we extend many of these protocols too to java.lang.Number | ||
;; to enjoy automatic interop of existing numeric types with the GA | ||
;; system. thanks, lisp dialect! |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
excellent! We can beef this up to get it working for the various cljs types too.
;; | ||
|
||
(defprotocol IHestenic | ||
(scl [this s]) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Stingy with your character count :) For the final push, you can also put docstrings on protocol methods, right after the arg vector.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It might be worth separating out the functions that you think are going to be covered by the existing generics - neg
, prd
, inv
, quo
, dot
, eq?
, scl
, sum
.
We have a wedge product in the differential geometry stuff, so we can make that a generic and have the same function do the right thing for differential forms and GA.
src/sicmutils/hestenic.cljc
Outdated
(grade-part [this n]))
(defprotocol IGradable
(grade [this]))
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
same note here about docstrings!
(grade-part [this n])) | ||
|
||
(defprotocol IGradable | ||
(grade [this])) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
same note here about docstrings!
|
||
|
||
;; | ||
;; A Gradeling is a bevy of Bladoids of the same grade. It may or may not be |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
what's a bevy of bladoids?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
(as discussed yesterday)
src/sicmutils/hestenic.cljc
Outdated
(defn gradeling [grade-or-bladoids] | ||
(if | ||
(integer? grade-or-bladoids) | ||
(Gradeling. grade-or-bladoids ()) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think you depend on these being vectors in a few spots, so prefer []
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
excellent. so let the record show!
IGradeling | ||
(bladoids [_] bldds) | ||
(bladoid-with-basis [this b] | ||
(first (filter (fn [el] (= (basis el) b)) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I wouldn't do it here but just for Clojure fun you could also:
(some #(when (= b (basis %)) %)
(bladoids this))
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
any reason this'd be preferred? (some
's vague and indeterminate connotation (in english) feels like a miscue to me in this context... but then i'm easily duped.)
src/sicmutils/hestenic.cljc
Outdated
Object | ||
(toString [_] (str "g" gr "{" | ||
(reduce (fn [sofar bl] | ||
(str sofar (if (empty? sofar) "" " ") bl)) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
(clojure.string/join " " bldds)
for the guts.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done.
src/sicmutils/hestenic.cljc
Outdated
|
||
Object | ||
(toString [_] (str "MV[" | ||
(reduce (fn [sofar gr] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
(clojure.string/join " " grdlgs)
for the guts
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
prima! toll! fabelhaft! (schon gemacht)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
digging it everywhere all the time!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Okay, so much good stuff here!!!
src/sicmutils/hestenic.cljc
Outdated
(nil? neck) | ||
(list head) | ||
(same-basis? head neck) | ||
(recur (sum head neck) (second trunk) (rest trunk)) | A3D4
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We've got it! I'll recommend
(defn- collapse [blades]
(map (partial reduce sum)
(partition-by basis blades)))
(defn- order-swap-count [basl basr] | ||
(loop [cnt 0 | ||
lind (dec (count basl))] | ||
(if (< lind 0) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I find it more readable sometimes in case checks like this to use the explicit neg?
, pos?
zero?
...
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
for me, those predicates (pos?
et al.) pertain meaningfully to interrogating the essence of an immutable thing; whereas here we're doing what amounts to a low-level imperative-programming loop, with temporary index variables that are changing and whose instantaneous state needs to be tested. the (< x 0)
style feels consonant with that. a matter of taste, of course...
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
While predicates mostly seem to be implemented in Java for speed, taking pos?
as a specific example, those implementations are still doing an inequality check at the end of the day, since pos?
is a wrapper around a function called isPos
. No prizes for guessing how that's implemented. A rose by any other name...
The important idea here is binding that procedure to a name that scans faster, clearly communicates the aglorithm being used, and has less arguments you have to worry about getting wrong. I think it only feels consonant because the expectation that looping conditions look like that has been burnt into our minds by decades of C-overexposure.
cnt | ||
(let [lval (nth basl lind) | ||
sc (scoot-count lval basr)] | ||
(if (= sc 0) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
zero?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
keep wishing that clojure had a nonzero?
predicate!
src/sicmutils/hestenic.cljc
Outdated
(grade [_] gr) | ||
|
||
Object | ||
(toString [_] (str "g" gr "{" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Tip for toString:
;; also, add an entry to src/data_readers.cljc:
{c sicmutils.complex/complex-from-pair}
;; This is a function of the data structure, or FORM, (already parsed by
;; Clojure's reader) that comes after #c.
(defn complex-from-pair [[re im]]
(complex re im))
(defmethod print-method Complex [^Complex v ^java.io.Writer w]
(.write w (str "#c " [(g/real-part v)
(g/imag-part v)])))
(defmethod print-dup Complex [^Complex v ^java.io.Writer w]
(.write w (str "#c " [(g/real-part v)
(g/imag-part v)])))
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Whoops, ignore the print-dup
thing, you only need print-method
.
src/sicmutils/hestenic.cljc
Outdated
(same-basis? [this otha])) | ||
|
||
|
||
(deftype Bladoid [cf bss] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
these abbreviations are a little cryptic for me... can we call them coef
and basis
? You can still write accessors for them with those same names.
Also, if you add an m
field, you can implement metadata by implementing IObj:
;; at the top of the file
(:import (clojure.lang IObj))
;; in the typedef
IObj
(meta [_] m)
(withMeta [_ m] (Bladoid. coef basis m))
The clojurescript version will be slightly different. I can help you get this all working for cljs too!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
a personal proscription is in play here. more on that via a different medium.
have adopted the following scheme: all fields' symbols' names will be the obvious ascii, prepended by f_
.
so in this case we now have
(deftype Bladoid [f_coef f_basis]
IBladoid
(coef [_] f_coef)
(basis [_] f_basis)
...
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
... as to the three-letter naming schema's crypticicity -- one may note that way way down at the bottom of the source code there are now explicitly semantic expansions for all the IHestenic protocol's denizens. e.g.:
(def grade-involution gri)
src/sicmutils/hestenic.cljc
Outdated
|
||
(defn- mv-map-biexploded-gradelings-and-sum [funq mvl mvr] | ||
(reduce mv-absorb-mv | ||
(MV. ()) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You might consider creating and binding this empty multivector once.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
sarantastic! done.
hm. looking at it in a bunch of code revealed that empty-mv
wasn't as visually distinguished as (MV. [])
... but problem solved by upgrading the name to the-empty-mv
, which also de-ambiguifies empty's part of speech. have gone back and done zero-element
--> the-zero-element
as well.
and also laid in a fresh monosupply of the-empty-gradeling
for good measure, and because the mood demands it.
;; rung conversions: one, yea, unto another. | ||
;; | ||
|
||
(extend-type Bladoid |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You can do these inside the type definition too, by the way.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
aye. though not all protocol implementations can be so done, because of forward reference issues.
this one'd work, i think, but i prefer it in a separate corral for cognitive-clustery goodness.
src/sicmutils/hestenic.cljc
Outdated
(asGradeling [this] | ||
(Gradeling. 1 (filter (fn [bl] (not= 0 (coef bl))) | ||
(map-indexed | ||
(fn [ind cf] (bladoid cf (vector ind))) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Prefer the literal [ind]
to (vector ind)
, especially if you change vect
to vector
above!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
as vect
ain't going nowheauh...
... can ye kindly explain the preference?
spankOutNothingness | ||
(gradelings this)) | ||
spnkd (filter | ||
(fn [grdl] (not (number? grdl))) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
v/number?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ibid..dibi
src/sicmutils/hestenic.cljc
Outdated
(quo [this otha] | ||
(prd this (inv otha))) | ||
(dot [this otha] | ||
(reduce + |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
no need for the 0
, reduce
calls the 0-arity of its aggregator function if there is no initializer, and that will return 0
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
sho' 'nuf.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
right. i kind of liked it originally for its signalling that it's specifically a scalar getting accumulated... but have now taken it out.
... for which: thanks abundant to sritchie! many improvements stylistic; a few representational. more and then more to come!
... meaning that their printed forms can now be recognized by the reader and hoovered back in. Congruent ouput versions too for Gradeling and MV, though as yet unclear whether there's value in reader-specialized input for these two.
…t... ... as well as supporting characters like the 'scalar?' predicate.
src/sicmutils/hestenic.cljc
Outdated
(defmacro with-metric | ||
[tric & formses] | ||
`(binding [*hestenic-metric* ~tric] | ||
~(conj formses 'do))) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You shouldn't need the do
, binding
can handle multiple forms internally! Try ~@formses
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
excellent; thanks! (and: done.)
src/sicmutils/hestenic.cljc
Outdated
(if (not= gra (grade head)) | ||
(throw (Exception. (str "incompatible grade: " | ||
head " but should be " gra))) | ||
(if (not (empty? body)) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
prefer (if (seq body) ...)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
prithee: wherefore?
src/sicmutils/hestenic.cljc
Outdated
([blds gra] | ||
(if (empty? blds) | ||
blds | ||
(loop [head (first blds) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The doseq
is going to be clearer, I think, vs an explicit loop/recur...
additional convenience funq for accumulating metric factors. Because we... care.
afa6dd7
to
c33ef42
Compare
This PR appears to be stalled. What's the holdup? Looking forward to using this to learn GA. |
Good day! And thanks for your interest in this GA implementation.
The 'hestenic' chunk of code in question needs a bunch of additional work before it would be appropriate to merge with the scimutils bloodline. And while my ardor for that project remains undimmed, I won't have time for a little while.
It's worth mentioning, though, that the design intent is to provide a set of GA tools that interoperates with the sicmutils system-of-systems but that also functions in a self-contained, standalone manner. And so... if your intent was to play around with GA in the context of sicmutils, then the news is not great short term (though eventually good); but if you wanted to experiment with 'hestenic' by itself, I could certainly provide access to it in an isolated repo.
john
… On Aug 14, 2022, at 10:59 AM, Huahai Yang ***@***.***> wrote:
This PR appears to be stalled. What's the holdup? Looking forward to using this to learn GA.
—
Reply to this email directly, view it on GitHub, or unsubscribe.
You are receiving this because you authored the thread.
|
@huahaiy this was a boutique exploration into GA, as @vanderoops notes; if you're interested in learning GA with sicmutils, I encourage you to go for it! What sort of materials are you looking for? An implementation of the types, sure, but beyond that, is there a book you're following along with, or something like that? Or are you looking for essays etc that go through the concepts, in addition to code? |
@vanderoops @sritchie Thanks for responding. I am not familiar with sicmutils at this moment, and certainly would be willing to dive in more, particularly if it has a good GA implementation, as that was my main interest. I have a few elementary books on GA, and they all mention the use of some software for some parts of the study. For example, Alan Macdonald's Linear and Geometric Algebra uses a GA module in SymPy; Miroslav Josipovic's Geometric Multiplication of Vectors uses Cl3 in Mathematica; Dorst et al.'s Geomtric algrebra for computer science discusses implementation of GA and has their own C++ implementation. I would ideally like an implementation of GA in Clojure to play with, hence my interest in this PR. |
…c ... ... and, indeed, add both 'grade' and 'grades' methods. Also, rename the grade selection (projection) operator from 'grade-part' to 'grp', to underscore its fundamentalness and parity with other operators. But then also alias the old prolix name back to the new ensveltened one.
... and also fix a shockingly naive-and-incomplete implementation of dot product for Vect.
... in order to support standalone loading (and by 'support' we mean 'enable at all without causing an error' (and by 'we' we mean 'i' (and by 'mean' we mean 'stony-hearted'))).
Here's another geometric algebra note for when we get this ported over: https://marctenbosch.com/quaternions/