Evolife
Evolife has been developed to study Genetic algorithms, Natural evolution and behavioural ecology.
Group.py
Go to the documentation of this file.
1#!/usr/bin/env python3
2""" @brief Groups are lists of Individuals.
3
4Reproduction, selection and behavioural games
5take place within the group.
6"""
7
8
9#============================================================================#
10# EVOLIFE http://evolife.telecom-paris.fr Jean-Louis Dessalles #
11# Telecom Paris 2022-04-11 www.dessalles.fr #
12# -------------------------------------------------------------------------- #
13# License: Creative Commons BY-NC-SA #
14#============================================================================#
15# Documentation: https://evolife.telecom-paris.fr/Classes #
16#============================================================================#
17
18
19
22
23
24import sys
25if __name__ == '__main__':
26 sys.path.append('../..') # for tests
27 from Evolife.Scenarii.MyScenario import InstantiateScenario
28 InstantiateScenario('Cooperation')
29
30
31from random import randint, sample, shuffle
32
33from Evolife.Ecology.Individual import Individual, EvolifeIndividual
34from Evolife.Ecology.Observer import Examiner # for statistics
35from Evolife.Tools.Tools import error
36
37class Group:
38 """ A group is mainly a list of individuals
39 """
40 def __init__(self, Scenario, ID=1, Size=100):
41 self.Scenario = Scenario # Scenario just holds parameters
42 self.size = 0
43 self.members = []
44 # ranking is used to store a sorted list of individuals in the group
45 self.ranking = []
46 self.best_score = 0
47 self.ID = ID
48 self.location = 0 # geographical position
49 self.Examiner = Examiner('GroupObs'+str(self.ID))
50 for individual in range(Size):
51 Indiv = self.createIndividual(Newborn=False)
52 self.receive(Indiv)
53 self.update_(flagRanking=True)
54 self.statistics()
55
56 def free_ID(self, Prefix=None):
57 """ returns an available ID
58 """
59 IDs = [m.ID for m in self.members]
60 for ii in range(100000):
61 if Prefix is not None: ID = '%s%d' % (Prefix, ii)
62 else: ID = '%d_%d' % (self.ID, ii) # considering group number as prefix
63 if ID not in IDs: return ID
64 return -1
65
66 def createIndividual(self, ID=None, Newborn=True):
67 """ Calls the 'Individual' class
68 """
69 return Individual(self.Scenario, ID=self.free_ID(), Newborn=Newborn)
70
71 def whoIs(self, Number):
72 """ Returns the Numberth individual
73 """
74 try: return self.members[Number]
75 except IndexError: error('Group', 'selecting non-existent individual')
76
77 def isMember(self, indiv): return indiv in self.members
78
79 def update_(self, flagRanking = False, display=False):
80 """ updates various facts about the group
81 """
82 # removing old chaps
83 for m in self.members[:]: # must duplicate the list to avoid looping over a modifying list
84 if m.dead(): self.remove_member(m)
85 self.size = len(self.members)
86 if self.size == 0: return 0
87 # ranking individuals
88 if flagRanking:
89 # ranking individuals in the group according to their score
90 self.ranking = self.members[:] # duplicates the list, not the elements
91 self.ranking.sort(key=lambda x: x.score(),reverse=True)
92 if self.ranking != [] and self.ranking[0].score() == 0 and self.ranking[-1] == 0:
93 # all scores are zero
94 shuffle(self.ranking) # not always the same ones first
95 self.best_score = self.ranking[0].score()
96 return self.size
97
98 def statistics(self):
99 """ Updates various statistics about the group.
100 Calls 'observation' for each member
101 """
102 self.Examiner.reset()
103 self.Examiner.open_(self.size)
104 for i in self.members:
105 i.observation(self.Examiner)
106 self.Examiner.close_() # makes statistics for each slot
107
108 def positions(self):
109 """ lists agents' locations
110 """
111 return [(A.ID, A.location()) for A in self.members]
112
113 def season(self, year):
114 """ This function is called at the beginning of each year.
115 Individuals get older each year
116 """
117 for m in self.members: m.aging()
118
119 def kill(self, memberNbr):
120 """ suppress one specified individual of the group
121 """
122 # the victim suffers from an accident
123 return self.remove_(memberNbr)
124
125 def remove_(self, memberNbr):
126 """ tells a member it should die and then removes it from the group
127 """
128 indiv = self.whoIs(memberNbr)
129 indiv.dies() # let the victim know
130 self.size -= 1
131 return self.members.pop(memberNbr)
132
133 def remove_member(self, indiv):
134 """ calls 'remove_' with indiv's index in the group
135 """
136 self.remove_(self.members.index(indiv))
137
138 def extract(self, indiv):
139 """ synonymous to 'remove_member'
140 """
141 return self.remove_member(indiv)
142
143 def receive(self, newcomer):
144 """ insert a new member in the group
145 """
146 if newcomer is not None:
147 self.members.append(newcomer)
148 self.size += 1
149
150 def __len__(self): return len(self.members)
151
152 def __iter__(self): return iter(self.members)
153
154 def __str__(self):
155 """ printing a sorted list of individuals, one per line
156 """
157 if self.ranking: return ">\n".join(["%s" % ind for ind in self.ranking]) + "\n"
158 else: return "\n".join(["%s" % ind for ind in self.members]) + "\n"
159
160
161
163 """ class Group: list of individuals that interact and reproduce.
164 Same as Group + reproduction + calls to Scenario functions.
165 """
166
167 def createIndividual(self, Newborn=True):
168 """ calls the 'EvolifeIndividual' class
169 calls 'Scenario.new_agent'
170 """
171 # Indiv = Group.createIndividual(self, Newborn=Newborn)
172 Indiv = EvolifeIndividual(self.Scenario, ID=self.free_ID(), Newborn=Newborn)
173 # let scenario know that there is a newcomer
174 if not Newborn: self.Scenario.new_agent(Indiv, None)
175 return Indiv
176
177 def uploadDNA(self, Start):
178 """ loads given DNAs into individuals
179 """
180 if Start:
181 # if len(Start) != self.size:
182 # error("Group", "%d DNAs for %d individuals" % (len(Start), self.size))
183 for m in self.members:
184 m.DNAfill([int(n) for n in self.Start.pop(0).split()])
185
186 def update_(self, flagRanking = False, display=False):
187 """ updates various facts about the group + positions
188 """
189 size = Group.update_(self, flagRanking=flagRanking)
190 if display:
191 if flagRanking: self.Scenario.update_positions(self.ranking, self.location)
192 else: self.Scenario.update_positions(self.members, self.location)
193 # updating social links
194 for m in self.members: m.checkNetwork(membershipFunction=self.isMember)
195 return size
196
197 def reproduction(self):
198 """ reproduction within the group
199 creates individuals from couples returned by 'Scenario.couples'
200 by calling 'hybrid' on the parents' genome
201 and then by mutating the individual and inserting into the group
202 """
203 # The function 'couples' returns as many couples as children are to be born
204 # The probability of parents to beget children depends on their rank within the group
205 self.update_update_(flagRanking=True) # updates individual ranks
206 for C in self.Scenario.couples(self.ranking):
207 # making of the child
208 # child = EvolifeIndividual(self.Scenario, ID=self.free_ID(), Newborn=True)
209 child = self.createIndividualcreateIndividual(Newborn=True)
210 if child is not None:
211 child.hybrid(C[0],C[1]) # child's DNA results from parents' DNA crossover
212 child.mutate()
213 child.update() # computes the value of genes, as DNA is available only now
214 if self.Scenario.new_agent(child, C): # let scenario decide something about the newcomer
215 self.receive(child) # adds child to the group
216
217 def season(self, year):
218 """ This function is called at the beginning of each year
219 It calls Scenario.season
220 """
221 Group.season(self, year)
222 self.Scenario.season(year, self.members)
223
224 def kill(self, memberNbr):
225 """ kills or weakens one specified individual of the group
226 """
227 # the victim suffers from an accident
228 indiv = self.whoIs(memberNbr)
229 indiv.accident()
230 if indiv.dead(): return self.remove_remove_(memberNbr)
231 return None
232
233 def remove_(self, memberNbr):
234 """ calls Group.remove_ and also Scenario.remove_agent
235 """
236 indiv = self.whoIs(memberNbr)
237 self.Scenario.remove_agent(indiv) # let scenario know
238 return Group.remove_(self, memberNbr)
239
240 def life_game(self):
241 """ Calls Scenario.life_game
242 """
243 # Let's play the game as defined in the scenario
244 self.Scenario.life_game(self.members)
245 # life game is supposed to change individual scores and life points
246
247 def get_average(self):
248 """ computes an average individual in the group
249 """
250 Avg_DNA = [int(round(B)) for B in self.Examiner.storages['DNA'].average]
251 Avg = EvolifeIndividual(self.Scenario, Newborn=True) # individual with average DNA (standard Evolife (dummy) individual
252 Avg.DNAfill(Avg_DNA)
253 return Avg
254
255 def get_best(self):
256 """ returns the phenotype of the best or representative individual
257 """
258 return self.Scenario.behaviour(self.ranking[0], self.get_average())
259
260
261
264
265if __name__ == "__main__":
266 print(__doc__)
267 print(Group.__doc__ + '\n')
268 gr_size = 10
269 MyGroup = Group(1,gr_size)
270 print(MyGroup)
271 raw_input('[Return to continue]')
272 for ii in range(22):
273 MyGroup.life_game()
274 MyGroup.update_(flagRanking = True)
275 print("%d > " % ii)
276 print("%.02f" % (sum([1.0*i.score() for i in MyGroup.members])/gr_size))
277 print(MyGroup.Examiner)
278 MyGroup.reproduction(MyScenario.Parameter('ReproductionRate'))
279 while MyGroup.size > gr_size:
280 MyGroup.kill(randint(0,MyGroup.size-1))
281 #print toto
282 raw_input('[Return to terminate]')
283
284__author__ = 'Dessalles'
class Group: list of individuals that interact and reproduce.
Definition: Group.py:162
def reproduction(self)
reproduction within the group creates individuals from couples returned by 'Scenario....
Definition: Group.py:197
def createIndividual(self, Newborn=True)
calls the 'EvolifeIndividual' class calls 'Scenario.new_agent'
Definition: Group.py:167
def remove_(self, memberNbr)
calls Group.remove_ and also Scenario.remove_agent
Definition: Group.py:233
def season(self, year)
This function is called at the beginning of each year It calls Scenario.season.
Definition: Group.py:217
def get_best(self)
returns the phenotype of the best or representative individual
Definition: Group.py:255
def kill(self, memberNbr)
kills or weakens one specified individual of the group
Definition: Group.py:224
def update_(self, flagRanking=False, display=False)
updates various facts about the group + positions
Definition: Group.py:186
def uploadDNA(self, Start)
loads given DNAs into individuals
Definition: Group.py:177
def get_average(self)
computes an average individual in the group
Definition: Group.py:247
def life_game(self)
Calls Scenario.life_game.
Definition: Group.py:240
A group is mainly a list of individuals.
Definition: Group.py:37
def season(self, year)
This function is called at the beginning of each year.
Definition: Group.py:113
def kill(self, memberNbr)
suppress one specified individual of the group
Definition: Group.py:119
def createIndividual(self, ID=None, Newborn=True)
Calls the 'Individual' class.
Definition: Group.py:66
def receive(self, newcomer)
insert a new member in the group
Definition: Group.py:143
def isMember(self, indiv)
Definition: Group.py:77
def update_(self, flagRanking=False, display=False)
updates various facts about the group
Definition: Group.py:79
def statistics(self)
Updates various statistics about the group.
Definition: Group.py:98
def free_ID(self, Prefix=None)
returns an available ID
Definition: Group.py:56
def remove_(self, memberNbr)
tells a member it should die and then removes it from the group
Definition: Group.py:125
def extract(self, indiv)
synonymous to 'remove_member'
Definition: Group.py:138
def remove_member(self, indiv)
calls 'remove_' with indiv's index in the group
Definition: Group.py:133
def __init__(self, Scenario, ID=1, Size=100)
Definition: Group.py:40
def whoIs(self, Number)
Returns the Numberth individual.
Definition: Group.py:71
def positions(self)
lists agents' locations
Definition: Group.py:108
Individual + genome + phenome + social links.
Definition: Individual.py:110
class Individual: basic individual.
Definition: Individual.py:32
Groups several storages in different slots with different names.
Definition: Observer.py:204
An Individual has a genome, several genes, a score and behaviours.
Definition: Individual.py:1
Gets data from various modules and stores them for display and statistics.
Definition: Observer.py:1
Various functions.
Definition: Tools.py:1
def error(ErrMsg, Explanation='')
Definition: Tools.py:182