-
-
Save jjsimpso/4a9e35d082f8c35d6e1250f8e518a1bb to your computer and use it in GitHub Desktop.
mandelbrot parallelization tests
This file contains hidden or 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
| #lang racket | |
| ;; Code for the book Chaos, Fractals, and Dynamics: Computer Experiments in Mathematics. | |
| ;; | |
| #| | |
| (require 2htdp/image) ; draw a picture | |
| (define (sierpinski [n 8]) | |
| (cond | |
| [(zero? n) (triangle 2 'solid 'red)] | |
| [else (define t (sierpinski (- n 1))) | |
| (freeze (above t (beside t t)))])) | |
| |# | |
| (require racket/gui/base | |
| racket/flonum | |
| racket/fixnum) | |
| (require racket/future) | |
| (require future-visualizer) | |
| #| | |
| ;; this bit of code replaces the standard flonum functions with their unsafe versions, | |
| ;; but I don't see a performance improvement when using it. | |
| (require racket/require racket/require-syntax) | |
| (define-require-syntax overriding-in | |
| (syntax-rules () [(_ R1 R2) (combine-in R2 (subtract-in R1 R2))])) | |
| (require (overriding-in | |
| racket/flonum | |
| (filtered-in (lambda (name) (regexp-replace #rx"unsafe-" name "")) | |
| racket/unsafe/ops))) | |
| |# | |
| (struct range (min max) | |
| #:transparent) | |
| (define (update-range r value) | |
| (cond | |
| [(< value (range-min r)) (range value (range-max r))] | |
| [(> value (range-max r)) (range (range-min r) value)] | |
| [#t r])) | |
| (define (make-logistic-func c) | |
| (lambda (x) (* c x (- 1 x)))) | |
| (define (make-quadratic-func c) | |
| (lambda (x) (+ (* x x) c)) | |
| #;(lambda (x) | |
| (define rx (flreal-part x)) | |
| (define ix (flimag-part x)) | |
| (+ (make-flrectangular | |
| (fl- (fl* rx rx) (fl* ix ix)) | |
| (fl+ (fl* rx ix) (fl* rx ix))) | |
| c)) | |
| ) | |
| (define (iterate f x i) | |
| (if (= i 1) (f x) | |
| (iterate f (f x) (- i 1)))) | |
| (define (iterate-print f x i) | |
| (define (iterate-print-helper x counter) | |
| (let ([result (f x)]) | |
| (printf "~a: ~a~n" counter result) | |
| (if (= counter i) result | |
| (iterate-print-helper result (+ counter 1))))) | |
| (iterate-print-helper x 1)) | |
| (define (iterate-plot f x i) | |
| (define target (make-bitmap 300 300)) | |
| (define dc (new bitmap-dc% [bitmap target])) | |
| (define (iterate-plot-helper x counter) | |
| (define result (f x)) | |
| (send dc set-pixel (exact-round (* 300 result)) 100 (make-color 255 0 0)) | |
| (if (= counter i) | |
| (send dc get-bitmap) | |
| (iterate-plot-helper result (+ counter 1)))) | |
| (iterate-plot-helper x 1)) | |
| ;; ex: (iterate-complex-plot (lambda (x) (* x x)) (make-rectangular 0.6 0.8) 50) | |
| (define (iterate-complex-plot f x i) | |
| (define target (make-bitmap 300 300)) | |
| (define dc (new bitmap-dc% [bitmap target])) | |
| ; range of -2 to 2 | |
| (define x-scale (/ 300 4)) | |
| (define y-scale (* -1 (/ 300 4))) | |
| (define x-origin (/ 300 2)) | |
| (define y-origin (/ 300 2)) | |
| (define (iterate-plot-helper x counter) | |
| (define result (f x)) | |
| (send dc set-pixel (exact-round (+ x-origin | |
| (* x-scale (real-part result)))) | |
| (exact-round (+ y-origin | |
| (* y-scale (imag-part result)))) | |
| (make-color 255 0 0)) | |
| (if (= counter i) | |
| (send dc get-bitmap) | |
| (iterate-plot-helper result (+ counter 1)))) | |
| (iterate-plot-helper x 1)) | |
| ;; creates a window that calls draw-func to paint itself | |
| (define (draw-something draw-func) | |
| (define frame (new frame% | |
| [label "Example"] | |
| [width 300] | |
| [height 300])) | |
| (new canvas% [parent frame] | |
| [paint-callback | |
| (lambda (canvas dc) | |
| (draw-func dc))]) | |
| (send frame show #t)) | |
| (define (draw-text dc) | |
| (send dc set-scale 3 3) | |
| (send dc set-text-foreground "blue") | |
| (send dc draw-text "Don't Panic!" 0 0)) | |
| ;; define a canvas that displays a bitmap when its on-paint | |
| ;; method is called | |
| (define bitmap-canvas% | |
| (class canvas% | |
| (init-field [bitmap #f]) | |
| (inherit get-dc) | |
| (define/override (on-paint) | |
| (send (get-dc) draw-bitmap bitmap 0 0)) | |
| (super-new))) | |
| ;; create a window that displays bitmap | |
| (define (show-bitmap bitmap w h) | |
| (define frame (new frame% | |
| [label "Bitmap"] | |
| [width w] | |
| [height h])) | |
| (new bitmap-canvas% [parent frame] [bitmap bitmap]) | |
| (send frame show #t)) | |
| ;; sample usage: | |
| ;;(show-bitmap (iterate-plot sin -30 10)) | |
| ;; returns a simple bitmap | |
| (define (test-bitmap) | |
| (define target (make-bitmap 300 300)) | |
| (define dc (new bitmap-dc% [bitmap target])) | |
| (send dc set-pixel 10 10 (make-color 255 0 0)) | |
| (send dc get-bitmap)) | |
| ;; plots the function f on the coordinate system ranging from - x-axis-length/2 | |
| ;; to x-axis-length/2. Assume the drawing context dc has width pixels. | |
| (define (draw-plot dc f x-axis-length width) | |
| (define xmax (/ x-axis-length 2)) | |
| (define x-increment (/ x-axis-length width)) | |
| (let ([p (new dc-path%)]) | |
| (send p move-to (- xmax) (f (- xmax))) | |
| (for ([x (in-range (- xmax) xmax x-increment)]) | |
| (send p line-to x (f x))) | |
| (send dc set-pen "red" (/ x-axis-length width) 'solid) | |
| (send dc set-brush "white" 'transparent) | |
| (send dc draw-path p))) | |
| (define (draw-graphical-analysis dc f x x-axis-length width) | |
| (send dc set-pen "blue" (/ x-axis-length width) 'solid) | |
| (define (draw-graphical-analysis-helper x counter) | |
| (define f-of-x (f x)) | |
| (cond | |
| [(= counter 0) #t] | |
| [(= x f-of-x) #t] | |
| [else | |
| (send dc draw-line x x x f-of-x) | |
| (send dc draw-line x f-of-x f-of-x f-of-x) | |
| (draw-graphical-analysis-helper f-of-x (- counter 1))])) | |
| (draw-graphical-analysis-helper x 10)) | |
| ;; f is the function to plot, x0 is the initial x for orbit analysis | |
| ;; x/y-axis-length are the lengths of the cartessian coordinate system axes to show eg. abs(-x) + x | |
| ;; width and height are the dimensions of the bitmap returned | |
| ;; ex: (show-bitmap (plot-orbit-to-bitmap (make-logistic-func 1.5) -0.01 2 2 600 600) 600 600) | |
| (define (plot-orbit-to-bitmap f x0 x-axis-length y-axis-length width height) | |
| (define (draw-axes dc x-axis-length y-axis-length) | |
| (define xmax (/ x-axis-length 2)) | |
| (define xmin (- xmax)) | |
| (define ymax (/ y-axis-length 2)) | |
| (define ymin (- ymax)) | |
| (send dc draw-line xmin 0 xmax 0) | |
| (send dc draw-line 0 ymin 0 ymax)) | |
| (define (draw-y-eq-x dc x-axis-length y-axis-length) | |
| (define xmax (/ x-axis-length 2)) | |
| (define xmin (- xmax)) | |
| (define ymax (/ y-axis-length 2)) | |
| (define ymin (- ymax)) | |
| (send dc draw-line xmin ymin xmax ymax)) | |
| (define target (make-bitmap width height)) | |
| (define dc (new bitmap-dc% [bitmap target])) | |
| (send dc set-smoothing 'smoothed) | |
| (send dc set-origin (/ width 2) (/ height 2)) | |
| (send dc set-scale (/ width x-axis-length) (- (/ height y-axis-length))) | |
| (send dc set-pen "black" (/ x-axis-length width) 'solid) | |
| (draw-axes dc x-axis-length y-axis-length) | |
| (draw-y-eq-x dc x-axis-length y-axis-length) | |
| (draw-plot dc f x-axis-length width) | |
| (draw-graphical-analysis dc f x0 x-axis-length width) | |
| (send dc get-bitmap)) | |
| ;; f-class is a function that takes c as an argument and returns the function f we are evaluating | |
| ;; x0 is the initial value of x for f(x) | |
| ;; num-iter is the number of iterations for each orbit | |
| ;; show-after is the number of iterations before we plot the results | |
| ;; c-range is the min and max value of c | |
| ;; x-width and y-height is the size of the output bitmap | |
| ;; example: (orbit-diagram make-quadratic-func 0 200 50 (range -2 0.25) 300 300) | |
| (define (orbit-diagram f-class x0 num-iter show-after c-range x-width y-height) | |
| (define target (make-bitmap x-width y-height)) | |
| (define dc (new bitmap-dc% [bitmap target])) | |
| (define plot-color (make-color 255 0 0)) | |
| (define c-step (/ (- (range-max c-range) (range-min c-range)) x-width)) | |
| (define y-range (range 0 0)) | |
| ; set the y range based on the range of values from the minimum c value | |
| ; i don't really like the set! calls, but oh well | |
| (let ([f (f-class (range-min c-range))] | |
| [value x0]) | |
| (for ([i num-iter]) | |
| (set! value (f value)) | |
| (set! y-range (update-range y-range value)))) | |
| (define y-min (range-min y-range)) | |
| (define y-max (range-max y-range)) | |
| (define y-diff (- y-max y-min)) | |
| (for ([c (in-range (range-min c-range) (range-max c-range) c-step)] | |
| [x x-width]) | |
| (let ([f (f-class c)] | |
| [value x0]) | |
| (for ([i num-iter]) | |
| (set! value (f value)) | |
| (if (> i show-after) | |
| (send dc | |
| set-pixel | |
| x | |
| (- y-height | |
| (exact-round (* (/ (- value y-min) y-diff) | |
| y-height))) | |
| plot-color) | |
| #f)))) | |
| (send dc get-bitmap)) | |
| ;; z is a complex number | |
| (define (orbit-escapes f escape-value before-iter initial-z) | |
| (let loop ([z initial-z] | |
| [i 0]) | |
| (cond [(fl> (magnitude z) escape-value) #t] | |
| [(>= i before-iter) #f] | |
| [else (loop (f z) (+ i 1))]))) | |
| ;; ex: (plot-julia-set (make-quadratic-func (make-rectangular -1 0)) 20 2.0 4 4 200 200) | |
| (define (plot-julia-set f escape-iter escape-magnitude x-axis-length y-axis-length width height) | |
| (define target (make-bitmap width height)) | |
| (define dc (new bitmap-dc% [bitmap target])) | |
| (define fill-color (bytes 255 0 0 0));(make-color 0 0 0)) | |
| (define back-color (bytes 255 255 255 255));(make-color 255 255 255)) | |
| (define x-scale (/ x-axis-length width)) | |
| (define y-scale (/ y-axis-length height)) | |
| (define argb-pixels (make-bytes (* width height 4) 0)) | |
| (define row-bytes (* width 4)) | |
| (printf "Calculating~n") | |
| (for* ([x (in-range width)] | |
| [y (in-range height)]) | |
| ;(printf ".") | |
| ; using make-flrectangular makes a huge performance difference with some julia sets | |
| (if (orbit-escapes f escape-magnitude escape-iter | |
| (make-flrectangular (+ (- (/ x-axis-length 2.0)) | |
| (* x x-scale)) | |
| (- (/ y-axis-length 2.0) | |
| (* y y-scale)))) | |
| (bytes-copy! argb-pixels (+ (* y row-bytes) (* x 4)) back-color 0 4) | |
| (bytes-copy! argb-pixels (+ (* y row-bytes) (* x 4)) fill-color 0 4))) | |
| (send dc set-argb-pixels 0 0 width height argb-pixels) | |
| (send dc get-bitmap)) | |
| ;; ex: (plot-mandelbrot-set 30 2.0 4 4 300 300) | |
| (define (plot-mandelbrot-set escape-iter escape-magnitude x-axis-length y-axis-length width height) | |
| (define target (make-bitmap width height)) | |
| (define dc (new bitmap-dc% [bitmap target])) | |
| (define fill-color (bytes 255 0 0 0));(make-color 0 0 0)) | |
| (define back-color (bytes 255 255 255 255));(make-color 255 255 255)) | |
| (define x-scale (real->double-flonum (/ x-axis-length width))) | |
| (define y-scale (real->double-flonum (/ y-axis-length height))) | |
| (define x-length (real->double-flonum (/ x-axis-length 2.0))) | |
| (define y-length (real->double-flonum (/ y-axis-length 2.0))) | |
| (define argb-pixels (make-bytes (* width height 4) 0)) | |
| (define row-bytes (* width 4)) | |
| (printf "Calculating~n") | |
| (for* ([x (in-range width)] | |
| [y (in-range height)]) | |
| ;(printf ".") | |
| ; using make-flrectangular makes a huge performance difference with some sets | |
| (if (orbit-escapes (make-quadratic-func (make-flrectangular (fl+ (fl- x-length) | |
| (fl* (->fl x) x-scale)) | |
| (fl- y-length | |
| (fl* (->fl y) y-scale)))) | |
| escape-magnitude | |
| escape-iter | |
| (make-flrectangular 0.0 0.0)) | |
| (bytes-copy! argb-pixels (+ (* y row-bytes) (* x 4)) back-color 0 4) | |
| (bytes-copy! argb-pixels (+ (* y row-bytes) (* x 4)) fill-color 0 4))) | |
| (send dc set-argb-pixels 0 0 width height argb-pixels) | |
| (send dc get-bitmap)) | |
| ;; writes to a buffer of pixels in argb-pixels argument | |
| (define (calc-orbit-escapes-shared argb-pixels escape-iter escape-magnitude x-length y-length x-scale y-scale batch w h) | |
| (define fill-color (bytes 255 0 0 0));(make-color 0 0 0)) | |
| (define back-color (bytes 255 255 255 255));(make-color 255 255 255)) | |
| (define row-bytes (* w 4)) | |
| (define y-start (* batch h)) | |
| (for ([y (in-range y-start (* (add1 batch) h))]) | |
| (for ([x (in-range w)]) | |
| ; using make-flrectangular makes a huge performance difference with some sets | |
| (if (orbit-escapes (make-quadratic-func (make-flrectangular (fl+ (fl- x-length) | |
| (fl* (->fl x) x-scale)) | |
| (fl- y-length | |
| (fl* (->fl y) y-scale)))) | |
| escape-magnitude | |
| escape-iter | |
| (make-flrectangular 0.0 0.0)) | |
| (bytes-copy! argb-pixels (+ (* y row-bytes) (* x 4)) back-color 0 4) | |
| (bytes-copy! argb-pixels (+ (* y row-bytes) (* x 4)) fill-color 0 4))))) | |
| ;; returns a buffer of pixels | |
| (define (calc-orbit-escapes escape-iter escape-magnitude x-length y-length x-scale y-scale batch w h) | |
| (define fill-color (bytes 255 0 0 0));(make-color 0 0 0)) | |
| (define back-color (bytes 255 255 255 255));(make-color 255 255 255)) | |
| (define argb-pixels (make-bytes (* w h 4) 0)) | |
| (define row-bytes (* w 4)) | |
| (define y-start (* batch h)) | |
| (for ([y (in-range y-start (* (add1 batch) h))]) | |
| (for ([x (in-range w)]) | |
| ; using make-flrectangular makes a huge performance difference with some sets | |
| (if (orbit-escapes (make-quadratic-func (make-flrectangular (fl+ (fl- x-length) | |
| (fl* (->fl x) x-scale)) | |
| (fl- y-length | |
| (fl* (->fl y) y-scale)))) | |
| escape-magnitude | |
| escape-iter | |
| (make-flrectangular 0.0 0.0)) | |
| (bytes-copy! argb-pixels (+ (* (- y y-start) row-bytes) (* x 4)) back-color 0 4) | |
| (bytes-copy! argb-pixels (+ (* (- y y-start) row-bytes) (* x 4)) fill-color 0 4)))) | |
| argb-pixels) | |
| (define (plot-mandelbrot-set-futures-shared escape-iter escape-magnitude x-axis-length y-axis-length width height) | |
| (define target (make-bitmap width height)) | |
| (define dc (new bitmap-dc% [bitmap target])) | |
| (define x-scale (real->double-flonum (/ x-axis-length width))) | |
| (define y-scale (real->double-flonum (/ y-axis-length height))) | |
| (define x-length (real->double-flonum (/ x-axis-length 2.0))) | |
| (define y-length (real->double-flonum (/ y-axis-length 2.0))) | |
| (define argb-pixels (make-bytes (* width height 4) 0)) | |
| (define num-threads (processor-count)) | |
| (define batch-height (/ height num-threads)) | |
| (printf "Calculating~n") | |
| (define fs | |
| (for/list ([i num-threads]) | |
| (future | |
| (lambda () | |
| (calc-orbit-escapes-shared argb-pixels escape-iter escape-magnitude x-length y-length x-scale y-scale i width batch-height))))) | |
| (for ([f (in-list fs)]) | |
| (touch f)) | |
| (send dc set-argb-pixels 0 0 width height argb-pixels) | |
| (send dc get-bitmap)) | |
| (define (plot-mandelbrot-set-threads-shared escape-iter escape-magnitude x-axis-length y-axis-length width height) | |
| (define target (make-bitmap width height)) | |
| (define dc (new bitmap-dc% [bitmap target])) | |
| (define x-scale (real->double-flonum (/ x-axis-length width))) | |
| (define y-scale (real->double-flonum (/ y-axis-length height))) | |
| (define x-length (real->double-flonum (/ x-axis-length 2.0))) | |
| (define y-length (real->double-flonum (/ y-axis-length 2.0))) | |
| (define argb-pixels (make-bytes (* width height 4) 0)) | |
| (define num-threads (processor-count)) | |
| (define batch-height (/ height num-threads)) | |
| (printf "Calculating~n") | |
| (define thds | |
| (for/list ([i num-threads]) | |
| (thread | |
| (lambda () | |
| (calc-orbit-escapes-shared argb-pixels escape-iter escape-magnitude x-length y-length x-scale y-scale i width batch-height)) | |
| #:pool 'own | |
| #:keep 'results))) | |
| (for ([thd (in-list thds)]) | |
| (thread-wait thd)) | |
| (send dc set-argb-pixels 0 0 width height argb-pixels) | |
| (send dc get-bitmap)) | |
| (define (plot-mandelbrot-set-futures escape-iter escape-magnitude x-axis-length y-axis-length width height) | |
| (define target (make-bitmap width height)) | |
| (define dc (new bitmap-dc% [bitmap target])) | |
| (define x-scale (real->double-flonum (/ x-axis-length width))) | |
| (define y-scale (real->double-flonum (/ y-axis-length height))) | |
| (define x-length (real->double-flonum (/ x-axis-length 2.0))) | |
| (define y-length (real->double-flonum (/ y-axis-length 2.0))) | |
| (define num-threads (processor-count)) | |
| (define batch-height (/ height num-threads)) | |
| (printf "Calculating~n") | |
| (define fs | |
| (for/list ([i num-threads]) | |
| (future | |
| (lambda () | |
| (calc-orbit-escapes escape-iter escape-magnitude x-length y-length x-scale y-scale i width batch-height))))) | |
| (define argb-pixels | |
| (bytes-append* | |
| (for/list ([f (in-list fs)]) | |
| (touch f)))) | |
| (send dc set-argb-pixels 0 0 width height argb-pixels) | |
| (send dc get-bitmap)) | |
| (define (plot-mandelbrot-set-threads escape-iter escape-magnitude x-axis-length y-axis-length width height) | |
| (define target (make-bitmap width height)) | |
| (define dc (new bitmap-dc% [bitmap target])) | |
| (define x-scale (real->double-flonum (/ x-axis-length width))) | |
| (define y-scale (real->double-flonum (/ y-axis-length height))) | |
| (define x-length (real->double-flonum (/ x-axis-length 2.0))) | |
| (define y-length (real->double-flonum (/ y-axis-length 2.0))) | |
| (define num-threads (processor-count)) | |
| (define batch-height (/ height num-threads)) | |
| (printf "Calculating~n") | |
| (define thds | |
| (for/list ([i num-threads]) | |
| (thread | |
| (lambda () | |
| (calc-orbit-escapes escape-iter escape-magnitude x-length y-length x-scale y-scale i width batch-height)) | |
| #:pool 'own | |
| #:keep 'results))) | |
| (define argb-pixels | |
| (bytes-append* | |
| (for/list ([thd (in-list thds)]) | |
| (thread-wait thd)))) | |
| (send dc set-argb-pixels 0 0 width height argb-pixels) | |
| (send dc get-bitmap)) | |
| (define mandelbrot-frame% | |
| (class frame% | |
| (init-field [x-axis-length 4]) | |
| (init-field [y-axis-length 4]) | |
| (super-new) | |
| (inherit get-width) | |
| (inherit get-height) | |
| (define/override (on-subwindow-event receiver event) | |
| (define type-of-event (send event get-event-type)) | |
| (cond [(eq? type-of-event 'left-down) | |
| (define x (send event get-x)) | |
| (define y (send event get-y)) | |
| (define x-scale (/ x-axis-length (get-width))) | |
| (define y-scale (/ y-axis-length (get-height))) | |
| (define f (make-quadratic-func (make-flrectangular (+ (- (/ x-axis-length 2.0)) | |
| (* x x-scale)) | |
| (- (/ y-axis-length 2.0) | |
| (* y y-scale))))) | |
| (show-bitmap | |
| (plot-julia-set f 20 2.0 4 4 (get-width) (get-height)) | |
| ;(orbit-diagram make-quadratic-func 0 200 50 (range -2 0.25) (get-width) (get-height)) | |
| (get-width) | |
| (get-height))] | |
| [else #f])) | |
| )) | |
| (define (show-mandelbrot w h) | |
| (define frame (new mandelbrot-frame% | |
| [label "Mandelbrot Set"] | |
| [width w] | |
| [height h])) | |
| (define bitmap (plot-mandelbrot-set-futures-shared 30 2.0 4 4 w h)) | |
| (new bitmap-canvas% [parent frame] [bitmap bitmap]) | |
| (send frame show #t)) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment