diff --git a/src/main/scala/scim/datastruct/Configuration.scala b/src/main/scala/scim/datastruct/Configuration.scala index aec98fd..fc7d72e 100644 --- a/src/main/scala/scim/datastruct/Configuration.scala +++ b/src/main/scala/scim/datastruct/Configuration.scala @@ -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) { diff --git a/src/main/scala/scim/lib/Library.scala b/src/main/scala/scim/lib/Library.scala index 79f6cb3..2a1c359 100644 --- a/src/main/scala/scim/lib/Library.scala +++ b/src/main/scala/scim/lib/Library.scala @@ -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 {