-
-
Notifications
You must be signed in to change notification settings - Fork 68
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
dot-product, inner-product, outer-product, and many more structure functions #193
Conversation
Codecov Report
@@ Coverage Diff @@
## master #193 +/- ##
==========================================
- Coverage 84.94% 84.76% -0.19%
==========================================
Files 74 74
Lines 7042 7206 +164
Branches 386 401 +15
==========================================
+ Hits 5982 6108 +126
- Misses 674 697 +23
- Partials 386 401 +15
Continue to review full report at Codecov.
|
@@ -382,11 +382,10 @@ | |||
(fn [i v_i] | |||
(structural-derivative | |||
(fn [w] | |||
(g (struct/structure-assoc-in v [i] w))) |
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.
woohoo, I figured out the interfaces we needed to make the native thing 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.
nice. It is a noticeable improvement.
@@ -475,6 +476,8 @@ | |||
(define-unary-operation g/square #(diff-* % %)) | |||
(define-unary-operation g/cube #(diff-* % (diff-* % %))) | |||
|
|||
(define-binary-operation g/dot-product diff-*) |
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.
this is the only one that scmutils implements - differential feels like it should implement conjugate and inner product, yeah?
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 agree. scm punts on conjugate. inner-product is not exposed in the version I'm using. dot-product and outer-product work, so we should do all the ones we can.
@@ -85,7 +85,7 @@ | |||
" var _000e = Math.cos(_000a);\n" | |||
" var _0010 = Math.sin(_000a);\n" | |||
" var _0011 = Math.pow(_0010, 2);\n" | |||
" return [1, [thetadot, phidot], [(- l1 * m2 * _0006 * _0010 * _000e - l2 * m2 * _0005 * _0010 + g * m2 * _000e * _0008 - g * m1 * _0009 - g * m2 * _0009) / (l1 * m2 * _0011 + l1 * m1), (l2 * m2 * _0005 * _0010 * _000e + l1 * m1 * _0006 * _0010 + l1 * m2 * _0006 * _0010 + g * m1 * _0009 * _000e + g * m2 * _0009 * _000e - g * m1 * _0008 - g * m2 * _0008) / (l2 * m2 * _0011 + l2 * m1)]];\n" |
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.
that structure change caused some of these tests to switch variable order.
(is (= (if (v/one? x) 1 x) | ||
(g/* x 1)) "First unity gets returned.") | ||
(is (= x (g/* 1 x)) "Anything times a 1 returns itself."))) | ||
(checking "g/*" 100 [x gen/any] |
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/=
replaces =
, for the rarish case of (= 0 0.0)
turning up false.
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.
Huh! I forgot about that. (Clojure also has ==
that does 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.
re: ==
: I think that can ONLY do numbers, so when I generate via gen/any
it solves our problem but breaks on non-numeric things.
@littleredcomputer , I ended up spending another day fleshing out the This uncovered a few bugs with the way we were handling deeply nested structures. It didn't matter as much (except the double pendulum equations of motion had an issue that you'll see), but the behavior of the I think this brings us up to as much parity with the refman as I could hope for. The PR is pretty big because of a ton of tests. I am happy to split this up - most of the reading is in Would love feedback here, since I know you've been deep in the Structure Mines and have thoughts here! |
641ba7d
to
3d2a3c7
Compare
@@ -475,6 +476,8 @@ | |||
(define-unary-operation g/square #(diff-* % %)) | |||
(define-unary-operation g/cube #(diff-* % (diff-* % %))) | |||
|
|||
(define-binary-operation g/dot-product diff-*) |
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 agree. scm punts on conjugate. inner-product is not exposed in the version I'm using. dot-product and outer-product work, so we should do all the ones we can.
(pairs))] | ||
(reduce - 0 (map (fn [[[m1 p1] [m2 p2]]] | ||
(/ (* m1 m2) | ||
(sqrt (square (- p1 p2))))) |
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 could use abs
here
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.
will do in my followup!
(is (= (if (v/one? x) 1 x) | ||
(g/* x 1)) "First unity gets returned.") | ||
(is (= x (g/* 1 x)) "Anything times a 1 returns itself."))) | ||
(checking "g/*" 100 [x gen/any] |
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.
Huh! I forgot about that. (Clojure also has ==
that does this).
@@ -382,11 +382,10 @@ | |||
(fn [i v_i] | |||
(structural-derivative | |||
(fn [w] | |||
(g (struct/structure-assoc-in v [i] w))) |
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.
nice. It is a noticeable improvement.
If `n` is not supplied returns an infinite sequence." | ||
([i] (map (partial kronecker i) | ||
(range))) | ||
([n i] (into [] (take n) (basis-unit i)))) |
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.
why not let them both return a seq
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.
good idea, I for some reason thought this was the defensive way to go, but it looks like any place this is used makes a vector if it needs to.
:else false) | ||
:else false)) | ||
|
||
(defn structure? |
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.
Did you consider leaning on our keyword-based type system for these decisions?
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.
Good idea. I'll do that in the same followup as the other suggestion.
(let [path (join ":" chain)] | ||
(symbol | ||
(str name path)))) | ||
(structure->access-chains 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.
we could keep compatibility with scmutils of course. We could also, instead of using :
, use ↑
and _
. Then it would be the basis for a literal structure. WDYT?
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.
Yes, this is awesome. I'm going to do this in a separate PR. I can do it be returning a sequence of [::up ::down ::down]
etc attached as metadata to the chain... then anyone can get access to this info if they want, and we can use it here.
That will, as you say, give us the property that this structure will match our literal structures AND our literal matrix notation.
row (m/up->row-matrix s)] | ||
(is (= (g/outer-product s s) | ||
(g/outer-product col row)))))) | ||
|
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 could have (unless I overlooked it) a test that asserts that (* (transpose v) v)
is square for any structure 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.
is that true? I think any structure now will collapse to a number...
That IS true for transpose-outer
with 2-tensors. Good test, will add.
Our structure operations have a few incompatibilities with the refman / scmutils implementation that I thought we might get dialed before release.
As of this PR, we have some new generic operations:
g/dot-product
, for scalars, differentials, structures, functions androw/column matrices
g/inner-product
for scalars, structures, functions and row/column matricesg/outer-product
for functions, structures of length 3 and matrices, betweena row and a column only
g/cross-product
now works for row/column matrices in addition to structures(and functions that accept these)
Structures got a lot of love too:
Structures and matrices both gain the ability to do native
get-in
,assoc-in
andempty
. These work as expected, like a potentially nestedvector. (#193)
matrix.cljc
gainsup->row-matrix
,up->column-matrix
,row-matrix->up
,column-matrix->up
(#193)
structure.cljc
gains many features in(#193):
kronecker
andbasis-unit
for generating potentially infinite basisvectors
(conj (up 1 2) 3) => (up 1 2 3)
map-chain
takes a 2-arg function and presents itwith each element of a deeply nested structure, along with a vector of its
"chain", the path into its location. The fn's return becomes the new item at
that location.
structure->prototype
generates a same-shape structure as its argument,with symbolic entries that display their location.
typical-object
returns a structure of the same shape and orientation ass
, generated by substituting gensymmed symbols in for each entry.compatible-zero
returns a structure compatible for multiplication withs
down to 0.
transpose-outer
returns a new structure with the same orientation as thefirst element of
s
, filled with elements of the same orientation ass
.Each element is generating by taking the first element of each entry in
s
,the the second, etc... In that sense this is similar to a traditional matrix
transpose.
dot-product
takes the dot product of two structures. They must be the sametop-level orientation and dimension; beyond that, their entries are
pairwise-multiplied and summed.
inner-product
is the same, but the left structure is conjugated first.outer-product
now works multiple levels deep.vector-outer-product
andvector-inner-product
are similar, but onlyenforce the top-level length; all internal structures are NOT flattened and
must be compatible for
g/*
.compatible-for-contraction?
now searches recursively down into astructure; previously it only checked the top level.
*allow-incompatible-multiplication*
dynamic variable is set totrue
by default. Set it false to force a setting where, when you multiplystructures, they must be:
the left
case any multiplication is not commutative.