Skip to content

Answer to exercise 1-4 ch.5 #17

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 4 commits into from
Oct 5, 2015
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions build.sbt
Original file line number Diff line number Diff line change
Expand Up @@ -39,4 +39,8 @@ libraryDependencies += "org.scalaz" %% "scalaz-concurrent" % "7.0.6"

libraryDependencies += "com.typesafe.akka" %% "akka-stream-experimental" % "0.4"

libraryDependencies += "com.quantifind" %% "wisp" % "0.0.4"

libraryDependencies += "org.scalafx" %% "scalafx" % "8.0.0-R4"

libraryDependencies += "com.storm-enroute" %% "reactive-collections" % "0.5"
72 changes: 72 additions & 0 deletions src/main/scala/org/learningconcurrency/exercises/ch5/Ex2.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
package org.learningconcurrency
package exercises
package ch5

import scala.util.Random

/**
* Count the occurrences of the whitespace character in a randomly generated string,
* where the probability of a whitespace at each position is determined by a p parameter.
*
* Use the parallel foreach method.
*
* Plot a graph that correlates the running time of this operation with the p parameter.
*/
object Ex2 extends App {

import org.learningconcurrency.ch5._

var r = new Random

val chars = ('a' to 'z') ++ ('A' to 'Z')

def generateSymbol(p: Double): Char =
if (r.nextDouble() > p) chars(Random.nextInt(chars.length)) else ' '

def generateString(p: Double, length: Int = 10000): Seq[Char] = {
(0 to length).map((i) => generateSymbol(p))
}

def timedForeach(s: Seq[Char]) = {
var count = 0
def add = synchronized {
count += 1
}

warmedTimed(times = 400) {
s.par.foreach((s) => if (s == ' ') add)
}
}

def timedCount(s: Seq[Char]) = {
warmedTimed(times = 400) {
s.par.count(_ == ' ')
}
}

//probability
val p = (0 until 10).map { i => i / 9.0 }

log("---- Calculation occurrences with foreach method")
val dataForeach = p.map((p) => (p, generateString(p))).map {
case (p, s) => log(s"p = $p"); (p, timedForeach(s))
}

log("---- Calculation occurrences with count method")
val dataCount = p.map((p) => (p, generateString(p))).map {
case (p, s) => log(s"p = $p"); (p, timedCount(s))
}

//plot graph
//uses https://github.com/quantifind/wisp

import com.quantifind.charts.Highcharts._

hold
line(dataForeach)
line(dataCount)
title("Ch5 Ex2")
legend(Seq("foreach method", "count method"))
xAxis("probability")
yAxis("time (ms)")
}
96 changes: 96 additions & 0 deletions src/main/scala/org/learningconcurrency/exercises/ch5/Ex3.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
package org.learningconcurrency
package exercises
package ch5

import scala.annotation.tailrec
import scalafx.application.JFXApp
import scalafx.scene.Scene
import scalafx.scene.layout.Pane
import scalafx.scene.paint.Color
import scalafx.scene.shape.Rectangle

/**
* Implement a program that renders the Mandelbrot set in parallel.
*/

object Ex3 extends JFXApp {

val width = 400
val height = 400

val minX = -1.75
val maxX = 0.8

val minY = -1.2
val maxY = 1.2

val stepX = (maxX - minX) / width
val stepY = (maxY - minY) / height

val threshold = 300

case class RGB(red: Int, green: Int, blue: Int)

case class Pixel(x: Int, y: Int, gray: Double)

def buildPixel(x: Int, y: Int) = {
val xc = minX + stepX * x
val yc = minY + stepY * y

val count = calcIterations(x = 0, y = 0, xc = xc, yc = yc, i = 0)

Pixel(x = x, y = y, gray = 1.0 - count * 1.0 / threshold)
}

@tailrec
def calcIterations(x: Double, y: Double, xc: Double, yc: Double, i: Int): Int = {

if ((x * x + y * y < 2) && (i < threshold))
calcIterations(
x = x * x - y * y + xc,
y = 2 * x * y + yc,
xc = xc,
yc = yc,
i = i + 1
)
else {
i
}
}

//render set
val pixels = (for {
x <- 0 until width
y <- 0 until height
} yield (x,y)).par.map {
case (x,y) => buildPixel(x,y)
}

//build javaFX rectangle
val rectangles = pixels.map {
case p: Pixel => new Rectangle() {
x = p.x
y = p.y
width = 1
height = 1
fill = Color.gray(p.gray)
}
}

val pane = new Pane {
content = rectangles.toList
}

//build scene
stage = new JFXApp.PrimaryStage {
title.value = "Ch5 Ex3"
scene = new Scene {
fill = Color.gray(1)
content = pane
}
}

stage.setHeight(width)
stage.setWidth(height)

}
54 changes: 54 additions & 0 deletions src/main/scala/org/learningconcurrency/exercises/ch5/ex1.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
package org.learningconcurrency
package exercises
package ch5

/**
* Measure the average running time of allocating a simple object on the JVM.
*/

object Ex1 extends App {

object Timed {

@volatile
var dummy: Any = _

def buildObjects(count:Int) = {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: you could use ScalaMeter here.

var i = 0
val start = System.nanoTime
while (i < count) {
dummy = new Object
i += 1
}
(System.nanoTime - start)/count.toDouble
}

}

var i = 0
var summ = 0D

var timePrev = 0D
while (i < 30) {

val time = Timed.buildObjects(10000000)
val e = Math.abs(time - timePrev)/time*100

//check steady state
if (e < 10) {
i += 1
summ += time
} else {
i = 0
summ = time
}

timePrev = time
log(s"time = ${time.toString} e = ${Math.round(e)}, i = $i")

}

log("----------------------------------------------------")
log(s"avg = ${summ/(i+1)} nanoseconds")

}
146 changes: 146 additions & 0 deletions src/main/scala/org/learningconcurrency/exercises/ch5/ex4.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,146 @@
package org.learningconcurrency
package exercises
package ch5

import javafx.scene.layout.HBox

import scalafx.Includes._
import scalafx.application.JFXApp
import scalafx.application.JFXApp.PrimaryStage
import scalafx.geometry.Insets
import scalafx.scene.Scene
import scalafx.scene.control._
import scalafx.scene.layout.{Pane, VBox}
import scalafx.scene.paint.Color
import scalafx.scene.shape.Rectangle

object Ex4 extends JFXApp {

/**
* Implement a program that simulates a cellular automaton in parallel.
*/

val maxX = 40
val maxY = 40

case class Cell(state: Boolean, index: Int, neighbors: Seq[Int])

def index(i: Int, j: Int) = i + j * maxX

def findNeighbors(x: Int, y: Int) = {
for {
i <- x - 1 to x + 1
j <- y - 1 to y + 1
if i > -1 && i < maxX && j > -1 && j < maxY && ((i != x) || (j != x))
} yield index(i, j)
}

def checkInitialState(x: Int, y: Int) = (x == maxX / 2 - 1 || x == maxX / 2 + 1) && y == maxY / 2

def initialize: IndexedSeq[Cell] = {
(
for {
x <- 0 until maxX
y <- 0 until maxY
} yield (x, y)
).map {
case (x, y) => Cell(
state = checkInitialState(x,y),
index = index(x, y),
neighbors = findNeighbors(x, y)
)
}
}

def countNeighbors(cell: Cell, cells: Seq[Cell]) =
cell.neighbors.count((i) => cells(i).state)

def defState(countNeighbors: Int) = {
(countNeighbors == 2) || (countNeighbors == 3)
}

def next(cells: Seq[Cell]) = {
cells.par.map(
(cell) => cell.copy(state = defState(countNeighbors(cell, cells)))).toIndexedSeq
}

//Test App

var cells = List(initialize)

val cellAreaWidth = 400
val cellAreaHeight = 400

val rectWidth = cellAreaWidth / maxX
val rectHeight = cellAreaHeight / maxY

def buildRectangles = (
for {
y <- 0 until maxY
x <- 0 until maxX
} yield (x, y)).
map {
case (posX, posY) => new Rectangle() {
x = posX * rectWidth
y = posY * rectHeight
width = rectWidth
height = rectHeight
fill = Color.GRAY
}
}.toArray


val rectangles = buildRectangles

val cellsPane = new Pane {
maxWidth = cellAreaWidth
maxHeight = cellAreaHeight
}
rectangles.foreach(cellsPane.children.add(_))

def drawCells = cells.head.foreach((c) => rectangles(c.index).setFill(if (c.state) Color.RED else Color.WHITE))

val nextButton = new Button() {
text = "=>"
onAction = handle {
cells = next(cells.head) :: cells
drawCells
}
}

val prevButton = new Button() {
text = "<="
onAction = handle {
cells = cells match {
case h :: Nil => cells
case h :: t => t
}
drawCells
}
}

val hbox = new HBox()
hbox.children.add(prevButton)
hbox.children.add(nextButton)


val vbox = new VBox {
padding = Insets(20)
spacing = 10
}

vbox.children.add(hbox)
vbox.children.add(cellsPane)

stage = new PrimaryStage {
title.value = "Ch5 Ex4"
scene = new Scene {
content = vbox
}
}

stage.sizeToScene()

drawCells

}