2""" @brief Gets data from various modules
and stores them
for display
and statistics.
4 - Generic_Observer --> interface between simulation
and window system
5 - Experiment_Observer --> idem + headers to store curves
7 - Storage --> stores vectors
8 - Examiner --> different Storages, one per slot
9 - Meta_Examiner --> stores similar Examiners
with sames slots + statistics
11 - Observer --> Meta_Examiner + Experiment_Observer
12 - EvolifeObserver --> specific observer (knows about genomes, phenomes, ...)
16#============================================================================#
17# EVOLIFE http://evolife.telecom-paris.fr Jean-Louis Dessalles
32import sys, os, os.path
34if __name__ ==
'__main__': sys.path.append(
'../..')
37from time
import strftime
43 """ Legend of a curve (color, text)
44 for Experiment_Observer
46 def __init__(self, Name='Curve', Color='red', Legend=''):
53 """ Legend of a curves
54 for Experiment_Observer
57 """ merely calls reset
62 """ Defines Curves and their current Values
63 Stores curves' designation and legend
71 def append(self, Name='Curve', Color='red', Legend=''):
72 """ Creates a new (local) curve and stores it
74 if Color
not in self.
Colors:
75 if not Legend: Legend = Name
81 else:
error(
'Observer',
'Two curves with same colour: "%s" already in %s' % (Color, self.
Colors))
84 """ returns the color of a curve
86 return self.
Curves[Name].Color
88 def Value(self, Name, Value=None):
89 """ sets or returns a curve's current value
103 """ returns curves' designations
108 """ iterates through curves
110 return iter(self.
Curves.keys())
115 """ Returns current curves' values (at time x)
117 Point = lambda v: v
if isinstance(v, tuple)
else (x, v)
123 """ Kind of matrix. Stores raw data, typically vectors of integers
126 def __init__(self, Name):
133 """ initializes the 'storage', 'average' and 'best' lists
143 """ marks the storage as 'open'
146 error(
'Observer: ',self.
Name+
': opened twice')
151 """ stores a vecor in the storage
154 error(
'Observer: ',self.
Name+
': not open')
158 error(
'Observer: ', self.
Name +
': Inconsistent item length')
160 except (AttributeError, TypeError):
169 """ sets the storage as 'closed'
171 if not self.
open:
error(
'Observer: ', self.
Name+
': closing while not open')
174 error(
'Observer: ', self.
Name+
': Inconsistent lengths')
179 """ returns a tuple of all the vectors in the storage
181 return tuple([tuple(T)
for T
in self.
storage])
186 '.\tBest:\t' +
' -- '.join([
"%.2f" % x
for x
in self.
best]) + \
188 '.\tAvg:\t' +
' -- '.join([
"%.2f" % x
for x
in self.
average])
191 """ Storage + basic statistics
194 """ computes best and average
197 self.bestbest = list(map(lambda x: max(x), TStorage))
205 """ Groups several storages in different slots with different names.
206 Use by calling in sequence:
208 open_(size) size = number of slots
209 store(Slotname, Value, Numeric) any time
210 close_() --> this performs statistics
for each numeric slot
213 def __init__(self, Name=''):
214 """ initializes a dict of storages
220 """ resets all storages
226 """ opens all storages
231 def store(self, StorageName, vector, Numeric=True):
232 """ stores a data vector into a slot named StorageName
234 if StorageName
not in self.
storages:
244 """ performs statistics in all individual storages
250 """ closes all storages
256 """ displays all storages as text, one per line
258 return self.
storages[StorageName].__str__()
261 """ retrieves a data vector from slot named StorageName
264 return storages[StorageName].
get_data()
274 """ Meta storage: stores several lower-level examiners
275 having same slots and performs weighted statistics
for each slot
278 def __init__(self, Name=''):
279 """ Defines a storage that will contain various examiners (which are dicts of storages)
280 All examiners are supposed to have the same slots (low-level storages)
282 Storage.__init__(self, Name)
286 """ gathers data from the stored examiners
287 and stores them
as a dictionary of tuples (a tuple per slot)
288 (number_of_instances, best_of_each_coordinate,
289 average_of_each_coordinate, list_of_instances)
292 for Slot
in self.
storage[0].storages:
293 if len(list(set([Exam.storages[Slot].itemLength
for Exam
in self.
storage]))) > 1:
294 error(
'Observer: ',self.
Name +
': Inconsistent item length accross examiners')
296 best = list(map(
lambda x: max(x),
transpose([Exam.storages[Slot].best \
299 cumulative_number = sum([Exam.storages[Slot].length
for Exam
in self.
storage])
301 totals =
transpose([list(map(
lambda x: x*Exam.storages[Slot].length,
302 Exam.storages[Slot].average))
for Exam
in self.
storage])
303 if cumulative_number:
304 average = list(map(
lambda x: sum(x)/cumulative_number, totals))
306 average = list(map(
lambda x: sum(x), totals))
307 self.
Statistics[Slot] = {
'length': cumulative_number,
310 'data': functools.reduce(
lambda x,y: x+y,
311 tuple(tuple(Exam.storages[Slot].storage
316 """ Performs statistics on storage 'Slot'
329 """ initializes ScenarioName, EvolifeMainDir, CurveNames, Title, Field_grid and Trajectory_grid
337 self.
recordInfo(
'EvolifeMainDir', os.path.dirname(sys.argv[0]))
348 """ sets or retrieves display period
354 """ increments StepId
356 if year
is not None: self.
StepId = year
361 """ decides whether the situation should be displayed
370 """ Checks whether time limit has been reached
371 and has
not been manually bypassed
381 """ set output directory ('___Results' by default)
384 if not os.path.exists(ResultDir):
388 self.
recordInfo(
'ResultFile', os.path.join(ResultDir, os.path.basename(self.
get_info(
'ResultFile'))))
391 """ stores Value in Slot
394 self.
Infos[Slot] = Value
396 def get_info(self, Slot, default=None, erase=False):
397 """ returns factual information previously stored in Slot
398 returns 'default' (which
is None by default)
if Slot
is not found
400 if Slot ==
'PlotOrders':
402 elif Slot ==
'CurveNames':
403 CN = self.
Infos[Slot]
406 Result = self.
Infos[Slot]
407 if erase: del self.
Infos[Slot]
409 except KeyError:
return default
415 """ Info is sent by the simulation -
416 Typically a single char, corresponding to a key pressed
417 Useful to customize action
422 """ Parameter names are stored with the date in the result file header
423 Header is just the string
"Date" by default
427 def record(self, Position, Window='Field', Reset=False):
428 """ stores current position changes into the Window's buffer ('Field' by default, could be 'Trajectories')
429 'Position' can also be the string
"erase"
431 if isinstance(Position, list): Buffer = list(Position)
432 elif isinstance(Position, tuple): Buffer = [Position]
433 elif Position.lower() ==
'erase': Buffer = [
'erase']
434 else:
error(
'Observer',
"Should be 'erase' or tuple or list: " + str(Position))
441 """ returns initial drawing for 'Field'
446 """ returns initial drawing for 'Trajectories'
451 """ Retrieves data from Slot.
452 Erases Slot's content if Consumption is True
454 if Slot
in [
'Positions',
'Field']:
459 elif Slot ==
'Trajectories':
463 if CC:
return tuple(CC)
468 """ Remembers that display occurred (to ensure that it answers once a year)
473 """ Erases the text buffer
478 """ stores a string that will be displayed at appropriate time.
479 Text is currently printed on the console (to be changed)
486 def curve(self, Name=None, Value=None, Color=None, Legend=None):
487 """ creates or retrieves a curve or return curve's current value.
488 If Name is None: resets all curves.
491 for C
in self.
Curves: C.reset()
494 if Color
is not None and Name
not in self.
Curves:
495 self.
Curves.append(Name, Color, Legend)
496 return (self.
Curves.Color(Name), self.
Curves.Value(Name, Value))
499 """ returns curves' legends
504 """ returns curves' names
509 """ Returns current curves' values if observer in visible state
521 """ Typical observer for an experiment with parameters
525 """ Initializes ScenarioName, EvolifeMainDir, CurveNames, Title, Field_grid and Trajectory_grid
526 Sets DisplayPeriod, TimeLimit, Icon, ... from values taken
from ParameterSet
527 ExperienceID
is set to current date
528 Sets ResultFile (appends ExperienceID
in batch mode)
532 Title = self.Parameter('Title', Default=
'Evolife').replace(
'_',
' ')
533 Generic_Observer.__init__(self, Title)
537 self.
recordInfo(
'ExperienceID', strftime(
"%y%m%d%H%M%S"))
539 CurveOffset = self.
Parameter(
'DumpStart', Default=0)
540 if type(CurveOffset) == str
and CurveOffset.strip().endswith(
'%'):
548 if self.
Parameter(
'ResultDir', Default=
None)
is not None:
553 """ Relevant parameter names are stored into the result file header, juste after the string "Date"
554 Parameter values are added just below the header
556 Header = 'Date;' +
';'.join(self.
ParamSet.RelevantParamNames()) +
';\n'
559 Header +=
';'.join([str(self.
Parameter(P, Silent=
True))
560 for P
in self.
ParamSet.RelevantParamNames()]) +
';'
565 """ returns factual information previously stored in Slot.
566 default value is None by default
569 if Slot ==
'ResultHeader':
572 return Generic_Observer.get_info(self, Slot, default=default)
576 """ Contains instantaneous data updated from the simulation
577 for statistics
and display
580 def __init__(self, Scenario=None):
581 """ calls Experiment_Observer constructor if Scenario is not None, Generic_Observer otherwise
582 calls Meta_Examiner constructor
585 if Scenario: Experiment_Observer.__init__(self, Scenario)
586 else: Generic_Observer.__init__(self)
587 Meta_Examiner.__init__(self)
590 """ Retrieves data stored in Slot from Experiment_Observer (or, if None, from Meta_Examiner)
592 Data = Experiment_Observer.get_data(self, Slot, Consumption=Consumption)
594 Data = Meta_Examiner.get_data(self, Slot)
599 """ Evolife-aware observer based on the use of a scenario.
600 Retrieves curves' names and legends, and satellite window names, legends and wallpapers
601 as provided by scenario
602 Contains instantaneous data updated
from the simulation
603 for statistics
and display
606 def __init__(self, Scenario):
607 Observer.__init__(self, Scenario)
609 except KeyError:
pass
617 for Window
in [
'Field',
'Curves',
'Genome',
'Log',
'Help',
'Trajectories',
'Network']:
622 for Curve_description
in self.
Scenario.display_():
623 (Colour, Name, Legend) = Curve_description + (0,
'',
'')[len(Curve_description):]
625 if Name
in self.
Scenario.get_gene_names(): Legend =
'Average value of gene %s in the population' % Name
626 elif Name
in self.
Scenario.phenemap(): Legend =
'Average value of phene %s in the population' % Name
627 self.
curve(Name=Name, Color=Colour, Legend=Legend)
630 """ Gets the curves to be displayed from the scenario and
631 returns intantaneous values to be displayed on these curves
637 value = self.
Statistics[
'Properties'][
'best'][1]
638 elif Curve ==
'average':
639 value = self.
Statistics[
'Properties'][
'average'][1]
640 elif Curve
in self.
Scenario.get_gene_names():
643 elif Curve
in self.
Scenario.phenemap():
648 try: value = int(getattr(self.
Scenario, Curve))
650 error(self.
Name,
": bad value for " + Curve)
652 error(self.
Name,
": unknown display instruction: " + Curve)
654 self.
curve(Curve, int(value))
655 return Observer.GetPlotOrders(self)
658 """ returns factual information previously stored in Slot
660 if Slot ==
'Trajectories':
662 if Best
is not None:
return Best
663 return Observer.get_info(self, Slot, default=default)
666 """ stores a string that will be displayed at appropriate time
669 return Experiment_Observer.TextDisplay(self,Str)
674 """ returns initial drawing for 'Field'
678 """ returns initial drawing for 'Trajectories'
683 Str = self.
Name +
'\nStep: ' + str(self.
StepId) + \
684 '\tIndividuals: ' + str(self.
Statistics[
'Genomes'][
'length']) + \
685 '\tBest: ' +
"%.2f" % self.
Statistics[
'Properties'][
'best'][1] + \
686 '\tAverage: ' +
"%.2f" % self.
Statistics[
'Properties'][
'average'][1] +
'\n'
687 Str +=
'\n'.join([gr.display(
'Properties')
for gr
in self.
storage])
691if __name__ ==
"__main__":
694 BO.store(
'Slot1',[1,2,3,8,2,6])
695 BO.store(
'Slot1',[9,8,7,5,0,2])
696 BO.store(
'Slot1',[8,8,8,3,1,2])
697 BO.store(
'Slot2',[7,8,9])
698 BO.store(
'Slot2',[9,8,7])
699 BO.store(
'Slot2',[8,8,8])
703 BO2.store(
'Slot1',[10,18,27,1,1,1])
704 BO2.store(
'Slot2',[10,10,10])
713 print(MBO.statistics())
715 raw_input(
'[Return]')
718__author__ =
'Dessalles'
Legend of a curve (color, text) for Experiment_Observer.
Legend of a curves for Experiment_Observer.
def Color(self, Name)
returns the color of a curve
def reset(self)
Defines Curves and their current Values Stores curves' designation and legend.
def legend(self)
return legends
def CurveNames(self)
returns curves' designations
def Orders(self, x)
Returns current curves' values (at time x)
def Value(self, Name, Value=None)
sets or returns a curve's current value
def append(self, Name='Curve', Color='red', Legend='')
Creates a new (local) curve and stores it.
def __iter__(self)
iterates through curves
Evolife-aware observer based on the use of a scenario.
def TextDisplay(self, Str="")
stores a string that will be displayed at appropriate time
def Trajectory_grid(self)
returns initial drawing for 'Trajectories'
def GetPlotOrders(self)
Gets the curves to be displayed from the scenario and returns intantaneous values to be displayed on ...
def get_info(self, Slot, default=None)
returns factual information previously stored in Slot
def Field_grid(self)
returns initial drawing for 'Field'
Groups several storages in different slots with different names.
def reset(self, length=-1)
resets all storages
def store(self, StorageName, vector, Numeric=True)
stores a data vector into a slot named StorageName
def open_(self, length=-1)
opens all storages
def display(self, StorageName)
displays all storages as text, one per line
def close_(self)
closes all storages
def get_data(self, StorageName)
retrieves a data vector from slot named StorageName
def statistics(self)
performs statistics in all individual storages
Typical observer for an experiment with parameters.
def get_info(self, Slot, default=None)
returns factual information previously stored in Slot.
def ResultHeader(self)
Relevant parameter names are stored into the result file header, juste after the string "Date" Parame...
def __init__(self, ParameterSet)
Initializes ScenarioName, EvolifeMainDir, CurveNames, Title, Field_grid and Trajectory_grid Sets Disp...
def displayed(self)
Remembers that display occurred (to ensure that it answers once a year)
def get_info(self, Slot, default=None, erase=False)
returns factual information previously stored in Slot returns 'default' (which is None by default) if...
def legend(self)
returns curves' legends
def TextDisplay(self, Str="")
stores a string that will be displayed at appropriate time.
def recordInfo(self, Slot, Value)
stores Value in Slot
def inform(self, Info)
Info is sent by the simulation - Typically a single char, corresponding to a key pressed Useful to cu...
def GetPlotOrders(self)
Returns current curves' values if observer in visible state.
def curve(self, Name=None, Value=None, Color=None, Legend=None)
creates or retrieves a curve or return curve's current value.
def CurveNames(self)
returns curves' names
def season(self, year=None)
increments StepId
def setOutputDir(self, ResultDir='___Results')
set output directory ('___Results' by default)
def Over(self)
Checks whether time limit has been reached and has not been manually bypassed.
def ResultHeader(self)
Parameter names are stored with the date in the result file header Header is just the string "Date" b...
def get_data(self, Slot, Consumption=True)
Retrieves data from Slot.
def DisplayPeriod(self, Per=0)
sets or retrieves display period
def __init__(self, ObsName='', TimeLimit=10000)
initializes ScenarioName, EvolifeMainDir, CurveNames, Title, Field_grid and Trajectory_grid
def Trajectory_grid(self)
returns initial drawing for 'Trajectories'
def Visible(self)
decides whether the situation should be displayed
def Field_grid(self)
returns initial drawing for 'Field'
def TextErase(self)
Erases the text buffer.
def record(self, Position, Window='Field', Reset=False)
stores current position changes into the Window's buffer ('Field' by default, could be 'Trajectories'...
Storage + basic statistics.
def statistics(self)
computes best and average
Contains instantaneous data updated from the simulation for statistics and display.
def get_data(self, Slot, Consumption=True)
Retrieves data stored in Slot from Experiment_Observer (or, if None, from Meta_Examiner)
def close_(self)
sets the storage as 'closed'
def store(self, vector)
stores a vecor in the storage
def open_(self, length=-1)
marks the storage as 'open'
def reset(self, length=-1)
initializes the 'storage', 'average' and 'best' lists
def get_data(self)
returns a tuple of all the vectors in the storage
def statistics(self)
to be overloaded