# HG changeset patch # User Christian Urban # Date 1678574529 0 # Node ID 73ced118f73df398d487e8dfa6ccf45d015b540d # Parent 0315d9983cd017871d67b76828886ebcea80d599 updated to scala 3 diff -r 0315d9983cd0 -r 73ced118f73d progs/cube.scala --- a/progs/cube.scala Sat Mar 11 22:01:53 2023 +0000 +++ b/progs/cube.scala Sat Mar 11 22:42:09 2023 +0000 @@ -1,6 +1,14 @@ // 2 x 2 x 2 Rubik's Cube //======================== +// !! UPDATE for Scala 3 +// !! +// !! Scala 3 allocates much more memory to +// !! the JVM such that the memory issues from +// !! Scala 2 and the video do not arise. + + + // for more memory for the JVM, call // // JAVA_OPTS="-Xmx2g" scala @@ -142,7 +150,7 @@ println(s"Depth: $d Cands: ${cs.length}") val res = cs.find(_._1 == solved) if (res.isDefined) res.get - else search_list(cs.flatMap{case (c, as) => actions_list(c, as) }, d + 1) + else search_list(cs.flatMap{ (c, as) => actions_list(c, as) }, d + 1) } search_list(List((init, Nil)), 0)._2.reverse.mkString("\n") @@ -159,7 +167,7 @@ println(s"Depth: $d Cands: ${cs.keySet.size}") val res = cs.keySet.find(_ == solved) if (res.isDefined) cs(res.get) - else search_map(cs.flatMap{case (c, as) => actions_list(c, as) }, d + 1) + else search_map(cs.flatMap{ (c, as) => actions_list(c, as) }, d + 1) } @@ -173,20 +181,6 @@ println(s"Depth: $d Cands: ${cs.keySet.size}/${bs.keySet.size}") val res = cs.keySet intersect bs.keySet if (!res.isEmpty) (cs(res.head).reverse ::: bs(res.head)) - else bsearch(cs.flatMap{case (c, as) => actions_map(c, as) }, - bs.flatMap{case (c, as) => actions_map(c, as) }, d + 1) -} - -bsearch(Map(init -> Nil), Map(solved -> Nil), 0).mkString("\n") - - - -// bidirectional breadth-first search -def bsearch(cs: Map[Cube, Actions], - bs: Map[Cube, Actions], d: Int) : Actions = { - println(s"Depth: $d Cands: ${cs.keySet.size}/${bs.keySet.size}") - val res = cs.keySet intersect bs.keySet - if (!res.isEmpty) (cs(res.head).reverse ::: bs(res.head)) else bsearch(cs.flatMap{ (c, as) => actions_map(c, as) }, bs.flatMap{ (c, as) => actions_map(c, as) }, d + 1) } diff -r 0315d9983cd0 -r 73ced118f73d progs/mandelbrot.scala --- a/progs/mandelbrot.scala Sat Mar 11 22:01:53 2023 +0000 +++ b/progs/mandelbrot.scala Sat Mar 11 22:42:09 2023 +0000 @@ -3,9 +3,14 @@ // // see https://en.wikipedia.org/wiki/Mandelbrot_set // -// under scala 2.13.XX needs to be called with +// under scala 3.2.2 needs to be called with // -// scala -cp scala-parallel-collections_2.13-0.2.0.jar mandelbrot.scala +// scala -cp scala-parallel-collections_3-1.0.4.jar +// +// !! 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. + import java.awt.Color import java.awt.Dimension @@ -31,7 +36,9 @@ // to allow the notation n + m * i object i extends Complex(0, 1) -implicit def double2complex(re: Double) = Complex(re, 0) + +// implicit conversion from Doubles to Complex +given Conversion[Double, Complex] = Complex(_, 0) // some customn colours for the "sliding effect" @@ -104,17 +111,17 @@ 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) { + for (y <- (0 until H)) { + for (x <- (0 until W)) { val c = start + (x * d_x + y * d_y * i) val iters = iterations(c, max) - val col = + val colour = if (iters == max) black else colours(iters % 16) - pixel(x, y, col) + pixel(x, y, colour) } viewer.updateUI() } diff -r 0315d9983cd0 -r 73ced118f73d progs/mandelbrot2.scala --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/progs/mandelbrot2.scala Sat Mar 11 22:42:09 2023 +0000 @@ -0,0 +1,186 @@ +// Mandelbrot pictures +//===================== +// +// see https://en.wikipedia.org/wiki/Mandelbrot_set +// +// under scala 2.13.XX needs to be called with +// +// scala -cp scala-parallel-collections_2.13-0.2.0.jar mandelbrot.scala + +import java.awt.Color +import java.awt.Dimension +import java.awt.Graphics +import java.awt.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._ + +// complex numbers +case class Complex(val re: Double, val im: Double) { + // represents the complex number re + im * i + 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 notation n + m * i +object i extends Complex(0, 1) +implicit def double2complex(re: Double) = Complex(re, 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)) + +// 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) = + g.asInstanceOf[Graphics2D].drawImage(canvas, null, null) + + override def getPreferredSize() = + new 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 panel +def openViewer(width: Int, height: Int) : Viewer = { + val frame = new JFrame("XYPlane") + val viewer = new Viewer(width, height) + frame.add(viewer) + frame.pack() + frame.setVisible(true) + frame.setResizable(false) + frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE) + viewer +} + +// some hardcoded parameters +val W = 900 // width +val H = 800 // height +val black = Color.black +val viewer = openViewer(W, H) + +// draw a pixel on the canvas +def 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 satisfied +def 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 iterations +def 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 col = + if (iters == max) black + else colours(iters % 16) + + pixel(x, y, col) + } + viewer.updateUI() + } +} + + +// Examples +//========== + +//for measuring time +def time_needed[T](code: => T) = { + val start = System.nanoTime() + code + val end = System.nanoTime() + (end - start) / 1.0e9 +} + + + +// example 1 +val exa1 = -2.0 + -1.5 * i +val exa2 = 1.0 + 1.5 * i + +println(s"${time_needed(mandelbrot(exa1, exa2, 1000))} secs") + +// example 2 +val exb1 = -0.37465401 + 0.659227668 * i +val exb2 = -0.37332410 + 0.66020767 * i + +//time_needed(mandelbrot(exb1, exb2, 1000)) + +// example 3 +val exc1 = 0.435396403 + 0.367981352 * i +val exc2 = 0.451687191 + 0.380210061 * i + +//time_needed(mandelbrot(exc1, exc2, 1000)) + + + +// some more computations with example 3 + +val delta = (exc2 - exc1) * 0.0333 + +//println(s"${time_needed( +// for (n <- (0 to 12)) +// mandelbrot(exc1 + delta * n, +// exc2 - delta * n, 100))} secs") + + + +// Larry Paulson's example +val exl1 = -0.74364990 + 0.13188170 * i +val exl2 = -0.74291189 + 0.13261971 * i + +//println(s"${time_needed(mandelbrot(exl1, exl2, 1000))} secs") + + +// example by Jorgen Villadsen +val exj1 = 0.10284 - 0.63275 * i +val exj2 = 0.11084 - 0.64075 * i + +//time_needed(mandelbrot(exj1, exj2, 1000)) + + +// another example +val exA = 0.3439274 + 0.6516478 * i +val exB = 0.3654477 + 0.6301795 * i + +//time_needed(mandelbrot(exA, exB, 1000))