Create a gist now

Instantly share code, notes, and snippets.

What would you like to do?
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…
(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