# HG changeset patch # User Christian Urban # Date 1717708695 -3600 # Node ID 4778fefecd0cfa909e606de72d835b9bb9943a62 # Parent d51cacc924800b40dd9aca0a7650800f171946f5 updated diff -r d51cacc92480 -r 4778fefecd0c progs/mandelbrot.scala --- a/progs/mandelbrot.scala Thu Jun 06 19:14:33 2024 +0100 +++ b/progs/mandelbrot.scala Thu Jun 06 22:18:15 2024 +0100 @@ -2,32 +2,31 @@ //===================== // // see https://en.wikipedia.org/wiki/Mandelbrot_set -// +// // needs to be called with -// -// scala-cli --extra-jars scala-parallel-collections_3-1.0.4.jar +// +// scala-cli --extra-jars scala-parallel-collections_3-1.0.4.jar // -// the library is also uploaded to KEATS +// 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, @@ -36,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 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) @@ -90,44 +88,42 @@ 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()) -// calculates the number of iterations using lazy lists -// (streams) +// calculates the number of iterations using lazy lists (streams) // 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() - } + } } @@ -169,9 +165,9 @@ val delta = (exc2 - exc1) * 0.0333 println(s"${time_needed( - for (n <- (0 to 12)) - mandelbrot(exc1 + delta * n, - exc2 - delta * n, 100))} secs") + for (n <- (0 to 25)) + mandelbrot(exc1 + delta * n, + exc2 - delta * n, 1000))} secs")