(ns test-project.synmods)
(defn add-open
[edges]
(let [[a b c d e f] edges
[a2 b2 c2 d2 e2 f2] (map (fn [x] (* x x)) edges )]
(do
(reduce + [
(reduce * [f2 a2 b2])
(reduce * [d2 a2 c2])
(reduce * [a2 b2 e2])
(reduce * [c2 b2 d2])
(reduce * [e2 c2 a2])
(reduce * [f2 c2 b2])
(reduce * [e2 d2 a2])
(reduce * [b2 d2 f2])
(reduce * [b2 e2 f2])
(reduce * [d2 e2 c2])
(reduce * [a2 f2 e2])
(reduce * [d2 f2 c2])])
)))
(defn add-closed
[edges]
(let [[a b c d e f] edges
[a2 b2 c2 d2 e2 f2] (map (fn [x] (* x x)) edges )]
(do
(reduce + [
(reduce * [a2 b2 d2])
(reduce * [d2 e2 f2])
(reduce * [b2 c2 e2])
(reduce * [a2 c2 f2])])
)))
(defn add-opposite
[edges]
(let [[a b c d e f] edges
[a2 b2 c2 d2 e2 f2] (map (fn [x] (* x x)) edges )]
(do
(reduce + [
(reduce * [a2 e2 (+ a2 e2)])
(reduce * [b2 f2 (+ b2 f2)])
(reduce * [c2 d2 (+ c2 d2)])])
)))
(defn Volume
[edges]
(let [ open ( add-open edges)
closed ( add-closed edges)
opposite ( add-opposite edges)]
(Math/sqrt (* (- (- open closed) opposite) 0.5))))
(println (format "All edges D=1, Volume: %s" (Volume [1.0 1.0 1.0 1.0 1.0 1.0]) ))
; A Module
(def a 1.0)
(def EF (* a (/ (Math/sqrt 6.0) 12.0 )))
(def EC (* a (/ (Math/sqrt 6.0) 4.0 )))
(def ED (* a (/ (Math/sqrt 2.0) 4.0 )))
(def FC (* a (/ (Math/sqrt 3.0) 3.0 )))
(def CD (/ a 2.0) )
(def DF (* a (/ (Math/sqrt 3.0) 6.0 )))
(def Avol (Volume [EF EC ED FC CD DF]))
(println (format "Amod volume: %s" Avol))
; E Module
; Fig. 986.411A T & E Module
; http://www.rwgrayprojects.com/synergetics/s09/figs/f86411a.html
(def D 1.0)
(def R (/ D 2.0))
(def h R)
(def OC h)
(def OA (* h (Math/sqrt (/ (- 5.0 (Math/sqrt 5.0)) 2.0))) )
(def OB (* h (Math/sqrt (/ (- 9.0 (* 3 (Math/sqrt 5.0))) 2.0))))
(def CA (* (/ h 2.0) (- (Math/sqrt 5.0) 1.0)))
(def AB (* h (Math/sqrt (- 5.0 (* 2.0 (Math/sqrt 5.0))))))
(def BC (* (/ h 2.0) (- 3.0 (Math/sqrt 5.0))))
(def Evol (Volume [OC OA OB CA AB BC]))
(println (format "Emod volume: %s" Evol))
; S Module
; Fig. 988.13A S Quanta Module Edge Lengths
; http://www.rwgrayprojects.com/synergetics/s09/figs/f8813a.html
(def a D)
(def FG (* (/ a 2.0) (* (Math/sqrt 3.0) (Math/sqrt (- 7.0 (* 3.0 ( Math/sqrt 5.0))))) ) )
(def FE (* a (Math/sqrt (- 7.0 (* 3.0 (Math/sqrt 5))))))
(def FH (* (/ a 2.0) (- (Math/sqrt 5.0) 1.0)))
(def GE (* (/ a 2.0) (Math/sqrt (- 7.0 (* 3.0 ( Math/sqrt 5))))))
(def EH (* (/ a 2.0) (- 3.0 (Math/sqrt 5.0))))
(def HG GE)
(def Svol (Volume [FG FE FH GE EH HG]))
(println (format "Smod volume: %s" Svol))
(println (format "sFactor: %s" (/ Svol Evol)))
--
You received this message because you are subscribed to the Google
Groups "Clojure" group.
To post to this group, send email to clo...@googlegroups.com
Note that posts from new members are moderated - please be patient with your first post.
To unsubscribe from this group, send email to
clojure+u...@googlegroups.com
For more options, visit this group at
http://groups.google.com/group/clojure?hl=en
---
You received this message because you are subscribed to the Google Groups "Clojure" group.
To unsubscribe from this group and stop receiving emails from it, send an email to clojure+u...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.
Thanks to excellent feedback, I now realize my code was overly verbose, a common phenomenon among beginners in many a computer language.
As an example, the newer version replaces this:
===(ns test-project.synmods)
(defn add-open
[edges]
(let [[a b c d e f] edges
[a2 b2 c2 d2 e2 f2] (map (fn [x] (* x x)) edges )]
(do
(reduce + [
(reduce * [f2 a2 b2])
(reduce * [d2 a2 c2])
(reduce * [a2 b2 e2])
(reduce * [c2 b2 d2])
(reduce * [e2 c2 a2])
(reduce * [f2 c2 b2])
(reduce * [e2 d2 a2])
(reduce * [b2 d2 f2])
(reduce * [b2 e2 f2])
(reduce * [d2 e2 c2])
(reduce * [a2 f2 e2])
(reduce * [d2 f2 c2])])
)))
... with this:
(defn add-open
[edges]
(let [[a b c d e f] edges
[a2 b2 c2 d2 e2 f2] (map (fn [x] (* x x)) edges )]
(+ (* f2 a2 b2)
(* d2 a2 c2)
(* a2 b2 e2)
(* c2 b2 d2)
(* e2 c2 a2)
(* f2 c2 b2)
(* e2 d2 a2)
(* b2 d2 f2)
(* b2 e2 f2)
(* d2 e2 c2)
(* a2 f2 e2)
(* d2 f2 c2))
))
Much simpler! Thank you. I'll look into testing features.
In my Python version of the above, I do in fact, invoke the unittest framework.
Kirby
;; instead of relying on the caller to pass the edges in the right order,
;; we accept a map and process the keys in the correct order
(defn- squared-edge-values
[edges]
(->> [:oc :oa :ob :ca :ab :bc]
(map #(edges %1))
(map #(* %1 %1))))
;; all operations on the edges are performed on the squared values.
;; the squared values are guaranteed to be in the correct order.
;; this separates out the logic specific to opposite edges and can be tested separately
(defn- opposite-edge-values
[edges]
(let [[a2 b2 c2 d2 e2 f2] (squared-edge-values edges)]
[[a2 e2 (+ a2 e2)]
[b2 f2 (+ b2 f2)]
[c2 d2 (+ c2 d2)]]))
(defn- closed-edge-values
[edges]
(let [[a2 b2 c2 d2 e2 f2] (squared-edge-values edges)]
[[a2 b2 d2]
[d2 e2 f2]
[b2 c2 e2]
[a2 c2 f2]]))
(defn- open-edge-values
[edges]
;; implement later
[[0 0 0]])
(defn- compute-edge-values
[edge-fn edges]
(->> edges
(edge-fn)
(map (fn [[x y z]] (* x y z)))
(reduce +)))
(def ^:private add-opposite (partial compute-edge-values opposite-edge-values))
(def ^:private add-closed (partial compute-edge-values closed-edge-values))
(def ^:private add-open (partial compute-edge-values open-edge-values))
;; this is the public entry point.
;; the precondition ensures all the edges are present in the input
(defn volume
[{:keys [oa ob oc ab bc ca] :as edges}]
{:pre [(every? #(number? %1) [oa ob oc ab bc ca])]}
(let [opposite (add-opposite edges)
closed (add-closed edges)
open (add-open edges)]
(Math/sqrt (* (- (- open closed) opposite) 0.5))))
;; sample input
(defn a-mod-input
[]
(let [a 1.0]
{:oc (* a (/ (Math/sqrt 6.0) 12.0))
:oa (* a (/ (Math/sqrt 6.0) 4.0))
:ob (* a (/ (Math/sqrt 2.0) 4.0))
:ca (* a (/ (Math/sqrt 3.0) 3.0))
:ab (/ a 2.0)
:bc (* a (/ (Math/sqrt 3.0) 6.0))}))
(defn e-mod-input
[]
(let [d 1.0
r (/ d 2.0)
h r]
{:oc h
:oa 1
:ob 1
:ca 1
:ab 1
:bc 1}))
(def a-mod-volume (volume (a-mod-input)))
(def e-mod-volume (volume (e-mod-input)))
This still seems very verbose to me. I think it is because the definition of "open," "opposite," and "closed" are implicit in the great big blocks of arithmetic you are doing. I think a useful exercise would be to define edges in terms of points, and maybe faces in terms of edges and an `face?` function. Then define different properties like `open?` in terms of functions on edges.
(ns test-project.synmods)
(defn add-open
[a2 b2 c2 d2 e2 f2]
(+ (* f2 a2 b2)
(* d2 a2 c2)
(* a2 b2 e2)
(* c2 b2 d2)
(* e2 c2 a2)
(* f2 c2 b2)
(* e2 d2 a2)
(* b2 d2 f2)
(* b2 e2 f2)
(* d2 e2 c2)
(* a2 f2 e2)
(* d2 f2 c2)))
(defn add-closed
[a2 b2 c2 d2 e2 f2]
(+ (* a2 b2 d2)(* d2 e2 f2)(* b2 c2 e2)(* a2 c2 f2)))
(defn add-opposite
[a2 b2 c2 d2 e2 f2]
(+ (* a2 e2 (+ a2 e2)) (* b2 f2 (+ b2 f2))(* c2 d2 (+ c2 d2))))
(defn Volume
[edges]
(let [[a2 b2 c2 d2 e2 f2] (map (fn [x] (* x x)) edges )]
(Math/sqrt (*
(-
(- (add-open a2 b2 c2 d2 e2 f2)(add-closed a2 b2 c2 d2 e2 f2) )
(add-opposite a2 b2 c2 d2 e2 f2))
0.5))))
(println (format "All edges D=1, Volume: %s" (Volume [1.0 1.0 1.0 1.0 1.0 1.0]) ))
; A Module
Hi,
From a cursory glance, I didn't really understand the domain, so the function names I used in my rewrite might seem silly. But I wanted to illustrate that there is a lot of repetition in your code. Also discrete functions (with proper names) can make the code easier to grok.
https://gist.github.com/amithgeorge/15b1cb607c32d39b70c7
On Thu, Jul 30, 2015 at 6:14 PM, Leif wrote:This still seems very verbose to me. I think it is because the definition of "open," "opposite," and "closed" are implicit in the great big blocks of arithmetic you are doing. I think a useful exercise would be to define edges in terms of points, and maybe faces in terms of edges and an `face?` function. Then define different properties like `open?` in terms of functions on edges.Yes, in the ecosystem I'm coming from, edges are indeed defined by two points, points being likewise vectors (in the coordinate system sense).
An Edge is defined by two Vectors e.g. (def a (length (Edge v0 v1))). For vectors, I sometimes use non-XYZ 4-tuples called Quadrays (check Wikipedia).
"""
(cl) K. Urner, MIT License 2015
Python -> Java -> Clojure curriculum
2D + 3D Graphics: Martian Math
Topic: Quadrays
http://www.grunch.net/synergetics/quadintro.html
https://en.wikipedia.org/wiki/Quadray_coordinates
Asynchronous Learning Engine (Open Source project)
http://controlroom.blogspot.com/2015/08/asynchronous-learning-engine-ale.htmlLink to Python version: https://mail.python.org/pipermail/edu-sig/2015-August/011291.html
"""
(ns test-project.quadrays)
(defprotocol Ops
(q-add [this other])
(q-sub [this other])
(q-len [this])
(q-neg [this])
(q-norm [this]))
(defrecord Quadray [OA OB OC OD]
Ops
(q-norm [this]
(let [[a b c d] [(:OA this) (:OB this) (:OC this) (:OD this)]
[x] [(min a b c d)]]
(Quadray. (- a x) (- b x) (- c x) (- d x))))
(q-neg [this] (q-norm (Quadray. (- 0 (:OA this))
(- 0 (:OB this) )
(- 0 (:OC this))
(- 0 (:OD this)))))
(q-len [this] (let [[a b c d] [(:OA this) (:OB this) (:OC this) (:OD this)]
[k] [(/ (+ a b c d) 4)]
[t0 t1 t2 t3] [(- a k) (- b k) (- c k) (- d k)]]
(* (Math/sqrt 2.0)
(Math/sqrt (+ (* t0 t0) (* t1 t1) (* t2 t2) (* t3 t3))))))
(q-add [this other]
(q-norm (Quadray. (+ (:OA this) (:OA other))
(+ (:OB this) (:OB other))
(+ (:OC this) (:OC other))
(+ (:OD this) (:OD other)))))
(q-sub [this other] (q-add this (q-neg other))))
(def v0 (Quadray. 1 0 0 0))
(def v1 (Quadray. 0 1 0 0))
(println str (q-sub v0 v1))
(println str (q-add v0 v1))
(println str (q-neg v1))
(println str (q-len v1))
(ns test-project.quadrays)
(defprotocol Ops
(q-add [this other])
(q-sub [this other])
(q-len [this])
(q-neg [this])
(q-norm [this]))
(defrecord Quadray [OA OB OC OD]
Ops
(q-norm [this]
(let [[a b c d] [(:OA this) (:OB this) (:OC this) (:OD this)]
[x] [(min a b c d)]]
(Quadray. (- a x) (- b x) (- c x) (- d x))))
(q-neg [this] (q-norm (Quadray. (- 0 (:OA this))
(- 0 (:OB this) )
(- 0 (:OC this))
(- 0 (:OD this)))))
(q-len [this] (let [[a b c d] [(:OA this) (:OB this) (:OC this) (:OD this)]
[k] [(/ (+ a b c d) 4)]
[t0 t1 t2 t3] [(- a k) (- b k) (- c k) (- d k)]]
(* (Math/sqrt 2.0)
(Math/sqrt (+ (* t0 t0) (* t1 t1) (* t2 t2) (* t3 t3))))))
Also, don't forget to explore the test framework versus global defs and print statements.
--
You received this message because you are subscribed to the Google
Groups "Clojure" group.
To post to this group, send email to clo...@googlegroups.com
Note that posts from new members are moderated - please be patient with your first post.
To unsubscribe from this group, send email to
clojure+u...@googlegroups.com
For more options, visit this group at
http://groups.google.com/group/clojure?hl=en
---
You received this message because you are subscribed to a topic in the Google Groups "Clojure" group.
To unsubscribe from this topic, visit https://groups.google.com/d/topic/clojure/RvHQPfBKJuM/unsubscribe.
To unsubscribe from this group and all its topics, send an email to clojure+u...@googlegroups.com.
--
You received this message because you are subscribed to the Google
Groups "Clojure" group.
To post to this group, send email to clo...@googlegroups.com
Note that posts from new members are moderated - please be patient with your first post.
To unsubscribe from this group, send email to
clojure+u...@googlegroups.com
For more options, visit this group at
http://groups.google.com/group/clojure?hl=en
---
You received this message because you are subscribed to the Google Groups "Clojure" group.
To unsubscribe from this group and stop receiving emails from it, send an email to clojure+u...@googlegroups.com.
and use for both vectors and quadrays, rather than a v-add / q-add, etc.Right, so if you use protocols, you'd just have one name:add, sub, norm, len, neg
If there are things that apply only to vectors and not quadrays, you could make those their own protocol (or individual functions).
And of course, multimethods are yet another way to achieve polymorphism in Clojure. Multimethods would really shine if you want to get into complicated mixtures of adding vectors and quadrays, etc., or dispatch on something other than the type (e.g., maybe pre-normalized quadrays dispatch to something more efficient). Protocols (like traditional OO) can only dispatch on the type of the first input.
(defn q-neg [{:keys [OA OB OC OD]}] (->Quadray (- OA)(- OB)(- OC) (- OD)))One other code simplification tip: you can destructure in the parameter, e.g., if you were to rewrite q-neg to be a plain function as opposed to a protocol, you could still get convenient access to the member variables by writing it like this:
http://www.john2x.com/blog/clojure-destructuring/
On Thu, Aug 6, 2015 at 1:52 PM, kirby urner <kirby...@gmail.com> wrote:Also, don't forget to explore the test framework versus global defs and print statements.--
(defrecord XYZray [OX OY OZ]
VectorOps
(norm [this] (this))
Your way "works" because basically you are building two extra vectors which are implicitly getting destructured, but that's syntactically noisy and also a lot of extra computational work that is unneeded.