Last active
August 29, 2015 14:06
-
-
Save rm-hull/11890fb5bb8789847259 to your computer and use it in GitHub Desktop.
A force-directed graph (using _arbor.js_) showing the orbits of small numbers under the Collatz map. Lothar Collatz first proposed the following conjecture in 1937: Take any natural number $n$. If $n$ is even, divide it by 2 to get $n / 2$. If $n$ is odd, multiply it by 3 and add 1 to obtain $3n + 1$. Repeat the process indefinitely. The conject…
This file contains 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
(ns arbor-demo.collatz-orbit | |
(:require | |
[arbor :as arbor] | |
[jayq.core :refer [show]] | |
[enchilada :refer [ctx canvas value-of]] | |
[monet.canvas :refer [begin-path move-to line-to save translate rotate restore | |
fill-style fill fill-rect circle text text-align text-baseline | |
stroke-style stroke-width stroke]])) | |
(defn draw-edge! [edge pt1 pt2] | |
(let [x1 (.-x pt1) | |
y1 (.-y pt1) | |
x2 (.-x pt2) | |
y2 (.-y pt2) | |
angle (+ (Math/atan (/ (- y2 y1) (- x2 x1))) | |
(/ Math/PI (if (> x2 x1) 2 -2)))] | |
(-> | |
ctx | |
(move-to x1 y1) ; line | |
(line-to x2 y2) | |
(save) ; arrow on (x2,y2) | |
(translate x2 y2) | |
(rotate angle) | |
(move-to 3 15) | |
(line-to 0 8) | |
(line-to -3 15) | |
(restore)))) | |
(defn draw-node! [node pt] | |
(let [args {:x (.-x pt) :y (.-y pt) :r 10 :text (.-name node)}] | |
(-> | |
ctx | |
(fill-style :lightgreen) | |
(circle args) | |
(fill) | |
(fill-style :black) | |
(text args)))) | |
(deftype Renderer [init redraw]) | |
(defn renderer [width height] | |
(let [particle-system (atom nil)] | |
(Renderer. | |
; init | |
(fn [system] | |
(reset! particle-system system) | |
(. @particle-system (screenSize width height)) | |
(. @particle-system (screenPadding 30))) | |
; redraw | |
(fn [] | |
(-> | |
ctx | |
(text-align :center) | |
(text-baseline :middle) | |
(fill-style :white) | |
(fill-rect {:x 0 :y 0 :w width :h height}) | |
(stroke-style :lightgrey) | |
(stroke-width 1) | |
(begin-path)) | |
(. @particle-system (eachEdge draw-edge!)) | |
(stroke ctx) | |
(. @particle-system (eachNode draw-node!)))))) | |
(defn collatz-seq [n] | |
(cons | |
n | |
(lazy-seq | |
(cond | |
(<= n 1) nil | |
(even? n) (collatz-seq (quot n 2)) | |
:else (collatz-seq (inc (* 3 n))))))) | |
(defn find-edges [state val] | |
(loop [[a b & more] val | |
edges state] | |
(if (or (nil? b) (edges a)) | |
edges | |
(recur | |
(cons b more) | |
(assoc edges a b))))) | |
(defn digraph [colls] | |
(reduce find-edges {} colls)) | |
; Start here | |
(let [n (js/parseInt (value-of :num 27)) | |
edges (->> (inc n) (range) (map collatz-seq) (digraph)) | |
sys (arbor/ParticleSystem. | |
(js/parseInt (value-of :repulsion 200)) | |
(js/parseInt (value-of :stiffness 500)) | |
(js/parseFloat (value-of :friction 0.3)) | |
false)] ; gravity | |
(show canvas) | |
(set! (.-renderer sys) (renderer 800 600)) | |
(doseq [[from to] edges] | |
(.addEdge sys (str from) (str to) (clj->js {"length" 2}))) | |
(doseq [[node _] edges] | |
(.addNode sys (str node) (clj->js {"mass" 1.0})))) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment