// Mandelbrot pictures//=====================//// see https://en.wikipedia.org/wiki/Mandelbrot_set//// You can run on the file one the commandline with//// scala mandelbrot.sc//////// !! 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.// for parallel collections//> using dep org.scala-lang.modules::scala-parallel-collections:1.0.4import scala.language.implicitConversions.*import scala.collection.parallel.CollectionConverters.*// for graphicsimport javax.swing.{JFrame, JPanel, WindowConstants}import java.awt.{Color, Dimension, Graphics, Graphics2D}import java.awt.image.BufferedImage// for implicits in comples numbersimport scala.language.implicitConversions// complex numbers// represents the complex number re + im * icase 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, this.re * that.im + that.re * this.im) def *(that: Double) = Complex(this.re * that, this.im * that) def abs() = Math.sqrt(this.re * this.re + this.im * this.im)}// to allow the usual mathmo notation n + m * iobject i extends Complex(0, 1)// implicit conversion from Doubles to Complexgiven Conversion[Double, Complex] = Complex(_, 0)// some customn colours for the "sliding effect" outside// the mandelbrot setval colours = List( 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 canvasclass Viewer(width: Int, height: Int) extends JPanel { val canvas = BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB) override def paintComponent(g: Graphics) = g.asInstanceOf[Graphics2D].drawImage(canvas, null, null) override def getPreferredSize() = Dimension(width, height) def clearCanvas(color: Color) = { for (x <- 0 to width - 1; y <- 0 to height - 1) canvas.setRGB(x, y, color.getRGB()) repaint() }}// initialising the viewer paneldef openViewer(width: Int, height: Int) : Viewer = { val viewer = Viewer(width, height) val frame = JFrame("XYPlane") frame.add(viewer) frame.pack() frame.setVisible(true) frame.setResizable(false) frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE) viewer}// some hardcoded parametersval W = 900 // widthval H = 800 // heightval black = Color.blackval viewer = openViewer(W, H)// draw a pixel on the canvasdef pixel(x: Int, y: Int, color: Color) = viewer.canvas.setRGB(x, y, color.getRGB())// 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 satisfieddef iterations(c: Complex, max: Int) : Int = { 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,// max is the number of maximum iterationsdef mandelbrot(start: Complex, end: Complex, max: Int) : Unit = { viewer.clearCanvas(black) // 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 colour = if (iters == max) black else colours(iters % 16) pixel(x, y, colour) } viewer.updateUI() }}// Examples//==========//for measuring timedef time_needed[T](code: => T) = { val start = System.nanoTime() code val end = System.nanoTime() (end - start) / 1.0e9}// example 1val exa1 = -2.0 + -1.5 * ival exa2 = 1.0 + 1.5 * iprintln(s"${time_needed(mandelbrot(exa1, exa2, 1000))} secs")// example 2val exb1 = -0.37465401 + 0.659227668 * ival exb2 = -0.37332410 + 0.66020767 * i//time_needed(mandelbrot(exb1, exb2, 1000))// example 3val exc1 = 0.435396403 + 0.367981352 * ival exc2 = 0.451687191 + 0.380210061 * i//time_needed(mandelbrot(exc1, exc2, 1000))// some more computations with example 3val delta = (exc2 - exc1) * 0.01println(s"${time_needed( for (n <- (0 to 25)) mandelbrot(exc1 + delta * n, exc2 - delta * n, 1000))} secs")// Larry Paulson's exampleval exl1 = -0.74364990 + 0.13188170 * ival exl2 = -0.74291189 + 0.13261971 * i//println(s"${time_needed(mandelbrot(exl1, exl2, 1000))} secs")// example by Jorgen Villadsenval exj1 = 0.10284 - 0.63275 * ival exj2 = 0.11084 - 0.64075 * i//time_needed(mandelbrot(exj1, exj2, 1000))// another exampleval exA = 0.3439274 + 0.6516478 * ival exB = 0.3654477 + 0.6301795 * i//time_needed(mandelbrot(exA, exB, 1000))