Created
March 17, 2014 12:32
-
-
Save JonyEpsilon/9598415 to your computer and use it in GitHub Desktop.
Matrix form test
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
;; gorilla-repl.fileformat = 1 | |
;; ** | |
;;; # Thinking about core.matrix rendering | |
;;; | |
;;; Gorilla's renderer at the moment works by dispatching the render call on type. How might this work with core.matrix, and other things that are defined by _protocol_? | |
;;; | |
;;; One idea, sketched out in this worksheet is to use a view-function, much like is done in Mathematica. Internally it will work by wrapping the matrix in a marker type, but this should be viewed as an implementation detail. | |
;;; | |
;;; In Mathematica, matrices are represented by lists-of-lists, and on the whole, the notebook doesn't do anything special with them, displaying them like flat lists-of-lists. There'a a function, `MatrixForm` whose job is to tag the data for display in the front end as a matrix. | |
;;; | |
;;; ### Implementation | |
;;; | |
;;; We'll start with the implementation - skip below to see how it looks from the user perspective. | |
;; ** | |
;; @@ | |
(use 'clojure.core.matrix) | |
(use 'gorilla-renderable.core) | |
;; @@ | |
;; => | |
;;; {"type":"html","content":"<span class='clj-nil'>nil</span>","value":"nil"} | |
;; <= | |
;; ** | |
;;; This type is just a marker for the front end, to know to render its contents as a matrix. | |
;; ** | |
;; @@ | |
(defrecord MatrixForm [contents]) | |
;; @@ | |
;; => | |
;;; {"type":"html","content":"<span class='clj-unkown'>user.MatrixForm</span>","value":"user.MatrixForm"} | |
;; <= | |
;; ** | |
;;; A helper function, and an `extend-type` call (which at the minute are straight stolen from the table renderer, so you'll have to use your imagination on the formatting) tell Gorilla how to render things tagged as `MatrixForm`. These rendering functions would work using protocol methods, meaning it would work for any implementation. | |
;; ** | |
;; @@ | |
(defn list-like | |
[data value open close separator] | |
{:type :list-like | |
:open open | |
:close close | |
:separator separator | |
:items data | |
:value value}) | |
;; @@ | |
;; => | |
;;; {"type":"html","content":"<span class='clj-var'>#'user/list-like</span>","value":"#'user/list-like"} | |
;; <= | |
;; @@ | |
(extend-type MatrixForm | |
Renderable | |
(render [self] | |
(let [contents (:contents self) | |
rows (map (fn [r] (list-like (map render r) | |
(pr-str r) "<tr><td>" "</td></tr>" "</td><td>")) contents) | |
body (list-like rows | |
(pr-str self) "<center><table>" "</table></center>" "\n")] | |
body))) | |
;; @@ | |
;; => | |
;;; {"type":"html","content":"<span class='clj-nil'>nil</span>","value":"nil"} | |
;; <= | |
;; ** | |
;;; And then, finally the user-facing function, which from their perspective, shows the given object as a matrix. | |
;; ** | |
;; @@ | |
(defn matrix-form [i] (MatrixForm. i)) | |
;; @@ | |
;; => | |
;;; {"type":"html","content":"<span class='clj-var'>#'user/matrix-form</span>","value":"#'user/matrix-form"} | |
;; <= | |
;; ** | |
;;; ### User perspective | |
;;; | |
;;; The user can define a matrix: | |
;; ** | |
;; @@ | |
(def i (identity-matrix 5)) | |
;; @@ | |
;; => | |
;;; {"type":"html","content":"<span class='clj-var'>#'user/i</span>","value":"#'user/i"} | |
;; <= | |
;; ** | |
;;; And if they look at it, it will be faithfully rendered according to the underlying implementation. This is kind of nice in a way, as you can really see what's going on. | |
;; ** | |
;; @@ | |
i | |
;; @@ | |
;; => | |
;;; {"type":"list-like","open":"<span class='clj-vector'>[<span>","close":"<span class='clj-vector'>]</span>","separator":" ","items":[{"type":"list-like","open":"<span class='clj-vector'>[<span>","close":"<span class='clj-vector'>]</span>","separator":" ","items":[{"type":"html","content":"<span class='clj-double'>1.0</span>","value":"1.0"},{"type":"html","content":"<span class='clj-double'>0.0</span>","value":"0.0"},{"type":"html","content":"<span class='clj-double'>0.0</span>","value":"0.0"},{"type":"html","content":"<span class='clj-double'>0.0</span>","value":"0.0"},{"type":"html","content":"<span class='clj-double'>0.0</span>","value":"0.0"}],"value":"[1.0 0.0 0.0 0.0 0.0]"},{"type":"list-like","open":"<span class='clj-vector'>[<span>","close":"<span class='clj-vector'>]</span>","separator":" ","items":[{"type":"html","content":"<span class='clj-double'>0.0</span>","value":"0.0"},{"type":"html","content":"<span class='clj-double'>1.0</span>","value":"1.0"},{"type":"html","content":"<span class='clj-double'>0.0</span>","value":"0.0"},{"type":"html","content":"<span class='clj-double'>0.0</span>","value":"0.0"},{"type":"html","content":"<span class='clj-double'>0.0</span>","value":"0.0"}],"value":"[0.0 1.0 0.0 0.0 0.0]"},{"type":"list-like","open":"<span class='clj-vector'>[<span>","close":"<span class='clj-vector'>]</span>","separator":" ","items":[{"type":"html","content":"<span class='clj-double'>0.0</span>","value":"0.0"},{"type":"html","content":"<span class='clj-double'>0.0</span>","value":"0.0"},{"type":"html","content":"<span class='clj-double'>1.0</span>","value":"1.0"},{"type":"html","content":"<span class='clj-double'>0.0</span>","value":"0.0"},{"type":"html","content":"<span class='clj-double'>0.0</span>","value":"0.0"}],"value":"[0.0 0.0 1.0 0.0 0.0]"},{"type":"list-like","open":"<span class='clj-vector'>[<span>","close":"<span class='clj-vector'>]</span>","separator":" ","items":[{"type":"html","content":"<span class='clj-double'>0.0</span>","value":"0.0"},{"type":"html","content":"<span class='clj-double'>0.0</span>","value":"0.0"},{"type":"html","content":"<span class='clj-double'>0.0</span>","value":"0.0"},{"type":"html","content":"<span class='clj-double'>1.0</span>","value":"1.0"},{"type":"html","content":"<span class='clj-double'>0.0</span>","value":"0.0"}],"value":"[0.0 0.0 0.0 1.0 0.0]"},{"type":"list-like","open":"<span class='clj-vector'>[<span>","close":"<span class='clj-vector'>]</span>","separator":" ","items":[{"type":"html","content":"<span class='clj-double'>0.0</span>","value":"0.0"},{"type":"html","content":"<span class='clj-double'>0.0</span>","value":"0.0"},{"type":"html","content":"<span class='clj-double'>0.0</span>","value":"0.0"},{"type":"html","content":"<span class='clj-double'>0.0</span>","value":"0.0"},{"type":"html","content":"<span class='clj-double'>1.0</span>","value":"1.0"}],"value":"[0.0 0.0 0.0 0.0 1.0]"}],"value":"[[1.0 0.0 0.0 0.0 0.0] [0.0 1.0 0.0 0.0 0.0] [0.0 0.0 1.0 0.0 0.0] [0.0 0.0 0.0 1.0 0.0] [0.0 0.0 0.0 0.0 1.0]]"} | |
;; <= | |
;; ** | |
;;; But, if you want to look at it as a matrix, then you can put it in to matrix-form. | |
;; ** | |
;; @@ | |
(matrix-form i) | |
;; @@ | |
;; => | |
;;; {"type":"list-like","open":"<center><table>","close":"</table></center>","separator":"\n","items":[{"type":"list-like","open":"<tr><td>","close":"</td></tr>","separator":"</td><td>","items":[{"type":"html","content":"<span class='clj-double'>1.0</span>","value":"1.0"},{"type":"html","content":"<span class='clj-double'>0.0</span>","value":"0.0"},{"type":"html","content":"<span class='clj-double'>0.0</span>","value":"0.0"},{"type":"html","content":"<span class='clj-double'>0.0</span>","value":"0.0"},{"type":"html","content":"<span class='clj-double'>0.0</span>","value":"0.0"}],"value":"[1.0 0.0 0.0 0.0 0.0]"},{"type":"list-like","open":"<tr><td>","close":"</td></tr>","separator":"</td><td>","items":[{"type":"html","content":"<span class='clj-double'>0.0</span>","value":"0.0"},{"type":"html","content":"<span class='clj-double'>1.0</span>","value":"1.0"},{"type":"html","content":"<span class='clj-double'>0.0</span>","value":"0.0"},{"type":"html","content":"<span class='clj-double'>0.0</span>","value":"0.0"},{"type":"html","content":"<span class='clj-double'>0.0</span>","value":"0.0"}],"value":"[0.0 1.0 0.0 0.0 0.0]"},{"type":"list-like","open":"<tr><td>","close":"</td></tr>","separator":"</td><td>","items":[{"type":"html","content":"<span class='clj-double'>0.0</span>","value":"0.0"},{"type":"html","content":"<span class='clj-double'>0.0</span>","value":"0.0"},{"type":"html","content":"<span class='clj-double'>1.0</span>","value":"1.0"},{"type":"html","content":"<span class='clj-double'>0.0</span>","value":"0.0"},{"type":"html","content":"<span class='clj-double'>0.0</span>","value":"0.0"}],"value":"[0.0 0.0 1.0 0.0 0.0]"},{"type":"list-like","open":"<tr><td>","close":"</td></tr>","separator":"</td><td>","items":[{"type":"html","content":"<span class='clj-double'>0.0</span>","value":"0.0"},{"type":"html","content":"<span class='clj-double'>0.0</span>","value":"0.0"},{"type":"html","content":"<span class='clj-double'>0.0</span>","value":"0.0"},{"type":"html","content":"<span class='clj-double'>1.0</span>","value":"1.0"},{"type":"html","content":"<span class='clj-double'>0.0</span>","value":"0.0"}],"value":"[0.0 0.0 0.0 1.0 0.0]"},{"type":"list-like","open":"<tr><td>","close":"</td></tr>","separator":"</td><td>","items":[{"type":"html","content":"<span class='clj-double'>0.0</span>","value":"0.0"},{"type":"html","content":"<span class='clj-double'>0.0</span>","value":"0.0"},{"type":"html","content":"<span class='clj-double'>0.0</span>","value":"0.0"},{"type":"html","content":"<span class='clj-double'>0.0</span>","value":"0.0"},{"type":"html","content":"<span class='clj-double'>1.0</span>","value":"1.0"}],"value":"[0.0 0.0 0.0 0.0 1.0]"}],"value":"#user.MatrixForm{:contents [[1.0 0.0 0.0 0.0 0.0] [0.0 1.0 0.0 0.0 0.0] [0.0 0.0 1.0 0.0 0.0] [0.0 0.0 0.0 1.0 0.0] [0.0 0.0 0.0 0.0 1.0]]}"} | |
;; <= |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment