diff options
Diffstat (limited to 'model_population.py')
-rw-r--r-- | model_population.py | 243 |
1 files changed, 243 insertions, 0 deletions
diff --git a/model_population.py b/model_population.py new file mode 100644 index 0000000..93ae43e --- /dev/null +++ b/model_population.py @@ -0,0 +1,243 @@ +# coding: UTF8 +# Copyright 2009 Thomas Jourdan +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +import pickle +import sys +import os.path +import random +import ka_debug +import ka_random +import model_protozoon + +STATE_INIT = 'I' +STATE_RANDOMIZED = 'R' +STATE_EVOLVED = 'E' + +class KandidModel(object): + """ + inv: self.size >= 2 + inv: 1 <= self.fade_away <= self.size + #inv: 0.0 <= self._flurry_rate <= 9.0 + inv: len(self.fitness) == self.size + inv: forall(self.fitness, lambda f: 0.0 <= f <= 9.0) + inv: len(self.protozoans) == self.size + inv: forall(self.protozoans, lambda p: p is not None) + # all protozoans must be distinct objects, maybe with equal content + inv: all_uniqe_reference(self.protozoans) + """ + + def __init__(self, init_size): + self._state = STATE_INIT + self.size = init_size + self.fade_away = init_size / 2 + #self._flurry_rate = 5.0 + self.protozoans = [model_protozoon.Protozoon() for i in range(self.size)] + self.fitness = [4.0 for i in range(self.size)] + ka_debug.info('initializing model with population size %u' % init_size) + + def get_flurry_rate(self): + return ka_random.get_flurry() +# return self._flurry_rate + + def set_flurry_rate(self, value): + """ + pre: 0 <= value <= 9 + """ + ka_random.set_flurry(value) +# self._flurry_rate = value + + def is_overwrite_allowed(self): + """Preserve an already evolved population from over writing.""" + return not self._state == STATE_EVOLVED + + def classify(self): + """ + # __return__[0] -> good + # __return__[1] -> moderate + # __return__[2] -> poor + post: len(__return__[0])+len(__return__[1])+len(__return__[2]) == self.size + post: len(__return__[0]) >= 1 + post: len(__return__[2]) >= 1 + + # mutual exclusive + post: forall(__return__[0], lambda x: not contains_reference(x, __return__[1])) + post: forall(__return__[0], lambda x: not contains_reference(x, __return__[2])) + post: forall(__return__[2], lambda x: not contains_reference(x, __return__[0])) + post: forall(__return__[2], lambda x: not contains_reference(x, __return__[1])) + """ + good, moderate, poor = [], [], [] + sorted_fitness = sorted(self.fitness) + poor_level = sorted_fitness[self.fade_away-1] + good_level = sorted_fitness[-1] + for protoz, fit in zip(self.protozoans, self.fitness): + if fit >= good_level and len(good) < 1: + good.append(protoz) + elif fit <= poor_level: + if len(poor) >= self.fade_away: + index = random.randint(0, len(poor)-1) + moderate.append(poor[index]) + del poor[index] + poor.append(protoz) + else: + moderate.append(protoz) + return good, moderate, poor + + def reduce_fitness(self, index): + """ + pre: 0 <= index < len(self.fitness) + post: self.fitness.count(0.0) == 1 + """ + for raise_at, fit in enumerate(self.fitness): + if fit < 1.0: + self.fitness[raise_at] = 1.0 + self.fitness[index] = 0.0 + + def raise_fitness(self, index): + """ + pre: 0 <= index < len(self.fitness) + post: self.fitness.count(9.0) == 1 + """ + for lower_at, fit in enumerate(self.fitness): + if 5.0 < fit: + self.fitness[lower_at] = round(self.fitness[lower_at] - 1.0) + self.fitness[index] = 9.0 + + def randomize(self): + self._state = STATE_RANDOMIZED + for protoz in self.protozoans: + protoz.randomize() + + def random(self): + """ + post: len(__return__) > 0 + post: forall(__return__, lambda x: 0 <= x < self.size) + """ + new_indices = [] + self._state = STATE_EVOLVED + good, moderate, poor = self.classify() + for new_at, protoz in enumerate(self.protozoans): + if protoz in poor: + self.protozoans[new_at].randomize() + self.fitness[new_at] = 4.0 + new_indices.append(new_at) + print 'new_indices', new_indices + return new_indices + + def breed(self): + """ + post: len(__return__) > 0 + post: forall(__return__, lambda x: 0 <= x < self.size) + """ + new_indices = [] + self._state = STATE_EVOLVED + good, moderate, poor = self.classify() + index = 0 + for new_at, protoz in enumerate(self.protozoans): + if protoz in poor: + new_one = good[0].crossingover(moderate[index % len(moderate)]) + new_one.shuffle() + new_one.mutate() + self.protozoans[new_at] = new_one + self.fitness[new_at] = 4.0 + new_indices.append(new_at) + index += 1 + print 'new_indices', new_indices + return new_indices + + def replace(self, new_one): + """Replace protozoon with lowest fitness. + pre: isinstance(new_one, model_protozoon.Protozoon) + """ + poor_level = 999999.9 + for protoz, fit in zip(self.protozoans, self.fitness): + if fit < poor_level: + poor_level = fit + poor = protoz + for new_at, protoz in enumerate(self.protozoans): + if protoz is poor: + self.protozoans[new_at] = new_one + self.fitness[new_at] = 5.0 + return new_at + return -1 + + flurry_rate = property(get_flurry_rate, set_flurry_rate) + + +def from_buffer(str_buffer): + ka_debug.info('read from_buffer') + obj = None + try: + obj = pickle.loads(str_buffer) + except: + ka_debug.err('failed reading buffer [%s] [%s]' % \ + (sys.exc_info()[0], sys.exc_info()[1])) + ka_debug.info('[%s]' % str_buffer) + return obj + +def to_buffer(obj): + ka_debug.info('write %s to_buffer' % type(obj)) + try: + return pickle.dumps(obj) + except: + ka_debug.err('failed writing buffer [%s] [%s]' % \ + (sys.exc_info()[0], sys.exc_info()[1])) + +def read_file(file_path): + model = None + if os.path.isfile(file_path): + in_file = None + try: + in_file = open(file_path, 'r') + ka_debug.info('in_file [%s]' % in_file.name) + model = pickle.load(in_file) + except: + ka_debug.err('failed reading [%s] [%s] [%s]' % \ + (in_file.name, sys.exc_info()[0], sys.exc_info()[1])) + finally: + if in_file: + in_file.close() + return model + +def write_file(file_path, model): + out_file = None + try: + out_file = open(file_path, 'w') + ka_debug.info('write out_file [%s]' % out_file.name) + pickle.dump(model, out_file) + except: + ka_debug.err('failed writing [%s] [%s] [%s]' % \ + (out_file.name, sys.exc_info()[0], sys.exc_info()[1])) + finally: + if out_file: + out_file.close() + +def all_uniqe_reference(sequ): + # Brute force is all that's left. + unique = [] + for elem in sequ: + if contains_reference(elem, unique): + return False + else: + unique.append(elem) + return len(unique) == len(sequ) + +def contains_reference(find_elem, sequ): + for elem in sequ: + if id(find_elem) == id(elem): + return True + return False + |