1 // Mandelbrot pictures |
1 // Mandelbrot pictures |
2 //===================== |
2 //===================== |
3 // |
3 // |
4 // see https://en.wikipedia.org/wiki/Mandelbrot_set |
4 // see https://en.wikipedia.org/wiki/Mandelbrot_set |
5 // |
5 // |
6 // needs to be called with |
6 // You can run on the file one the commandline with |
7 // |
7 // |
8 // scala-cli --extra-jars scala-parallel-collections_3-1.0.4.jar |
8 // scala-cli mandelbrot.sc |
9 // |
|
10 // the jar-file is uploaded to KEATS |
|
11 // |
9 // |
12 // |
10 // |
13 // !! UPDATE ON TIMING: On my faster Mac-M1 machine |
11 // |
14 // !! the times for the first example are ca. 4 secs for |
12 // !! UPDATE ON TIMING: On my faster Mac-M1 machine |
15 // !! the sequential version and around 0.7 secs for the |
13 // !! the times for the first example are ca. 4 secs for |
|
14 // !! the sequential version and around 0.7 secs for the |
16 // !! par-version. |
15 // !! par-version. |
17 |
16 |
|
17 // for parallel collections |
|
18 //> using dep org.scala-lang.modules::scala-parallel-collections:1.0.4 |
|
19 import scala.language.implicitConversions |
|
20 import scala.collection.parallel.CollectionConverters.* |
18 |
21 |
|
22 // for graphics |
19 import javax.swing.{JFrame, JPanel, WindowConstants} |
23 import javax.swing.{JFrame, JPanel, WindowConstants} |
20 import java.awt.{Color, Dimension, Graphics, Graphics2D} |
24 import java.awt.{Color, Dimension, Graphics, Graphics2D} |
21 import java.awt.image.BufferedImage |
25 import java.awt.image.BufferedImage |
22 |
26 |
23 import scala.language.implicitConversions |
27 |
24 import scala.collection.parallel.CollectionConverters.* |
28 |
25 |
29 |
26 // complex numbers |
30 // complex numbers |
27 // represents the complex number re + im * i |
31 // represents the complex number re + im * i |
28 case class Complex(val re: Double, val im: Double) { |
32 case class Complex(val re: Double, val im: Double) { |
29 |
33 |
30 def +(that: Complex) = Complex(this.re + that.re, this.im + that.im) |
34 def +(that: Complex) = Complex(this.re + that.re, this.im + that.im) |
31 def -(that: Complex) = Complex(this.re - that.re, this.im - that.im) |
35 def -(that: Complex) = Complex(this.re - that.re, this.im - that.im) |
32 def *(that: Complex) = Complex(this.re * that.re - this.im * that.im, |
36 def *(that: Complex) = Complex(this.re * that.re - this.im * that.im, |
33 this.re * that.im + that.re * this.im) |
37 this.re * that.im + that.re * this.im) |
34 def *(that: Double) = Complex(this.re * that, this.im * that) |
38 def *(that: Double) = Complex(this.re * that, this.im * that) |
39 object i extends Complex(0, 1) |
43 object i extends Complex(0, 1) |
40 |
44 |
41 // implicit conversion from Doubles to Complex |
45 // implicit conversion from Doubles to Complex |
42 given Conversion[Double, Complex] = Complex(_, 0) |
46 given Conversion[Double, Complex] = Complex(_, 0) |
43 |
47 |
44 // some customn colours for the "sliding effect" |
48 // some customn colours for the "sliding effect" outside |
|
49 // the mandelbrot set |
45 val colours = List( |
50 val colours = List( |
46 Color(66, 30, 15), Color(25, 7, 26), |
51 Color(66, 30, 15), Color(25, 7, 26), |
47 Color(9, 1, 47), Color(4, 4, 73), |
52 Color(9, 1, 47), Color(4, 4, 73), |
48 Color(0, 7, 100), Color(12, 44, 138), |
53 Color(0, 7, 100), Color(12, 44, 138), |
49 Color(24, 82, 177), Color(57, 125, 209), |
54 Color(24, 82, 177), Color(57, 125, 209), |
69 } |
74 } |
70 } |
75 } |
71 |
76 |
72 // initialising the viewer panel |
77 // initialising the viewer panel |
73 def openViewer(width: Int, height: Int) : Viewer = { |
78 def openViewer(width: Int, height: Int) : Viewer = { |
|
79 val viewer = Viewer(width, height) |
74 val frame = JFrame("XYPlane") |
80 val frame = JFrame("XYPlane") |
75 val viewer = Viewer(width, height) |
|
76 frame.add(viewer) |
81 frame.add(viewer) |
77 frame.pack() |
82 frame.pack() |
78 frame.setVisible(true) |
83 frame.setVisible(true) |
79 frame.setResizable(false) |
84 frame.setResizable(false) |
80 frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE) |
85 frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE) |
114 for (y <- (0 until H).par) { |
119 for (y <- (0 until H).par) { |
115 for (x <- (0 until W).par) { |
120 for (x <- (0 until W).par) { |
116 |
121 |
117 val c = start + x * d_x + y * d_y * i |
122 val c = start + x * d_x + y * d_y * i |
118 val iters = iterations(c, max) |
123 val iters = iterations(c, max) |
119 val colour = |
124 val colour = |
120 if (iters == max) black |
125 if (iters == max) black |
121 else colours(iters % 16) |
126 else colours(iters % 16) |
122 |
127 |
123 pixel(x, y, colour) |
128 pixel(x, y, colour) |
124 } |
129 } |
125 viewer.updateUI() |
130 viewer.updateUI() |
126 } |
131 } |
127 } |
132 } |
|
133 |
|
134 |
128 |
135 |
129 |
136 |
130 // Examples |
137 // Examples |
131 //========== |
138 //========== |
132 |
139 |
156 val exc1 = 0.435396403 + 0.367981352 * i |
163 val exc1 = 0.435396403 + 0.367981352 * i |
157 val exc2 = 0.451687191 + 0.380210061 * i |
164 val exc2 = 0.451687191 + 0.380210061 * i |
158 |
165 |
159 //time_needed(mandelbrot(exc1, exc2, 1000)) |
166 //time_needed(mandelbrot(exc1, exc2, 1000)) |
160 |
167 |
161 |
|
162 |
|
163 // some more computations with example 3 |
168 // some more computations with example 3 |
164 |
169 |
165 val delta = (exc2 - exc1) * 0.0333 |
170 val delta = (exc2 - exc1) * 0.01 |
166 |
171 |
167 println(s"${time_needed( |
172 println(s"${time_needed( |
168 for (n <- (0 to 25)) |
173 for (n <- (0 to 25)) |
169 mandelbrot(exc1 + delta * n, |
174 mandelbrot(exc1 + delta * n, |
170 exc2 - delta * n, 1000))} secs") |
175 exc2 - delta * n, 1000))} secs") |