[add][mod] added function to return closest keys in map

- [mod] modified Time to extend Ordered
This commit is contained in:
2020-01-29 01:19:10 -06:00
parent 6028326872
commit cea02cc076
2 changed files with 92 additions and 3 deletions

View File

@@ -10,10 +10,15 @@ import scala.collection.parallel.ForkJoinTaskSupport
// Note: case classes implement equality and compare their values and not the memory address
// It only compares vals from the constructor
case class Time(time: Int, duration: Int){
case class Time(time: Int, duration: Int) extends Ordered[Time]{
def prev: Time = { Time(time - 1, duration) }
def start: Boolean = { time == 0 }
def get: Int = { time }
override def compare(that: Time): Int = {
time.compare(that.time)
}
}
// while it would seem convinient to just throw the sensors/behaviours as value into these
@@ -23,6 +28,10 @@ case class SharedMemory(sensor: Map[Time, Map[Cell, Map[Group, Vector[SensorResu
groundTruth: Map[Time, Map[Cell, Map[Group, Truth]]],
config: SimulationConfig,
output: Vector[BroadcastObject[Boolean]]) {
// memory optimization: remove sensor and throw output into output
// only map Truths from config into groundtruth, do a if groundTruth.contains(time) groundTruth(time) else prevTruth in case of time.start Truth(None) (or better map it to time.start anyways in parser)
// can drop cell from ground truth
// This could be spatially optimized to have a function to invoke a new simulation tick
// a template of Map[Cell, Map[Group, Vector[SensorResult]]] would have to be kept and deep copied when
// another tick is simulated. this won't work for ground truth, as it may already be defined
@@ -77,13 +86,28 @@ case class SimulationConfig(duration: Int, runs: Int, tickfactor: Int = 1,
val sensorThreadPool: ForkJoinTaskSupport = new ForkJoinTaskSupport(new scala.concurrent.forkjoin.ForkJoinPool(parSensorThreads))
}
case class SensorResult(result: BroadcastObject[(Group, Cell, Option[Double])]) extends BroadcastHandler(result)
/* rough size estimation
Group(name: String, sensorParent: Option[String] = None)
String: 2*x, String: 2*x
case class Cell(x: Int, y: Int)
Int: 4, Int: 4
Double: 8
4*8+4+4+8 ~ 64
SensorResult(result: BroadcastObject[(Group, Cell, Option[Double])])
default: 64
value: 64
locks: 8*4 (at least) = 32 (probably 64)
frame: 4
bool: 1
~ 3*64 = 192 byte
*/
case class SensorID(group: Group, Id: Int)
case class Duration(simDuration: Int)
case class TickFactor(factor: Int) // processed when parsing configuration, artifically place timings
case class Cell(x: Int, y: Int)
case class Group(name: String, sensorParent: Option[String] = None){
// the sensorParent serves as indicator for the parser that a ground truth is not required
// FIXME: use parent as get function and parent.set as setter to make var private
// TODO: use parent as get function and parent.set as setter to make var private
var parent: Option[String] = sensorParent // have to make this mutable to reassign it during parsing
def getParentOrGroup: Group = {
if(parent.isEmpty) {

View File

@@ -3,11 +3,14 @@ package scim.lib
// java imports
import java.io.{File, FileInputStream}
import scala.collection.immutable.ListMap
// scala imports
import scala.collection.JavaConverters._
import scala.collection.convert.wrapAll._
import scala.collection.mutable
import scala.collection.JavaConverters._
// external imports
import org.yaml.snakeyaml.Yaml
@@ -45,6 +48,7 @@ package object printUtil {
}
package object evalUtil {
def time[A](name: String, f: => A): A = {
val t0 = System.nanoTime()
val result = f
@@ -52,6 +56,14 @@ package object evalUtil {
println(name + " Elapsed time: " + (t1 - t0) + "ns")
result
}
// FIXME: obviously need to assign something and not null
def memSize(obj: Any): Long = {
// import java.lang.instrument.Instrumentation
// val instrumentation: Instrumentation = null
// instrumentation.getObjectSize(obj)
0
}
}
package object debugUtil {
@@ -144,6 +156,59 @@ package object mapUtil {
}
}
def getFirstElement[A, B](map: Map[A, B])(implicit ordering:Ordering[A]): (A, B) = {
ListMap(map.toSeq.sortBy(_._1):_*).toVector(0)
}
def getLastElement[A, B](map: Map[A, B])(implicit ordering:Ordering[A]): (A, B) = {
ListMap(map.toSeq.sortBy(_._1):_*).toVector(map.size - 1)
}
// this is just a binary search that returns the closest match
private def getClosestKeysHelper[A, B](key: A, start: Int, end: Int, vector: Vector[(A, B)])(implicit ordering:Ordering[A]): ((A, B), Option[(A, B)]) = {
val mid = start + (end - start) / 2
val foundKey = vector(mid)._1
// dont check for equality but order
if(ordering.compare(key, foundKey) == 0) return (vector(mid), Some(vector(mid + 1)))
// special case for 2 elements left
if((end - start) == 1) {
if(ordering.compare(key, vector(end)._1) >= 0) {
(vector(end), None)
} else {
// use getFirstElement to check if this is the beginning
(vector(start), Some(vector(end)))
}
} else {
if (ordering.compare(key, foundKey) > 0) {
getClosestKeysHelper(key, mid, end, vector)
} else {
getClosestKeysHelper(key, start, mid, vector)
}
}
}
def getClosestKeys[A, B](key: A, map: Map[A, B])(implicit ordering:Ordering[A]): ((A, B), Option[(A, B)]) = {
val vectorMap = ListMap(map.toSeq.sortBy(_._1):_*).toVector
getClosestKeysHelper(key, 0, vectorMap.size - 1, vectorMap)
}
def getKeyOrNext[A, B](key: A, map: Map[A, B])(implicit ordering:Ordering[A]): (A, B) = {
if(map.contains(key)) return (key, map(key))
val vectorMap = ListMap(map.toSeq.sortBy(_._1):_*).toVector
val result = getClosestKeysHelper(key, 0, vectorMap.size - 1, vectorMap)
if(ordering.compare(key, result._1._1)<= 0) {
result._1
} else {
result._2.getOrElse(result._1)
}
}
def getKeyOrPrev[A, B](key: A, map: Map[A, B])(implicit ordering:Ordering[A]): (A, B) = {
if(map.contains(key)) return (key, map(key))
val vectorMap = ListMap(map.toSeq.sortBy(_._1):_*).toVector
val result = getClosestKeysHelper(key, 0, vectorMap.size - 1, vectorMap)
result._1
}
}
package object yml {