progs/mandelbrot.sc
changeset 489 d51cacc92480
parent 488 5deaf53c2faa
--- 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")