--- a/progs/mandelbrot.sc Fri Apr 26 17:37:56 2024 +0100
+++ b/progs/mandelbrot.sc Thu Jun 06 19:14:33 2024 +0100
@@ -2,30 +2,31 @@
//=====================
//
// see https://en.wikipedia.org/wiki/Mandelbrot_set
-//
+//
// needs to be called with
-//
-// scala -cp scala-parallel-collections_3-1.0.4.jar
+//
+// scala-cli --extra-jars scala-parallel-collections_3-1.0.4.jar
+//
+// the jar-file is uploaded to KEATS
//
-// !! UPDATE: On my faster Mac-M1 machine the times
-// !! are ca. 4 secs for the sequential version and
-// !! around 0.7 secs for the par-version.
+//
+// !! UPDATE ON TIMING: On my faster Mac-M1 machine
+// !! the times for the first example are ca. 4 secs for
+// !! the sequential version and around 0.7 secs for the
+// !! par-version.
-import java.awt.Color
-import java.awt.Dimension
-import java.awt.Graphics
-import java.awt.Graphics2D
+import javax.swing.{JFrame, JPanel, WindowConstants}
+import java.awt.{Color, Dimension, Graphics, Graphics2D}
import java.awt.image.BufferedImage
-import javax.swing.JFrame
-import javax.swing.JPanel
-import javax.swing.WindowConstants
-import scala.language.implicitConversions
-import scala.collection.parallel.CollectionConverters._
+
+import scala.language.implicitConversions
+import scala.collection.parallel.CollectionConverters.*
// complex numbers
-case class Complex(val re: Double, val im: Double) {
- // represents the complex number re + im * i
+// represents the complex number re + im * i
+case class Complex(val re: Double, val im: Double) {
+
def +(that: Complex) = Complex(this.re + that.re, this.im + that.im)
def -(that: Complex) = Complex(this.re - that.re, this.im - that.im)
def *(that: Complex) = Complex(this.re * that.re - this.im * that.im,
@@ -34,45 +35,44 @@
def abs() = Math.sqrt(this.re * this.re + this.im * this.im)
}
-// to allow the notation n + m * i
+// to allow the usual mathmo notation n + m * i
object i extends Complex(0, 1)
// implicit conversion from Doubles to Complex
-implicit def d2c(d: Double) : Complex = Complex(d, 0)
-
+given Conversion[Double, Complex] = Complex(_, 0)
// some customn colours for the "sliding effect"
val colours = List(
- new Color(66, 30, 15), new Color(25, 7, 26),
- new Color(9, 1, 47), new Color(4, 4, 73),
- new Color(0, 7, 100), new Color(12, 44, 138),
- new Color(24, 82, 177), new Color(57, 125, 209),
- new Color(134, 181, 229), new Color(211, 236, 248),
- new Color(241, 233, 191), new Color(248, 201, 95),
- new Color(255, 170, 0), new Color(204, 128, 0),
- new Color(153, 87, 0), new Color(106, 52, 3))
+ Color(66, 30, 15), Color(25, 7, 26),
+ Color(9, 1, 47), Color(4, 4, 73),
+ Color(0, 7, 100), Color(12, 44, 138),
+ Color(24, 82, 177), Color(57, 125, 209),
+ Color(134, 181, 229), Color(211, 236, 248),
+ Color(241, 233, 191), Color(248, 201, 95),
+ Color(255, 170, 0), Color(204, 128, 0),
+ Color(153, 87, 0), Color(106, 52, 3))
// the viewer panel with an image canvas
class Viewer(width: Int, height: Int) extends JPanel {
- val canvas = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB)
-
- override def paintComponent(g: Graphics) =
+ val canvas = BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB)
+
+ override def paintComponent(g: Graphics) =
g.asInstanceOf[Graphics2D].drawImage(canvas, null, null)
-
- override def getPreferredSize() =
- new Dimension(width, height)
+
+ override def getPreferredSize() =
+ Dimension(width, height)
def clearCanvas(color: Color) = {
- for (x <- 0 to width - 1; y <- 0 to height - 1)
+ for (x <- 0 to width - 1; y <- 0 to height - 1)
canvas.setRGB(x, y, color.getRGB())
repaint()
- }
+ }
}
// initialising the viewer panel
def openViewer(width: Int, height: Int) : Viewer = {
- val frame = new JFrame("XYPlane")
- val viewer = new Viewer(width, height)
+ val frame = JFrame("XYPlane")
+ val viewer = Viewer(width, height)
frame.add(viewer)
frame.pack()
frame.setVisible(true)
@@ -88,7 +88,7 @@
val viewer = openViewer(W, H)
// draw a pixel on the canvas
-def pixel(x: Int, y: Int, color: Color) =
+def pixel(x: Int, y: Int, color: Color) =
viewer.canvas.setRGB(x, y, color.getRGB())
@@ -96,35 +96,34 @@
// the iteration goes on for a maximum of max steps,
// but might leave early when the pred is satisfied
def iterations(c: Complex, max: Int) : Int = {
- def next(z: Complex) = z * z + c
+ def next(z: Complex) = z * z + c
def pred(z: Complex) = z.abs() < 2 // exit condition
LazyList.iterate(0.0 * i, max)(next).takeWhile(pred).size
}
-// main function
-// start and end are the upper-left and lower-right corners,
+// main function
+// start and end are the upper-left and lower-right corners,
// max is the number of maximum iterations
def mandelbrot(start: Complex, end: Complex, max: Int) : Unit = {
viewer.clearCanvas(black)
-
- // deltas for each grid step
+
+ // deltas for each grid step
val d_x = (end.re - start.re) / W
val d_y = (end.im - start.im) / H
-
+
for (y <- (0 until H).par) {
for (x <- (0 until W).par) {
-
- val c = start +
- (x * d_x + y * d_y * i)
- val iters = iterations(c, max)
+
+ val c = start + x * d_x + y * d_y * i
+ val iters = iterations(c, max)
val colour =
- if (iters == max) black
- else colours(iters % 16)
+ if (iters == max) black
+ else colours(iters % 16)
pixel(x, y, colour)
}
viewer.updateUI()
- }
+ }
}
@@ -166,9 +165,9 @@
val delta = (exc2 - exc1) * 0.0333
println(s"${time_needed(
- for (n <- (0 to 25))
- mandelbrot(exc1 + delta * n,
- exc2 - delta * n, 1000))} secs")
+ for (n <- (0 to 25))
+ mandelbrot(exc1 + delta * n,
+ exc2 - delta * n, 1000))} secs")