Permalink
Switch branches/tags
Nothing to show
Find file Copy path
Fetching contributors…
Cannot retrieve contributors at this time
747 lines (675 sloc) 32.7 KB
# simulation setup and simulation objects
# WORST SPAGETTI CODE EVER!
from __future__ import generators # retain python 2.2 compatibility
import copy, re
from PyPlotter import Gfx, Colors
from PopulationDynamics import Dynamics
import PrisonersDilemma as PD
from Strategies import *
from PolymorphicStrategies import PolymorphicStrategy
import GroupSelection as GS
from PopulationDynamics.Compatibility import *
from Logging import H1,H2,H3, H1X,H2X,H3X, LogNotificationInterface, HTMLLog
NUM_GENERATIONS = 50 # number of generations to start with in the
# population dynamical simulation
NUM_SAMPLES = PD.NUM_SAMPLES # Samples to take of a match if randomizing
# strategies or in game noise is involved
NUM_ITERATIONS = PD.NUM_ITERATIONS # number of rounds in the reiterated PD
NO_GRAPH_OPTIMIZATION = False # graph drawing will be slowed down but
# accuracy is increased (for printing and saving)
FLUSH_CACHE = True # flush the cache when a new simulation is started
###############################################################################
#
# Deme class for group selection that takes into account all parameters
# from the simulation setup.
#
###############################################################################
class RichPDDeme(GS.PDDeme):
"""A Deme where the species represent stategies in the reiterated
two person prisoner's dilemma. Other than GS.PDDeme, RichPDDeme
takes all simulation parameters into account.
Attributes:
mutators: customized list of mutators for this deme
setup: the parameters of the simulation
fF : fitness function
"""
def __init__(self, setup, name="", species_override = None,
distribution_or = None):
if species_override == None: species_override = setup.strategyList
if distribution_or == None: distribution_or = setup.population
# assert GS.check_instances(species_override, Strategy),\
# "All species must be prisoner's dilemma strategies!"
self.mutators = []
for m in setup.mutators:
if m.rate > 0.0:
mt = m.transform(setup.strategyList, species_override)
if mt.mutated == len(species_override):
species_override = species_override + \
[setup.strategyList[m.mutated]]
distribution_or = array(list(distribution_or) + [0.0])
self.mutators.append(mt)
GS.PDDeme.__init__(self, species_override, distribution_or, name)
self.setup = setup
# self.payoff = None
if self.setup.correlation:
self.fF = lambda d,p: Dynamics.Fitness2(d,p,self.setup.correlation)
else: self.fF = Dynamics.QuickFitness2
def new(self, species, distribution = None, name=""):
return self.__class__(self.setup, name, species, distribution)
def container(self, demes, distribution, name=""):
return RichSuperDeme(self.setup, name, demes, distribution)
def merged(self, *others):
"""Retruns a copy of the deme that is merged with a sequence of
other demes. The species and distribution arrays of the new
deme have the same order as setup.strategyList!"""
species_dict = {}; share_dict = {}
for deme in (self,)+others:
for i in xrange(len(deme.species)):
species = deme.species[i]
name = str(species)
if species_dict.has_key(name):
share_dict[name] += deme.distribution[i]
else:
species_dict[name] = species
share_dict[name] = deme.distribution[i]
species = [s for s in self.setup.strategyList \
if species_dict.has_key(s.name)] # keep species order!
dist = array([share_dict[s.name] for s in species])
return self.new(species, dist)
def _fitness(self):
if self.polymorphic:
self.payoff = self.setup.genReducedPayoffMatrix(self.species)
elif self.payoff == None:
self.payoff = self.setup.derivePayoffMatrix(self.species)
return self.fF(self.distribution, self.payoff)
def replicate(self):
if self.setup.noise:
p = Dynamics.Replicator(self.distribution, self.fitness(),
self.setup.noise)
else:
p = Dynamics.QuickReplicator(self.distribution, self.fitness())
if self.mutators: p = mutation(asarray(p), self.mutators)
self.distribution = asarray(p)
self.evolution()
def evolution(self):
"""Lets the polymorphic strategies evolve, in case there are any."""
for s in self.species:
if isinstance(s, PolymorphicStrategy):
s.evolve(self)
class RichSuperDeme(GS.SuperDeme):
"""A super deme that takes into account all simulation parameters,
like evolutionary noise etc.
Attributes:
setup: the simulation parameters
rF: replicator function
"""
def __init__(self, setup, name="", species_override = None,
distribution_or = None):
if species_override == None: species_override = setup.strategyList
if distribution_or == None: distribution_or = setup.population
GS.SuperDeme.__init__(self, species_override, distribution_or, name)
self.setup = setup
if self.setup.noise:
self.rF = lambda d,f: Dynamics.Replicator(d, f, self.setup.noise)
else: self.rF = Dynamics.QuickReplicator
def new(self, species, distribution = None, name=""):
return self.__class__(self.setup, name, species, distribution)
def container(self, demes, distribution, name=""):
return self.__class__(self.setup, name, demes, distribution)
def replicate(self):
#for d in self.species:
# if isinstance(d, GS.Deme): d.replicate()
for d in self.species: d.replicate() # species should be demes anyway!
self.distribution = self.rF(self.distribution, self.fitness())
###############################################################################
#
# classes for the description of simulation setups
#
###############################################################################
class Mutator(object):
"""Describes the mutation of a strategy in the simulation.
original = int: the ordinal number of the strategy that is going
to mutate
mutated = int: the ordinal number of the startegy that 'original' is
going to mutate into
rate = float [0.0 - 1.0]: mutation rate
"""
def __eq__(self, other):
if not isinstance(other, Mutator): return False
if self.original != other.original: return False
if self.mutated != other.mutated: return False
if self.rate != other.rate: return False
return True
def __init__(self, original, mutated, rate=0.01):
self.original = original
self.mutated = mutated
self.rate = rate
def transform(self, src, dst):
"""Returns a new mutator, adjusted for strategy set 'dst', assumed
that self is adjusted for strategy set 'src'.
Usually this entails only adjustments of the indices m.original
and m.mutated to the new list. Special cases occur, when the
strategies indexed by either m.original or m.mutated are not included
in dst. If m.mutated is not in dst, then mutated is set to
len(dst). If m.original is not in dst, then rate is set to 0.0.
"""
original, mutated, rate = self.original, self.mutated, self.rate
d = {}
for i in xrange(len(dst)): d[dst[i].name] = i
original_name = src[self.original].name
mutated_name = src[self.mutated].name
if d.has_key(original_name): original = d[original_name]
else: rate = 0.0
if d.has_key(mutated_name): mutated = d[mutated_name]
else: mutated = len(dst)
return Mutator(original, mutated, rate)
def mutation(population, mutatorList):
"""Apply mutation to a population"""
p = population.copy()
for m in mutatorList:
x = population[m.original] * m.rate
p[m.original] -= x
p[m.mutated] += x
return p
class DemeDescriptor(object):
"""Describes the deme structure of the simulation.
num = number of demes
minSize,
maxSize = minimum and maximum size of the demes
interval = how many generations it takes, until demes are reshaped
"""
def __eq__(self, other):
if not isinstance(other, DemeDescriptor): return False
if self.num != other.num or self.minSize != other.minSize or \
self.maxSize != other.maxSize or self.interval != other.inverval:
return False
return True
def __init__(self, num, minSize, maxSize, reshapeInterval):
self.num = num
self.minSize = minSize
self.maxSize = maxSize
self.interval = reshapeInterval
def verify(self, popsize):
"""-> sufficient demes for population size."""
return self.minSize * self.num >= popsize
def asTuple(self):
"""-> (num, minSize, maxSize, interval)."""
return (self.num, self.minSize, self.maxSize, self.interval)
class SimSetup(object):
"""Contains all data defining a simulation.
name = string: name of the model
strategyList = list of Strategy objects: the list of the strategies
population = tuple: population share for each strategy
correlation = float [0.0-1.0]: correlation factor
gameNoise = float [0.0-1.0]: in game noise
noise = float [0.0-1.0]: evolutionary background noise
iterations = int: number of iterations for one match
samples = int: number of sample matches to take (only useful for
randomizing strategies)
payoff = tuple of floats: payoff tuple (T, R, P, S)
demes = DemeDescriptor: defines the deme structure of the
population, or 'None' if there are no demes
mutators = list of Mutator objects: description of possible
mutation of strategies during the course of the
evolutionary development.
indexDict = dictionary of strategy indices indexed by strategy names
cachedPM = cached payoff matrix
cachedLog = cached tournament log object
"""
def __eq__(self, other):
if not isinstance(other, SimSetup): return False
# names make no difference! if self.name != other.name: return False
if len(self.strategyList) != len(other.strategyList):
return False
for i in xrange(len(self.strategyList)):
if self.strategyList[i] != other.strategyList[i]: return False
if tuple(self.population) != tuple(other.population): return False
if self.correlation != other.correlation: return False
if self.gameNoise != other.gameNoise: return False
if self.noise != other.noise: return False
if self.iterations != other.iterations: return False
if self.samples != other.samples: return False
if self.payoff != other.payoff: return False
if len(self.mutators) != len(other.mutators):
return False
if self.demes != other.demes: return False
for i in xrange(len(self.mutators)):
if self.mutators[i] != other.mutators[i]: return False
return True
## def __setattr__(self, name, value):
## object.__setattr__(self, name, value)
## if name == "population":
## assert len(value) == len(self.strategyList),
## "population vector does not match length of strategy list!"
## elif name == "strategyList":
## if len(value) != len(self.population):
## obejct.__setattr__(self, "population",
## Dynamics.UniformDistribution(len(value)))
def __init__(self, name, strategyList = [], population = None,
correlation = 0.0, gameNoise = 0.0, noise = 0.0,
iterations = NUM_ITERATIONS, samples = NUM_SAMPLES, payoff = (5.,3.,1.,0.),
demes = None, mutators = [], PM = None, log = None):
self.name = name
self.strategyList = strategyList
if population == None:
self.population = Dynamics.UniformDistribution(len(self.strategyList))
else: self.population = array(population)
self.correlation = correlation
self.gameNoise = gameNoise
self.noise = noise
self.iterations = iterations
self.samples = samples
self.__payoff = payoff; p = payoff
self._payoffArray = array([[[p[2],p[2]],[p[0],p[3]]],
[[p[3],p[0]],[p[1],p[1]]]])
self.mutators = mutators
if demes:
if not isinstance(demes, DemeDescriptor): # assume demes is a 4-tuple
demes = DemeDescriptor(*demes)
assert demes.verify(len(strategyList)), \
"Not enough demes or demes too small for population!"
self.demes = demes
self.indexDict = None
self.cachedPM = PM
self.cachedLog = log
self._userDefined = True # SimApp marks its own setups as False
def getPayoff(self):
return self.__payoff
def setPayoff(self, p):
self.__payoff = p
self._payoffArray = array([[[p[2],p[2]],[p[0],p[3]]],
[[p[3],p[0]],[p[1],p[1]]]])
payoff = property(getPayoff, setPayoff)
def fname(self):
"""Returns the name of the setup as a proper file name."""
return self.name.replace("*","x").replace("?","x").replace("/","x")\
.replace("\\","x").replace(" ","_")
def getPayoffMatrix(self, log = None, progressCallback = lambda f:1):
"""Returns the payoff matrix for the setup."""
if self.cachedPM == None:
self.cachedPM = PD.GenPayoffMatrix(self.strategyList,
self._payoffArray, self.iterations, self.samples, self.gameNoise,
log, progressCallback)
return self.cachedPM
def genReducedPayoffMatrix(self, strategies):
"""Returns a payoff matrix for the subset 'strategies' of the
strategyList only. The payoff matrix is always freshly generated."""
return PD.GenPayoffMatrix(strategies, self._payoffArray,
self.iterations, self.samples,
self.gameNoise)
def derivePayoffMatrix(self, strategies):
"""Returns a payoff matrix for the subset 'strategies' of the
strategyList only."""
if self.indexDict == None:
self.indexDict = {}
for i in xrange(len(self.strategyList)):
self.indexDict[self.strategyList[i].name] = i
m = self.getPayoffMatrix()
l = len(strategies)
dm = zeros((l,l),"d")
for i in xrange(l):
r = self.indexDict[strategies[i].name]
for k in xrange(l):
c = self.indexDict[strategies[k].name]
dm[i,k] = m[r,c]
return dm
def htmlRepresentation(self):
"""Returns extensive information about this setup in HTML format."""
def rr(s):
"replace trailing zeros with blanks"
l = len(s); s2 = s.rstrip("0")
return (s2 + " "*(l - len(s2)))
html = ["<p>" + H2 + '<a name="setup"></a>Simulation setup of ' + \
self.name + H2X + "<br />\n\n"]
## t = "<b>Strategies:</b> "
## for s in self.strategyList:
## t += str(s)
## if len(t) >= 70:
## t += "<br />\n"; html.append(t); t = ""
## else: t += ", "
## if t != "": html.append(t[:-2]+"<br />\n")
html.append("<b>Strategies:</b> ")
snames = [str(s) for s in self.strategyList]
html.append(", ".join(snames))
html.append("<br /><br />\n\n<tt>")
p0 = self.population[0]; scale = 1.0/(1000*len(self.population))
for p in self.population:
if abs(p - p0) > scale:
pop = [rr("%1.5f"%s) for s in self.population]
lines = [", ".join(pop[i:i+5]) for i in xrange(0,len(pop),5)]
html.append("<b>population shares:</b><br />\n")
html.append("<br />\n".join(lines))
html.append("<br /><br />\n\n")
break
else:
html.append("uniform population distribution<br />\n")
if self.demes != None:
html.append("%i demes with sizes varying from %i to %i.<br />\n" % \
(self.demes.num, self.demes.minSize, self.demes.maxSize))
if self.demes.interval == 1:
html.append("Population is reshaped every generation<br /><br />\n\n")
else:
html.append("Population is reshaped every %i generations<br /><br />\n\n" % \
self.demes.interval)
else: html.append("<br />\n")
if self.mutators != []:
html.append("<b>mutations:</b><br />\n")
for d in self.mutators:
s1 = str(self.strategyList[d.original])
s2 = str(self.strategyList[d.mutated])
s1 += "&nbsp;" * max(20-len(s1), 1)
s2 += "&nbsp;" * max(20-len(s2), 1)
html.append(s1 + "=>&nbsp;" + s2 + "&nbsp;" + \
("%1.5f" % d.rate).rstrip("0") + "<br />\n")
html.append("<br />\n")
if self.correlation != 0.0:
html.append("correlation:"+"&nbsp;"*8+"%f<br />\n"%self.correlation)
if self.gameNoise != 0.0:
html.append("game Noise:"+"&nbsp;"*9+"%f<br />\n"%self.gameNoise)
if self.noise != 0.0:
html.append("evolutionary Noise:&nbsp;%f<br />\n"%self.noise)
html.append("payoff parameters:&nbsp;T,R,P,S = "+\
"%.2f, %.2f, %.2f, %.2f"%self.payoff + "<br />\n")
html.append("iterations:"+"&nbsp;"*9+"%i<br />\n"%self.iterations)
if self.gameNoise > 0.0 or \
reduce(lambda a,b: a or b.randomizing, self.strategyList, True):
html.append("match samples:"+"&nbsp;"*6+"%i<br />\n"%self.samples)
html.append("</tt></p>\n")
return "".join(html)
###############################################################################
#
# Simulation class
#
###############################################################################
# generator functions to optimize graph drawing
class xaxisIter(object):
"""-> iterate over virtual x-coordinates with one point for
each screen pixel.
"""
def __init__(self, graph, x1, x2):
self.graph = graph
a = self.graph._scaleX(x1); b = self.graph._scaleX(x2)
self.rngIter = xrange(a, b+2).__iter__()
self.pos = self.graph._invX(self.rngIter.next())
def check(self, x):
if x >= self.pos:
try:
self.pos = self.graph._invX(self.rngIter.next())
except StopIteration:
pass # actually this should never happen, catching it anyway!
return True
else: return NO_GRAPH_OPTIMIZATION
NORMAL_CAPTION_PEN = Gfx.BLACK_PEN
SMALL_CAPTION_PEN = Gfx.Pen(color = Gfx.BLACK, fsize = Gfx.SMALL)
class Simulation(object):
"""The simulation class is responsible for running a simulation
and produing an output of the results in graphical form as well
as as html log.
Attributes:
graph : A Graph.Cartesian object for the graphical representation
of the population dynamics
simlpex : A Simplex.Diagram object for producing a simplex
diagram of the population dynamics (only if exactly
three strategies are present in the simulation!)
notifier : A Logging.LogNotificationInterface for communicating
the progress of the simulation to the GUI
log : A Logging.HTMLLog for logging the simulation results
setup : A copy (!) of the simulation setup.
masterDeme : The "root" of the population structure. If the population
is not divided into different demes, then 'masterDeme'
contains only one subdeme with the whole population
simplexMD : Master Deme for the simplex representation
payoffMatrix: The payoff matrix of the tournament part of the
simulation
rangeStack : Sequence of the respective range parameters of the
simulation graph (x1,y1,x2,y2), one for each call
of the method 'continueSim'
imgDirName : Name of the directory to write the images of the html
log to (only if the log is actually saved to disk!)
simplexName : file name of the simplex graph, if the html log is saved
firstGeneration: the first generation to start the next population
dynamical cycle with (when calling continueSim)
lastGeneration: the last generation of the next cycle
numStgies : number of Strategies
bestStgies : 3-tuple: the numbers of the three strategies with the
greatest population share.
updateSimplexFlag: simplex data has changes and simplex needs to be
updated.
"""
def __init__(self, graph, simplex, log, notifier):
self.graph = graph
self.simplex = simplex
self.notifier = notifier
self.log = log
self.setup = None
self.masterDeme = None
self.simplexMD = None
self.payoffMatrix = None
self.rangeStack = []
self.imgdirName = ""
self.simplexName = ""
self.firstGeneration = 1
self.lastGeneration = NUM_GENERATIONS
self.numStgies = 0
self.bestStgies = (0,0,0)
self.updateSimplexFlag = False
self._dontLogTwiceFlag = False
def _prepareEvLog(self):
if not self._alreadyLogged:
self._alreadyLogged = True
self.imgdirName = self.setup.fname() + "_images"
if PD.MATCH_LOG_OUTSOURCED: nr = "3"
else: nr = "4"
self.log.appendAt("toc", '<a href="#evranking">' + nr + \
'. Evolutionary Simulation</a><br />\n')
self.log.append(H2 + \
'<a name="evranking"></a>Evolutionary Simulation:' + \
H2X + "<br />\n\n")
if len(self.setup.strategyList) == 3:
self.simplexName = self.setup.fname() + "_simplex"
path = self.imgdirName + "/" + self.simplexName
self.log.append('<div align="center">' + \
'<a href="'+path+'.png">' + \
'<img src="'+path+'_web.png" alt="Image: '+\
self.simplexName + '.png not found!" />' + \
'</a></div><br /><br />\n')
self.log.entryPoint("evranking")
def createMasterDeme(self, population_override = None):
if population_override == None:
population_override = self.setup.population
if self.setup.demes:
md = RichPDDeme(self.setup, distribution_or=population_override).\
spawn(self.setup.demes.num, self.setup.demes.minSize,
self.setup.demes.maxSize)
md.counter = self.setup.demes.interval
else:
md = RichPDDeme(self.setup, distribution_or=population_override)
md.counter = -1
return md
def dynamics(self, masterDeme):
if masterDeme.counter == 0:
masterDeme.reshape(self.setup.demes.num,
self.setup.demes.minSize,
self.setup.demes.maxSize)
masterDeme.counter = self.setup.demes.interval
masterDeme.replicate()
masterDeme.counter -= 1
## s=self.masterDeme.aggregate().species
## assert s == self.setup.strategyList, "order of species changed!"
return masterDeme.aggregate().distribution
def simplexDynamics(self, population):
if self.simplexMD == None or \
isinstance(self.simplexMD, GS.SuperDeme) or \
any(self.simplexMD.distribution != population):
self.simplexMD = self.createMasterDeme(population)
return self.dynamics(self.simplexMD)
def extendedDynamics(self, population):
realP = [0.0] * self.numStgies
realP[self.bestStgies[0]] = population[0]
realP[self.bestStgies[1]] = population[1]
realP[self.bestStgies[2]] = population[2]
realP = self.simplexDynamics(tuple(realP))
return (realP[self.bestStgies[0]],
realP[self.bestStgies[1]],
realP[self.bestStgies[2]])
def _bestT(self):
"""-> (n,m) best and second best strategy in the tournament."""
M = self.payoffMatrix
l = [(sum(M[i]),i) for i in xrange(self.numStgies)]
l.sort(reverse=True)
return (l[0][1], l[1][1], l[2][1])
def _bestP(self):
"""-> (n,m) best and second best strategy populationwise."""
l = [(self.setup.population[i], i) for i in xrange(self.numStgies)]
l.sort(reverse=True)
return (l[0][1], l[1][1], l[2][1])
def newSetup(self, setup, progressCallback = lambda f:1):
self._alreadyLogged = False
self.setup = copy.copy(setup)
for s in self.setup.strategyList: s.register(self.setup)
self.firstGeneration = 1;
self.lastGeneration = NUM_GENERATIONS
if FLUSH_CACHE:
PD.cache.flush()
self.setup.cachedPM = None; setup.cachedPM = None
self.setup.cachedLog = None; setup.cachedLog = None
if self.setup.cachedPM == None:
self.log.clear()
self.log.pageTitle(self.setup.name)
self.log.append(H1+'<a name="top"></a>CoopSim - Simulation: '+\
self.setup.name + H1X + "\n\n")
self.log.entryPoint("title")
self.log.append(H2+'<a name="toc"></a>Table of Contents'+ \
H2X + "\n\n<p>")
self.log.append('<a href="#setup">0. Simulation Setup</a><br />\n')
self.log.entryPoint("toc")
self.log.append("</p><br />\n")
self.log.append(setup.htmlRepresentation())
self.log.append('<div align="right"><a href="#top">[top]' + \
'</a></div><br />\n')
self.payoffMatrix = setup.getPayoffMatrix(self.log,
progressCallback)
setup.cachedPM = self.payoffMatrix
self.setup.cachedPM = setup.cachedPM
setup.cachedLog = self.log.backup()
self.setup.cachedLog = setup.cachedLog
else:
self.payoffMatrix = self.setup.cachedPM
self.log.replay(self.setup.cachedLog)
self.notifier.updateLog(self.log.getHTMLPage())
self.masterDeme = None; self.simplexMD = None
ysize = 1.0 / max(1.0, len(self.setup.strategyList)-1)
self.graph.reset(0, 0.0, self.lastGeneration, ysize)
self.rangeStack = []
i = 0
for s in self.setup.strategyList:
if Colors.colors[i] == (1.0, 1.0, 0.0): i += 1
self.graph.addPen(str(s), Gfx.Pen(Colors.colors[i], Gfx.MEDIUM),
False)
i += 1
if i > len(Colors.colors): i = 0
self.graph.setTitle('Population dynamics of "'+self.setup.name+'"')
if len(self.setup.strategyList) > 10:
self.graph.setStyle(captionPen = SMALL_CAPTION_PEN, redraw = False)
else:
self.graph.setStyle(captionPen = NORMAL_CAPTION_PEN, redraw = False)
self.graph.redrawCaption()
self.numStgies = len(self.setup.strategyList)
self.simplex.setTitle('Simplex diagram of "'+self.setup.name+'"')
if self.numStgies == 3:
self.simplex.setFunction(self.simplexDynamics)
self.simplex.setLabels(str(self.setup.strategyList[0]),
str(self.setup.strategyList[1]),
str(self.setup.strategyList[2]))
elif self.numStgies > 3:
#self.simplex.setTitle("Too many strategies for " + \
# "a simplex diagram!")
self.bestStgies = self._bestT()
self.simplex.setFunction(self.extendedDynamics)
sl = self.setup.strategyList
self.simplex.setLabels(str(sl[self.bestStgies[0]]),
str(sl[self.bestStgies[1]]),
str(sl[self.bestStgies[2]]))
else:
self.simplex.setFunction(lambda p:p)
self.simplex.setTitle("Too few strategies for "\
"a simplex diagram!")
self.simplex.setLabels("","","")
self._prepareEvLog()
def continueSim(self, record = None, refreshCallback = lambda :1,
withSimplex = True):
if self.setup == None: return
self.notifier.statusBarHint("Running...")
self.updateSimplexFlag = False
if self.firstGeneration > 1:
self.graph.adjustRange(0, 0.0, self.lastGeneration, self.graph.y2)
if self.numStgies > 3:
oldBest = set(self.bestStgies)
self.bestStgies = self._bestP()
if oldBest != set(self.bestStgies):
self.simplex.setFunction(self.extendedDynamics)
sl = self.setup.strategyList
self.simplex.setLabels(str(sl[self.bestStgies[0]]),
str(sl[self.bestStgies[1]]),
str(sl[self.bestStgies[2]]))
if withSimplex: self.simplex.show()
else: self.updateSimplexFlag = True
else:
k = 0
for s in self.setup.strategyList:
self.graph.addValue(str(s), 0, self.setup.population[k])
k += 1
if withSimplex: self.simplex.show()
else: self. updateSimplexFlag = True
self.masterDeme = self.createMasterDeme()
pixelSteps = xaxisIter(self.graph, self.firstGeneration,
self.lastGeneration)
refreshTicker = (self.lastGeneration + 1 - self.firstGeneration) / 10
for i in xrange(self.firstGeneration, self.lastGeneration+1):
p = self.dynamics(self.masterDeme)
if pixelSteps.check(i):
k = 0
for s in self.setup.strategyList:
self.graph.addValue(str(s), i, p[k])
k += 1
if i % refreshTicker == 0: refreshCallback()
# if i % 120 == 0: self.notifier.SafeYield()
if record: record.append(p)
self.setup.population = p
self._prepareEvLog()
anchor = "generation%i" % self.lastGeneration
linkstr = '&nbsp;&nbsp;&nbsp;&nbsp;<a href="#'+anchor+'">'+ \
'Ranking after %i generations</a>' % \
self.lastGeneration + "<br />\n"
self.log.appendAt("toc", linkstr)
self.log.appendAt("evranking", re.sub("&nbsp;","",linkstr))
self.log.append("\n"+H3+'<a name="'+anchor+'"></a>' +\
"Ranking after %i generations:" % \
self.lastGeneration + H3X + "<br />\n\n<p><pre>")
ranking = zip(self.setup.population,
Dynamics.QuickFitness2(self.setup.population, self.payoffMatrix),
[str(s) for s in self.setup.strategyList])
ranking.sort(); ranking.reverse()
k = 1
for r, f, name in ranking:
s = "%3i." % k + name + " "*max(40-len(name),1) + \
"%1.4f "%r + "(%1.4f)"%f + "\n" # repr(r) + "\n"
self.log.append(s)
k += 1
self.log.append("</pre><br />\n")
imgName = self.setup.fname() + "_gn%i" % self.lastGeneration
path = self.imgdirName + "/" + imgName
self.log.append('<div align="center">'+\
'<a href="' + path + '.png">' + \
'<img src="'+path+'_web.png"'+'" alt="Image: ' + \
imgName + '.png not found!" /></a></div><br />\n')
self.log.append("</p>\n")
self.log.append('<div align="right"><a href="#top">[top]' + \
'</a></div><br />\n')
self.rangeStack.append((imgName, self.graph.x1, self.graph.y1,
self.graph.x2, min(self.graph.y2, 1.0)))
self.notifier.updateLog(self.log.getHTMLPage())
if self.firstGeneration <= 1: self.notifier.logToStart()
self.firstGeneration = self.lastGeneration + 1
self.lastGeneration = self.lastGeneration * 2
self.notifier.statusBarHint("Ready.")