diff --git a/papers/0e1ff664a2fdc8d1fd082c6e75e4f06fdef1.pdf b/papers/0e1ff664a2fdc8d1fd082c6e75e4f06fdef1.pdf new file mode 100644 index 0000000..56e6f10 Binary files /dev/null and b/papers/0e1ff664a2fdc8d1fd082c6e75e4f06fdef1.pdf differ diff --git a/papers/active-hc-svd-8570249.pdf b/papers/active-hc-svd-8570249.pdf new file mode 100644 index 0000000..da9ede9 Binary files /dev/null and b/papers/active-hc-svd-8570249.pdf differ diff --git a/papers/hc-begin-PM279.pdf b/papers/hc-begin-PM279.pdf new file mode 100644 index 0000000..8b58b71 Binary files /dev/null and b/papers/hc-begin-PM279.pdf differ diff --git a/papers/hc-dict-Lazendic-0726.pdf b/papers/hc-dict-Lazendic-0726.pdf new file mode 100644 index 0000000..618d708 Binary files /dev/null and b/papers/hc-dict-Lazendic-0726.pdf differ diff --git a/papers/hc-dsp-1568981962.pdf b/papers/hc-dsp-1568981962.pdf new file mode 100644 index 0000000..9458f84 Binary files /dev/null and b/papers/hc-dsp-1568981962.pdf differ diff --git a/papers/hc-dsp-2004_Signal_Processing_Quater_NLB.pdf b/papers/hc-dsp-2004_Signal_Processing_Quater_NLB.pdf new file mode 100644 index 0000000..5d7691d Binary files /dev/null and b/papers/hc-dsp-2004_Signal_Processing_Quater_NLB.pdf differ diff --git a/papers/hc-dsp-c2l-b01.pdf b/papers/hc-dsp-c2l-b01.pdf new file mode 100644 index 0000000..add95bb Binary files /dev/null and b/papers/hc-dsp-c2l-b01.pdf differ diff --git a/papers/hc-handbook-main-01e.pdf b/papers/hc-handbook-main-01e.pdf new file mode 100644 index 0000000..766e896 Binary files /dev/null and b/papers/hc-handbook-main-01e.pdf differ diff --git a/papers/hc-historya65bfe1d9d3b004338fdd56b8a0029e0e276.pdf b/papers/hc-historya65bfe1d9d3b004338fdd56b8a0029e0e276.pdf new file mode 100644 index 0000000..fc60500 Binary files /dev/null and b/papers/hc-historya65bfe1d9d3b004338fdd56b8a0029e0e276.pdf differ diff --git a/papers/hc-mat-25260840.pdf b/papers/hc-mat-25260840.pdf new file mode 100644 index 0000000..3ca8d1c Binary files /dev/null and b/papers/hc-mat-25260840.pdf differ diff --git a/papers/hc-mat-octonion_matrix.pdf b/papers/hc-mat-octonion_matrix.pdf new file mode 100644 index 0000000..42c86e3 Binary files /dev/null and b/papers/hc-mat-octonion_matrix.pdf differ diff --git a/papers/hc-matx-hcnumbers.pdf b/papers/hc-matx-hcnumbers.pdf new file mode 100644 index 0000000..0e446a1 Binary files /dev/null and b/papers/hc-matx-hcnumbers.pdf differ diff --git a/papers/hc-mult-9.pdf b/papers/hc-mult-9.pdf new file mode 100644 index 0000000..4129b94 Binary files /dev/null and b/papers/hc-mult-9.pdf differ diff --git a/papers/hc-numerical-1708.04021.pdf b/papers/hc-numerical-1708.04021.pdf new file mode 100644 index 0000000..89e56f4 Binary files /dev/null and b/papers/hc-numerical-1708.04021.pdf differ diff --git a/papers/hc-pca-1801.03773.pdf b/papers/hc-pca-1801.03773.pdf new file mode 100644 index 0000000..11a1090 Binary files /dev/null and b/papers/hc-pca-1801.03773.pdf differ diff --git a/papers/hc-svd-0003979.pdf b/papers/hc-svd-0003979.pdf new file mode 100644 index 0000000..4010371 Binary files /dev/null and b/papers/hc-svd-0003979.pdf differ diff --git a/papers/hc-svd-0603251.pdf b/papers/hc-svd-0603251.pdf new file mode 100644 index 0000000..99c0b11 Binary files /dev/null and b/papers/hc-svd-0603251.pdf differ diff --git a/papers/hc-svd-Computing-the-SVD-of-a-quaternion-matrix.pdf b/papers/hc-svd-Computing-the-SVD-of-a-quaternion-matrix.pdf new file mode 100644 index 0000000..14426f5 Binary files /dev/null and b/papers/hc-svd-Computing-the-SVD-of-a-quaternion-matrix.pdf differ diff --git a/papers/hc-svd-icme13_kqsvd_supp.pdf b/papers/hc-svd-icme13_kqsvd_supp.pdf new file mode 100644 index 0000000..9f1ad1a Binary files /dev/null and b/papers/hc-svd-icme13_kqsvd_supp.pdf differ diff --git a/papers/hc-svd5d8d0f9537bf9d699d3305fe91e6025d5ad1.pdf b/papers/hc-svd5d8d0f9537bf9d699d3305fe91e6025d5ad1.pdf new file mode 100644 index 0000000..5cf3191 Binary files /dev/null and b/papers/hc-svd5d8d0f9537bf9d699d3305fe91e6025d5ad1.pdf differ diff --git a/project.clj b/project.clj index ee1ae5d..fe3479b 100644 --- a/project.clj +++ b/project.clj @@ -7,9 +7,26 @@ :plugins [[lein-ancient "0.6.14"] [jonase/eastwood "0.2.5"] [lein-kibit "0.1.5"] - [lein-bikeshed "0.5.0"]] - :dependencies [[org.clojure/clojure "1.10.0-beta7"] - [org.apache.commons/commons-math3 "3.6.1"]] + [lein-bikeshed "0.5.0"] + [venantius/yagni "0.1.7"]] + :dependencies [[org.clojure/clojure "1.10.0"] + [org.clojure/test.check "0.10.0-alpha3"] + [org.apache.commons/commons-math3 "3.6.1"] + [me.raynes/fs "1.4.6"] + [net.mikera/imagez "0.12.0"] + [com.taoensso/nippy "2.14.0"] + [thi.ng/geom "0.0.908"] + [thi.ng/geom-core "0.0.908"] + [thi.ng/geom-types "0.0.908"] + [thi.ng/geom-meshops "0.0.908"] + [thi.ng/geom-physics "0.0.908"] + [thi.ng/geom-svg "0.0.908"] + [thi.ng/geom-viz "0.0.908"] + [thi.ng/geom-voxel "0.0.908"] + [thi.ng/geom-webgl "0.0.908"]] + :jvm-opts ["-Xmx30G" + "-XX:+UseCompressedOops" + "-XX:+HeapDumpOnOutOfMemoryError"] :main ^:skip-aot hypercomplex.core :target-path "target/%s" :profiles {:uberjar {:aot :all}}) diff --git a/src/hypercomplex/alpha/core_spec.clj b/src/hypercomplex/alpha/core_spec.clj new file mode 100644 index 0000000..5d7f50c --- /dev/null +++ b/src/hypercomplex/alpha/core_spec.clj @@ -0,0 +1,112 @@ +(ns hypercomplex.alpha.core-spec + (:require [clojure.spec.alpha :as s] + [clojure.spec.gen.alpha :as gen] + [hypercomplex.core :refer :all] + [hypercomplex.alpha.fractal-spec :as fs] + [hypercomplex.cayley-dickson-construction :refer + [complex quaternion octonion sedenion + pathion n-hypercomplex power-of?]]) + (:import (hypercomplex.core Complex2Apache Complex2 Construction))) + +(set! *unchecked-math* true) +(set! *warn-on-reflection* true) + +(def MAX-TRIES 10000) + +(s/def ::complex2-apache + (s/with-gen + #(and (instance? Complex2Apache %) + (satisfies? Nion %) + (satisfies? NionOps %)) + (fn [] + (gen/fmap + (fn [[a b]] + (init-complex2 a b :apache)) + (gen/tuple + (s/gen ::fs/coeff) + (s/gen ::fs/coeff)))))) + +(s/def ::complex2-plain + (s/with-gen + #(and (instance? Complex2 %) + (satisfies? Nion %) + (satisfies? NionOps %)) + (fn [] + (gen/fmap + (fn [[a b]] + (init-complex2 a b :plain)) + (gen/tuple + (s/gen ::fs/coeff) + (s/gen ::fs/coeff)))))) + +(s/def ::hypercomplex-apache + (s/with-gen + #(and (instance? Construction %) + (satisfies? Nion %) + (satisfies? NionOps %)) + (fn [] + (gen/fmap + (fn [coeffs] + (n-hypercomplex coeffs :apache)) + (gen/such-that + (fn [coeffs] + (and + (power-of? (count coeffs) 2))) + (gen/vector-distinct + (s/gen ::fs/coeff) + {:min-elements 2 + :max-elements 257}) + MAX-TRIES))))) + +(s/def ::hypercomplex-plain + (s/with-gen + #(and (instance? Construction %) + (satisfies? Nion %) + (satisfies? NionOps %)) + (fn [] + (gen/fmap + (fn [coeffs] + (n-hypercomplex coeffs :plain)) + (gen/such-that + (fn [coeffs] + (and + (power-of? (count coeffs) 2))) + (gen/vector-distinct + (s/gen ::fs/coeff) + {:min-elements 2 + :max-elements 257}) + MAX-TRIES))))) + +(s/def ::construction-apache + (s/with-gen + #(and (instance? Construction %) + (satisfies? Nion %) + (satisfies? NionOps %)) + (fn [] + (gen/fmap + (fn [[a b]] + (init-construction a b)) + (gen/such-that + (fn [[a b]] + (eq-order? a b)) + (gen/tuple + (s/gen ::hypercomplex-apache) + (s/gen ::hypercomplex-apache)) + MAX-TRIES))))) + +(s/def ::construction-plain + (s/with-gen + #(and (instance? Construction %) + (satisfies? Nion %) + (satisfies? NionOps %)) + (fn [] + (gen/fmap + (fn [[a b]] + (init-construction a b)) + (gen/such-that + (fn [[a b]] + (eq-order? a b)) + (gen/tuple + (s/gen ::hypercomplex-plain) + (s/gen ::hypercomplex-plain)) + MAX-TRIES))))) diff --git a/src/hypercomplex/alpha/fractal_colors.clj b/src/hypercomplex/alpha/fractal_colors.clj new file mode 100644 index 0000000..f952065 --- /dev/null +++ b/src/hypercomplex/alpha/fractal_colors.clj @@ -0,0 +1,176 @@ +(ns hypercomplex.alpha.fractal-colors) + +(def MAX-COLOR-YELLOW (int-array [220 230 22 255])) + +(defn palette-green-to-red [iters max-iters] + (if (or #_(< iterations 10) + (= iters max-iters)) + MAX-COLOR-YELLOW + (let [total-intensity (int (/ (* iters 255) max-iters)) + r (min + (int (+ 20 total-intensity)) 255) + g (min + (int (- 255 total-intensity)) 255) + b (min + (int (Math/abs (- total-intensity 80))) 255)] + (int-array [r g b 255])))) + +(defn palette-rainbox [iters max-iters] + (let [total-intensity (/ iters max-iters) + [r g b imax] (cond + (<= 0.0 total-intensity 0.2) [3 146 207 0.2] + (<= 0.2 total-intensity 0.4) [123 192 67 0.4] + (<= 0.4 total-intensity 0.6) [253 244 152 0.6] + (<= 0.6 total-intensity 0.8) [243 119 54 0.8] + (<= 0.8 total-intensity 1.0) [238 64 53 1.0]) + [r g b] (->> + [r g b] + (map + #(* % (/ total-intensity imax))) + (map int))] + (int-array [r g b 255]))) + +(defn blend [w1 [r1 g1 b1] w2 [r2 g2 b2]] + [ + (int (/ (+ (* w1 r1) (* w2 r2)) (+ w1 w2))) + (int (/ (+ (* w1 g1) (* w2 g2)) (+ w1 w2))) + (int (/ (+ (* w1 b1) (* w2 b2)) (+ w1 w2))) + ]) + +(defn palette-rainbox2 [iters max-iters] + + (let [tenth (/ max-iters 10.0) + [base sub-pct] (cond + (< iters tenth) [[3 146 207] (/ iters tenth)] + (< iters (* 2 tenth)) [[55 146 170] (/ iters (* 2 tenth))] + (< iters (* 3 tenth)) [[75 155 130] (/ iters (* 3 tenth))] + (< iters (* 4 tenth)) [[153 204 94] (/ iters (* 4 tenth))] + (< iters (* 5 tenth)) [[203 222 123] (/ iters (* 5 tenth))] + (< iters (* 6 tenth)) [[253 244 152] (/ iters (* 6 tenth))] + (< iters (* 7 tenth)) [[250 201 101] (/ iters (* 7 tenth))] + (< iters (* 8 tenth)) [[243 119 54] (/ iters (* 8 tenth))] + (< iters (* 9 tenth)) [[240 64 51] (/ iters (* 9 tenth))] + (<= iters (* 10 tenth)) [[235 3 44] (/ iters max-iters)]) + [r g b] (blend + sub-pct + base + (- 1.0 sub-pct) + [100 100 100])] + (int-array [r g b 255]))) + +(defn palette-rainbox3 [iters max-iters] + (let [pct-intensity (/ iters max-iters) + [r g b] (cond + (zero? pct-intensity) [0 0 255] + (<= 0.0 pct-intensity 0.01) [3 146 207] + (<= 0.01 pct-intensity 0.02) [10 149 200] + (<= 0.02 pct-intensity 0.03) [15 152 190] + (<= 0.03 pct-intensity 0.04) [20 155 180] + (<= 0.04 pct-intensity 0.05) [25 160 175] + (<= 0.05 pct-intensity 0.06) [30 165 171] + (<= 0.06 pct-intensity 0.07) [35 168 168] + (<= 0.07 pct-intensity 0.08) [40 171 164] + (<= 0.08 pct-intensity 0.09) [45 175 160] + (<= 0.09 pct-intensity 0.1) [50 180 154] + (<= 0.1 pct-intensity 0.11) [55 182 144] + (<= 0.11 pct-intensity 0.12) [60 184 134] + (<= 0.12 pct-intensity 0.13) [70 186 124] + (<= 0.13 pct-intensity 0.14) [80 188 114] + (<= 0.14 pct-intensity 0.15) [90 192 110] + (<= 0.15 pct-intensity 0.16) [100 194 105] + (<= 0.16 pct-intensity 0.17) [110 196 100] + (<= 0.17 pct-intensity 0.18) [120 197 95] + (<= 0.18 pct-intensity 0.19) [130 198 90] + (<= 0.19 pct-intensity 0.2) [143 200 87] + + (<= 0.20 pct-intensity 0.21) [153 204 94] + (<= 0.21 pct-intensity 0.22) [158 206 97] + (<= 0.22 pct-intensity 0.23) [162 208 102] + (<= 0.23 pct-intensity 0.24) [166 210 106] + (<= 0.24 pct-intensity 0.25) [171 212 110] + (<= 0.25 pct-intensity 0.26) [175 214 114] + (<= 0.26 pct-intensity 0.27) [180 216 117] + (<= 0.27 pct-intensity 0.28) [187 219 120] + (<= 0.28 pct-intensity 0.29) [191 222 123] + (<= 0.29 pct-intensity 0.3) [195 225 126] + (<= 0.3 pct-intensity 0.31) [199 228 129] + (<= 0.31 pct-intensity 0.32) [202 231 133] + (<= 0.32 pct-intensity 0.33) [208 232 136] + (<= 0.33 pct-intensity 0.34) [215 235 139] + (<= 0.34 pct-intensity 0.35) [219 237 143] + (<= 0.35 pct-intensity 0.36) [223 238 144] + (<= 0.36 pct-intensity 0.37) [228 239 146] + (<= 0.37 pct-intensity 0.38) [235 240 148] + (<= 0.38 pct-intensity 0.39) [241 241 150] + (<= 0.39 pct-intensity 0.4) [245 242 151] + + (<= 0.4 pct-intensity 0.41) [253 244 152] + + (<= 0.41 pct-intensity 0.42) [252 238 148] + (<= 0.42 pct-intensity 0.43) [251 233 143] + (<= 0.43 pct-intensity 0.44) [250 228 138] + (<= 0.44 pct-intensity 0.45) [249 222 133] + (<= 0.45 pct-intensity 0.46) [248 218 128] + (<= 0.46 pct-intensity 0.47) [247 210 122] + (<= 0.47 pct-intensity 0.48) [246 204 118] + (<= 0.48 pct-intensity 0.49) [245 195 113] + (<= 0.49 pct-intensity 0.5) [244 190 108] + (<= 0.5 pct-intensity 0.51) [244 180 103] + (<= 0.51 pct-intensity 0.52) [244 175 98] + (<= 0.52 pct-intensity 0.53) [244 170 93] + (<= 0.53 pct-intensity 0.54) [244 160 88] + (<= 0.54 pct-intensity 0.55) [244 155 83] + (<= 0.55 pct-intensity 0.56) [244 150 78] + (<= 0.56 pct-intensity 0.57) [244 145 72] + (<= 0.57 pct-intensity 0.58) [244 140 65] + (<= 0.58 pct-intensity 0.59) [244 135 62] + (<= 0.59 pct-intensity 0.6) [244 125 59] + + + (<= 0.6 pct-intensity 0.61) [243 119 54] + + (<= 0.61 pct-intensity 0.62) [242 117 54] + (<= 0.62 pct-intensity 0.63) [241 115 54] + (<= 0.63 pct-intensity 0.64) [240 113 54] + (<= 0.64 pct-intensity 0.65) [239 110 54] + (<= 0.65 pct-intensity 0.66) [238 107 54] + (<= 0.66 pct-intensity 0.67) [238 104 54] + (<= 0.67 pct-intensity 0.68) [238 100 54] + (<= 0.68 pct-intensity 0.69) [238 98 54] + (<= 0.69 pct-intensity 0.7) [238 94 54] + (<= 0.7 pct-intensity 0.71) [238 90 54] + (<= 0.71 pct-intensity 0.72) [238 85 54] + (<= 0.72 pct-intensity 0.73) [238 82 54] + (<= 0.73 pct-intensity 0.74) [238 80 54] + (<= 0.74 pct-intensity 0.75) [238 78 54] + (<= 0.75 pct-intensity 0.76) [238 74 54] + (<= 0.76 pct-intensity 0.77) [238 72 54] + (<= 0.77 pct-intensity 0.78) [238 70 54] + (<= 0.78 pct-intensity 0.79) [238 68 54] + (<= 0.79 pct-intensity 0.8) [238 66 54] + + (<= 0.8 pct-intensity 0.81) [239 64 53] + (<= 0.81 pct-intensity 0.82) [240 62 53] + (<= 0.82 pct-intensity 0.83) [241 60 53] + (<= 0.83 pct-intensity 0.84) [242 58 53] + (<= 0.84 pct-intensity 0.85) [243 55 52] + (<= 0.85 pct-intensity 0.86) [244 53 52] + (<= 0.86 pct-intensity 0.87) [245 50 52] + (<= 0.87 pct-intensity 0.88) [246 48 52] + (<= 0.88 pct-intensity 0.89) [247 46 52] + (<= 0.89 pct-intensity 0.9) [248 42 52] + (<= 0.9 pct-intensity 0.91) [249 38 52] + (<= 0.91 pct-intensity 0.92) [250 33 51] + (<= 0.92 pct-intensity 0.93) [251 28 51] + (<= 0.93 pct-intensity 0.94) [253 22 50] + (<= 0.94 pct-intensity 0.95) [254 18 49] + (<= 0.95 pct-intensity 0.96) [254 15 48] + (<= 0.96 pct-intensity 0.97) [250 12 47] + (<= 0.97 pct-intensity 0.98) [245 9 46] + (<= 0.98 pct-intensity 0.99) [240 6 45] + + (<= 0.99 pct-intensity 1.00) [235 3 44] + )] + (int-array [r g b 255]))) + + diff --git a/src/hypercomplex/alpha/fractal_generate.clj b/src/hypercomplex/alpha/fractal_generate.clj new file mode 100644 index 0000000..feaa6e3 --- /dev/null +++ b/src/hypercomplex/alpha/fractal_generate.clj @@ -0,0 +1,418 @@ +(ns hypercomplex.alpha.fractal-generate + (:require [me.raynes.fs :as fs] + [clojure.spec.alpha :as s] + [clojure.java.shell :refer [sh]] + [mikera.image.core :as imgz] + [clojure.spec.alpha :as s] + [clojure.spec.gen.alpha :as gen] + [hypercomplex.cayley-dickson-construction :as c] + [hypercomplex.alpha.fractal-spec :as fspec] + [hypercomplex.alpha.fractal-pixels :as fp] + [hypercomplex.core :refer :all] + [me.raynes.fs :as fs] + [hypercomplex.alpha.fractal-iters :as f]) + (:import (java.awt.image BufferedImage WritableRaster) + (java.awt Color Graphics) + (java.util Date))) + + +(set! *unchecked-math* true) +(set! *warn-on-reflection* true) + + +(defn animate-results-gif [glob output] + (println "Creating animated gif from files, to file: " glob " -> " output) + (try + (sh "convert" " -dispose" "2" "-delay" "7" "-loop" "0" glob output) + (catch Throwable t + (println "Could not create animated gif:" t)))) + +(defn animate-results-ffmpeg [imgdir output] + (println "Creating animated mp4 from files, to file: " imgdir " -> " output) + (try + (sh "ffmpeg" "-framerate" "6" "-i" + (str imgdir "/img-%04d.png") "-c:v" "libx264" "-r" "30" + output))) + + + +(defn intensities-gen-spec [generator quant] + (pmap + (fn [i] + (when (= 0 (rem i (int (/ quant 10)))) + (println "Generating intensity " i " / " quant " , " + (int (* 100 (/ i quant))) "% complete, t=" + (System/currentTimeMillis))) + (gen/generate generator)) + (range quant))) + +(defn width->iters [w] + (cond + (> w 0.5) 32 + (> w 0.4) 36 + (> w 0.3) 40 + (> w 0.1) 45 + (> w 0.05) 50 + (> w 0.04) 55 + (> w 0.03) 60 + (> w 0.01) 85 + (> w 0.008) 90 + (> w 0.006) 95 + (> w 0.005) 100 + (> w 0.003) 105 + (> w 0.002) 110 + (> w 0.001) 125 + (> w 0.00075) 150 + (> w 0.0005) 160 + (> w 0.0001) 180 + (> w 0.00005) 210 + (> w 0.00001) 230 + (> w 0.00005) 250 + (> w 0.000001) 270 + :else 300)) + +(defn complex-between-pct [c1 c2 pct] + (c/complex + {:a (+ (:a c1) (* pct (- (:a c2) (:a c1)))) + :b (+ (:b c1) (* pct (- (:b c2) (:b c1)))) + :impl :plain})) + +(defn domains + [{:keys [views type wf hf w0 h0 x0 y0 xf yf julia-coeff0 julia-coefff iter-scale] + :or {iter-scale 1.0} + :as d}] + (->> + (range views -1 -1) + (map + (fn [i] + (let [width-range (- w0 wf) + height-range (- h0 hf) + pct-desc (/ i views) + pct-asc (- 1.0 pct-desc) + dx (* pct-asc (- xf x0)) + dy (* pct-asc (- yf y0)) + dw (+ (/ wf 2) (* pct-desc (/ width-range 2))) + dh (+ (/ hf 2) (* pct-desc (/ height-range 2)))] + [[(+ (- x0 dw) dx) + (+ x0 dw dx)] + [(+ (- y0 dh) dy) + (+ y0 dh dy)] + (int (* iter-scale (width->iters (* 2 dw)))) + (when (= :julia type) + (complex-between-pct julia-coeff0 julia-coefff pct-asc))]))))) + +(defn combine-domains [ds views] + (->> + ds + (map #(assoc % :views views)) + (map domains) + (mapcat identity))) + +(defn multidom-with + "Ops: + :pan [new-x-coord new-y] + :zoom [new-w new-h] + :iter-var new-scale + :frac-var new-frac-var + " + [doms & ops] + (let [{:keys [xf yf wf hf type + julia-coefff iter-scale] + :or {iter-scale 1.0}} (last doms) + {:keys [pan zoom fractal-iters-change fractal-coeff-change] + :or {fractal-iters-change iter-scale}} ops + my-type type + my-julia-coeff0 julia-coefff + my-julia-coefff (or fractal-coeff-change julia-coefff) + my-x0 xf + my-y0 yf + my-h0 hf + my-w0 wf + my-xf (if pan (first pan) xf) + my-yf (if pan (second pan) yf) + my-wf (if zoom (first zoom) wf) + my-hf (if zoom (second zoom) hf)] + (conj doms + {:iter-scale fractal-iters-change + :x0 my-x0 + :y0 my-y0 + :xf my-xf + :yf my-yf + :w0 my-w0 + :wf my-wf + :h0 my-h0 + :hf my-hf + :type my-type + :julia-coeff0 my-julia-coeff0 + :julia-coefff my-julia-coefff}))) + +(def fractal-config + { + ;Moves, zooms, on Mandelbrot + :c2 {:x0 -1.4 + :y0 0.0 + :xf -1.4 + :yf 0.0 + :w0 1.0 + :wf 0.004 + :h0 1.0 + :hf 0.004 + :type :mandel} + ;Moves, zooms, on constant Julia coeff + :c3 {:x0 -1.0 + :y0 0.5397 + :xf -1.0 + :yf 0.5397 + :w0 4.0 + :wf 0.004 + :h0 4.0 + :hf 0.004 + :type :julia + :julia-coeff0 (c/complex {:a -0.1 :b 0.7 :impl :plain}) + :julia-coefff (c/complex {:a -0.1 :b 0.7 :impl :plain})} + ;Moves, zooms, and varies Julia coeff (all variations) + :c4 {:x0 -0.5 + :y0 0.5397 + :xf 0.5 + :yf -0.5 + :w0 2.0 + :wf 0.1 + :h0 2.0 + :hf 0.1 + :type :julia + :julia-coeff0 (c/complex {:a -0.2 :b 0.9 :impl :plain}) + :julia-coefff (c/complex {:a -0.1 :b 0.7 :impl :plain})} + + ;Multidomain + :c9 {:type :julia + :multidom + [{:iter-scale 1.0 + :x0 -1.0 + :y0 0.0 + :xf 1.0 + :yf 0.0 + :w0 4.0 + :wf 4.0 + :h0 4.0 + :hf 2.0 + :type :julia + :julia-coeff0 (c/complex {:a -0.1 :b 1.0 :impl :plain}) + :julia-coefff (c/complex {:a -0.1 :b 0.6 :impl :plain})} + {:iter-scale 1.0 + :x0 1.0 + :y0 0.0 + :xf -1.0 + :yf 0.0 + :w0 4.0 + :wf 4.0 + :h0 2.0 + :hf 4.0 + :type :julia + :julia-coeff0 (c/complex {:a -0.1 :b 0.6 :impl :plain}) + :julia-coefff (c/complex {:a -0.1 :b 1.0 :impl :plain})}]} + + ;Good points + :c11 {:type :julia + :multidom + [{:iter-scale 2.0 + :x0 0.0 + :y0 0.0 + :xf 0.0 + :yf 0.0 + :w0 4.0 + :wf 4.0 + :h0 4.0 + :hf 4.0 + :type :julia + :julia-coeff0 (c/complex {:a -0.1 :b -0.7 :impl :plain}) + :julia-coefff (c/complex {:a 0.1 :b -0.7 :impl :plain})} + {:iter-scale 2.0 + :x0 0.0 + :y0 0.0 + :xf 0.0 + :yf 0.0 + :w0 4.0 + :wf 4.0 + :h0 4.0 + :hf 4.0 + :type :julia + :julia-coeff0 (c/complex {:a 0.1 :b -0.7 :impl :plain}) + :julia-coefff (c/complex {:a -0.1 :b -0.7 :impl :plain})}]} + :c12 {:type :julia + :palette :rainbow + :multidom (-> + [{:iter-scale 2.0 + :x0 0.0 + :y0 0.0 + :xf 0.0 + :yf 0.0 + :w0 3.5 + :wf 3.5 + :h0 3.5 + :hf 3.5 + :type :julia + :julia-coeff0 (c/complex + {:a 0.0 :b -0.7 :impl :plain}) + :julia-coefff (c/complex + {:a -0.1 :b -0.7 :impl :plain})}] + (multidom-with + :fractal-coeff-change + (c/complex {:a -0.1 :b 0.7 :impl :plain})) + (multidom-with + :fractal-coeff-change + (c/complex {:a 0.0 :b 0.7 :impl :plain})) + (multidom-with + :fractal-coeff-change + (c/complex {:a -0.1 :b 0.7 :impl :plain})) + (multidom-with + :fractal-coeff-change + (c/complex {:a -0.1 :b -0.7 :impl :plain})) + (multidom-with + :fractal-coeff-change + (c/complex {:a 0.0 :b -0.7 :impl :plain})))} + :c13 {:type :julia + :palette :rainbow2 + :multidom (-> + [{:iter-scale 15.0 + :x0 0.0 + :y0 0.0 + :xf 0.0 + :yf 0.0 + :w0 3.5 + :wf 3.5 + :h0 3.5 + :hf 3.5 + :type :julia + :julia-coeff0 (c/complex + {:a -0.08 :b -0.65 :impl :plain}) + :julia-coefff (c/complex + {:a -0.01 :b -0.72 :impl :plain})}] + (multidom-with + :fractal-coeff-change + (c/complex {:a -0.05 :b -0.62 :impl :plain})) + (multidom-with + :fractal-coeff-change + (c/complex {:a -0.1 :b -0.69 :impl :plain})) + )}}) + + +(def render-config + {:fast {:test-size 20000 + :views 10 + :img-w 100 + :img-h 100 + :img-scale-fn #(imgz/scale % 12)} + :medium {:test-size 500000 + :views 10 + :img-w 400 + :img-h 400 + :img-scale-fn #(imgz/scale % 3)} + :slow {:test-size 5000000 + :views 50 + :img-w 1200 + :img-h 1200 + :img-scale-fn identity} + :render {:test-size 20000000 + :views 20 + :img-w 1600 + :img-h 1600 + :img-scale-fn identity} + :insane {:test-size 100000000 + :views 3 + :img-w 2400 + :img-h 2400 + :img-scale-fn identity}}) + + +(defn intensities-random-sample + [xrange yrange iters julia-coeff render-size test-size] + (->> + (range test-size) + (pmap + (fn [i] + [i + (fspec/i->x (rand-int render-size) render-size xrange) + (fspec/i->x (rand-int render-size) render-size yrange)])) + (filter + (fn [[i x y]] + (> 2.0 (mag (c/complex {:a x :b y}))))) + (pmap + (fn [[i x y]] + (when (= 0 (rem i (int (/ test-size 10)))) + (println (Date.) " Computing " (int (* 100 (/ i test-size))) + "% complete ")) + [x y + (f/compute-iters-julia + x + y + :plain + iters + julia-coeff)])) + (filter #(not (zero? (nth % 2)))))) + +(defn run [] + (let [render-mode :pixels + gen-mode :rand-sample + fconfig :c13 + rconfig :fast + dir (str + "gen-img-test/test-" + (System/currentTimeMillis) "-" + (name fconfig) "-" + (name rconfig)) + {:keys [type multidom palette] + :or {palette :green-red} + :as fconfig-data} (fractal-config fconfig) + {:keys + [test-size views img-w + img-h img-scale-fn]} (render-config rconfig) + fconfig-data (assoc fconfig-data :views views) + domans (if multidom + (combine-domains multidom views) + (domains fconfig-data)) + frac-spec (case type + :julia ::fspec/interesting-intensity-plain-julia + ;TODO mandel specs + ;:mandel :TODO + ) + imgc* (atom 1)] + (if-not (fs/exists? dir) + (fs/mkdir dir)) + (doseq [[xrange yrange iters julia-coeff] domans] + (println "Domain, iters, size : " xrange yrange iters test-size) + (when julia-coeff + (reset! fspec/JULIA-COEFF-PLAIN* julia-coeff)) + (reset! fspec/X-RANGE* xrange) + (reset! fspec/Y-RANGE* yrange) + (reset! fspec/MAX-CONV-ITERS* iters) + (let [image (BufferedImage. + img-w + img-h + BufferedImage/TYPE_INT_ARGB) + intensities (case gen-mode + :spec-sample (intensities-gen-spec + (s/gen frac-spec) + test-size) + :rand-sample (intensities-random-sample + xrange yrange iters + julia-coeff 1000000 test-size)) + + imgf (str dir (format "/img-%04d" @imgc*) ".png")] + (case render-mode + :voxels (do (throw (RuntimeException. "NOT IMPLD"))) + :pixels (do (fp/draw-intensities-w-raster intensities image img-w img-h palette) + (imgz/save (img-scale-fn image) imgf) + (println "Wrote: " imgf) + (when (or (= :insane rconfig) + (= :render rconfig) + (= :slow rconfig)) + (animate-results-ffmpeg dir (str dir "/fractal-part-" @imgc* ".mp4"))) + )) + (swap! imgc* inc))) + (animate-results-ffmpeg dir (str dir "/fractal-all.mp4")))) + +(comment + (try + (run) + (catch Exception e + (clojure.pprint/pprint e)))) \ No newline at end of file diff --git a/src/hypercomplex/alpha/fractal_iters.clj b/src/hypercomplex/alpha/fractal_iters.clj new file mode 100644 index 0000000..d685dad --- /dev/null +++ b/src/hypercomplex/alpha/fractal_iters.clj @@ -0,0 +1,163 @@ +(ns hypercomplex.alpha.fractal-iters + (:require [hypercomplex.core :refer :all] + [hypercomplex.cayley-dickson-construction :refer + [complex quaternion octonion sedenion + pathion n-hypercomplex power-of?]] + [taoensso.nippy :as nippy] + [me.raynes.fs :as fs] + [clojure.set :as set]) + (:import (java.util Date))) + + + +(set! *unchecked-math* true) +(set! *warn-on-reflection* true) + + + +(defn compute-iters-mandel + "Computer iterations required for equation: + z_n+1 = z_n^2 + c, where z_0 = c, and + c = p + q*i. + Iterations are complete when |z| > 2. + Impl is :apache or :plain." + [p q impl max-iterations] + (let [c (complex {:a p :b q :impl impl})] + (loop [z c + iterations 0] + ;(println "hc Mandelbrot z: " z) + (if (or (> (mag z) 2.0) + (> iterations max-iterations)) + (if (= 0 iterations) + 0 + (dec iterations)) + (recur + (plus + c + (times z z)) + (inc iterations)))))) + +(defn- compute-iters-julia-f + "Computer iterations of equation: + z_n+1 = z_n^2 + d, where z_0 = p + q*i, + and d is the provided julia coefficient. + Iterations are complete when |z| > 2. + Impl is :apache or :plain." + [p q impl max-iterations julia-coeff] + (let [c (complex {:a p :b q :impl impl}) + julia-coeff julia-coeff] + (loop [z c + iterations 0] + ;(println "hc Mandelbrot z: " z) + (if (or (> (mag z) 2.0) + (> iterations max-iterations)) + (if (= 0 iterations) + 0 + (dec iterations)) + (recur + (plus + julia-coeff + (times z z)) + (inc iterations)))))) + +(def compute-iters-julia (memoize compute-iters-julia-f)) + + +(defn compute-iters-quat-julia + [p q impl max-iterations julia-coeff] + (let [c (quaternion {:a p :b q :c 0.0 :d 0.0 :impl impl}) + julia-coeff julia-coeff] + (loop [z c + iterations 0] + ;(println "hc Mandelbrot z: " z) + (if (or (> (mag z) 2.0) + (> iterations max-iterations)) + (if (= 0 iterations) + 0 + (dec iterations)) + (recur + (plus + julia-coeff + (times z z)) + (inc iterations)))))) + + + +(defn ppmap + "Partitioned pmap, for grouping map ops together to make parallel + overhead worthwhile" + [name grain-size f & colls] + (let [c* (atom 0) + parts (int (Math/ceil (/ (count (apply concat colls)) grain-size)))] + (apply concat + (apply pmap + (fn [& pgroups] + (println name " doing part: " + (swap! c* inc) " / " + parts " " (Date.)) + (doall (apply map f pgroups))) + (map (partial partition-all grain-size) colls))))) + +(defn iter-key->iters + [{:keys [itype p q imax coeff impl x y z] :as iter-key}] + (let [iter-val (case itype + :julia-2 (compute-iters-julia-f p q impl imax coeff))] + [iter-key iter-val])) + +(defn preload [cfile] + (future + (if (fs/exists? cfile) + (do (println "Preloading cache") + (nippy/thaw-from-file cfile)) + {}))) + +(defn cached-compute-iters [iter-keys cfile] + (println "Loading cache " cfile) + (let [cache (if (future? cfile) + @cfile + (if (fs/exists? cfile) + (nippy/thaw-from-file cfile) + {})) + cache-keys-and-old (into + {} + (ppmap + "Splitting coords from cache keys" + 200000 + (fn [ik] + [(dissoc ik :x :y :z) [(:x ik) (:y ik) (:z ik)]]) + iter-keys)) + cache-keys (keys cache-keys-and-old) + cache-hits (select-keys cache cache-keys) + _ (println "Cache hits: " (count cache-hits) + " / " (count cache-keys) + " , cache size: " (count cache)) + found-keys (keys cache-hits) + to-xompute-keys (set/difference + (set cache-keys) + (set found-keys)) + _ (println "Computing: " (count to-xompute-keys)) + computed (into {} + (ppmap + "Computing iters " + 200000 + iter-key->iters + to-xompute-keys)) + pfuture (future + (when-not (empty? to-xompute-keys) + (println "Persisting cache ") + (nippy/freeze-to-file cfile (merge cache computed))))] + + + (let [wo-xyz (merge cache-hits computed) + w-xyz (into + {} + (ppmap + "Adding back voxel xyz to cached iter data " + 200000 + (fn [[kk vv]] + (let [wxyz (get cache-keys-and-old kk)] + [wxyz + vv])) + wo-xyz))] + [pfuture w-xyz])) + ) diff --git a/src/hypercomplex/alpha/fractal_pixels.clj b/src/hypercomplex/alpha/fractal_pixels.clj new file mode 100644 index 0000000..b8c8171 --- /dev/null +++ b/src/hypercomplex/alpha/fractal_pixels.clj @@ -0,0 +1,65 @@ +(ns hypercomplex.alpha.fractal-pixels + (:require [hypercomplex.alpha.fractal-spec :as fspec] + [hypercomplex.alpha.fractal-colors :as fc]) + (:import (java.awt Color Graphics) + (java.awt.image WritableRaster BufferedImage))) + + +(defn- calc-pixel-color-argb + [iterations max-iterations palette] + (case palette + :green-red (fc/palette-green-to-red iterations max-iterations) + :rainbow (fc/palette-rainbox iterations max-iterations) + :rainbow2 (fc/palette-rainbox2 iterations max-iterations))) + +(defn intensity-coord->img-coord + [intensity-coord img-dim-size intensity-domain flip?] + (let [c (->> + intensity-domain + (reverse) + (apply -) + (/ img-dim-size) + (* (- intensity-coord (first intensity-domain))) + (int) + (max 0) + (min (dec img-dim-size)))] + (if flip? + (- (dec img-dim-size) c) + c))) + +(defn img-intensities + [intensities surface-width surface-height palette] + (pmap + (fn [[x y iters]] + (let [i (intensity-coord->img-coord + x surface-width @fspec/X-RANGE* false) + j (intensity-coord->img-coord + y surface-height @fspec/Y-RANGE* true) + ^ints c (calc-pixel-color-argb + iters @fspec/MAX-CONV-ITERS* palette)] + [i j c])) + intensities)) + + + +(defn draw-intensities-w-raster + [intensities ^BufferedImage image surface-width surface-height palette] + (let [^WritableRaster raster (.getRaster image) + ^Graphics g (.getGraphics image) + img-vals (set + (img-intensities + intensities surface-width + surface-height palette)) + x-zero (intensity-coord->img-coord + 0 surface-width @fspec/X-RANGE* false) + y-zero (intensity-coord->img-coord + 0 surface-height @fspec/Y-RANGE* true)] + (doseq [[^int i ^int j ^ints argb] img-vals] + (.setPixel raster i j argb)) + (.setColor g Color/BLACK) + (.drawLine g + 0 y-zero + surface-width y-zero) + (.drawLine g + x-zero 0 + x-zero surface-height))) \ No newline at end of file diff --git a/src/hypercomplex/alpha/fractal_spec.clj b/src/hypercomplex/alpha/fractal_spec.clj new file mode 100644 index 0000000..730514a --- /dev/null +++ b/src/hypercomplex/alpha/fractal_spec.clj @@ -0,0 +1,164 @@ +(ns hypercomplex.alpha.fractal-spec + (:require [clojure.spec.alpha :as s] + [clojure.spec.gen.alpha :as gen] + [hypercomplex.alpha.fractal-iters :as f] + [hypercomplex.core :refer :all] + [hypercomplex.cayley-dickson-construction :refer + [complex quaternion octonion sedenion + pathion n-hypercomplex power-of?]])) + + +;;TODO major perf issues doing derefs millions of times by different threads... + +(set! *unchecked-math* true) +(set! *warn-on-reflection* true) + +(def MAX-TRIES 10000) +(def SCALE 1000000) + +(def XY-RANGE* (atom [-2.0 0.5])) +(def X-RANGE* (atom [-0.4 0.2])) +(def Y-RANGE* (atom [-1.1 -0.5])) +(def MAX-CONV-ITERS* (atom 64)) +(def JULIA-COEFF-PLAIN* (atom (complex {:a -0.1 :b 0.7 :impl :plain}))) + + +(defn- regular-number? [n domain] + (and + (<= (first domain) n (second domain)) + (not + (or + (= n ##-Inf) + (= n ##Inf) + (= n ##NaN))))) + + +(defn i->x [i imax range] + (let [dr (apply - (reverse range)) + ri (/ i imax)] + (+ + (first range) + (* ri dr)))) + +;This doesn't sample uniformly at all +(s/def ::int-in + (s/int-in 0 (inc SCALE))) + + +(s/def ::ycoeff + (s/with-gen + #(and + (number? %) + (regular-number? % @Y-RANGE*)) + (fn [] + (gen/fmap + (fn [i] + (i->x (rand-int (inc SCALE)) SCALE @Y-RANGE*)) + (gen/int))))) + +(s/def ::xcoeff + (s/with-gen + #(and + (number? %) + (regular-number? % @X-RANGE*)) + (fn [] + (gen/fmap + (fn [i] + (i->x (rand-int (inc SCALE)) SCALE @X-RANGE*)) + (gen/int))))) + +(s/def ::coeff + (s/with-gen + #(and + (number? %) + (regular-number? % @XY-RANGE*)) + (fn [] + (gen/fmap + (fn [i] + (i->x (rand-int SCALE) (inc SCALE) @XY-RANGE*)) + (gen/int))))) + +(s/def ::2d-domain + (s/with-gen + (fn [d] + (= 2 (count d))) + (fn [] + (gen/tuple + (s/gen ::xcoeff) + (s/gen ::ycoeff))))) + +(s/def ::intensity-plain-julia + (s/with-gen + (fn [d] + (and (= 3 (count d)) + (let [[a b insy] d] + (and + (<= 0 insy @MAX-CONV-ITERS*))))) + (fn [] + (gen/fmap + (fn [[a b]] + [a b + (f/compute-iters-julia a b :plain @MAX-CONV-ITERS* @JULIA-COEFF-PLAIN*)]) + (s/gen ::2d-domain))))) + +;interesting in the sense that it's not 0 and not max-iters, +;so some value that would render something interesting +(s/def ::interesting-intensity-plain-julia + (s/with-gen + (fn [i] + (and (< 0 (nth i 2)) + #_(> @MAX-CONV-ITERS* (nth i 2)))) + (fn [] + (gen/such-that + (fn [i] + (and (< 0 (nth i 2)) + #_(> @MAX-CONV-ITERS* (nth i 2)))) + (s/gen ::intensity-plain-julia) + MAX-TRIES)))) + +(s/def ::interesting-intensities-plain-julia + (s/with-gen + (fn [i] + (coll? i)) + (fn [] + (gen/vector-distinct + (s/gen ::interesting-intensity-plain-julia) + {:num-elements 100})))) + +(s/def ::intensity-plain-mandel + (s/with-gen + (fn [d] + (and (= 3 (count d)) + (let [[a b insy] d] + (and + (<= 0 insy @MAX-CONV-ITERS*))))) + (fn [] + (gen/fmap + (fn [[a b]] + [a b + (f/compute-iters-mandel a b :plain @MAX-CONV-ITERS*)]) + (s/gen ::2d-domain))))) + +;interesting in the sense that it's not 0 and not max-iters, +;so some value that would render something interesting +(s/def ::interesting-intensity-plain-mandel + (s/with-gen + (fn [i] + (and (< 0 (nth i 2)) + #_(> @MAX-CONV-ITERS* (nth i 2)))) + (fn [] + (gen/such-that + (fn [i] + (and (< 0 (nth i 2)) + #_(> @MAX-CONV-ITERS* (nth i 2)))) + (s/gen ::intensity-plain-mandel) + MAX-TRIES)))) + +(s/def ::interesting-intensities-plain-mandel + (s/with-gen + (fn [i] + (coll? i)) + (fn [] + (gen/vector-distinct + (s/gen ::interesting-intensity-plain-mandel) + {:num-elements 100})))) diff --git a/src/hypercomplex/alpha/fractal_voxels.clj b/src/hypercomplex/alpha/fractal_voxels.clj new file mode 100644 index 0000000..bc90a0e --- /dev/null +++ b/src/hypercomplex/alpha/fractal_voxels.clj @@ -0,0 +1,215 @@ +(ns hypercomplex.alpha.fractal-voxels + (:require + [hypercomplex.alpha.fractal-iters :as fi] + [thi.ng.geom.core :as g] + [thi.ng.geom.core.vector :refer [vec3]] + [thi.ng.geom.voxel.svo :as svo] + [thi.ng.geom.voxel.isosurface :as iso] + [thi.ng.math.simplexnoise :as n] + [thi.ng.geom.mesh.io :as mio] + [thi.ng.math.core :as m] + [clojure.java.io :as io] + [hypercomplex.cayley-dickson-construction :as c]) + (:import (java.util Date))) + +(defn- i->x [i imin xmin s] + (+ xmin (* s (- i imin)))) + +(defn iters-cached + [cfuture cartesian-domain3 imin xmin ymin zmin sx sy sz julia-a julia-b max-iters] + (-> + (doall + (fi/ppmap + "Computing iter keys " + 200000 + (fn [[x y z]] + (let [xx (i->x x imin xmin sx) + yy (i->x y imin ymin sy) + zz (i->x z imin zmin sz) + ja (or julia-a zz) + jb (or julia-b zz)] + {:itype :julia-2 + :p xx + :q yy + :x x + :y y + :z z + :imax max-iters + :coeff (c/complex + {:a ja :b jb :impl :plain}) + :impl :plain})) + cartesian-domain3)) + (fi/cached-compute-iters cfuture))) + +(defn iter-voxels + [{:keys [iso-val delta-i irng + xrng yrng zrng iter-thresh max-iters + julia-a julia-b fname]}] + + (println "Computing cells " fname) + + (let [cfuture (fi/preload "cache/cache-01.nippy") + r (range + (first irng) (second irng) delta-i) + cartesian-domain3 (time + (doall + (for [x r y r z r] + [x y z]))) + [imin imax] irng + [xmin xmax] xrng + [ymin ymax] yrng + [zmin zmax] zrng + sx (/ (- xmax xmin) (- imax imin)) + sy (/ (- ymax ymin) (- imax imin)) + sz (/ (- zmax zmin) (- imax imin)) + _ (println "Computing iters") + [pfuture iter-res] (iters-cached + cfuture cartesian-domain3 imin xmin ymin zmin + sx sy sz julia-a julia-b max-iters) + iters (time + (into + {} + iter-res)) + _ (println "Gathering voxels") + v (time + (->> + (for [[x y z] cartesian-domain3 + :when (< iter-thresh + (get iters [x y z]))] + (vec3 x y z)) + (svo/apply-voxels + svo/set-at + (svo/voxeltree 32 delta-i))))] + (println "Writing " fname) + (time + (with-open [o (io/output-stream fname)] + (mio/write-stl + (mio/wrapped-output-stream o) + (g/tessellate (iso/surface-mesh v 10 iso-val))))) + @pfuture + (println "Done"))) + +(def conf-1 + {:fname "gen-voxels-test/fractal-1.stl" + :iso-val 0.5 + :delta-i (double 1/4) + :irng [1 31] + :xrng [-1.5 1.5] + :yrng [-1.5 1.5] + :zrng [0.0 -1.5] + :julia-b 0.7 + :max-iters 11 + :iter-thresh 10}) + +(def conf-2 + {:fname "gen-voxels-test/fractal-2.stl" + :iso-val 0.5 + :delta-i (double 1/4) + :irng [1 31] + :xrng [-2.0 2.0] + :yrng [-2.0 2.0] + :zrng [-2.0 2.0] + :julia-a 0.065 + :max-iters 11 + :iter-thresh 10}) + +(def conf-3 + {:fname "gen-voxels-test/fractal-3.stl" + :iso-val 0.5 + :delta-i (double 1/4) + :irng [1 31] + :xrng [-3.5 3.5] + :yrng [-3.5 3.5] + :zrng [-4.5 4.5] + :julia-a 0.065 + :max-iters 3 + :iter-thresh 2}) + +(def conf-4 + {:fname "gen-voxels-test/fractal-4.stl" + :iso-val 0.5 + :delta-i (double 1/4) + :irng [1 31] + :xrng [-3.5 3.5] + :yrng [-3.5 3.5] + :zrng [-4.5 4.5] + :julia-a 0.65 + :max-iters 3 + :iter-thresh 2}) + +(def conf-5 + {:fname "gen-voxels-test/fractal-5.stl" + :iso-val 0.5 + :delta-i (double 1/4) + :irng [1 31] + :xrng [0.6 1.8] + :yrng [0.6 1.8] + :zrng [0.0 4.0] + :julia-b -0.65 + :max-iters 5 + :iter-thresh 4}) + +(def conf-6 + {:fname "gen-voxels-test/fractal-6.stl" + :iso-val 0.5 + :delta-i (double 1/8) + :irng [1 31] + :xrng [-0.1 1.8] + :yrng [-0.1 1.8] + :zrng [-0.3 0.3] + :julia-b -0.85 + :max-iters 15 + :iter-thresh 14}) + +(def conf-7 + {:fname "gen-voxels-test/fractal-7.stl" + :iso-val 0.5 + :delta-i (double 1/8) + :irng [1 31] + :xrng [-0.4 0.8] + :yrng [-0.4 0.8] + :zrng [-0.2 0.2] + :julia-b -0.85 + :max-iters 15 + :iter-thresh 14}) + +(def conf-8 + {:fname "gen-voxels-test/fractal-8.stl" + :iso-val 0.5 + :delta-i (double 1/8) + :irng [1 31] + :xrng [0.0 0.4] + :yrng [0.4 0.8] + :zrng [-0.2 0.2] + :julia-b -0.85 + :max-iters 20 + :iter-thresh 19}) + +(def conf-9 + {:fname "gen-voxels-test/fractal-9.stl" + :iso-val 0.5 + :delta-i (double 1/8) + :irng [1 31] + :xrng [0.155 0.275] + :yrng [0.555 0.675] + :zrng [-0.05 0.2] + :julia-b -0.85 + :max-iters 20 + :iter-thresh 19}) + +(def conf-10 + {:fname "gen-voxels-test/fractal-10.stl" + :iso-val 0.5 + :delta-i (double 1/4) + :irng [1 31] + :xrng [0.125 0.3] + :yrng [0.525 0.7] + :zrng [-0.65 -0.75] + :julia-a -0.004 + :max-iters 20 + :iter-thresh 19}) + +(try + (iter-voxels conf-10) + (catch Exception e + (clojure.pprint/pprint e))) \ No newline at end of file diff --git a/src/hypercomplex/cayley_dickson_construction.clj b/src/hypercomplex/cayley_dickson_construction.clj index 36f6e15..f2a6e89 100644 --- a/src/hypercomplex/cayley_dickson_construction.clj +++ b/src/hypercomplex/cayley_dickson_construction.clj @@ -84,10 +84,19 @@ coefficient vector does not contain a power-of-2 amount of elements, an Exception is thrown." [coeffs impl] - (if + (if-not (and (power-of? (count coeffs) 2) (< 1 (count coeffs))) + (let [err-str (str + "Fn n-hypercomplex requires coefficients count + to be a power of 2, and GT 1. Provided: " + (vec coeffs))] + (println + err-str) + (throw + (Exception. + err-str))) (if (= 2 (count coeffs)) (complex {:a (nth coeffs 0) :b (nth coeffs 1) :impl impl}) (let [[first-half-coeffs @@ -96,12 +105,4 @@ coeffs)] (init-construction (n-hypercomplex first-half-coeffs impl) - (n-hypercomplex second-half-coeffs impl)))) - (let [err-str (str - "n-complex requires coefficients count to be a power of 2. Provided: " - (vec coeffs))] - (println - err-str) - (throw - (Exception. - err-str))))) + (n-hypercomplex second-half-coeffs impl)))))) \ No newline at end of file diff --git a/src/hypercomplex/core.clj b/src/hypercomplex/core.clj index 6a75ca2..cb0303d 100644 --- a/src/hypercomplex/core.clj +++ b/src/hypercomplex/core.clj @@ -42,7 +42,7 @@ new-new-this)))) (defn- nion-ops-norm [this] - (loop [sum 0 + (loop [sum 0.0 idx (dec (:order this))] (let [new-sum (+ sum @@ -63,7 +63,6 @@ this) (inv other))) - (defn eq-order? [a b] (and (:order a) @@ -71,37 +70,48 @@ (= (:order a) (:order b)))) - (defrecord Complex2Apache [a b] Nion (init [this] - (assoc this :order 2 - :obj (Complex. a b))) + (assoc this + :order 2 + :obj (Complex. a b))) (c [this] (let [cpx-cnj (.conjugate ^Complex (:obj this))] - (assoc this :obj cpx-cnj - :a (.getReal cpx-cnj) - :b (.getImaginary cpx-cnj)))) + (assoc this + :obj cpx-cnj + :a (.getReal cpx-cnj) + :b (.getImaginary cpx-cnj)))) (neg [this] (let [cpx-neg (.negate ^Complex (:obj this))] - (assoc this :obj cpx-neg - :a (.getReal ^Complex cpx-neg) - :b (.getImaginary ^Complex cpx-neg)))) + (assoc this + :obj cpx-neg + :a (.getReal ^Complex cpx-neg) + :b (.getImaginary ^Complex cpx-neg)))) (times [this other] - (let [cpx-times (.multiply ^Complex (:obj this) ^Complex (:obj other))] - (assoc this :obj cpx-times - :a (.getReal ^Complex cpx-times) - :b (.getImaginary ^Complex cpx-times)))) + (let [cpx-times (.multiply + ^Complex (:obj this) + ^Complex (:obj other))] + (assoc this + :obj cpx-times + :a (.getReal ^Complex cpx-times) + :b (.getImaginary ^Complex cpx-times)))) (plus [this other] - (let [cpx-add (.add ^Complex (:obj this) ^Complex (:obj other))] - (assoc this :obj cpx-add - :a (.getReal ^Complex cpx-add) - :b (.getImaginary ^Complex cpx-add)))) + (let [cpx-add (.add + ^Complex (:obj this) + ^Complex (:obj other))] + (assoc this + :obj cpx-add + :a (.getReal ^Complex cpx-add) + :b (.getImaginary ^Complex cpx-add)))) (minus [this other] - (let [cpx-subtract (.subtract ^Complex (:obj this) ^Complex (:obj other))] - (assoc this :obj cpx-subtract - :a (.getReal ^Complex cpx-subtract) - :b (.getImaginary ^Complex cpx-subtract)))) + (let [cpx-subtract (.subtract + ^Complex (:obj this) + ^Complex (:obj other))] + (assoc this + :obj cpx-subtract + :a (.getReal ^Complex cpx-subtract) + :b (.getImaginary ^Complex cpx-subtract)))) (valid-idx? [this idx] "Throws exception when index is invalid. For a Complex2 type, index can only be 0 or 1 (a or b in a+bi)." @@ -179,7 +189,9 @@ (do (throw (ex-info - (str "Complex2 Index must be int 0 or 1: " idx) + (str + "Complex2 Index must be int 0 or 1: " + idx) {:type :invalid-index-access})) false) true)) @@ -216,7 +228,9 @@ (if-not (eq-order? a b) (throw (ex-info - (str "Orders of a and b must match to init hypercomplex: " a b) + (str + "Orders of a and b must match to init hypercomplex: " + a b) {:type :orders-mismatch})) (assoc this @@ -228,7 +242,9 @@ (if-not (eq-order? this other) (throw (ex-info - (str "Orders of this and other must match to multiply hypercomplex: " this other) + (str + "Orders of this and other must match to multiply hypercomplex: " + this other) {:type :orders-mismatch})) (assoc this :a (minus (times (:a this) (:a other)) @@ -243,7 +259,9 @@ (if-not (eq-order? this other) (throw (ex-info - (str "Orders of this and other must match to add hypercomplex: " this other) + (str + "Orders of this and other must match to add hypercomplex: " + this other) {:type :orders-mismatch})) (assoc this :a (plus (:a this) (:a other)) @@ -261,7 +279,9 @@ (do (throw (ex-info - (str "Construction index must be less than order: " idx (:order this)) + (str + "Construction index must be less than order: " + idx (:order this)) {:type :invalid-index-access})) false) true)) @@ -269,7 +289,7 @@ (when (valid-idx? this idx) (let [half-order (/ (:order this) 2) - new-idx (mod idx half-order) + new-idx (rem idx half-order) retval (if (< idx half-order) (get-idx (:a this) new-idx) (get-idx (:b this) new-idx))] @@ -279,7 +299,7 @@ (when (valid-idx? this idx) (let [half-order (/ (:order this) 2) - new-idx (mod idx half-order)] + new-idx (rem idx half-order)] (if (< idx half-order) (update-in this [:a] set-idx new-idx new-val) (update-in this [:b] set-idx new-idx new-val))))) @@ -306,5 +326,3 @@ (defn init-construction [a b] (init (->Construction a b))) - - diff --git a/test/hypercomplex/core_test.clj b/test/hypercomplex/core_test.clj index 47003ba..56fd586 100644 --- a/test/hypercomplex/core_test.clj +++ b/test/hypercomplex/core_test.clj @@ -131,11 +131,11 @@ (mag (quaternion {:a 1 :b 1 :c 1 :d 1}))))) (testing "Norm" - (is (= 2 + (is (= 2.0 (norm (complex {:a 1 :b 1})))) - (is (= 4 + (is (= 4.0 (norm (quaternion {:a 1 :b 1 :c 1 :d 1})))) - (is (= 32 + (is (= 32.0 (norm (pathion {:a 1 :b 1 :c 1 :d 1 :e 1 :f 1 :g 1 :h 1 :i 1 :j 1 :k 1 :l 1 :m 1 :n 1 :o 1 :p 1 :q 1 :r 1 :s 1 :t 1 :u 1 :v 1 :w 1 :x 1 diff --git a/test/hypercomplex/gen_img_test.clj b/test/hypercomplex/gen_img_test.clj new file mode 100644 index 0000000..2628d8e --- /dev/null +++ b/test/hypercomplex/gen_img_test.clj @@ -0,0 +1,8 @@ +(ns hypercomplex.gen-img-test + (:require [clojure.test :refer :all] + [hypercomplex.alpha.fractal-generate :as fg])) + +(deftest gen-img-test + (testing "Generates fractal image" + (println "Generating frac") + #_(fg/run))) diff --git a/test/hypercomplex/gen_test.clj b/test/hypercomplex/gen_test.clj new file mode 100644 index 0000000..fa99bc7 --- /dev/null +++ b/test/hypercomplex/gen_test.clj @@ -0,0 +1,83 @@ +(ns hypercomplex.gen-test + (:require + [clojure.test :refer :all] + [clojure.spec.alpha :as s] + [clojure.test.check.clojure-test :as ct] + [clojure.test.check.properties :as prop] + [hypercomplex.core :refer :all] + [hypercomplex.alpha.core-spec :as cs] + [hypercomplex.alpha.fractal-spec :as fs] + [hypercomplex.cayley-dickson-construction :refer + [complex quaternion octonion sedenion + pathion n-hypercomplex power-of?]])) + + +(def SEED 12345678987654321) + +(ct/defspec + creates-apache2 + {:num-tests 10 :seed SEED} + (prop/for-all [c2a (s/gen ::cs/complex2-apache)] + (is (s/valid? ::cs/complex2-apache c2a)))) + +(ct/defspec + creates-plain2 + {:num-tests 10 :seed SEED} + (prop/for-all [c2p (s/gen ::cs/complex2-plain)] + (is (s/valid? ::cs/complex2-plain c2p)))) + +(ct/defspec + creates-apache-hypercomplex + {:num-tests 10 :seed SEED} + (prop/for-all [ha (s/gen ::cs/hypercomplex-apache)] + (is (s/valid? ::cs/hypercomplex-apache ha)))) +(ct/defspec + creates-plain-hypercomplex + {:num-tests 10 :seed SEED} + (prop/for-all [ha (s/gen ::cs/hypercomplex-plain)] + (is (s/valid? ::cs/hypercomplex-plain ha)))) + +(ct/defspec + creates-apache-hypercomplex-construction + {:num-tests 10 :seed SEED} + (prop/for-all [ca (s/gen ::cs/construction-apache)] + ;(println ca) + (is (s/valid? ::cs/construction-apache ca)))) + +(ct/defspec + creates-plain-hypercomplex-construction + {:num-tests 10 :seed SEED} + (prop/for-all [ca (s/gen ::cs/construction-plain)] + ;(println ca) + (is (s/valid? ::cs/construction-plain ca)))) + +(ct/defspec + creates-plain-intensity-julia + {:num-tests 10 :seed SEED} + (prop/for-all [i (s/gen ::fs/interesting-intensity-plain-julia)] + (is (s/valid? ::fs/interesting-intensity-plain-julia i)))) + +(ct/defspec + creates-plain-intensities-julia + {:num-tests 10 :seed SEED} + (prop/for-all + [its (s/gen ::fs/interesting-intensities-plain-julia)] + ;(println "Intensities count: " (count its)) + (is (s/valid? ::fs/interesting-intensities-plain-julia its)))) + +(ct/defspec + creates-plain-intensity-julia + {:num-tests 10 :seed SEED} + (prop/for-all [i (s/gen ::fs/interesting-intensity-plain-julia)] + (is (s/valid? ::fs/interesting-intensity-plain-julia i)))) + +(ct/defspec + creates-plain-intensities-julia + {:num-tests 10 :seed SEED} + (prop/for-all + [its (s/gen ::fs/interesting-intensities-plain-julia)] + ;(println "Intensities count: " (count its)) + (is (s/valid? ::fs/interesting-intensities-plain-julia its)))) + + +;(run-tests 'hypercomplex.gen-test)