Skip to content
Snippets Groups Projects

Compare revisions

Changes are shown as if the source revision was being merged into the target revision. Learn more about comparing revisions.

Source

Select target project
No results found

Target

Select target project
  • lara/cs206-demos
  • gcharles/cs206-demos
  • gambhir/cs206-demos
3 results
Show changes
Commits on Source (6)
......@@ -21,4 +21,4 @@ test:
tags:
- cs320
script:
- sbt "runMain lecture1.javaThreads; runMain lecture1.scalaThreadWrapper; runMain lecture1.ExampleThread; runMain lecture3.intersectionWrong; runMain lecture3.intersectionCorrect; runMain lecture3.intersectionNoSideEffect; runMain lecture3.parallelGraphContraction; runMain lecture3.parallelGraphContractionCorrect; runMain midterm22.mock1; runMain midterm22.part3; runMain ed.patternMatching; runMain lecture13.askPatternDemo; test; scalafmtCheck; Test / scalafmtCheck"
- sbt "runMain lecture1.javaThreads; runMain lecture1.scalaThreadWrapper; runMain lecture1.ExampleThread; runMain lecture3.intersectionWrong; runMain lecture3.intersectionCorrect; runMain lecture3.intersectionNoSideEffect; runMain lecture3.parallelGraphContraction; runMain lecture3.parallelGraphContractionCorrect; runMain midterm22.mock1; runMain midterm22.part3; runMain ed.patternMatching; runMain lecture13.askPatternDemo; test; runMain lecture13.becomeDemo; runMain ed.futuresForTranslation; runMain concpar20final03.concpar20final03; scalafmtCheck; Test / scalafmtCheck"
package concpar20final03
import scala.concurrent.{Await, Future}
import scala.concurrent.duration.Duration
import scala.concurrent.ExecutionContext.Implicits.global
import scala.util.{Failure, Success}
def sequence1[A](fs: List[Future[A]]): Future[List[A]] =
fs match
case f :: fs =>
for
x <- f
xs <- sequence1(fs)
yield x :: xs
case Nil =>
Future.successful(Nil)
def sequence2[A](fs: List[Future[A]]): Future[List[A]] =
fs match
case f :: fs =>
f.flatMap(x => sequence2(fs).map(xs => x :: xs))
case Nil =>
Future.successful(Nil)
def sequence3[A](fs: List[Future[A]]): Future[List[A]] =
fs match
case f :: fs =>
f.transformWith {
case Failure(e) => Future.failed(e)
case Success(value) =>
sequence3(fs).transform {
case res: Failure[List[A]] => res
case Success(values) => Success(value :: values)
}
}
case Nil =>
Future.successful(Nil)
def sequence4[A](fs: List[Future[A]]): Future[List[A]] =
fs match
case f :: fs =>
val fsFuture: Future[List[A]] = sequence4(fs)
f.zip(fsFuture).map((fValue, fsValue) => fValue :: fsValue)
case Nil =>
Future.successful(Nil)
@main def concpar20final03 =
val xs = List(Future { 1 }, Future { 2 }, Future { 3 })
val ys = List(Future { 1 }, Future.failed(Error("BOOM")), Future { 3 })
println(Await.result(sequence1(xs), Duration.Inf))
// println(Await.result(sequence1(xs), Duration.Inf)) // Throws exception
println(Await.result(sequence2(xs), Duration.Inf))
// println(Await.result(sequence2(ys), Duration.Inf)) // Throws exception
println(Await.result(sequence3(xs), Duration.Inf))
// println(Await.result(sequence3(ys), Duration.Inf)) // Throws exception
println(Await.result(sequence4(xs), Duration.Inf))
// println(Await.result(sequence4(ys), Duration.Inf)) // Throws exception
package ed
// To demonstrate different ways of pattern matching, let's consider the
// following example case class and instance:
case class Person(name: String, age: Int)
......
package ed
import concurrent.{Await, Future}
import concurrent.duration.Duration
import concurrent.ExecutionContext.Implicits.global
// Pro Tip: you can print the code generated by the Scala compiler after the
// translation of for-comprehensions by running:
//
// scala -Xprint:firstTransform src/main/scala/ed/40056.scala
@main def futuresForTranslation =
val f1 = Future { 451 }
val f2 = Future { 1984 }
val f3 = for v1 <- f1; v2 <- f2 yield v1 + v2
println(Await.result(f3, Duration.Inf))
val f4 = Future { 451 }
val f5 = Future { 1984 }
val f6 = f4.flatMap(v4 => f5.map(v5 => v4 + v5))
println(Await.result(f6, Duration.Inf))
......@@ -114,9 +114,8 @@ class PersonsDatabase extends Actor:
// are completed.
val futureOfNames: Future[List[String]] = Future.sequence(namesFutures)
// Finally, map the `Future[List[String]]` to a
// `Future[PersonNames]` and pipe it to the sender of the
// `GetPersonNames` message.
// Finally, map the `Future[List[String]]` to a `Future[PersonNames]` and
// pipe it to the sender of the `GetPersonNames` message.
futureOfNames.map(PersonNames.apply).pipeTo(sender())
}
......
package lecture13
import akka.actor.{Actor, ActorContext, ActorRef, ActorSystem, Props}
import akka.event.LoggingReceive
import akka.testkit.{ImplicitSender, TestKit}
class CounterRight extends Actor:
def counter(n: Int): Receive = {
case "increment" => context.become(counter(n + 1), discardOld = false)
// ^^^^^^^^^^^^^^^^^^
// This is needed.
case "get" => sender() ! n
case "decrement" => if n != 0 then context.unbecome()
}
def receive = counter(0)
class CounterWrong extends Actor:
def counter(n: Int): Receive = {
case "increment" => context.become(counter(n + 1))
case "get" => sender() ! n
case "decrement" => if n != 0 then context.unbecome()
}
def receive = counter(0)
@main def becomeDemo() =
new TestKit(ActorSystem("DebugSystem")) with ImplicitSender:
try
val counter = system.actorOf(Props(CounterRight()), "counter")
counter ! "increment"
counter ! "get"
expectMsg(1)
counter ! "increment"
counter ! "get"
expectMsg(2)
counter ! "decrement"
counter ! "get"
expectMsg(1)
// This is wrong if we use CounterWrong because it doesn't set the
// discardOld parameter to false. Therefore, it will not remember the
// previous state and reset the behavior to the initial one, which is
// `counter(0)`.
counter ! "decrement"
counter ! "get"
expectMsg(0)
finally shutdown(system)
......@@ -16,13 +16,30 @@ def sequentialConvolve(
from: Int,
until: Int
): Unit = {
// Approach A, as described in the clarification announcement for this
// exercise, where we treat `from` and `until` as indices on `output`
// instead of `input` as in the given code.
var iOutput = from
while iOutput < until do
var iKernel = math.max(0, iOutput - input.length + 1)
while iKernel < kernel.length && iKernel <= iOutput do
// `output` is only ever written to between the indices `from` and
// `until`, the range of `iOutput`. The indices for `input` and
// `kernel` are computed accordingly.
output(iOutput) += input(iOutput - iKernel) * kernel(iKernel)
iKernel += 1
iOutput += 1
// ALTERNATE SOLUTION: Approach B, as described in the clarification
// announcement for this exercise, which is unchanged from the given
// code, i.e. we treat `from` and `until` as indices on `input`.
var iInput = from
while iInput < until do
var iKernel = 0
while iKernel < kernel.length do
output(iInput + iKernel) += input(iInput) * kernel(iKernel)
iKernel += 1
iInput += 1
}
def parallelConvolve(
......@@ -32,7 +49,12 @@ def parallelConvolve(
from: Int,
until: Int,
threshold: Int
): Unit =
): Unit =
// Approach A, as described in the clarification announcement for this
// exercise, where we treat `from` and `until` as indices on `output`
// instead of `input` as in the given code. This does not require us to
// change anything in this function. Only receives full credit if used
// together with Approach A for `sequentialConvolve`.
if (until - from) <= threshold then
sequentialConvolve(input, kernel, output, from, until)
else
......@@ -42,6 +64,31 @@ def parallelConvolve(
parallelConvolve(input, kernel, output, mid, until, threshold)
)
// ALTERNATE SOLUTION: Approach B, as described in the clarification
// announcement for this exercise, where we treat `from` and `until` as
// indices on `input` as in the given code. This requires up to leave a
// gap in the parallel calls to be filled in sequentially as described
// below. Only receives full credit if used together with Approach B for
// `sequentialConvolve`.
if (until - from) <= threshold then
sequentialConvolve(input, kernel, output, from, until)
else
val mid = from + (until - from) / 2
val gap = numContributeTo(input, kernel, output, mid)
// Leave a gap large enough that accesses to `output` from the first
// parallel call will not overlap with accesses from the second. This
// gap is of size equal to the number of elements of `input` that will
// contribute to the computation of the result at the lowest index of
// `output` in the second parallel call, namely, at index `mid`.
// However, we are careful not to access indices lower than `from`.
val gapBeforeMid = Math.max(from, mid - gap + 1)
parallel(
parallelConvolve(input, kernel, output, from, gapBeforeMid, threshold),
parallelConvolve(input, kernel, output, mid, until, threshold)
)
// Fill in the gap sequentially.
sequentialConvolve(input, kernel, output, gapBeforeMid, mid)
object Original_WithOutputRace:
def sequentialConvolve(
......@@ -50,15 +97,13 @@ object Original_WithOutputRace:
output: Array[Int],
from: Int,
until: Int): Unit =
var iOutput = from
while iOutput < until do
var iInput = from
while iInput < until do
var iKernel = 0
while iKernel < kernel.length do
val iInput = iOutput - iKernel
if 0 <= iInput && iInput < input.length then
output(iOutput) += input(iInput) * kernel(iKernel)
output(iInput + iKernel) += input(iInput) * kernel(iKernel)
iKernel += 1
iOutput += 1
iInput += 1
def parallelConvolve(
input: Array[Int],
......