diff --git a/src/main/scala/scim/Main.scala b/src/main/scala/scim/Main.scala index 6516877..2e9c533 100644 --- a/src/main/scala/scim/Main.scala +++ b/src/main/scala/scim/Main.scala @@ -28,7 +28,7 @@ object Main { //lib.evalUtil.time("par", parlist.par.map({_ => Thread.sleep(10); 2})) //lib.evalUtil.time("ser", parlist.map({_ => Thread.sleep(10); 2})) - + //startSimulation() } def startSimulation(): Unit = { @@ -42,6 +42,7 @@ object Main { outputThread.start() simulator.start() outputThread.join() + sharedMemory.outputReset() } } diff --git a/src/main/scala/scim/components/Output.scala b/src/main/scala/scim/components/Output.scala index c2664dc..677e25d 100644 --- a/src/main/scala/scim/components/Output.scala +++ b/src/main/scala/scim/components/Output.scala @@ -1,15 +1,22 @@ package scim.components -import scim.datastruct.{Cell, Group, SensorResult, SharedMemory} +import scim.datastruct.{Cell, Group, SensorResult, SharedMemory, Time, Truth} class Output(sharedMemory: SharedMemory) extends Runnable { def run(): Unit = { - val output = sharedMemory.output - (0 until output.size, output).zipped.foreach((time, result) => outputData(time, result.watch())) + val outputBroadcast = sharedMemory.output + val duration = sharedMemory.config.duration + def outputHelper(time: Time): Unit = { + outputBroadcast(time.time).watch() + outputData(time, sharedMemory.getResult(time), sharedMemory.getTruth(time)) + } + + Vector.tabulate(sharedMemory.config.duration)(t => Time(t, duration)).foreach(outputHelper) } - def outputData(time: Int, output: Map[Cell, Map[Group, Vector[SensorResult]]]): Unit = { + def outputData(time: Time, sensors: Map[Cell, Map[Group, Vector[SensorResult]]], groundTruths: Map[Cell, Map[Group, Truth]]): Unit = { println("TICK: " + time) - println(output) + println(sensors) + println(groundTruths) } } diff --git a/src/main/scala/scim/components/Simulation.scala b/src/main/scala/scim/components/Simulation.scala index f36b290..4132d08 100644 --- a/src/main/scala/scim/components/Simulation.scala +++ b/src/main/scala/scim/components/Simulation.scala @@ -40,7 +40,7 @@ class Simulation(config: Configuration) { cells.foreach(simCell) } // broadcast the results - output(time.time).broadcast(sensorResults) + output(time.time).broadcast(true) } private def simGroups(time: Time, cell: Cell, groups: Map[Group, List[(Group, Sensor, Option[GroundTruth])]], prevTruths: Map[Group, Truth], resultTruths: Map[Group, Truth], resultSensors: Map[Group, Vector[SensorResult]]): Unit = { diff --git a/src/main/scala/scim/datastruct/Configuration.scala b/src/main/scala/scim/datastruct/Configuration.scala index e299adf..aec98fd 100644 --- a/src/main/scala/scim/datastruct/Configuration.scala +++ b/src/main/scala/scim/datastruct/Configuration.scala @@ -2,6 +2,7 @@ package scim.datastruct import scim.lib.ConcurrentBroadcast.BroadcastObject import scim.lib.simulation._ + import scala.collection.parallel.ForkJoinTaskSupport // configuration @@ -21,23 +22,30 @@ case class Time(time: Int, duration: Int){ case class SharedMemory(sensor: Map[Time, Map[Cell, Map[Group, Vector[SensorResult]]]], groundTruth: Map[Time, Map[Cell, Map[Group, Truth]]], config: SimulationConfig, - output: Vector[BroadcastObject[Map[Cell, Map[Group, Vector[SensorResult]]]]]) { + output: Vector[BroadcastObject[Boolean]]) { // This could be spatially optimized to have a function to invoke a new simulation tick - // a template of Map[SensorID, SensorResult] would have to be kept and deep copied when + // 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 - // through the configuration. it can however be deleted once it is no longer required, tho this seems - // to be rather unbeneficial, as the space was already preallocated. Sensors however could be replaced - // or deleted, depending if a buffer or list is used. - + // through the configuration throughout the entire simulation. it can however be deleted once it is no longer + // required, tho this seems to be rather unbeneficial, as the space was already preallocated. + // Sensors however could be replaced or deleted, depending if a buffer or list is used. in a producer/consumer manner def getTruth(time: Time, cell: Cell, group: Group): Truth = { groundTruth(time)(cell)(group) } + def getTruth(time: Time): Map[Cell, Map[Group, Truth]] = { + groundTruth(time) + } def getResult(time: Time, cell: Cell, group: Group): Vector[SensorResult] = { sensor(time)(cell)(group) } - def getAllResults(time: Time): Map[Cell, Map[Group, Vector[SensorResult]]] = { + def getResult(time: Time): Map[Cell, Map[Group, Vector[SensorResult]]] = { sensor(time) } + def outputReset(): Unit = { + sensor.foreach(kv => kv._2.foreach(kv2 => kv2._2.foreach(kv3 => kv3._2.foreach(res => res.reset())))) + groundTruth.foreach(kv => kv._2.foreach(kv2 => kv2._2.foreach(kv3 => kv3._2.reset()))) + output.foreach(e => e.broadcastReset()) + } } abstract class BroadcastHandler[A](broadcastObject: BroadcastObject[A]) { @@ -50,6 +58,9 @@ abstract class BroadcastHandler[A](broadcastObject: BroadcastObject[A]) { def exists: Boolean = { !broadcastObject.peak().isEmpty } + def reset(): Unit = { + broadcastObject.broadcastReset() + } } case class SimulationBehaviours(functions: Map[String, SimulationBehaviour]) { def get(name: String): Option[SimulationBehaviour] = { diff --git a/src/main/scala/scim/lib/Concurrency.scala b/src/main/scala/scim/lib/Concurrency.scala index da7bc13..75938fe 100644 --- a/src/main/scala/scim/lib/Concurrency.scala +++ b/src/main/scala/scim/lib/Concurrency.scala @@ -63,6 +63,8 @@ object ScalaLocks { object ConcurrentBroadcast { + // WARNING: Type A should be immutable and not hold any mutable data + // could add a clone/copy when retrieving for AnyRef types class BroadcastObject[A](default: Option[A] = None) { import ScalaLocks._