Skip to content

Commit c775e8d

Browse files
authored
Merge pull request #72 from harold/dragon-complex-bits
Dragon complex bits
2 parents eb05b5c + 05b23a0 commit c775e8d

File tree

2 files changed

+121
-0
lines changed

2 files changed

+121
-0
lines changed
Lines changed: 121 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,121 @@
1+
^{:kindly/hide-code true
2+
:clay {:title "Dragon Curve Fractal - Complex & Bits"
3+
:quarto {:type :post
4+
:author [:harold]
5+
:date "2025-09-10"
6+
:draft true
7+
:description "A familiar image is re-discovered in a sequence of complex numbers and the binary representation of the natural numbers."
8+
:image "dragon-curve.png"
9+
:category :math
10+
:tags [:fractals :dragon :curve :complex :imaginary :binary]
11+
:keywords [:fractals :dragon :curve :complex :imaginary :binary]}}}
12+
(ns math.fractals.dragon.complex-bits
13+
(:require [clojure.string :as s]
14+
[fastmath.complex :as c]
15+
[scicloj.kindly.v4.kind :as kind]))
16+
17+
;; ### Part 1: Complex Numbers
18+
19+
;; Clojure's [fastmath](https://generateme.github.io/fastmath/notebooks/notebooks/complex_quaternion/index.html) library provides [complex numbers](https://en.wikipedia.org/wiki/Complex_number).
20+
21+
;; For example, if we let `a=b=1`, then
22+
23+
^:kindly/hide-code
24+
(kind/tex "a+bi=1+1i")
25+
26+
27+
(c/complex 1 1)
28+
29+
;; Here's a fun fact about powers of one more than the imaginary unit.
30+
31+
^:kindly/hide-code
32+
(kind/tex "(1+i)^k=\\sqrt{2}^ke^{ik\\pi/4}")
33+
34+
;; One does not need to be Euler to sense spinning,
35+
36+
;; and `k` from `(0 1 2 3 ...)` gives a sequence of points.
37+
38+
(def pts
39+
(for [k (range)]
40+
(c/pow (c/complex 1 1)
41+
(c/complex k 0))))
42+
43+
;; The first few of which are...
44+
45+
(take 10 pts)
46+
47+
;; I plot, therefore I am:
48+
49+
(kind/hiccup
50+
(into [:svg {:width "256" :height "256" :viewBox "-24 -24 48 48"}
51+
[:rect {:x -24 :y -24 :width 48 :height 48 :fill :#f8f8f8}]]
52+
(concat (for [[x y] (take 10 pts)]
53+
[:line {:x1 0 :y1 0 :x2 x :y2 y :stroke :#222}])
54+
(for [[x y] (take 10 pts)]
55+
[:circle {:cx x :cy y :r 1.5 :fill :#88f}]))))
56+
57+
;; Spinning indeed.
58+
59+
;; ---
60+
61+
;; ### Part 2: Binary Bits
62+
63+
;; In computers, numbers are made of bits.
64+
65+
(defn bit
66+
[n pos]
67+
(bit-and (int (/ n (Math/pow 2 pos))) 1))
68+
69+
(for [pos (reverse (range 8))]
70+
(bit 42 pos))
71+
72+
;; Hidden in the bits is a draconiform structure, we use them to carefully sum the `pts`.
73+
74+
(defn dragon-by-bits
75+
([n] (dragon-by-bits n (count (Integer/toBinaryString n))))
76+
([n pos]
77+
(letfn [(a [n pos]
78+
;; We move according to pts, occasionally turning
79+
(if (zero? (bit n pos))
80+
c/ZERO
81+
(let [turn? (if (zero? (bit n (inc pos)))
82+
c/ONE
83+
c/I)
84+
pt (nth pts pos)] ;; (1+i)^pos
85+
(c/mult turn? pt))))
86+
(m [n pos]
87+
;; When the bits flip, we turn
88+
(if (= (bit n pos) (bit n (inc pos)))
89+
c/ONE
90+
c/I))]
91+
(if (>= pos 0)
92+
(c/add (a n pos)
93+
(c/mult (m n pos)
94+
(dragon-by-bits n (dec pos))))
95+
c/ZERO))))
96+
97+
;; ---
98+
99+
;; ### Part 3: A Glimpse
100+
101+
;; > "It does not do to leave a live dragon out of your calculations, if you live near him."
102+
;; >
103+
;; > -- J.R.R. Tolkien
104+
105+
(let [dragon-pts (for [n (range 512)] (dragon-by-bits n))
106+
furthest (* 1.15 (apply max (map Math/abs (flatten dragon-pts))))
107+
[l t w h] [(- furthest) (- furthest) (* 2 furthest) (* 2 furthest)]]
108+
(kind/hiccup
109+
[:svg {:width "512" :height "512" :viewBox (s/join " " [l t w h])
110+
:shape-rendering :crispEdges}
111+
[:rect {:x l :y t :width w :height h :fill :#f8f8f8}]
112+
[:path {:d (reduce (fn [eax [x y]]
113+
(str eax " L" x " " y))
114+
(let [[x y] (first dragon-pts)]
115+
(str "M" x " " y))
116+
(rest dragon-pts))
117+
:vector-effect "non-scaling-stroke"
118+
:stroke :#222
119+
:fill :none}]]))
120+
121+
;; Inspired by this [lovely rosettacode gnuplot code](https://rosettacode.org/wiki/Dragon_curve#Version_#1.).
11.9 KB
Loading

0 commit comments

Comments
 (0)