[add] added configuration mapping to parser

This commit is contained in:
2020-01-29 01:19:11 -06:00
parent 1277695610
commit a7817d04ec
3 changed files with 104 additions and 10 deletions

View File

@@ -1,9 +1,10 @@
package scim.components
import scim.datastruct.{Behaviour, BehaviourVector, Cell, Configuration, FunctionArgs, Group, SensorCount, SharedMemory, SimulationBehaviours, SimulationConfig, Time, Truth}
import scim.datastruct.{Behaviour, BehaviourVector, Cell, Configuration, FunctionArgs, GroundTruth, Group, Sensor, SensorCount, SharedMemory, SimulationBehaviours, SimulationConfig, Time, Truth}
import scim.lib.ConcurrentBroadcast.BroadcastObject
import scim.lib.debugUtil.{DebugType, debugf}
import scim.lib.mapUtil._
import scim.lib.parser._
import scim.lib.simulation.SimulationBehaviour
import scim.lib.yml
@@ -31,7 +32,7 @@ class Parser() {
class SimulationConfigParser(input: Map[String, Any], simulationBehaviours: SimulationBehaviours) {
private val config: SimulationConfig = parseSimulationConfig(input("simulation").asInstanceOf[Map[String, Any]])
private val groups = mutable.Map[String, Group]().empty
private val sensorList = mutable.Map[Group, Map[Cell, SensorCount]]().empty
private val sensorList = mutable.Map[Cell, mutable.Map[Group, SensorCount]]().empty
private val behaviourListSensor = mutable.Map[Group, Behaviour]().empty
private val behaviourListGroundTruth = mutable.Map[Group, Behaviour]().empty
private val groundTruthValues = mutable.Map[Time, mutable.Map[Group, Truth]]() // FIXME: are not parsed correctly
@@ -50,6 +51,16 @@ class SimulationConfigParser(input: Map[String, Any], simulationBehaviours: Simu
// TODO: when inserting time based values, only overwrite None, dont overwrite Some() with None!
// e.g. truth was declared at tick 9 with value 11, but later again with None at tick 9, DONT OVERWRITE
// e.g. truth was declared at tick 9 with value none, but later again with value 9, OVERWRITE
//populate configuration
val configurationMapping = sensorList.map(cell => cell._1 -> cellMapper(cell._1, cell._2.toMap)).toMap
//TODO: initialize shared memory
//TODO: add ground truth preconfigured to shared memory
Unit
}
@@ -74,7 +85,20 @@ class SimulationConfigParser(input: Map[String, Any], simulationBehaviours: Simu
val group = Group(groupString, parentString)
if(!groups.contains(groupString)) {
groups(groupString) = group
sensorList(group) = cells
cells.foreach(kv => {
val cell = kv._1
val count = kv._2
if(sensorList.contains(cell)) {
if(sensorList(cell).contains(group)) {
// just add sensor count if one was already defined
sensorList(cell)(group) = sensorList(cell)(group).add(count)
} else {
sensorList(cell)(group) = count
}
} else {
sensorList(cell) = mutable.Map(group -> count)
}
})
} else {
debugf(DebugType.WARNING, "Duplicate Sensors in Group [%s]. Ignoring Sensor: %s", groupString, sensor.toString())
}
@@ -113,7 +137,7 @@ class SimulationConfigParser(input: Map[String, Any], simulationBehaviours: Simu
val name: String = function(1).asInstanceOf[String]
val args: Option[FunctionArgs] = if (function.size > 2) Some(FunctionArgs(function(2).asInstanceOf[Map[String, Any]])) else None
if (!simulationBehaviours.get(name).isEmpty) funcPointer = Some((simulationBehaviours.get(name).get, args))
Map[Int, Option[(SimulationBehaviour, Option[FunctionArgs])]](start -> funcPointer)
Map[Int, Option[(SimulationBehaviour, Option[FunctionArgs])]](start -> funcPointer) // using a map here since the second case can produces multiple keys
}
case function: Map[_, _] => {
val functionMap = function.asInstanceOf[Map[String, Any]]
@@ -125,7 +149,7 @@ class SimulationConfigParser(input: Map[String, Any], simulationBehaviours: Simu
val output: mutable.Map[Int, Option[(SimulationBehaviour, Option[FunctionArgs])]] = mutable.Map()
timeLineVector.map(tuple => {
output(tuple._1) = funcPointer
if (!tuple._2.isEmpty) output(tuple._2.get) = None
if (!tuple._2.isEmpty && !output.contains(tuple._2.get)) output(tuple._2.get) = None // only set None when it doesnt exist yet
})
output.toMap
}
@@ -134,7 +158,11 @@ class SimulationConfigParser(input: Map[String, Any], simulationBehaviours: Simu
}
val parsedFunction: mutable.Map[Int, Option[(SimulationBehaviour, Option[FunctionArgs])]] = mutable.Map().empty
// TODO: This will currently overwrite already assigned values; output warning
functions.map(function => parseFunctionHelper(function)).foreach(e => e.foreach(kv => parsedFunction(kv._1) = kv._2))
val a = functions.map(function => parseFunctionHelper(function))
a.foreach(e => e.foreach(kv => {
if(!kv._2.isEmpty || !parsedFunction.contains(kv._1)) // only set None when it doesnt exist yet
parsedFunction(kv._1) = kv._2
} ))
val timeVector: mutable.ArraySeq[Option[(SimulationBehaviour, Option[FunctionArgs])]] = new mutable.ArraySeq[Option[(SimulationBehaviour, Option[FunctionArgs])]](config.duration).map(_ => None)
val it = parsedFunction.toList.sortBy(_._1).iterator
println(parsedFunction.toList.sortBy(_._1))
@@ -191,6 +219,18 @@ class SimulationConfigParser(input: Map[String, Any], simulationBehaviours: Simu
}
}
private def getParentRoot(group: Group, groups: Map[String, Group], seen: Vector[String] = Vector()): Option[Group] = {
if(seen.contains(group.name)) {
debugf(DebugType.WARNING, "Circular dependency of groups: [%s]", seen.toString())
None
} else if(!groups.contains(group.name)) { // this should not happen and be caught earlier
debugf(DebugType.WARNING, "Group [%s] ignored, it is not part of the sensor groups [%s]", group.toString, groups.toString())
None
} else {
if(group.parent.isEmpty) Some(group) else getParentRoot(groups(group.parent.get), groups, seen ++ Vector(group.name))
}
}
private def parseTruth(truthElements: Vector[Any]): Map[Time, Truth] = {
val parseTruthHelper = (truthElement: Any) => {
truthElement match {
@@ -199,7 +239,7 @@ class SimulationConfigParser(input: Map[String, Any], simulationBehaviours: Simu
println(truthElement)
val start: Int = truthObject(0).asInstanceOf[Int]
// val end: Option[Int] = None // Not used
truth.set(Some(truthObject(1).asInstanceOf[Double]))
truth.set(parseDouble(truthObject(1)))
Map[Time, Truth](Time(start, config.duration) -> truth)
}
case truthObject: Map[_, _] => {
@@ -208,7 +248,7 @@ class SimulationConfigParser(input: Map[String, Any], simulationBehaviours: Simu
val truthObjectMap = truthObject.asInstanceOf[Map[String, Any]]
val timeline: Vector[Any] = truthObjectMap("timeline").asInstanceOf[Vector[Any]]
val timeLineVector: Vector[(Int, Option[Int])] = timeline.map(e => parseTimeLineElement(e))
truth.set(Some(truthObjectMap("value").asInstanceOf[Double]))
truth.set(parseDouble(truthObjectMap("value")))
val output: mutable.Map[Time, Truth] = mutable.Map()
timeLineVector.map(tuple => {
@@ -229,4 +269,42 @@ class SimulationConfigParser(input: Map[String, Any], simulationBehaviours: Simu
parsedTruth.toMap
}
def cellMapper(cell: Cell, groups: Map[Group, SensorCount]): Map[Group, List[(Group, Sensor, Option[GroundTruth])]] = {
val groupMap: mutable.Map[Group, List[(Group, Sensor, Option[GroundTruth])]] = mutable.Map()
val groupDone: mutable.HashSet[Group] = mutable.HashSet()
def groupMapper(group: Group, count: SensorCount): List[(Group, Sensor, Option[GroundTruth])] = {
if(!behaviourListSensor.contains(group)) {
debugf(DebugType.WARNING, "Group [%s] does not have a behaviour, using default", group.toString())
behaviourListSensor(group) = Behaviour(BehaviourVector(Vector.tabulate(config.duration)(_ => None)))
}
if(group.parent.isEmpty) {
groupDone.add(group)
List((group, Sensor(group, cell, count, behaviourListSensor(group), config.parSensor, config.sensorThreadPool),
if(behaviourListGroundTruth.contains(group)) Some(GroundTruth(group, Some(behaviourListGroundTruth(group)))) else None))
} else {
if(groupDone.contains(group)) {
debugf(DebugType.WARNING, "Circular dependency of groups: [%s]", groupDone.toString())
List()
} else {
groupDone.add(group)
val parentGroup = this.groups(group.parent.get) // this should really exist at this point
val parentCount = if(groups.contains(parentGroup)) groups(parentGroup) else SensorCount(0) // insert dummy parent group if not in cell
groupMapper(parentGroup, parentCount) ++ List((group, Sensor(group, cell, count, behaviourListSensor(group), config.parSensor, config.sensorThreadPool),
if(behaviourListGroundTruth.contains(group)) Some(GroundTruth(group, Some(behaviourListGroundTruth(group)))) else None))
}
}
}
groups.foreach(kv => {
val group = kv._1
val count = kv._2
val root = getParentRoot(group, this.groups.toMap)
if(!groupDone.contains(group) && !root.isEmpty) {
groupMap(root.get) = groupMapper(group, count)
}
})
groupMap.toMap
}
}

View File

@@ -290,7 +290,8 @@ package object mapUtil {
val currentKey = currentKV.get._1
if(ordering.compare(key, currentKey) >= 0) {
// TODO: find out if scala actually does not check the second condition if first one fails and always in that order
// find out if scala actually does not check the second condition if first one fails and always in that order
// Scala does Short-circuit evaluation (like java) [Programming in Scala: Updated for Scala 2.12] page 126
while(!nextKV.isEmpty && ordering.compare(key, nextKV.get._1) >= 0) {
// when trying to do this with recursion (shift than call this function again) resulted in a non reproducible stack overflow
shift()
@@ -325,4 +326,19 @@ package object simulation {
import scim.datastruct._
// maybe change to by-name parameters? have to check performance gain
type SimulationBehaviour = (Cell, Time, Option[Double], Option[FunctionArgs]) => Option[Double]
}
package object parser {
def parseDouble(number: Any): Option[Double] = {
number match {
case t: java.lang.Number => Some(t.doubleValue())
case _ => None
}
}
def parseInt(number: Any): Option[Int] = {
number match {
case t: java.lang.Number => Some(t.intValue())
case _ => None
}
}
}