Advertisement
jules0707

lineOfSight

Apr 5th, 2017
412
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Scala 5.79 KB | None | 0 0
  1. package reductions
  2.  
  3. import org.scalameter._
  4. import common._
  5. import scala.collection.par.Conc.Prepend
  6.  
  7. object LineOfSightRunner {
  8.  
  9.   val standardConfig = config(
  10.     Key.exec.minWarmupRuns -> 40,
  11.     Key.exec.maxWarmupRuns -> 80,
  12.     Key.exec.benchRuns -> 100,
  13.     Key.verbose -> true) withWarmer (new Warmer.Default)
  14.  
  15.   def main(args: Array[String]) {
  16.     val length = 10000000
  17.     val input = (0 until length).map(_ % 100 * 1.0f).toArray
  18.     val output = new Array[Float](length + 1)
  19.     val seqtime = standardConfig measure {
  20.       LineOfSight.lineOfSight(input, output)
  21.     }
  22.     println(s"sequential time: $seqtime ms")
  23.  
  24.     val partime = standardConfig measure {
  25.       LineOfSight.parLineOfSight(input, output, 10000)
  26.     }
  27.     println(s"parallel time: $partime ms")
  28.     println(s"speedup: ${seqtime / partime}")
  29.   }
  30. }
  31.  
  32. object LineOfSight {
  33.  
  34.   def max(a: Float, b: Float): Float = if (a > b) a else b
  35.  
  36.   def lineOfSight(input: Array[Float], output: Array[Float]): Unit = {
  37.     /*Using scanLeft
  38.         val out = input.scanLeft(0f)((a, b) => max(a, b / max(1, (input.indexOf(b)))))
  39.           var i = 0
  40.           var j = 0
  41.           while (i < input.length) {
  42.             output.update(i, out(j + 1))
  43.             i += 1
  44.             j += 1
  45.           }
  46.     */
  47.  
  48.     /*or re-implementing scanLeft*/
  49.     output(0) = 0f
  50.     var a = 0f
  51.     var i = 0
  52.     while (i < input.length - 1) {
  53.       a = max(a, input(i + 1) / max(1, (input.indexOf(input(i + 1)))))
  54.       println(a)
  55.       i += 1
  56.       output(i) = a
  57.     }
  58.  
  59.     /* elegant solution from Tom Lou thanks
  60.      * input.zipWithIndex.foreach{
  61.       case (xs, 0) => output(0) = 0
  62.       case (xs, i) => output(i) = Math.max(xs / i, output(i-1))
  63.     }
  64.      */
  65.   }
  66.  
  67.   sealed abstract class Tree {
  68.     def maxPrevious: Float
  69.   }
  70.  
  71.   case class Node(left: Tree, right: Tree) extends Tree {
  72.     val maxPrevious = max(left.maxPrevious, right.maxPrevious)
  73.   }
  74.  
  75.   case class Leaf(from: Int, until: Int, maxPrevious: Float) extends Tree
  76.  
  77.   /**
  78.    * Traverses the specified part of the array and returns the maximum angle.
  79.    */
  80.   def upsweepSequential(input: Array[Float], from: Int, until: Int): Float = {
  81.     /* elegant solution thanks Tom Lou */
  82.     (from until until).foldLeft(0f)((currentMax, i) => max(input(i) / i, currentMax))
  83.   }
  84.  
  85.   /**
  86.    * Traverses the part of the array starting at `from` and until `end`, and
  87.    *  returns the reduction tree for that part of the array.
  88.    *
  89.    *  The reduction tree is a `Leaf` if the length of the specified part of the
  90.    *  array is smaller or equal to `threshold`, and a `Node` otherwise.
  91.    *  If the specified part of the array is longer than `threshold`, then the
  92.    *  work is divided and done recursively in parallel.
  93.    */
  94.   def upsweep(input: Array[Float], from: Int, end: Int, threshold: Int): Tree = {
  95.     if (end - from <= threshold)
  96.       Leaf(from, end, upsweepSequential(input, from, end))
  97.     else {
  98.       val mid = from + (end - from) / 2
  99.       val (left, right) = parallel(
  100.         upsweep(input, from, mid, threshold),
  101.         upsweep(input, mid, end, threshold))
  102.       Node(left, right)
  103.     }
  104.   }
  105.  
  106.   /**
  107.    * Traverses the part of the `input` array starting at `from` and until
  108.    *  `until`, and computes the maximum angle for each entry of the output array,
  109.    *  given the `startingAngle`.
  110.    */
  111.   def downsweepSequential(input: Array[Float], output: Array[Float], startingAngle: Float,
  112.     from: Int, until: Int): Unit = {
  113.     // thanks Tom Lou
  114.     def maxAngle(start: Int, end: Int, previousMax: Float) {
  115.       if (start < end) {
  116.         output(start) = max(previousMax, input(start) / start)
  117.         maxAngle(start + 1, end, output(start))
  118.       }
  119.     }
  120.     maxAngle(from, until, startingAngle)
  121.   }
  122.  
  123.   /**
  124.    * Pushes the maximum angle in the prefix of the array to each leaf of the
  125.    *  reduction `tree` in parallel, and then calls `downsweepSequential` to write
  126.    *  the `output` angles.
  127.    */
  128.   def downsweep(input: Array[Float], output: Array[Float], startingAngle: Float, tree: Tree): Unit = {
  129.     tree match {
  130.       case Leaf(from, until, _) => downsweepSequential(input, output, startingAngle, from, until)
  131.       case Node(left, right) => {
  132.         parallel(
  133.           downsweep(input, output, startingAngle, left),
  134.           downsweep(input, output, max(startingAngle, left.maxPrevious), right))
  135.       }
  136.     }
  137.   }
  138.  
  139.   /** Compute the line-of-sight in parallel. */
  140.   def parLineOfSight(input: Array[Float], output: Array[Float], threshold: Int): Unit = {
  141.     val tree = upsweep(input, 0, input.length, threshold)
  142.     downsweep(input, output, 0f, tree)
  143.   }
  144. }
  145.  
  146. /* FYI AUTO GRADER OUTPUT. Your solution achieved a testing score of 137 out of 150.
  147.  
  148. [Test Description] parLineOfSight should invoke the parallel construct 30 times (15 times during upsweep and 15 times during downsweep) for an array of size 17, with threshold 1
  149. [Observed Error] 32 did not equal 30 (The number of parallel calls should be 30)
  150. [Lost Points] 3
  151.  
  152. [Test Description] parLineOfSight should correctly compute the output for threshold 3
  153. [Observed Error] List(NaN, 9.0, 9.0, 9.0, 9.0, 9.0) did not equal List(0.0, 9.0, 9.0, 9.0, 9.0, 9.0)
  154. [Lost Points] 2
  155.  
  156. [Test Description] parLineOfSight should call parallel constuct 6 times, where the last two parallel constructs should update the 4 sections of the array (1 until 5), (5 until 9), (9 until 13), (13 until 17), respectively
  157. [Observed Error] success was false [During the execution of first part of 5th call to parallel construct, the indices 1 until 5 of the output array was not correctly updated]
  158. [Lost Points] 6
  159.  
  160. [Test Description] parLineOfSight should correctly compute the output for threshold 2
  161. [Observed Error] List(NaN, 7.0, 7.0, 11.0, 12.0) did not equal List(0.0, 7.0, 7.0, 11.0, 12.0)
  162. [Lost Points] 2
  163.  
  164. */
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement