[add] added configuration mapping to parser
This commit is contained in:
@@ -65,4 +65,4 @@ behaviours:
|
|||||||
end: 166
|
end: 166
|
||||||
- [100, normalValue, {v: 2}]
|
- [100, normalValue, {v: 2}]
|
||||||
- [120, addValuePercent, {}]
|
- [120, addValuePercent, {}]
|
||||||
- [180, locationDefect, {x: 0, y: 2}]
|
- [180, normalValue, {x: 0, y: 2}]
|
||||||
@@ -1,9 +1,10 @@
|
|||||||
package scim.components
|
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.ConcurrentBroadcast.BroadcastObject
|
||||||
import scim.lib.debugUtil.{DebugType, debugf}
|
import scim.lib.debugUtil.{DebugType, debugf}
|
||||||
import scim.lib.mapUtil._
|
import scim.lib.mapUtil._
|
||||||
|
import scim.lib.parser._
|
||||||
import scim.lib.simulation.SimulationBehaviour
|
import scim.lib.simulation.SimulationBehaviour
|
||||||
import scim.lib.yml
|
import scim.lib.yml
|
||||||
|
|
||||||
@@ -31,7 +32,7 @@ class Parser() {
|
|||||||
class SimulationConfigParser(input: Map[String, Any], simulationBehaviours: SimulationBehaviours) {
|
class SimulationConfigParser(input: Map[String, Any], simulationBehaviours: SimulationBehaviours) {
|
||||||
private val config: SimulationConfig = parseSimulationConfig(input("simulation").asInstanceOf[Map[String, Any]])
|
private val config: SimulationConfig = parseSimulationConfig(input("simulation").asInstanceOf[Map[String, Any]])
|
||||||
private val groups = mutable.Map[String, Group]().empty
|
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 behaviourListSensor = mutable.Map[Group, Behaviour]().empty
|
||||||
private val behaviourListGroundTruth = 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
|
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!
|
// 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 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
|
// 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
|
Unit
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -74,7 +85,20 @@ class SimulationConfigParser(input: Map[String, Any], simulationBehaviours: Simu
|
|||||||
val group = Group(groupString, parentString)
|
val group = Group(groupString, parentString)
|
||||||
if(!groups.contains(groupString)) {
|
if(!groups.contains(groupString)) {
|
||||||
groups(groupString) = group
|
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 {
|
} else {
|
||||||
debugf(DebugType.WARNING, "Duplicate Sensors in Group [%s]. Ignoring Sensor: %s", groupString, sensor.toString())
|
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 name: String = function(1).asInstanceOf[String]
|
||||||
val args: Option[FunctionArgs] = if (function.size > 2) Some(FunctionArgs(function(2).asInstanceOf[Map[String, Any]])) else None
|
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))
|
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[_, _] => {
|
case function: Map[_, _] => {
|
||||||
val functionMap = function.asInstanceOf[Map[String, Any]]
|
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()
|
val output: mutable.Map[Int, Option[(SimulationBehaviour, Option[FunctionArgs])]] = mutable.Map()
|
||||||
timeLineVector.map(tuple => {
|
timeLineVector.map(tuple => {
|
||||||
output(tuple._1) = funcPointer
|
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
|
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
|
val parsedFunction: mutable.Map[Int, Option[(SimulationBehaviour, Option[FunctionArgs])]] = mutable.Map().empty
|
||||||
// TODO: This will currently overwrite already assigned values; output warning
|
// 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 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
|
val it = parsedFunction.toList.sortBy(_._1).iterator
|
||||||
println(parsedFunction.toList.sortBy(_._1))
|
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] = {
|
private def parseTruth(truthElements: Vector[Any]): Map[Time, Truth] = {
|
||||||
val parseTruthHelper = (truthElement: Any) => {
|
val parseTruthHelper = (truthElement: Any) => {
|
||||||
truthElement match {
|
truthElement match {
|
||||||
@@ -199,7 +239,7 @@ class SimulationConfigParser(input: Map[String, Any], simulationBehaviours: Simu
|
|||||||
println(truthElement)
|
println(truthElement)
|
||||||
val start: Int = truthObject(0).asInstanceOf[Int]
|
val start: Int = truthObject(0).asInstanceOf[Int]
|
||||||
// val end: Option[Int] = None // Not used
|
// 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)
|
Map[Time, Truth](Time(start, config.duration) -> truth)
|
||||||
}
|
}
|
||||||
case truthObject: Map[_, _] => {
|
case truthObject: Map[_, _] => {
|
||||||
@@ -208,7 +248,7 @@ class SimulationConfigParser(input: Map[String, Any], simulationBehaviours: Simu
|
|||||||
val truthObjectMap = truthObject.asInstanceOf[Map[String, Any]]
|
val truthObjectMap = truthObject.asInstanceOf[Map[String, Any]]
|
||||||
val timeline: Vector[Any] = truthObjectMap("timeline").asInstanceOf[Vector[Any]]
|
val timeline: Vector[Any] = truthObjectMap("timeline").asInstanceOf[Vector[Any]]
|
||||||
val timeLineVector: Vector[(Int, Option[Int])] = timeline.map(e => parseTimeLineElement(e))
|
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()
|
val output: mutable.Map[Time, Truth] = mutable.Map()
|
||||||
timeLineVector.map(tuple => {
|
timeLineVector.map(tuple => {
|
||||||
@@ -229,4 +269,42 @@ class SimulationConfigParser(input: Map[String, Any], simulationBehaviours: Simu
|
|||||||
parsedTruth.toMap
|
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
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -290,7 +290,8 @@ package object mapUtil {
|
|||||||
|
|
||||||
val currentKey = currentKV.get._1
|
val currentKey = currentKV.get._1
|
||||||
if(ordering.compare(key, currentKey) >= 0) {
|
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) {
|
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
|
// when trying to do this with recursion (shift than call this function again) resulted in a non reproducible stack overflow
|
||||||
shift()
|
shift()
|
||||||
@@ -325,4 +326,19 @@ package object simulation {
|
|||||||
import scim.datastruct._
|
import scim.datastruct._
|
||||||
// maybe change to by-name parameters? have to check performance gain
|
// maybe change to by-name parameters? have to check performance gain
|
||||||
type SimulationBehaviour = (Cell, Time, Option[Double], Option[FunctionArgs]) => Option[Double]
|
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
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
Reference in New Issue
Block a user