Evolife
Evolife has been developed to study Genetic algorithms, Natural evolution and behavioural ecology.
Observer.py
Go to the documentation of this file.
1#!/usr/bin/env python3
2""" @brief Gets data from various modules and stores them for display and statistics.
3
4 - Generic_Observer --> interface between simulation and window system
5 - Experiment_Observer --> idem + headers to store curves
6
7 - Storage --> stores vectors
8 - Examiner --> different Storages, one per slot
9 - Meta_Examiner --> stores similar Examiners with sames slots + statistics
10
11 - Observer --> Meta_Examiner + Experiment_Observer
12 - EvolifeObserver --> specific observer (knows about genomes, phenomes, ...)
13
14"""
15
16#============================================================================#
17# EVOLIFE http://evolife.telecom-paris.fr Jean-Louis Dessalles #
18# Telecom Paris 2022-04-11 www.dessalles.fr #
19# -------------------------------------------------------------------------- #
20# License: Creative Commons BY-NC-SA #
21#============================================================================#
22# Documentation: https://evolife.telecom-paris.fr/Classes #
23#============================================================================#
24
25
26
29
30
31
32import sys, os, os.path
33
34if __name__ == '__main__': sys.path.append('../..')
35
36import functools
37from time import strftime
38from Evolife.Tools.Tools import transpose, error
39
40
41
42class Curve:
43 """ Legend of a curve (color, text)
44 for Experiment_Observer
45 """
46 def __init__(self, Name='Curve', Color='red', Legend=''):
47 self.Name = Name
48 self.Color = Color
49 self.Legend = Legend
50 self.Value = 0
51
52class Curves:
53 """ Legend of a curves
54 for Experiment_Observer
55 """
56 def __init__(self):
57 """ merely calls reset
58 """
59 self.reset()
60
61 def reset(self):
62 """ Defines Curves and their current Values
63 Stores curves' designation and legend
64 """
65 self.Curves = dict()
66 self.Values = dict() # current values of Curves
67 self.Colors = []
68 self.Designations = []
69 self.Legends = []
70
71 def append(self, Name='Curve', Color='red', Legend=''):
72 """ Creates a new (local) curve and stores it
73 """
74 if Color not in self.Colors:
75 if not Legend: Legend = Name
76 self.Curves[Name] = Curve(Name, Color, Legend)
77 self.Colors.append(Color)
78 self.Designations.append((Color, Name, Legend))
79 self.Legends.append((Color, Legend))
80 self.Values[Name] = None
81 else: error('Observer', 'Two curves with same colour: "%s" already in %s' % (Color, self.Colors))
82
83 def Color(self, Name):
84 """ returns the color of a curve
85 """
86 return self.Curves[Name].Color
87
88 def Value(self, Name, Value=None):
89 """ sets or returns a curve's current value
90 """
91 if Value is not None:
92 # self.Curves[Name].Value = Value
93 self.Values[Name] = Value
94 # return self.Curves[Name].Value
95 return self.Values[Name]
96
97 def legend(self):
98 """ return legends
99 """
100 return self.Legends
101
102 def CurveNames(self):
103 """ returns curves' designations
104 """
105 return self.Designations
106
107 def __iter__(self):
108 """ iterates through curves
109 """
110 return iter(self.Curves.keys())
111
112 # def __contains__(self, Name): return Name in self.Names
113
114 def Orders(self, x):
115 """ Returns current curves' values (at time x)
116 """
117 Point = lambda v: v if isinstance(v, tuple) else (x, v)
118 return [(self.Color(C), Point(self.Values[C])) for C in self.Curves if self.Values[C] is not None]
119
120 def __str__(self): return str(self.Designations)
121
123 """ Kind of matrix. Stores raw data, typically vectors of integers
124 """
125
126 def __init__(self, Name):
127 """ calls reset
128 """
129 self.Name = Name
130 self.reset(0)
131
132 def reset(self, length = -1):
133 """ initializes the 'storage', 'average' and 'best' lists
134 """
135 self.open = False
136 self.storage = [] # contains data as they arrive (list of vectors)
137 self.average = [] # one average vector
138 self.best = [] # the best vector
139 self.length = length # number of vectors or items stored
140 self.itemLength = -1 # length of item stored
141
142 def open_(self, length = -1):
143 """ marks the storage as 'open'
144 """
145 if self.open:
146 error('Observer: ',self.Name+': opened twice')
147 self.open = True
148 self.length = length
149
150 def store(self, vector):
151 """ stores a vecor in the storage
152 """
153 if not self.open:
154 error('Observer: ',self.Name+': not open')
155 self.storage.append(vector)
156 try:
157 if self.itemLength > 0 and len(vector) != self.itemLength:
158 error('Observer: ', self.Name + ': Inconsistent item length')
159 self.itemLength = len(vector)
160 except (AttributeError, TypeError):
161 self.itemLength = 1
162
163 def statistics(self):
164 """ to be overloaded
165 """
166 pass
167
168 def close_(self):
169 """ sets the storage as 'closed'
170 """
171 if not self.open: error('Observer: ', self.Name+': closing while not open')
172 if self.length < 0: self.length = len(self.storage)
173 elif self.length != len(self.storage):
174 error('Observer: ', self.Name+': Inconsistent lengths')
175 self.statistics() # computes statistics
176 self.open = False
177
178 def get_data(self):
179 """ returns a tuple of all the vectors in the storage
180 """
181 return tuple([tuple(T) for T in self.storage])
182# return [tuple(T) for T in self.storage]
183
184 def __str__(self):
185 return self.Name + \
186 '.\tBest:\t' + ' -- '.join(["%.2f" % x for x in self.best]) + \
187 '\n' + self.Name + \
188 '.\tAvg:\t' + ' -- '.join(["%.2f" % x for x in self.average])
189
191 """ Storage + basic statistics
192 """
193 def statistics(self):
194 """ computes best and average
195 """
196 TStorage = transpose(self.storage)
197 self.bestbest = list(map(lambda x: max(x), TStorage))
198 if self.length <= 0:
199 return (0,0,0,[])
200 self.averageaverage = list(map(lambda x: sum(x,0.0)/len(self.storage), TStorage))
201
202 return (len(self.storage), self.bestbest, self.averageaverage, tuple(self.get_data()))
203
205 """ Groups several storages in different slots with different names.
206 Use by calling in sequence:
207 reset()
208 open_(size) size = number of slots
209 store(Slotname, Value, Numeric) any time
210 close_() --> this performs statistics for each numeric slot
211 """
212
213 def __init__(self, Name=''):
214 """ initializes a dict of storages
215 """
216 self.Name = Name
217 self.storages = dict()
218
219 def reset(self, length=-1):
220 """ resets all storages
221 """
222 for S in self.storages:
223 self.storages[S].reset(length)
224
225 def open_(self, length=-1):
226 """ opens all storages
227 """
228 for S in self.storages:
229 self.storages[S].open_(length)
230
231 def store(self, StorageName, vector, Numeric=True):
232 """ stores a data vector into a slot named StorageName
233 """
234 if StorageName not in self.storages:
235 # creating a new slot
236 if Numeric:
237 self.storages[StorageName] = NumericStorage(StorageName)
238 else:
239 self.storages[StorageName] = Storage(StorageName)
240 self.storages[StorageName].open_()
241 self.storages[StorageName].store(vector)
242
243 def statistics(self):
244 """ performs statistics in all individual storages
245 """
246 for S in self.storages:
247 self.storages[S].statistics()
248
249 def close_(self):
250 """ closes all storages
251 """
252 for S in self.storages:
253 self.storages[S].close_()
254
255 def display(self, StorageName):
256 """ displays all storages as text, one per line
257 """
258 return self.storages[StorageName].__str__()
259
260 def get_data(self, StorageName):
261 """ retrieves a data vector from slot named StorageName
262 """
263 try:
264 return storages[StorageName].get_data()
265 except KeyError:
266 return None
267 #error('Observer: ',self.Name + ': Accessing unknown observation slot in examiner')
268
269 def __str__(self):
270 return self.Name + ':\n' + '\n'.join([self.display(S) for S in self.storages])
271
272
274 """ Meta storage: stores several lower-level examiners
275 having same slots and performs weighted statistics for each slot
276 """
277
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)
281 """
282 Storage.__init__(self, Name) # will contain various Examiners
283 self.Statistics = dict()
284
285 def statistics(self):
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)
290 """
291 # one takes the first examiner as representative
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')
295 # computing the best value of each coordinate
296 best = list(map(lambda x: max(x), transpose([Exam.storages[Slot].best \
297 for Exam in self.storage])))
298 # computing the total number of individual data
299 cumulative_number = sum([Exam.storages[Slot].length for Exam in self.storage])
300 # computing global statistics by summing averages weighted by corresponding numbers
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))
305 else:
306 average = list(map(lambda x: sum(x), totals))
307 self.Statistics[Slot] = {'length': cumulative_number,
308 'best': best,
309 'average':average,
310 'data': functools.reduce(lambda x,y: x+y,
311 tuple(tuple(Exam.storages[Slot].storage
312 for Exam in self.storage)))}
313 return self.Statistics
314
315 def get_data(self, Slot):
316 """ Performs statistics on storage 'Slot'
317 """
318 try:
319 return tuple(self.Statistics[Slot]['data'])
320 except KeyError:
321 return None
322 #error('Observer: ', self.Name + self.Slot + ': Accessing unknown observation slot in meta-examiner')
323
324
326 """ Minimal observer
327 """
328 def __init__(self, ObsName='', TimeLimit=10000):
329 """ initializes ScenarioName, EvolifeMainDir, CurveNames, Title, Field_grid and Trajectory_grid
330 """
331 self.TimeLimit = TimeLimit
332 self.DispPeriod = 1
333 self.StepId = 0 # computational time
334 self.PreviousStep = -1
335 self.Infos = dict() # will record specific information about the simulation
336 self.recordInfo('ScenarioName', ObsName)
337 self.recordInfo('EvolifeMainDir', os.path.dirname(sys.argv[0]))
338 self.recordInfo('CurveNames', ())
339 self.setOutputDir('.')
340 self.recordInfo('Title', ObsName) # minimum x-value when computing curve average
341 self.recordInfo('ResultOffset', 0) # minimum x-value when computing curve average
342 self.TextErase()
343 self.Curves = Curves() # stores curve legends
346
347 def DisplayPeriod(self, Per=0):
348 """ sets or retrieves display period
349 """
350 if Per: self.DispPeriod = Per
351 return self.DispPeriod
352
353 def season(self, year=None):
354 """ increments StepId
355 """
356 if year is not None: self.StepId = year
357 else: self.StepId += 1
358 return self.StepId
359
360 def Visible(self):
361 """ decides whether the situation should be displayed
362 """
363 # Have we reached a display point ?
364 if self.StepId != self.PreviousStep:
365 # print(self.StepId, self.DispPeriod)
366 return (self.StepId % self.DispPeriod) == 0
367 return False
368
369 def Over(self):
370 """ Checks whether time limit has been reached
371 and has not been manually bypassed
372 """
373 if self.TimeLimit > 0:
374 return (self.StepId % self.TimeLimit) >= self.TimeLimit-1
375 return False
376 #return self.StepId > self.TimeLimit and self.Visible() \
377 # and ((self.StepId+1) % self.TimeLimit) < abs(self.DispPeriod)
378 # and self.Visible() \
379
380 def setOutputDir(self, ResultDir='___Results'):
381 """ set output directory ('___Results' by default)
382 """
383 self.recordInfo('OutputDir', ResultDir)
384 if not os.path.exists(ResultDir):
385 os.mkdir(ResultDir)
386 # Result file name changes
387 if self.get_info('ResultFile'):
388 self.recordInfo('ResultFile', os.path.join(ResultDir, os.path.basename(self.get_info('ResultFile'))))
389
390 def recordInfo(self, Slot, Value):
391 """ stores Value in Slot
392 """
393 # print(Slot, Value)
394 self.Infos[Slot] = Value
395
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
399 """
400 if Slot == 'PlotOrders':
401 return self.GetPlotOrders()
402 elif Slot == 'CurveNames':
403 CN = self.Infos[Slot] # backward compatibility
404 return CN if CN else self.CurveNames()
405 try:
406 Result = self.Infos[Slot]
407 if erase: del self.Infos[Slot]
408 return Result
409 except KeyError: return default
410
411 # def getinfo(self, *p, **pp): # compatibility
412 # return self.get_info(*p, **pp)
413
414 def inform(self, Info):
415 """ Info is sent by the simulation -
416 Typically a single char, corresponding to a key pressed
417 Useful to customize action
418 """
419 pass
420
421 def ResultHeader(self):
422 """ Parameter names are stored with the date in the result file header
423 Header is just the string "Date" by default
424 """
425 return 'Date;\n'
426
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"
430 """
431 if isinstance(Position, list): Buffer = list(Position)
432 elif isinstance(Position, tuple): Buffer = [Position]
433 elif Position.lower() == 'erase': Buffer = ['erase'] # order to erase the window
434 else: error('Observer', "Should be 'erase' or tuple or list: " + str(Position))
435 Keep = not Reset
436 if Window == 'Field': self.Field_buffer = Keep * self.Field_buffer + Buffer
437 elif Window == 'Trajectories': self.Trajectory_buffer = Keep * self.Trajectory_buffer + Buffer
438
439 # initial drawings
440 def Field_grid(self):
441 """ returns initial drawing for 'Field'
442 """
443 return []
444
445 def Trajectory_grid(self):
446 """ returns initial drawing for 'Trajectories'
447 """
448 return []
449
450 def get_data(self, Slot, Consumption=True):
451 """ Retrieves data from Slot.
452 Erases Slot's content if Consumption is True
453 """
454 if Slot in ['Positions', 'Field']:
455 # emptying Field_buffer
456 CC = self.Field_buffer
457 if Consumption: self.Field_buffer = []
458 return tuple(CC)
459 elif Slot == 'Trajectories':
460 # emptying Trajectory_buffer
461 CC = self.Trajectory_buffer
462 if Consumption: self.Trajectory_buffer = []
463 if CC: return tuple(CC)
464 return self.get_info(Slot) # retro-compatibility
465 return None
466
467 def displayed(self):
468 """ Remembers that display occurred (to ensure that it answers once a year)
469 """
470 self.PreviousStep = self.StepId # to ensure that it answers once a year
471
472 def TextErase(self):
473 """ Erases the text buffer
474 """
475 self.__TxtBuf = ""
476
477 def TextDisplay(self, Str=""):
478 """ stores a string that will be displayed at appropriate time.
479 Text is currently printed on the console (to be changed)
480 """
481 self.__TxtBuf += Str
482 print(self.__TxtBuf) # to be changed
483 self.TextErase()
484 return self.__TxtBuf
485
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.
489 """
490 if Name is None:
491 for C in self.Curves: C.reset()
492 self.Curves.reset()
493 return None
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))
497
498 def legend(self):
499 """ returns curves' legends
500 """
501 return self.Curves.legend()
502
503 def CurveNames(self):
504 """ returns curves' names
505 """
506 return self.Curves.CurveNames()
507
508 def GetPlotOrders(self):
509 """ Returns current curves' values if observer in visible state
510 """
511 # print(self.Curves.Orders(self.StepId))
512 if self.Visible():
513 return self.Curves.Orders(self.StepId)
514 return []
515
516 def __str__(self):
517 Str = self.get_info('Title') + '\nStep: ' + str(self.StepId)
518 return Str
519
521 """ Typical observer for an experiment with parameters
522 """
523
524 def __init__(self, ParameterSet):
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)
529 """
530 self.ParamSet = ParameterSet
531 self.Parameter = ParameterSet.Parameter
532 Title = self.Parameter('Title', Default='Evolife').replace('_', ' ')
533 Generic_Observer.__init__(self, Title)
534 self.recordInfo('ScenarioName', self.Parameter('ScenarioName'))
535 self.DispPeriodDispPeriod = self.Parameter('DisplayPeriod')
536 self.TimeLimitTimeLimit = self.Parameter('TimeLimit')
537 self.recordInfo('ExperienceID', strftime("%y%m%d%H%M%S"))
538 self.recordInfo('Icon', self.Parameter('Icon', Default=None))
539 CurveOffset = self.Parameter('DumpStart', Default=0) # minimum x-value when computing curve average
540 if type(CurveOffset) == str and CurveOffset.strip().endswith('%'): # Offset expressed in % of TimeLimit
541 CurveOffset = (self.TimeLimitTimeLimit * int(CurveOffset.strip('%'))) // 100
542 self.recordInfo('ResultOffset', CurveOffset) # to ignore transitory regime in curves
543 self.BatchMode = self.Parameter('BatchMode', Default=0)
544 if self.BatchMode:
545 self.recordInfo('ResultFile', self.get_infoget_info('ScenarioName') + '_' + self.get_infoget_info('ExperienceID'))
546 else:
547 self.recordInfo('ResultFile', self.get_infoget_info('ScenarioName') + '_')
548 if self.Parameter('ResultDir', Default=None) is not None:
549 self.setOutputDir(self.Parameter('ResultDir'))
550 else: self.setOutputDir() # default
551
552 def ResultHeader(self):
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
555 """
556 Header = 'Date;' + ';'.join(self.ParamSet.RelevantParamNames()) + ';\n'
557 # adding parameter values to result file
558 Header += self.get_infoget_info('ExperienceID') + ';'
559 Header += ';'.join([str(self.Parameter(P, Silent=True))
560 for P in self.ParamSet.RelevantParamNames()]) + ';'
561 return Header
562
563 # def get_info(self, Slot, *p, **pp):
564 def get_info(self, Slot, default=None):
565 """ returns factual information previously stored in Slot.
566 default value is None by default
567 """
568 # Header is computed by the time of the call, as relevant parameters are not known in advance
569 if Slot == 'ResultHeader':
570 return self.ResultHeaderResultHeader()
571 # return Generic_Observer.get_info(self, Slot, *p, *pp)
572 return Generic_Observer.get_info(self, Slot, default=default)
573
574
576 """ Contains instantaneous data updated from the simulation
577 for statistics and display
578 """
579
580 def __init__(self, Scenario=None):
581 """ calls Experiment_Observer constructor if Scenario is not None, Generic_Observer otherwise
582 calls Meta_Examiner constructor
583 """
584 self.Scenario = Scenario
585 if Scenario: Experiment_Observer.__init__(self, Scenario)
586 else: Generic_Observer.__init__(self)
587 Meta_Examiner.__init__(self)
588
589 def get_data(self, Slot, Consumption=True):
590 """ Retrieves data stored in Slot from Experiment_Observer (or, if None, from Meta_Examiner)
591 """
592 Data = Experiment_Observer.get_data(self, Slot, Consumption=Consumption)
593 if not Data:
594 Data = Meta_Examiner.get_data(self, Slot)
595 return Data
596
597
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
604 """
605
606 def __init__(self, Scenario):
607 Observer.__init__(self, Scenario)
608 try: self.Parameter('ScenarioName') # to make it relevant
609 except KeyError: pass
610
611 # Location of the Evolife Directory
612 # for R in os.walk(os.path.abspath('.')[0:os.path.abspath('.').find('Evo')]):
613 # if os.path.exists(os.path.join(R[0], 'Evolife', '__init__.py')):
614 # self.recordInfo('EvolifeMainDir', os.path.join(R[0], 'Evolife')) # location of the main programme
615 # break
616 self.recordInfo('GenePattern', self.Scenario.gene_pattern())
617 for Window in ['Field', 'Curves', 'Genome', 'Log', 'Help', 'Trajectories', 'Network']:
618 self.recordInfo(Window + 'Wallpaper', self.Scenario.wallpaper(Window))
619 self.recordInfo('DefaultViews', self.Scenario.default_view())
620 self.recordInfo('WindowLegends', self.Scenario.legends())
621 # declaring curves
622 for Curve_description in self.Scenario.display_():
623 (Colour, Name, Legend) = Curve_description + (0, '', '')[len(Curve_description):]
624 if not Legend:
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)
628
629 def GetPlotOrders(self):
630 """ Gets the curves to be displayed from the scenario and
631 returns intantaneous values to be displayed on these curves
632 """
633 PlotOrders = []
634
635 for Curve in self.Curves:
636 if Curve == 'best':
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():
641 # displaying average values of genes
642 value = self.Statistics['Genomes']['average'][self.Scenario.get_locus(Curve)]
643 elif Curve in self.Scenario.phenemap():
644 # displaying average values of phenes
645 value = self.Statistics['Phenomes']['average'][self.Scenario.phenemap().index(Curve)]
646 else: # looking for Curve in Scenario's local variables
647 if Curve in dir(self.Scenario):
648 try: value = int(getattr(self.Scenario, Curve))
649 except TypeError:
650 error(self.Name, ": bad value for " + Curve)
651 else:
652 error(self.Name, ": unknown display instruction: " + Curve)
653 value = 0
654 self.curve(Curve, int(value))
655 return Observer.GetPlotOrders(self)
656
657 def get_info(self, Slot, default=None):
658 """ returns factual information previously stored in Slot
659 """
660 if Slot == 'Trajectories':
661 Best= self.get_infoget_infoget_info('Best', default=default)
662 if Best is not None: return Best
663 return Observer.get_info(self, Slot, default=default)
664
665 def TextDisplay(self, Str=""):
666 """ stores a string that will be displayed at appropriate time
667 """
668 if not self.BatchMode:
669 return Experiment_Observer.TextDisplay(self,Str)
670 else: # do nothing
671 return ''
672
673 def Field_grid(self):
674 """ returns initial drawing for 'Field'
675 """
676 return self.Scenario.Field_grid()
678 """ returns initial drawing for 'Trajectories'
679 """
680 return self.Scenario.Trajectory_grid()
681
682 def __str__(self):
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])
688 return Str
689
690
691if __name__ == "__main__":
692 print(__doc__)
693 BO = Examiner('basic_obs')
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])
700 BO.close_()
701 print(BO)
702 BO2 = Examiner('basic_obs2')
703 BO2.store('Slot1',[10,18,27,1,1,1])
704 BO2.store('Slot2',[10,10,10])
705 BO2.close_()
706 print(BO2)
707 MBO = Meta_Examiner('Meta_Obs')
708 MBO.open_(2)
709 MBO.store(BO)
710 MBO.store(BO2)
711 MBO.close_()
712 print(MBO)
713 print(MBO.statistics())
714
715 raw_input('[Return]')
716
717
718__author__ = 'Dessalles'
Legend of a curve (color, text) for Experiment_Observer.
Definition: Observer.py:42
Legend of a curves for Experiment_Observer.
Definition: Observer.py:52
def Color(self, Name)
returns the color of a curve
Definition: Observer.py:83
def reset(self)
Defines Curves and their current Values Stores curves' designation and legend.
Definition: Observer.py:61
def legend(self)
return legends
Definition: Observer.py:97
def CurveNames(self)
returns curves' designations
Definition: Observer.py:102
def Orders(self, x)
Returns current curves' values (at time x)
Definition: Observer.py:114
def Value(self, Name, Value=None)
sets or returns a curve's current value
Definition: Observer.py:88
def append(self, Name='Curve', Color='red', Legend='')
Creates a new (local) curve and stores it.
Definition: Observer.py:71
def __iter__(self)
iterates through curves
Definition: Observer.py:107
Evolife-aware observer based on the use of a scenario.
Definition: Observer.py:598
def TextDisplay(self, Str="")
stores a string that will be displayed at appropriate time
Definition: Observer.py:665
def Trajectory_grid(self)
returns initial drawing for 'Trajectories'
Definition: Observer.py:677
def GetPlotOrders(self)
Gets the curves to be displayed from the scenario and returns intantaneous values to be displayed on ...
Definition: Observer.py:629
def get_info(self, Slot, default=None)
returns factual information previously stored in Slot
Definition: Observer.py:657
def Field_grid(self)
returns initial drawing for 'Field'
Definition: Observer.py:673
Groups several storages in different slots with different names.
Definition: Observer.py:204
def reset(self, length=-1)
resets all storages
Definition: Observer.py:219
def store(self, StorageName, vector, Numeric=True)
stores a data vector into a slot named StorageName
Definition: Observer.py:231
def open_(self, length=-1)
opens all storages
Definition: Observer.py:225
def display(self, StorageName)
displays all storages as text, one per line
Definition: Observer.py:255
def close_(self)
closes all storages
Definition: Observer.py:249
def get_data(self, StorageName)
retrieves a data vector from slot named StorageName
Definition: Observer.py:260
def statistics(self)
performs statistics in all individual storages
Definition: Observer.py:243
Typical observer for an experiment with parameters.
Definition: Observer.py:520
def get_info(self, Slot, default=None)
returns factual information previously stored in Slot.
Definition: Observer.py:564
def ResultHeader(self)
Relevant parameter names are stored into the result file header, juste after the string "Date" Parame...
Definition: Observer.py:552
def __init__(self, ParameterSet)
Initializes ScenarioName, EvolifeMainDir, CurveNames, Title, Field_grid and Trajectory_grid Sets Disp...
Definition: Observer.py:524
def displayed(self)
Remembers that display occurred (to ensure that it answers once a year)
Definition: Observer.py:467
def get_info(self, Slot, default=None, erase=False)
returns factual information previously stored in Slot returns 'default' (which is None by default) if...
Definition: Observer.py:396
def legend(self)
returns curves' legends
Definition: Observer.py:498
def TextDisplay(self, Str="")
stores a string that will be displayed at appropriate time.
Definition: Observer.py:477
def recordInfo(self, Slot, Value)
stores Value in Slot
Definition: Observer.py:390
def inform(self, Info)
Info is sent by the simulation - Typically a single char, corresponding to a key pressed Useful to cu...
Definition: Observer.py:414
def GetPlotOrders(self)
Returns current curves' values if observer in visible state.
Definition: Observer.py:508
def curve(self, Name=None, Value=None, Color=None, Legend=None)
creates or retrieves a curve or return curve's current value.
Definition: Observer.py:486
def CurveNames(self)
returns curves' names
Definition: Observer.py:503
def season(self, year=None)
increments StepId
Definition: Observer.py:353
def setOutputDir(self, ResultDir='___Results')
set output directory ('___Results' by default)
Definition: Observer.py:380
def Over(self)
Checks whether time limit has been reached and has not been manually bypassed.
Definition: Observer.py:369
def ResultHeader(self)
Parameter names are stored with the date in the result file header Header is just the string "Date" b...
Definition: Observer.py:421
def get_data(self, Slot, Consumption=True)
Retrieves data from Slot.
Definition: Observer.py:450
def DisplayPeriod(self, Per=0)
sets or retrieves display period
Definition: Observer.py:347
def __init__(self, ObsName='', TimeLimit=10000)
initializes ScenarioName, EvolifeMainDir, CurveNames, Title, Field_grid and Trajectory_grid
Definition: Observer.py:328
def Trajectory_grid(self)
returns initial drawing for 'Trajectories'
Definition: Observer.py:445
def Visible(self)
decides whether the situation should be displayed
Definition: Observer.py:360
def Field_grid(self)
returns initial drawing for 'Field'
Definition: Observer.py:440
def TextErase(self)
Erases the text buffer.
Definition: Observer.py:472
def record(self, Position, Window='Field', Reset=False)
stores current position changes into the Window's buffer ('Field' by default, could be 'Trajectories'...
Definition: Observer.py:427
Meta storage: stores several lower-level examiners having same slots and performs weighted statistics...
Definition: Observer.py:273
def get_data(self, Slot)
Performs statistics on storage 'Slot'.
Definition: Observer.py:315
def statistics(self)
gathers data from the stored examiners and stores them as a dictionary of tuples (a tuple per slot) (...
Definition: Observer.py:285
Storage + basic statistics.
Definition: Observer.py:190
def statistics(self)
computes best and average
Definition: Observer.py:193
Contains instantaneous data updated from the simulation for statistics and display.
Definition: Observer.py:575
def get_data(self, Slot, Consumption=True)
Retrieves data stored in Slot from Experiment_Observer (or, if None, from Meta_Examiner)
Definition: Observer.py:589
def close_(self)
sets the storage as 'closed'
Definition: Observer.py:168
def store(self, vector)
stores a vecor in the storage
Definition: Observer.py:150
def open_(self, length=-1)
marks the storage as 'open'
Definition: Observer.py:142
def reset(self, length=-1)
initializes the 'storage', 'average' and 'best' lists
Definition: Observer.py:132
def get_data(self)
returns a tuple of all the vectors in the storage
Definition: Observer.py:178
def statistics(self)
to be overloaded
Definition: Observer.py:163
Various functions.
Definition: Tools.py:1
def transpose(Matrix)
groups ith items in each list of Matrix
Definition: Tools.py:105
def error(ErrMsg, Explanation='')
Definition: Tools.py:182