introduce ResultStore to keep track of game sessions
parent
c25deecf0b
commit
70f72e6162
|
|
@ -1,15 +1,17 @@
|
|||
from typing import List
|
||||
|
||||
from .analyzer import Analyzer, Result
|
||||
from .analyzer.biogames import BoardDurationAnalyzer, SimulationRoundsAnalyzer, ActivationSequenceAnalyzer
|
||||
from .analyzer.default import LogEntryCountAnalyzer, LocationAnalyzer, LogEntrySequenceAnalyzer, ActionSequenceAnalyzer
|
||||
from .analyzer.biogames import BoardDurationAnalyzer, SimulationRoundsAnalyzer, ActivationSequenceAnalyzer, \
|
||||
BiogamesCategorizer
|
||||
from .analyzer.default import LogEntryCountAnalyzer, LocationAnalyzer, LogEntrySequenceAnalyzer, ActionSequenceAnalyzer, \
|
||||
CategorizerStub
|
||||
from .analyzer.locomotion import LocomotionActionAnalyzer, CacheSequenceAnalyzer
|
||||
from .analyzer.mask import MaskSpatials
|
||||
from .render import Render
|
||||
from .render.biogames import SimulationRoundsRender, BoardDurationHistRender, BoardDurationBoxRender
|
||||
from .render.default import PrintRender, JSONRender, TrackRender, HeatMapRender
|
||||
from .render.locomotion import LocomotionActionRelativeRender, LocomotionActionAbsoluteRender, \
|
||||
LocomotionActionRatioRender
|
||||
from .render.biogames import SimulationRoundsRender, BoardDurationHistRender, BoardDurationBoxRender
|
||||
|
||||
__FALLBACK__ = PrintRender
|
||||
__MAPPING__ = {
|
||||
|
|
|
|||
|
|
@ -1,11 +1,14 @@
|
|||
from analyzers.settings import LogSettings
|
||||
import logging
|
||||
from collections import KeysView
|
||||
from typing import Type, Sized, Collection
|
||||
|
||||
log = logging.getLogger(__name__)
|
||||
from analyzers.settings import LogSettings
|
||||
|
||||
log: logging.Logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class Result:
|
||||
def __init__(self, analysis, result):
|
||||
def __init__(self, analysis: Type, result: Sized):
|
||||
self.result = result
|
||||
self.__analysis__ = analysis
|
||||
log.debug("set" + str(len(self.result)))
|
||||
|
|
@ -18,18 +21,70 @@ class Result:
|
|||
return self.result
|
||||
|
||||
def __repr__(self):
|
||||
return "<Result " + str(self.__analysis__) + ": " + str(type(self.result)) + " "+str(len(self.result))+">"
|
||||
return "<Result " + str(self.__analysis__) + ": " + str(type(self.result)) + " " + str(len(self.result)) + ">"
|
||||
|
||||
|
||||
class ResultStore:
|
||||
"""Store Results"""
|
||||
|
||||
def __init__(self, store_entry: Type[Collection] = list, store_action: callable = list.append) -> None:
|
||||
self.store = {}
|
||||
self.category = None
|
||||
self.entry: Type[Collection] = store_entry
|
||||
self.action: callable = store_action
|
||||
|
||||
def new_category(self, key) -> None:
|
||||
self.category = key
|
||||
if not key in self.store:
|
||||
self.store[key] = self.entry()
|
||||
|
||||
def add(self, entry: Result) -> None:
|
||||
self.action(self.store[self.category], entry)
|
||||
|
||||
def get_store(self) -> dict:
|
||||
return dict(self.store)
|
||||
|
||||
def get_all(self) -> list:
|
||||
"""
|
||||
Throw all categories together
|
||||
:return:
|
||||
"""
|
||||
result = []
|
||||
for key in self.store:
|
||||
result += self.store[key]
|
||||
return result
|
||||
|
||||
def get_categories(self) -> KeysView:
|
||||
return self.store.keys()
|
||||
|
||||
def get_category(self, key):
|
||||
if key not in self.store:
|
||||
return self.entry
|
||||
return self.store[key]
|
||||
|
||||
def serializable(self):
|
||||
values = {}
|
||||
for key in self.store:
|
||||
values[key] = [{"analysis": str(result.analysis()), "result": result.get()} for result in self.store[key]]
|
||||
return values
|
||||
|
||||
|
||||
class Analyzer:
|
||||
def __init__(self, settings: LogSettings):
|
||||
self.settings = settings
|
||||
"""Operate on log entries, one at a time"""
|
||||
|
||||
def __init__(self, settings: LogSettings) -> None:
|
||||
self.settings: LogSettings = settings
|
||||
|
||||
def process(self, entry: dict) -> bool:
|
||||
"""
|
||||
Process an entry
|
||||
:param entry: Entry to process
|
||||
:return: True if consumed, False for further analysis
|
||||
"""
|
||||
raise NotImplementedError()
|
||||
|
||||
def result(self) -> Result:
|
||||
def result(self, store: ResultStore) -> None:
|
||||
raise NotImplementedError()
|
||||
|
||||
def name(self):
|
||||
def name(self) -> str:
|
||||
return self.__name__
|
||||
|
|
|
|||
|
|
@ -1,7 +1,8 @@
|
|||
import logging
|
||||
from collections import defaultdict
|
||||
|
||||
from . import Result, LogSettings, Analyzer
|
||||
from . import Result, LogSettings, Analyzer, ResultStore
|
||||
from .default import CategorizerStub
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
|
@ -15,7 +16,7 @@ class BoardDurationAnalyzer(Analyzer):
|
|||
def render(self) -> str:
|
||||
return "\n".join(["{}\t{}".format(entry["active"], entry["id"]) for entry in self.result().get()])
|
||||
|
||||
def result(self) -> Result:
|
||||
def result(self, store: ResultStore) -> None:
|
||||
result = []
|
||||
last_timestamp = None
|
||||
last_board = None
|
||||
|
|
@ -27,7 +28,7 @@ class BoardDurationAnalyzer(Analyzer):
|
|||
last_timestamp = timestamp
|
||||
last_board = board_id
|
||||
# TODO: last board?
|
||||
return Result(type(self), result)
|
||||
store.add(Result(type(self), result))
|
||||
|
||||
def process(self, entry: dict) -> bool:
|
||||
entry_type = entry[self.settings.type_field]
|
||||
|
|
@ -54,8 +55,8 @@ class SimulationRoundsAnalyzer(Analyzer):
|
|||
super().__init__(settings)
|
||||
self.store = defaultdict(lambda: -1) # TODO verify
|
||||
|
||||
def result(self) -> Result:
|
||||
return Result(type(self), dict(self.store))
|
||||
def result(self, store: ResultStore) -> None:
|
||||
store.add(Result(type(self), dict(self.store)))
|
||||
|
||||
def process(self, entry: dict) -> bool:
|
||||
entry_type = entry[self.settings.type_field]
|
||||
|
|
@ -73,8 +74,8 @@ class ActivationSequenceAnalyzer(Analyzer):
|
|||
super().__init__(settings)
|
||||
self.store = []
|
||||
|
||||
def result(self) -> Result:
|
||||
return Result(type(self), self.store)
|
||||
def result(self, store: ResultStore) -> None:
|
||||
store.add(Result(type(self), self.store))
|
||||
|
||||
def process(self, entry: dict) -> bool:
|
||||
if entry[self.settings.type_field] in self.settings.sequences['start']:
|
||||
|
|
@ -82,3 +83,15 @@ class ActivationSequenceAnalyzer(Analyzer):
|
|||
self.store.append(entry['cache']['@id'])
|
||||
else:
|
||||
logger.error("null cache")
|
||||
return False
|
||||
|
||||
|
||||
class BiogamesCategorizer(CategorizerStub):
|
||||
def __init__(self, settings: LogSettings):
|
||||
super().__init__(settings)
|
||||
|
||||
def process(self, entry: dict) -> bool:
|
||||
if self.key is "default":
|
||||
if entry[self.settings.type_field] in self.settings.custom['instance_start']:
|
||||
self.key = entry[self.settings.custom['instance_id']]
|
||||
return False
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
import logging
|
||||
from collections import defaultdict
|
||||
|
||||
from . import Result, LogSettings, Analyzer
|
||||
from . import Result, LogSettings, Analyzer, ResultStore
|
||||
|
||||
|
||||
class LocationAnalyzer(Analyzer):
|
||||
|
|
@ -15,14 +15,14 @@ class LocationAnalyzer(Analyzer):
|
|||
super().__init__(settings)
|
||||
self.entries = []
|
||||
|
||||
def result(self) -> Result:
|
||||
def result(self, store: ResultStore) -> None:
|
||||
self.log.debug(len(self.entries))
|
||||
return Result(type(self), list(self.entries))
|
||||
store.add(Result(type(self), list(self.entries)))
|
||||
|
||||
def process(self, entry: dict) -> bool:
|
||||
if entry[self.settings.type_field] in self.settings.spatials:
|
||||
self.entries.append(entry)
|
||||
#self.log.debug(len(self.entries))
|
||||
# self.log.debug(len(self.entries))
|
||||
return False
|
||||
|
||||
|
||||
|
|
@ -32,8 +32,8 @@ class LogEntryCountAnalyzer(Analyzer):
|
|||
"""
|
||||
__name__ = "LogEntryCount"
|
||||
|
||||
def result(self) -> Result:
|
||||
return Result(type(self), dict(self.store))
|
||||
def result(self, store: ResultStore) -> None:
|
||||
store.add(Result(type(self), dict(self.store)))
|
||||
|
||||
def process(self, entry: dict) -> bool:
|
||||
self.store[entry[self.settings.type_field]] += 1
|
||||
|
|
@ -50,8 +50,8 @@ class LogEntrySequenceAnalyzer(Analyzer):
|
|||
"""
|
||||
__name__ = "LogEntrySequence"
|
||||
|
||||
def result(self) -> Result:
|
||||
return Result(type(self), list(self.store))
|
||||
def result(self, store: ResultStore) -> None:
|
||||
store.add(Result(type(self), list(self.store)))
|
||||
|
||||
def process(self, entry: dict) -> bool:
|
||||
entry_type = entry[self.settings.type_field]
|
||||
|
|
@ -75,3 +75,21 @@ class ActionSequenceAnalyzer(LogEntrySequenceAnalyzer):
|
|||
return False
|
||||
self.store.append(entry_type)
|
||||
return False
|
||||
|
||||
|
||||
class CategorizerStub(Analyzer):
|
||||
"""
|
||||
generate a new Category in a ResultStore
|
||||
"""
|
||||
|
||||
def process(self, entry: dict) -> bool:
|
||||
raise NotImplementedError()
|
||||
|
||||
__name__ = "Categorizer"
|
||||
|
||||
def result(self, store: ResultStore) -> None:
|
||||
store.new_category(self.key)
|
||||
|
||||
def __init__(self, settings: LogSettings):
|
||||
super().__init__(settings)
|
||||
self.key = "default"
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
import util
|
||||
from . import Analyzer, LogSettings, Result
|
||||
from . import Analyzer, LogSettings, Result, ResultStore
|
||||
|
||||
|
||||
def init_filter(settings: LogSettings, state: str) -> callable:
|
||||
|
|
@ -41,7 +41,7 @@ class LocomotionActionAnalyzer(Analyzer):
|
|||
self.current_cache = None
|
||||
self.last = None
|
||||
|
||||
def result(self) -> Result:
|
||||
def result(self, store: ResultStore) -> None:
|
||||
if self.last is not None:
|
||||
if self.current_cache is None:
|
||||
self.locomotion.append(self.last - self.cache_time)
|
||||
|
|
@ -51,7 +51,7 @@ class LocomotionActionAnalyzer(Analyzer):
|
|||
locomotion = sum(self.locomotion)
|
||||
action = sum(self.actions)
|
||||
total = locomotion + action
|
||||
return Result(type(self), {
|
||||
store.add(Result(type(self), {
|
||||
'locomotion_sum': locomotion,
|
||||
'action_sum': action,
|
||||
'locomotion': self.locomotion,
|
||||
|
|
@ -60,7 +60,7 @@ class LocomotionActionAnalyzer(Analyzer):
|
|||
'locomotion_relative': locomotion / total,
|
||||
'action_relative': action / total,
|
||||
'locomotion_action_ratio': locomotion / action,
|
||||
})
|
||||
}))
|
||||
|
||||
def __init__(self, settings: LogSettings):
|
||||
super().__init__(settings)
|
||||
|
|
@ -86,8 +86,8 @@ class CacheSequenceAnalyzer(Analyzer):
|
|||
self.store.append((entry['timestamp'], entry['cache']))
|
||||
return False
|
||||
|
||||
def result(self) -> Result:
|
||||
return Result(type(self), list(self.store))
|
||||
def result(self, store: ResultStore) -> None:
|
||||
store.add(Result(type(self), list(self.store)))
|
||||
|
||||
def __init__(self, settings: LogSettings):
|
||||
super().__init__(settings)
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
from . import Analyzer
|
||||
from . import Analyzer, Result, ResultStore
|
||||
|
||||
|
||||
class MaskSpatials(Analyzer):
|
||||
|
|
@ -11,5 +11,5 @@ class MaskSpatials(Analyzer):
|
|||
return True
|
||||
return False
|
||||
|
||||
def result(self) -> int:
|
||||
return self.masked
|
||||
def result(self, store: ResultStore) -> None:
|
||||
store.add(Result(type(self), {"masked": self.masked}))
|
||||
|
|
|
|||
|
|
@ -13,18 +13,22 @@
|
|||
],
|
||||
"analyzers": {
|
||||
"analyzers": [
|
||||
"LocationAnalyzer"
|
||||
"BiogamesCategorizer",
|
||||
"LocomotionActionAnalyzer",
|
||||
"LogEntryCountAnalyzer"
|
||||
]
|
||||
},
|
||||
"disabled_analyzers":[
|
||||
"LogEntryCountAnalyzer",
|
||||
"LogEntrySequenceAnalyzer",
|
||||
"ActionSequenceAnalyzer",
|
||||
"BoardDurationAnalyzer",
|
||||
"LocomotionActionAnalyzer",
|
||||
"CacheSequenceAnalyzer",
|
||||
"SimulationRoundsAnalyzer",
|
||||
"ActivationSequenceAnalyzer"],
|
||||
"disabled_analyzers": [
|
||||
"LocationAnalyzer",
|
||||
"LogEntryCountAnalyzer",
|
||||
"LogEntrySequenceAnalyzer",
|
||||
"ActionSequenceAnalyzer",
|
||||
"BoardDurationAnalyzer",
|
||||
"LocomotionActionAnalyzer",
|
||||
"CacheSequenceAnalyzer",
|
||||
"SimulationRoundsAnalyzer",
|
||||
"ActivationSequenceAnalyzer"
|
||||
],
|
||||
"sequences": {
|
||||
"start": "de.findevielfalt.games.game2.instance.log.entry.LogEntryCache",
|
||||
"end": {
|
||||
|
|
@ -32,8 +36,14 @@
|
|||
"action.@class": "de.findevielfalt.games.game2.instance.action.CacheEnableAction"
|
||||
}
|
||||
},
|
||||
"custom":{
|
||||
"simulation_rounds": ["de.findevielfalt.games.game2.instance.log.entry.LogEntryQuestion"],
|
||||
"simu_data": ["de.findevielfalt.games.game2.instance.data.sequence.simulation.SimulationBoardData"]
|
||||
"custom": {
|
||||
"simulation_rounds": [
|
||||
"de.findevielfalt.games.game2.instance.log.entry.LogEntryQuestion"
|
||||
],
|
||||
"simu_data": [
|
||||
"de.findevielfalt.games.game2.instance.data.sequence.simulation.SimulationBoardData"
|
||||
],
|
||||
"instance_start": "de.findevielfalt.games.game2.instance.log.entry.LogEntryStartInstance",
|
||||
"instance_id": "instance_id"
|
||||
}
|
||||
}
|
||||
|
|
@ -1,23 +1,25 @@
|
|||
import json
|
||||
import logging
|
||||
from load import LOADERS
|
||||
from typing import List
|
||||
from analyzers import get_renderer, Analyzer, render
|
||||
from analyzers.settings import LogSettings, load_settings
|
||||
import analyzers
|
||||
|
||||
import analyzers
|
||||
from analyzers import get_renderer, Analyzer, render
|
||||
from analyzers.analyzer import ResultStore
|
||||
from analyzers.settings import LogSettings, load_settings
|
||||
from load import LOADERS
|
||||
|
||||
logging.basicConfig(format='%(levelname)s %(name)s:%(message)s', level=logging.DEBUG)
|
||||
log = logging.getLogger(__name__)
|
||||
log: logging.Logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
def process_log(log_id: str, settings: LogSettings) -> List[Analyzer]:
|
||||
logfile = "data/inst_{id}.{format}".format(id=log_id, format=settings.log_format)
|
||||
logfile: str = "data/inst_{id}.{format}".format(id=log_id, format=settings.log_format)
|
||||
loader = LOADERS[settings.log_format]()
|
||||
try:
|
||||
loader.load(logfile)
|
||||
except BaseException as e:
|
||||
raise RuntimeError(e)
|
||||
analyzers = []
|
||||
analyzers: List[Analyzer] = []
|
||||
log.debug("build analyzers")
|
||||
for analyzer in settings.analyzers:
|
||||
analyzers.append(analyzer(settings))
|
||||
|
|
@ -30,36 +32,37 @@ def process_log(log_id: str, settings: LogSettings) -> List[Analyzer]:
|
|||
|
||||
|
||||
if __name__ == '__main__':
|
||||
settings = load_settings("biogames2.json")
|
||||
log_ids = [
|
||||
settings: LogSettings = load_settings("biogames2.json")
|
||||
log_ids: List[str] = [
|
||||
"20d4244719404ffab0ca386c76e4b112",
|
||||
"56d9b64144ab44e7b90bf766f3be32e3",
|
||||
"dc2cdc28ca074715b905e4aa5badff10",
|
||||
"e32b16998440475b994ab46d481d3e0c",
|
||||
]
|
||||
log_ids = [
|
||||
log_ids: List[str] = [
|
||||
"34fecf49dbaca3401d745fb467",
|
||||
"44ea194de594cd8d63ac0314be",
|
||||
"57c444470dbf88605433ca935c",
|
||||
"78e0c545b594e82edfad55bd7f",
|
||||
"91abfd4b31a5562b1c66be37d9",
|
||||
"597b704fe9ace475316c345903",
|
||||
"e01a684aa29dff9ddd9705edf8",
|
||||
"fbf9d64ae0bdad0de7efa3eec6",
|
||||
"fe1331481f85560681f86827ec",
|
||||
# "44ea194de594cd8d63ac0314be",
|
||||
# "57c444470dbf88605433ca935c",
|
||||
# "78e0c545b594e82edfad55bd7f",
|
||||
# "91abfd4b31a5562b1c66be37d9",
|
||||
# "597b704fe9ace475316c345903",
|
||||
# "e01a684aa29dff9ddd9705edf8",
|
||||
# "fbf9d64ae0bdad0de7efa3eec6",
|
||||
# "fe1331481f85560681f86827ec",
|
||||
"fec57041458e6cef98652df625", ]
|
||||
results = []
|
||||
#TODO: capture session ID, dict
|
||||
store: ResultStore = ResultStore()
|
||||
for log_id in log_ids:
|
||||
for analysis in process_log(log_id, settings):
|
||||
log.info("* Result for " + analysis.name())
|
||||
# print(analysis.result())
|
||||
# print(analysis.render())
|
||||
results.append(analysis.result())
|
||||
analysis.result(store)
|
||||
if False:
|
||||
for r in get_renderer(analyzers.LocomotionActionAnalyzer):
|
||||
r().render(results)
|
||||
render(analyzers.LocationAnalyzer, results)
|
||||
r().render(store.get_all())
|
||||
if False:
|
||||
render(analyzers.LocationAnalyzer, store.get_all())
|
||||
print(json.dumps(store.serializable(), indent=1))
|
||||
|
||||
# for analyzers in analyzers:
|
||||
# if analyzers.name() in ["LogEntryCount", "ActionSequenceAnalyzer"]:
|
||||
|
|
|
|||
Loading…
Reference in New Issue