From 8018d7b7ea3aaf0204843820ad2528a7214d468a Mon Sep 17 00:00:00 2001 From: yugangzhang Date: Fri, 6 Jul 2018 17:42:35 -0400 Subject: [PATCH 01/10] Update to python3.3.6 --- pyevolve/Consts.py | 12 ++-- pyevolve/Crossovers.py | 38 +++++----- pyevolve/DBAdapters.py | 26 +++---- pyevolve/FunctionSlot.py | 8 +-- pyevolve/G1DBinaryString.py | 6 +- pyevolve/G1DList.py | 10 +-- pyevolve/G2DBinaryString.py | 12 ++-- pyevolve/G2DList.py | 10 +-- pyevolve/GAllele.py | 6 +- pyevolve/GPopulation.py | 28 ++++---- pyevolve/GSimpleGA.py | 50 ++++++------- pyevolve/GTree.py | 30 ++++---- pyevolve/GenomeBase.py | 12 ++-- pyevolve/Initializators.py | 28 ++++---- pyevolve/Interaction.py | 4 +- pyevolve/Migration.py | 14 ++-- pyevolve/Mutators.py | 138 ++++++++++++++++++------------------ pyevolve/Network.py | 22 +++--- pyevolve/Scaling.py | 18 ++--- pyevolve/Selectors.py | 32 ++++----- pyevolve/Statistics.py | 6 +- pyevolve/Util.py | 14 ++-- 22 files changed, 262 insertions(+), 262 deletions(-) diff --git a/pyevolve/Consts.py b/pyevolve/Consts.py index f1442cd..473cfaa 100644 --- a/pyevolve/Consts.py +++ b/pyevolve/Consts.py @@ -366,13 +366,13 @@ """ -import Scaling -import Selectors -import Initializators -import Mutators -import Crossovers +from . import Scaling +from . import Selectors +from . import Initializators +from . import Mutators +from . import Crossovers import logging -from GTree import GTreeGP +from .GTree import GTreeGP # Required python version 2.5+ CDefPythonRequire = (2, 5) diff --git a/pyevolve/Crossovers.py b/pyevolve/Crossovers.py index 7584a00..af81ef4 100644 --- a/pyevolve/Crossovers.py +++ b/pyevolve/Crossovers.py @@ -10,8 +10,8 @@ from random import randint as rand_randint, choice as rand_choice from random import random as rand_random import math -import Util -import Consts +from . import Util +from . import Consts ############################# ## 1D Binary String ## @@ -88,7 +88,7 @@ def G1DBinaryStringXUniform(genome, **args): sister.resetStats() brother.resetStats() - for i in xrange(len(gMom)): + for i in range(len(gMom)): if Util.randomFlipCoin(Consts.CDefG1DBinaryStringUniformProb): temp = sister[i] sister[i] = brother[i] @@ -175,7 +175,7 @@ def G1DListCrossoverUniform(genome, **args): sister.resetStats() brother.resetStats() - for i in xrange(len(gMom)): + for i in range(len(gMom)): if Util.randomFlipCoin(Consts.CDefG1DListCrossUniformProb): temp = sister[i] sister[i] = brother[i] @@ -231,7 +231,7 @@ def G1DListCrossoverEdge(genome, **args): for c, u in (sisterl, set(gMom)), (brotherl, set(gDad)): curr = None - for i in xrange(len(gMom)): + for i in range(len(gMom)): curr = rand_choice(tuple(u)) if not curr else curr c.append(curr) u.remove(curr) @@ -393,8 +393,8 @@ def G2DListCrossoverUniform(genome, **args): h, w = gMom.getSize() - for i in xrange(h): - for j in xrange(w): + for i in range(h): + for j in range(w): if Util.randomFlipCoin(Consts.CDefG2DListCrossUniformProb): temp = sister.getItem(i, j) sister.setItem(i, j, brother.getItem(i, j)) @@ -415,13 +415,13 @@ def G2DListCrossoverSingleVPoint(genome, **args): if args["count"] >= 1: sister = gMom.clone() sister.resetStats() - for i in xrange(sister.getHeight()): + for i in range(sister.getHeight()): sister[i][cut:] = gDad[i][cut:] if args["count"] == 2: brother = gDad.clone() brother.resetStats() - for i in xrange(brother.getHeight()): + for i in range(brother.getHeight()): brother[i][cut:] = gMom[i][cut:] return (sister, brother) @@ -438,13 +438,13 @@ def G2DListCrossoverSingleHPoint(genome, **args): if args["count"] >= 1: sister = gMom.clone() sister.resetStats() - for i in xrange(cut, sister.getHeight()): + for i in range(cut, sister.getHeight()): sister[i][:] = gDad[i][:] if args["count"] == 2: brother = gDad.clone() brother.resetStats() - for i in xrange(brother.getHeight()): + for i in range(brother.getHeight()): brother[i][:] = gMom[i][:] return (sister, brother) @@ -473,8 +473,8 @@ def G2DBinaryStringXUniform(genome, **args): h, w = gMom.getSize() - for i in xrange(h): - for j in xrange(w): + for i in range(h): + for j in range(w): if Util.randomFlipCoin(Consts.CDefG2DBinaryStringUniformProb): temp = sister.getItem(i, j) sister.setItem(i, j, brother.getItem(i, j)) @@ -499,13 +499,13 @@ def G2DBinaryStringXSingleVPoint(genome, **args): if args["count"] >= 1: sister = gMom.clone() sister.resetStats() - for i in xrange(sister.getHeight()): + for i in range(sister.getHeight()): sister[i][cut:] = gDad[i][cut:] if args["count"] == 2: brother = gDad.clone() brother.resetStats() - for i in xrange(brother.getHeight()): + for i in range(brother.getHeight()): brother[i][cut:] = gMom[i][cut:] return (sister, brother) @@ -527,13 +527,13 @@ def G2DBinaryStringXSingleHPoint(genome, **args): if args["count"] >= 1: sister = gMom.clone() sister.resetStats() - for i in xrange(cut, sister.getHeight()): + for i in range(cut, sister.getHeight()): sister[i][:] = gDad[i][:] if args["count"] == 2: brother = gDad.clone() brother.resetStats() - for i in xrange(brother.getHeight()): + for i in range(brother.getHeight()): brother[i][:] = gMom[i][:] return (sister, brother) @@ -640,7 +640,7 @@ def GTreeCrossoverSinglePointStrict(genome, **args): momRandom = None dadRandom = None - for i in xrange(max_attempt): + for i in range(max_attempt): if distr_leaf is None: dadRandom = gDad.getRandomNode() @@ -738,7 +738,7 @@ def GTreeGPCrossoverSinglePoint(genome, **args): momRandom = None dadRandom = None - for i in xrange(max_attempt): + for i in range(max_attempt): dadRandom = gDad.getRandomNode() diff --git a/pyevolve/DBAdapters.py b/pyevolve/DBAdapters.py index 63a4a35..e5fcbf2 100644 --- a/pyevolve/DBAdapters.py +++ b/pyevolve/DBAdapters.py @@ -18,12 +18,12 @@ """ from pyevolve import __version__ -import Consts -import Util +from . import Consts +from . import Util import logging import types import datetime -import Statistics +from . import Statistics class DBBaseAdapter(object): @@ -293,7 +293,7 @@ def __init__(self, dbname=Consts.CDefSQLiteDBName, identify=None, resetDB=False, self.resetDB = resetDB self.resetIdentify = resetIdentify self.dbName = dbname - self.typeDict = {types.FloatType: "real"} + self.typeDict = {float: "real"} self.cursorPool = None self.commitFreq = commit_freq @@ -366,7 +366,7 @@ def createStructure(self, stats): """ c = self.getCursor() pstmt = "create table if not exists %s(identify text, generation integer, " % (Consts.CDefSQLiteDBTable) - for k, v in stats.items(): + for k, v in list(stats.items()): pstmt += "%s %s, " % (k, self.typeDict[type(v)]) pstmt = pstmt[:-2] + ")" logging.debug("Creating table %s: %s.", Consts.CDefSQLiteDBTable, pstmt) @@ -388,9 +388,9 @@ def resetTableIdentify(self): try: c.execute(stmt, (self.getIdentify(),)) c.execute(stmt2, (self.getIdentify(),)) - except self.sqlite3mod.OperationalError, expt: + except self.sqlite3mod.OperationalError as expt: if str(expt).find("no such table") >= 0: - print "\n ## The DB Adapter can't find the tables ! Consider enable the parameter resetDB ! ##\n" + print("\n ## The DB Adapter can't find the tables ! Consider enable the parameter resetDB ! ##\n") self.commit() @@ -421,14 +421,14 @@ def insert(self, ga_engine): c = self.getCursor() pstmt = "insert into %s values (?, ?, " % (Consts.CDefSQLiteDBTable) - for i in xrange(len(stats)): + for i in range(len(stats)): pstmt += "?, " pstmt = pstmt[:-2] + ")" c.execute(pstmt, (self.getIdentify(), generation) + stats.asTuple()) pstmt = "insert into %s values(?, ?, ?, ?, ?)" % (Consts.CDefSQLiteDBTablePop,) tups = [] - for i in xrange(len(population)): + for i in range(len(population)): ind = population[i] tups.append((self.getIdentify(), generation, i, ind.fitness, ind.score)) @@ -648,7 +648,7 @@ def __init__(self, user, passwd, host=Consts.CDefMySQLDBHost, port=Consts.CDefMy self.port = port self.user = user self.passwd = passwd - self.typeDict = {types.FloatType: "DOUBLE(14,6)"} + self.typeDict = {float: "DOUBLE(14,6)"} self.cursorPool = None self.commitFreq = commit_freq @@ -722,7 +722,7 @@ def createStructure(self, stats): """ c = self.getCursor() pstmt = "create table if not exists %s(identify VARCHAR(80), generation INTEGER, " % (Consts.CDefMySQLDBTable) - for k, v in stats.items(): + for k, v in list(stats.items()): pstmt += "%s %s, " % (k, self.typeDict[type(v)]) pstmt = pstmt[:-2] + ")" logging.debug("Creating table %s: %s.", Consts.CDefSQLiteDBTable, pstmt) @@ -773,7 +773,7 @@ def insert(self, ga_engine): c = self.getCursor() pstmt = "insert into " + Consts.CDefMySQLDBTable + " values (%s, %s, " - for i in xrange(len(stats)): + for i in range(len(stats)): pstmt += "%s, " pstmt = pstmt[:-2] + ")" c.execute(pstmt, (self.getIdentify(), generation) + stats.asTuple()) @@ -781,7 +781,7 @@ def insert(self, ga_engine): pstmt = "insert into " + Consts.CDefMySQLDBTablePop + " values(%s, %s, %s, %s, %s)" tups = [] - for i in xrange(len(population)): + for i in range(len(population)): ind = population[i] tups.append((self.getIdentify(), generation, i, ind.fitness, ind.score)) diff --git a/pyevolve/FunctionSlot.py b/pyevolve/FunctionSlot.py index e5145e0..ccf4a5b 100644 --- a/pyevolve/FunctionSlot.py +++ b/pyevolve/FunctionSlot.py @@ -14,7 +14,7 @@ from random import uniform as rand_uniform from types import BooleanType -import Util +from . import Util class FunctionSlot(object): """ FunctionSlot Class - The function slot @@ -195,8 +195,8 @@ def __repr__(self): return strRet for f, w in zip(self.funcList, self.funcWeights): - strRet += "\t\tName: %s - Weight: %.2f\n" % (f.func_name, w) - if f.func_doc: - strRet += "\t\tDoc: " + f.func_doc + "\n" + strRet += "\t\tName: %s - Weight: %.2f\n" % (f.__name__, w) + if f.__doc__: + strRet += "\t\tDoc: " + f.__doc__ + "\n" return strRet diff --git a/pyevolve/G1DBinaryString.py b/pyevolve/G1DBinaryString.py index a1fb683..ec814db 100644 --- a/pyevolve/G1DBinaryString.py +++ b/pyevolve/G1DBinaryString.py @@ -34,9 +34,9 @@ """ -from GenomeBase import GenomeBase, G1DBase -import Consts -import Util +from .GenomeBase import GenomeBase, G1DBase +from . import Consts +from . import Util class G1DBinaryString(G1DBase): """ G1DBinaryString Class - The 1D Binary String chromosome diff --git a/pyevolve/G1DList.py b/pyevolve/G1DList.py index 62e487b..310ac09 100644 --- a/pyevolve/G1DList.py +++ b/pyevolve/G1DList.py @@ -34,8 +34,8 @@ ------------------------------------------------------------- """ -from GenomeBase import GenomeBase, G1DBase -import Consts +from .GenomeBase import GenomeBase, G1DBase +from . import Consts class G1DList(G1DBase): @@ -116,21 +116,21 @@ def __init__(self, size=10, cloning=False): def __mul__(self, other): """ Multiply every element of G1DList by "other" """ newObj = self.clone() - for i in xrange(len(newObj)): + for i in range(len(newObj)): newObj[i] *= other return newObj def __add__(self, other): """ Plus every element of G1DList by "other" """ newObj = self.clone() - for i in xrange(len(newObj)): + for i in range(len(newObj)): newObj[i] += other return newObj def __sub__(self, other): """ Plus every element of G1DList by "other" """ newObj = self.clone() - for i in xrange(len(newObj)): + for i in range(len(newObj)): newObj[i] -= other return newObj diff --git a/pyevolve/G2DBinaryString.py b/pyevolve/G2DBinaryString.py index 2b2bdab..39fdf62 100644 --- a/pyevolve/G2DBinaryString.py +++ b/pyevolve/G2DBinaryString.py @@ -38,9 +38,9 @@ ------------------------------------------------------------- """ -from GenomeBase import GenomeBase -import Consts -import Util +from .GenomeBase import GenomeBase +from . import Consts +from . import Util class G2DBinaryString(GenomeBase): @@ -68,7 +68,7 @@ def __init__(self, height, width): self.width = width self.genomeString = [None] * height - for i in xrange(height): + for i in range(height): self.genomeString[i] = [None] * width self.initializator.set(Consts.CDefG2DBinaryStringInit) @@ -167,7 +167,7 @@ def clearString(self): del self.genomeString[:] self.genomeString = [None] * self.height - for i in xrange(self.height): + for i in range(self.height): self.genomeString[i] = [None] * self.width def copy(self, g): @@ -182,7 +182,7 @@ def copy(self, g): GenomeBase.copy(self, g) g.height = self.height g.width = self.width - for i in xrange(self.height): + for i in range(self.height): g.genomeString[i] = self.genomeString[i][:] def clone(self): diff --git a/pyevolve/G2DList.py b/pyevolve/G2DList.py index 6c864e3..3dc0244 100644 --- a/pyevolve/G2DList.py +++ b/pyevolve/G2DList.py @@ -35,8 +35,8 @@ """ -from GenomeBase import GenomeBase -import Consts +from .GenomeBase import GenomeBase +from . import Consts class G2DList(GenomeBase): @@ -97,7 +97,7 @@ def __init__(self, height, width, cloning=False): self.width = width self.genomeList = [None] * height - for i in xrange(height): + for i in range(height): self.genomeList[i] = [None] * width if not cloning: @@ -199,7 +199,7 @@ def clearList(self): del self.genomeList[:] self.genomeList = [None] * self.height - for i in xrange(self.height): + for i in range(self.height): self.genomeList[i] = [None] * self.width def copy(self, g): @@ -214,7 +214,7 @@ def copy(self, g): GenomeBase.copy(self, g) g.height = self.height g.width = self.width - for i in xrange(self.height): + for i in range(self.height): g.genomeList[i] = self.genomeList[i][:] def clone(self): diff --git a/pyevolve/GAllele.py b/pyevolve/GAllele.py index 2012568..00bc626 100644 --- a/pyevolve/GAllele.py +++ b/pyevolve/GAllele.py @@ -9,8 +9,8 @@ class that holds the allele types) and all the """ import random -import Consts -import Util +from . import Consts +from . import Util class GAlleles(object): """ GAlleles Class - The set of alleles @@ -98,7 +98,7 @@ def __repr__(self): ret += "Allele for position 0:\n" ret += self.allele_list[0].__repr__() else: - for i in xrange(len(self)): + for i in range(len(self)): ret += "Allele for position %d:\n" % (i,) ret += self.allele_list[i].__repr__() return ret diff --git a/pyevolve/GPopulation.py b/pyevolve/GPopulation.py index 919ad18..5daa41b 100644 --- a/pyevolve/GPopulation.py +++ b/pyevolve/GPopulation.py @@ -32,10 +32,10 @@ """ -import Consts -import Util -from FunctionSlot import FunctionSlot -from Statistics import Statistics +from . import Consts +from . import Util +from .FunctionSlot import FunctionSlot +from .Statistics import Statistics from math import sqrt as math_sqrt import logging @@ -195,8 +195,8 @@ def __repr__(self): """ Returns the string representation of the population """ ret = "- GPopulation\n" ret += "\tPopulation Size:\t %d\n" % (self.popSize,) - ret += "\tSort Type:\t\t %s\n" % (Consts.sortType.keys()[Consts.sortType.values().index(self.sortType)].capitalize(),) - ret += "\tMinimax Type:\t\t %s\n" % (Consts.minimaxType.keys()[Consts.minimaxType.values().index(self.minimax)].capitalize(),) + ret += "\tSort Type:\t\t %s\n" % (list(Consts.sortType.keys())[list(Consts.sortType.values()).index(self.sortType)].capitalize(),) + ret += "\tMinimax Type:\t\t %s\n" % (list(Consts.minimaxType.keys())[list(Consts.minimaxType.values()).index(self.minimax)].capitalize(),) for slot in self.allSlots: ret += "\t" + slot.__repr__() ret += "\n" @@ -242,7 +242,7 @@ def statistics(self): raw_sum = 0 len_pop = len(self) - for ind in xrange(len_pop): + for ind in range(len_pop): raw_sum += self[ind].score self.stats["rawMax"] = max(self, key=key_raw_score).score @@ -250,7 +250,7 @@ def statistics(self): self.stats["rawAve"] = raw_sum / float(len_pop) tmpvar = 0.0 - for ind in xrange(len_pop): + for ind in range(len_pop): s = self[ind].score - self.stats["rawAve"] s *= s tmpvar += s @@ -353,11 +353,11 @@ def setSortType(self, sort_type): def create(self, **args): """ Clone the example genome to fill the population """ self.minimax = args["minimax"] - self.internalPop = [self.oneSelfGenome.clone() for i in xrange(self.popSize)] + self.internalPop = [self.oneSelfGenome.clone() for i in range(self.popSize)] self.clearFlags() def __findIndividual(self, individual, end): - for i in xrange(end): + for i in range(end): if individual.compare(self.internalPop[i]) == 0: return True @@ -367,7 +367,7 @@ def initialize(self, **args): logging.debug("Initializing the population") if self.oneSelfGenome.getParam("full_diversity", True) and hasattr(self.oneSelfGenome, "compare"): - for i in xrange(len(self.internalPop)): + for i in range(len(self.internalPop)): curr = self.internalPop[i] curr.initialize(**args) while self.__findIndividual(curr, i): @@ -393,7 +393,7 @@ def evaluate(self, **args): results = proc_pool.map(multiprocessing_eval_full, self.internalPop) proc_pool.close() proc_pool.join() - for i in xrange(len(self.internalPop)): + for i in range(len(self.internalPop)): self.internalPop[i] = results[i] else: results = proc_pool.map(multiprocessing_eval, self.internalPop) @@ -417,7 +417,7 @@ def scale(self, **args): pass fit_sum = 0 - for ind in xrange(len(self)): + for ind in range(len(self)): fit_sum += self[ind].fitness self.stats["fitMax"] = max(self, key=key_fitness_score).fitness @@ -434,7 +434,7 @@ def printStats(self): else: message = "Max/Min/Avg Raw [%(rawMax).2f/%(rawMin).2f/%(rawAve).2f]" % self.stats logging.info(message) - print message + print(message) return message def copy(self, pop): diff --git a/pyevolve/GSimpleGA.py b/pyevolve/GSimpleGA.py index 44775d5..447afb4 100644 --- a/pyevolve/GSimpleGA.py +++ b/pyevolve/GSimpleGA.py @@ -66,12 +66,12 @@ from sys import stdout as sys_stdout import code -from GPopulation import GPopulation -from FunctionSlot import FunctionSlot -from GenomeBase import GenomeBase -from DBAdapters import DBBaseAdapter -import Consts -import Util +from .GPopulation import GPopulation +from .FunctionSlot import FunctionSlot +from .GenomeBase import GenomeBase +from .DBAdapters import DBBaseAdapter +from . import Consts +from . import Util import pyevolve # Platform dependant code for the Interactive Mode @@ -366,7 +366,7 @@ def setInteractiveMode(self, flag=True): def __repr__(self): """ The string representation of the GA Engine """ - minimax_type = Consts.minimaxType.keys()[Consts.minimaxType.values().index(self.minimax)] + minimax_type = list(Consts.minimaxType.keys())[list(Consts.minimaxType.values()).index(self.minimax)] ret = "- GSimpleGA\n" ret += "\tGP Mode:\t\t %s\n" % self.getGPMode() ret += "\tPopulation Size:\t %d\n" % self.internalPop.popSize @@ -471,7 +471,7 @@ def setSortType(self, sort_type): :param sort_type: the Sort Type """ - if sort_type not in Consts.sortType.values(): + if sort_type not in list(Consts.sortType.values()): Util.raiseException("sort type must be a Consts.sortType type", TypeError) self.internalPop.sortType = sort_type @@ -529,7 +529,7 @@ def setMinimax(self, mtype): :param mtype: the minimax mode, from Consts.minimaxType """ - if mtype not in Consts.minimaxType.values(): + if mtype not in list(Consts.minimaxType.values()): Util.raiseException("Minimax must be maximize or minimize", TypeError) self.minimax = mtype @@ -597,10 +597,10 @@ def __gp_catch_functions(self, prefix): function_set = {} main_dict = mod_main.__dict__ - for obj, addr in main_dict.items(): + for obj, addr in list(main_dict.items()): if obj[0:len(prefix)] == prefix: try: - op_len = addr.func_code.co_argcount + op_len = addr.__code__.co_argcount except: continue function_set[obj] = op_len @@ -645,7 +645,7 @@ def step(self): crossover_empty = self.select(popID=self.currentGeneration).crossover.isEmpty() - for i in xrange(0, size_iterate, 2): + for i in range(0, size_iterate, 2): genomeMom = self.select(popID=self.currentGeneration) genomeDad = self.select(popID=self.currentGeneration) @@ -686,13 +686,13 @@ def step(self): if self.elitism: logging.debug("Doing elitism.") if self.getMinimax() == Consts.minimaxType["maximize"]: - for i in xrange(self.nElitismReplacement): + for i in range(self.nElitismReplacement): #re-evaluate before being sure this is the best self.internalPop.bestRaw(i).evaluate() if self.internalPop.bestRaw(i).score > newPop.bestRaw(i).score: newPop[len(newPop) - 1 - i] = self.internalPop.bestRaw(i) elif self.getMinimax() == Consts.minimaxType["minimize"]: - for i in xrange(self.nElitismReplacement): + for i in range(self.nElitismReplacement): #re-evaluate before being sure this is the best self.internalPop.bestRaw(i).evaluate() if self.internalPop.bestRaw(i).score < newPop.bestRaw(i).score: @@ -722,7 +722,7 @@ def printStats(self): percent = self.currentGeneration * 100 / float(self.nGenerations) message = "Gen. %d (%.2f%%):" % (self.currentGeneration, percent) logging.info(message) - print message, + print(message, end=' ') sys_stdout.flush() self.internalPop.statistics() stat_ret = self.internalPop.printStats() @@ -731,7 +731,7 @@ def printStats(self): def printTimeElapsed(self): """ Shows the time elapsed since the begin of evolution """ total_time = time() - self.time_init - print "Total time elapsed: %.3f seconds." % total_time + print("Total time elapsed: %.3f seconds." % total_time) return total_time def dumpStatsDB(self): @@ -805,26 +805,26 @@ def evolve(self, freq_stats=0): if stopFlagTerminationCriteria: logging.debug("Evolution stopped by the Termination Criteria !") if freq_stats: - print "\n\tEvolution stopped by Termination Criteria function !\n" + print("\n\tEvolution stopped by Termination Criteria function !\n") break if stopFlagCallback: logging.debug("Evolution stopped by Step Callback function !") if freq_stats: - print "\n\tEvolution stopped by Step Callback function !\n" + print("\n\tEvolution stopped by Step Callback function !\n") break if self.interactiveMode: if sys_platform[:3] == "win": if msvcrt.kbhit(): if ord(msvcrt.getch()) == Consts.CDefESCKey: - print "Loading modules for Interactive Mode...", + print("Loading modules for Interactive Mode...", end=' ') logging.debug( "Windows Interactive Mode key detected ! generation=%d", self.getCurrentGeneration() ) from pyevolve import Interaction - print " done !" + print(" done !") interact_banner = "## Pyevolve v.%s - Interactive Mode ##\n" \ "Press CTRL-Z to quit interactive mode." % (pyevolve.__version__,) session_locals = { @@ -833,18 +833,18 @@ def evolve(self, freq_stats=0): "pyevolve": pyevolve, "it": Interaction, } - print + print() code.interact(interact_banner, local=session_locals) is_interactive_generation = self.getInteractiveGeneration() == self.getCurrentGeneration() if self.getInteractiveGeneration() >= 0 and is_interactive_generation: - print "Loading modules for Interactive Mode...", + print("Loading modules for Interactive Mode...", end=' ') logging.debug( "Manual Interactive Mode key detected ! generation=%d", self.getCurrentGeneration() ) from pyevolve import Interaction - print " done !" + print(" done !") interact_banner = "## Pyevolve v.%s - Interactive Mode ##" % (pyevolve.__version__,) session_locals = { "ga_engine": self, @@ -852,7 +852,7 @@ def evolve(self, freq_stats=0): "pyevolve": pyevolve, "it": Interaction } - print + print() code.interact(interact_banner, local=session_locals) if self.step(): @@ -861,7 +861,7 @@ def evolve(self, freq_stats=0): except KeyboardInterrupt: logging.debug("CTRL-C detected, finishing evolution.") if freq_stats: - print "\n\tA break was detected, you have interrupted the evolution !\n" + print("\n\tA break was detected, you have interrupted the evolution !\n") if freq_stats != 0: self.printStats() diff --git a/pyevolve/GTree.py b/pyevolve/GTree.py index 381580d..366c7ff 100644 --- a/pyevolve/GTree.py +++ b/pyevolve/GTree.py @@ -34,9 +34,9 @@ ------------------------------------------------------------- """ import random -from GenomeBase import GenomeBase, GTreeBase, GTreeNodeBase -import Consts -import Util +from .GenomeBase import GenomeBase, GTreeBase, GTreeNodeBase +from . import Consts +from . import Util try: import pydot @@ -185,7 +185,7 @@ def buildGTreeGrow(depth, value_callback, max_siblings, max_depth): if depth == max_depth: return n - for i in xrange(random.randint(0, abs(max_siblings))): + for i in range(random.randint(0, abs(max_siblings))): child = buildGTreeGrow(depth + 1, value_callback, max_siblings, max_depth) child.setParent(n) n.addChild(child) @@ -216,7 +216,7 @@ def buildGTreeFull(depth, value_callback, max_siblings, max_depth): else: range_val = random.randint(1, abs(max_siblings)) - for i in xrange(range_val): + for i in range(range_val): child = buildGTreeFull(depth + 1, value_callback, max_siblings, max_depth) child.setParent(n) n.addChild(child) @@ -389,7 +389,7 @@ def writeDotGraph(self, graph, startNode=0): :param startNode: used to plot more than one individual """ if not HAVE_PYDOT: - print "You must install Pydot to use this feature !" + print("You must install Pydot to use this feature !") return count = startNode @@ -397,7 +397,7 @@ def writeDotGraph(self, graph, startNode=0): nodes_dict = {} import __main__ as main_module - for i in xrange(len(self.nodes_list)): + for i in range(len(self.nodes_list)): newnode = pydot.Node(str(count), style="filled") count += 1 @@ -480,7 +480,7 @@ def getPreOrderExpression(self, start_node=None): all_childs = start_node.getChilds() str_buff += "(" + self.getPreOrderExpression(all_childs[0]) - for index in xrange(1, len(all_childs)): + for index in range(1, len(all_childs)): child = all_childs[index] str_buff += ", " + self.getPreOrderExpression(child) str_buff += ")" @@ -569,7 +569,7 @@ def writePopulationDot(ga_engine, filename, format="jpeg", start=0, end=0): n = 0 end_index = len(pop) if end == 0 else end - for i in xrange(start, end_index): + for i in range(start, end_index): ind = pop[i] subg = pydot.Cluster( "cluster_%d" % i, @@ -606,7 +606,7 @@ def writePopulationDotRaw(ga_engine, filename, start=0, end=0): n = 0 end_index = len(pop) if end == 0 else end - for i in xrange(start, end_index): + for i in range(start, end_index): ind = pop[i] subg = pydot.Cluster( "cluster_%d" % i, @@ -670,9 +670,9 @@ def buildGTreeGPGrow(ga_engine, depth, max_depth): else: # Do not generate degenerative trees if depth == 0: - random_node = random.choice(gp_function_set.keys()) + random_node = random.choice(list(gp_function_set.keys())) else: - fchoice = random.choice([gp_function_set.keys(), gp_terminals]) + fchoice = random.choice([list(gp_function_set.keys()), gp_terminals]) random_node = random.choice(fchoice) if random_node in gp_terminals: @@ -681,7 +681,7 @@ def buildGTreeGPGrow(ga_engine, depth, max_depth): n = GTreeNodeGP(random_node, Consts.nodeType["NONTERMINAL"]) if n.getType() == Consts.nodeType["NONTERMINAL"]: - for i in xrange(gp_function_set[n.getData()]): + for i in range(gp_function_set[n.getData()]): child = buildGTreeGPGrow(ga_engine, depth + 1, max_depth) child.setParent(n) n.addChild(child) @@ -709,11 +709,11 @@ def buildGTreeGPFull(ga_engine, depth, max_depth): n = GTreeNodeGP(random_terminal, Consts.nodeType["TERMINAL"]) return n else: - random_oper = random.choice(gp_function_set.keys()) + random_oper = random.choice(list(gp_function_set.keys())) n = GTreeNodeGP(random_oper, Consts.nodeType["NONTERMINAL"]) if n.getType() == Consts.nodeType["NONTERMINAL"]: - for i in xrange(gp_function_set[n.getData()]): + for i in range(gp_function_set[n.getData()]): child = buildGTreeGPFull(ga_engine, depth + 1, max_depth) child.setParent(n) n.addChild(child) diff --git a/pyevolve/GenomeBase.py b/pyevolve/GenomeBase.py index f22b1cf..e07cf6c 100644 --- a/pyevolve/GenomeBase.py +++ b/pyevolve/GenomeBase.py @@ -11,8 +11,8 @@ from random import choice as rand_choice import inspect -from FunctionSlot import FunctionSlot -import Util +from .FunctionSlot import FunctionSlot +from . import Util class GenomeBase(object): """ GenomeBase Class - The base of all chromosome representation """ @@ -294,7 +294,7 @@ def __init__(self, parent, childs=None): if childs is not None: if type(childs) != list: Util.raiseException("Childs must be a list of nodes", TypeError) - typecheck_list = filter(lambda x: not isinstance(x, GTreeNodeBase), childs) + typecheck_list = [x for x in childs if not isinstance(x, GTreeNodeBase)] if len(typecheck_list) > 0: Util.raiseException("Childs must be a list of nodes", TypeError) self.childs += childs @@ -416,8 +416,8 @@ def processNodes(self, cloning=False): if self.root_node is None: return self.nodes_list = self.getAllNodes() - self.nodes_leaf = filter(lambda n: n.isLeaf(), self.nodes_list) - self.nodes_branch = filter(lambda n: n.isLeaf() is False, self.nodes_list) + self.nodes_leaf = [n for n in self.nodes_list if n.isLeaf()] + self.nodes_branch = [n for n in self.nodes_list if n.isLeaf() is False] if not cloning: self.tree_height = self.getNodeHeight(self.getRoot()) @@ -588,7 +588,7 @@ def copy(self, g, node=None, node_parent=None): newnode.setParent(node_parent) node_parent.replaceChild(node, newnode) - for ci in xrange(len(newnode)): + for ci in range(len(newnode)): GTreeBase.copy(self, g, newnode.getChild(ci), newnode) return newnode diff --git a/pyevolve/Initializators.py b/pyevolve/Initializators.py index ff99c8b..7c4bb68 100644 --- a/pyevolve/Initializators.py +++ b/pyevolve/Initializators.py @@ -15,8 +15,8 @@ """ from random import randint as rand_randint, uniform as rand_uniform, choice as rand_choice -import GTree -import Util +from . import GTree +from . import Util ############################# @@ -25,7 +25,7 @@ def G1DBinaryStringInitializator(genome, **args): """ 1D Binary String initializator """ - genome.genomeList = [rand_choice((0, 1)) for _ in xrange(genome.getListSize())] + genome.genomeList = [rand_choice((0, 1)) for _ in range(genome.getListSize())] ############################# @@ -40,8 +40,8 @@ def G2DBinaryStringInitializator(genome, **args): """ genome.clearString() - for i in xrange(genome.getHeight()): - for j in xrange(genome.getWidth()): + for i in range(genome.getHeight()): + for j in range(genome.getWidth()): random_gene = rand_choice((0, 1)) genome.setItem(i, j, random_gene) @@ -62,7 +62,7 @@ def G1DListInitializatorAllele(genome, **args): if allele is None: Util.raiseException("to use the G1DListInitializatorAllele, you must specify the 'allele' parameter") - genome.genomeList = [allele[i].getRandomAllele() for i in xrange(genome.getListSize())] + genome.genomeList = [allele[i].getRandomAllele() for i in range(genome.getListSize())] def G1DListInitializatorInteger(genome, **args): @@ -74,7 +74,7 @@ def G1DListInitializatorInteger(genome, **args): range_min = genome.getParam("rangemin", 0) range_max = genome.getParam("rangemax", 100) - genome.genomeList = [rand_randint(range_min, range_max) for i in xrange(genome.getListSize())] + genome.genomeList = [rand_randint(range_min, range_max) for i in range(genome.getListSize())] def G1DListInitializatorReal(genome, **args): @@ -86,7 +86,7 @@ def G1DListInitializatorReal(genome, **args): range_min = genome.getParam("rangemin", 0) range_max = genome.getParam("rangemax", 100) - genome.genomeList = [rand_uniform(range_min, range_max) for i in xrange(genome.getListSize())] + genome.genomeList = [rand_uniform(range_min, range_max) for i in range(genome.getListSize())] #################### @@ -101,8 +101,8 @@ def G2DListInitializatorInteger(genome, **args): """ genome.clearList() - for i in xrange(genome.getHeight()): - for j in xrange(genome.getWidth()): + for i in range(genome.getHeight()): + for j in range(genome.getWidth()): randomInteger = rand_randint(genome.getParam("rangemin", 0), genome.getParam("rangemax", 100)) genome.setItem(i, j, randomInteger) @@ -116,8 +116,8 @@ def G2DListInitializatorReal(genome, **args): """ genome.clearList() - for i in xrange(genome.getHeight()): - for j in xrange(genome.getWidth()): + for i in range(genome.getHeight()): + for j in range(genome.getWidth()): randomReal = rand_uniform(genome.getParam("rangemin", 0), genome.getParam("rangemax", 100)) genome.setItem(i, j, randomReal) @@ -142,8 +142,8 @@ def G2DListInitializatorAllele(genome, **args): genome.clearList() - for i in xrange(genome.getHeight()): - for j in xrange(genome.getWidth()): + for i in range(genome.getHeight()): + for j in range(genome.getWidth()): random_allele = allele[0].getRandomAllele() genome.setItem(i, j, random_allele) diff --git a/pyevolve/Interaction.py b/pyevolve/Interaction.py index e1f5774..2adf9b3 100644 --- a/pyevolve/Interaction.py +++ b/pyevolve/Interaction.py @@ -20,13 +20,13 @@ import pylab except: logging.debug("cannot import Matplotlib ! Plots will not be available !") - print "Warning: cannot import Matplotlib ! Plots will not be available !" + print("Warning: cannot import Matplotlib ! Plots will not be available !") try: import numpy except: logging.debug("cannot import Numpy ! Some functions will not be available !") - print "Warning: cannot import Numpy ! Some functions will not be available !" + print("Warning: cannot import Numpy ! Some functions will not be available !") def getPopScores(population, fitness=False): """ Returns a list of population scores diff --git a/pyevolve/Migration.py b/pyevolve/Migration.py index 3f566c9..3f7994d 100644 --- a/pyevolve/Migration.py +++ b/pyevolve/Migration.py @@ -10,11 +10,11 @@ """ -import Util +from . import Util from random import randint as rand_randint, choice as rand_choice -import Network -import Consts -from FunctionSlot import FunctionSlot +from . import Network +from . import Consts +from .FunctionSlot import FunctionSlot import logging try: @@ -133,7 +133,7 @@ def selectPool(self, num_individuals): :param num_individuals: the number of individuals to select :rtype: list with individuals """ - pool = [self.select() for i in xrange(num_individuals)] + pool = [self.select() for i in range(num_individuals)] return pool def exchange(self): @@ -259,7 +259,7 @@ def exchange(self): population = self.GAEngine.getPopulation() - for i in xrange(self.getNumReplacement()): + for i in range(self.getNumReplacement()): if len(pool) <= 0: break choice = rand_choice(pool) @@ -328,7 +328,7 @@ def exchange(self): population = self.GAEngine.getPopulation() pool = pool_received - for i in xrange(self.getNumReplacement()): + for i in range(self.getNumReplacement()): if len(pool) <= 0: break diff --git a/pyevolve/Mutators.py b/pyevolve/Mutators.py index 3c757df..347aaf9 100644 --- a/pyevolve/Mutators.py +++ b/pyevolve/Mutators.py @@ -7,11 +7,11 @@ """ -import Util +from . import Util from random import randint as rand_randint, gauss as rand_gauss, uniform as rand_uniform from random import choice as rand_choice -import Consts -import GTree +from . import Consts +from . import GTree ############################# ## 1D Binary String ## @@ -27,13 +27,13 @@ def G1DBinaryStringMutatorSwap(genome, **args): if mutations < 1.0: mutations = 0 - for it in xrange(stringLength): + for it in range(stringLength): if Util.randomFlipCoin(args["pmut"]): Util.listSwapElement(genome, it, rand_randint(0, stringLength - 1)) mutations += 1 else: - for it in xrange(int(round(mutations))): + for it in range(int(round(mutations))): Util.listSwapElement(genome, rand_randint(0, stringLength - 1), rand_randint(0, stringLength - 1)) @@ -48,7 +48,7 @@ def G1DBinaryStringMutatorFlip(genome, **args): if mutations < 1.0: mutations = 0 - for it in xrange(stringLength): + for it in range(stringLength): if Util.randomFlipCoin(args["pmut"]): if genome[it] == 0: genome[it] = 1 @@ -57,7 +57,7 @@ def G1DBinaryStringMutatorFlip(genome, **args): mutations += 1 else: - for it in xrange(int(round(mutations))): + for it in range(int(round(mutations))): which = rand_randint(0, stringLength - 1) if genome[which] == 0: genome[which] = 1 @@ -83,12 +83,12 @@ def G1DListMutatorSwap(genome, **args): if mutations < 1.0: mutations = 0 - for it in xrange(listSize): + for it in range(listSize): if Util.randomFlipCoin(args["pmut"]): Util.listSwapElement(genome, it, rand_randint(0, listSize - 1)) mutations += 1 else: - for it in xrange(int(round(mutations))): + for it in range(int(round(mutations))): Util.listSwapElement(genome, rand_randint(0, listSize - 1), rand_randint(0, listSize - 1)) return int(mutations) @@ -134,14 +134,14 @@ def G1DListMutatorIntegerRange(genome, **args): if mutations < 1.0: mutations = 0 - for it in xrange(listSize): + for it in range(listSize): if Util.randomFlipCoin(args["pmut"]): genome[it] = rand_randint(genome.getParam("rangemin", Consts.CDefRangeMin), genome.getParam("rangemax", Consts.CDefRangeMax)) mutations += 1 else: - for it in xrange(int(round(mutations))): + for it in range(int(round(mutations))): which_gene = rand_randint(0, listSize - 1) genome[which_gene] = rand_randint(genome.getParam("rangemin", Consts.CDefRangeMin), genome.getParam("rangemax", Consts.CDefRangeMax)) @@ -162,14 +162,14 @@ def G1DListMutatorRealRange(genome, **args): if mutations < 1.0: mutations = 0 - for it in xrange(listSize): + for it in range(listSize): if Util.randomFlipCoin(args["pmut"]): genome[it] = rand_uniform(genome.getParam("rangemin", Consts.CDefRangeMin), genome.getParam("rangemax", Consts.CDefRangeMax)) mutations += 1 else: - for it in xrange(int(round(mutations))): + for it in range(int(round(mutations))): which_gene = rand_randint(0, listSize - 1) genome[which_gene] = rand_uniform(genome.getParam("rangemin", Consts.CDefRangeMin), genome.getParam("rangemax", Consts.CDefRangeMax)) @@ -198,7 +198,7 @@ def G1DListMutatorIntegerGaussianGradient(genome, **args): if mutations < 1.0: mutations = 0 - for it in xrange(listSize): + for it in range(listSize): if Util.randomFlipCoin(args["pmut"]): final_value = int(genome[it] * abs(rand_gauss(mu, sigma))) @@ -208,7 +208,7 @@ def G1DListMutatorIntegerGaussianGradient(genome, **args): genome[it] = final_value mutations += 1 else: - for it in xrange(int(round(mutations))): + for it in range(int(round(mutations))): which_gene = rand_randint(0, listSize - 1) final_value = int(genome[which_gene] * abs(rand_gauss(mu, sigma))) @@ -243,7 +243,7 @@ def G1DListMutatorIntegerGaussian(genome, **args): if mutations < 1.0: mutations = 0 - for it in xrange(listSize): + for it in range(listSize): if Util.randomFlipCoin(args["pmut"]): final_value = genome[it] + int(rand_gauss(mu, sigma)) @@ -253,7 +253,7 @@ def G1DListMutatorIntegerGaussian(genome, **args): genome[it] = final_value mutations += 1 else: - for it in xrange(int(round(mutations))): + for it in range(int(round(mutations))): which_gene = rand_randint(0, listSize - 1) final_value = genome[which_gene] + int(rand_gauss(mu, sigma)) @@ -289,7 +289,7 @@ def G1DListMutatorRealGaussian(genome, **args): if mutations < 1.0: mutations = 0 - for it in xrange(listSize): + for it in range(listSize): if Util.randomFlipCoin(args["pmut"]): final_value = genome[it] + rand_gauss(mu, sigma) @@ -299,7 +299,7 @@ def G1DListMutatorRealGaussian(genome, **args): genome[it] = final_value mutations += 1 else: - for it in xrange(int(round(mutations))): + for it in range(int(round(mutations))): which_gene = rand_randint(0, listSize - 1) final_value = genome[which_gene] + rand_gauss(mu, sigma) @@ -337,7 +337,7 @@ def G1DListMutatorRealGaussianGradient(genome, **args): if mutations < 1.0: mutations = 0 - for it in xrange(listSize): + for it in range(listSize): if Util.randomFlipCoin(args["pmut"]): final_value = genome[it] * abs(rand_gauss(mu, sigma)) @@ -347,7 +347,7 @@ def G1DListMutatorRealGaussianGradient(genome, **args): genome[it] = final_value mutations += 1 else: - for it in xrange(int(round(mutations))): + for it in range(int(round(mutations))): which_gene = rand_randint(0, listSize - 1) final_value = genome[which_gene] * abs(rand_gauss(mu, sigma)) @@ -371,7 +371,7 @@ def G1DListMutatorIntegerBinary(genome, **args): if mutations < 1.0: mutations = 0 - for it in xrange(listSize): + for it in range(listSize): if Util.randomFlipCoin(args["pmut"]): if genome[it] == 0: genome[it] = 1 @@ -380,7 +380,7 @@ def G1DListMutatorIntegerBinary(genome, **args): mutations += 1 else: - for it in xrange(int(round(mutations))): + for it in range(int(round(mutations))): which_gene = rand_randint(0, listSize - 1) if genome[which_gene] == 0: genome[which_gene] = 1 @@ -407,13 +407,13 @@ def G1DListMutatorAllele(genome, **args): if mutations < 1.0: mutations = 0 - for it in xrange(listSize): + for it in range(listSize): if Util.randomFlipCoin(args["pmut"]): new_val = allele[it].getRandomAllele() genome[it] = new_val mutations += 1 else: - for it in xrange(int(round(mutations))): + for it in range(int(round(mutations))): which_gene = rand_randint(0, listSize - 1) new_val = allele[which_gene].getRandomAllele() genome[which_gene] = new_val @@ -445,7 +445,7 @@ def G1DListMutatorAlleleGaussian(genome, **arguments): if mutations < 1.0: mutations = 0 - for it in xrange(listSize): + for it in range(listSize): if Util.randomFlipCoin(arguments["pmut"]): final_value = genome[it] + rand_gauss(mu, sigma) assert len(allele[it].beginEnd) == 1, "only single ranges are supported" @@ -455,7 +455,7 @@ def G1DListMutatorAlleleGaussian(genome, **arguments): genome[it] = final_value mutations += 1 else: - for it in xrange(int(round(mutations))): + for it in range(int(round(mutations))): which_gene = rand_randint(0, listSize - 1) final_value = genome[which_gene] + rand_gauss(mu, sigma) assert len(allele[which_gene].beginEnd) == 1, "only single ranges are supported" @@ -486,14 +486,14 @@ def G2DListMutatorSwap(genome, **args): if mutations < 1.0: mutations = 0 - for i in xrange(height): - for j in xrange(width): + for i in range(height): + for j in range(width): if Util.randomFlipCoin(args["pmut"]): index_b = (rand_randint(0, height - 1), rand_randint(0, width - 1)) Util.list2DSwapElement(genome.genomeList, (i, j), index_b) mutations += 1 else: - for it in xrange(int(round(mutations))): + for it in range(int(round(mutations))): index_a = (rand_randint(0, height - 1), rand_randint(0, width - 1)) index_b = (rand_randint(0, height - 1), rand_randint(0, width - 1)) Util.list2DSwapElement(genome.genomeList, index_a, index_b) @@ -518,15 +518,15 @@ def G2DListMutatorIntegerRange(genome, **args): if mutations < 1.0: mutations = 0 - for i in xrange(genome.getHeight()): - for j in xrange(genome.getWidth()): + for i in range(genome.getHeight()): + for j in range(genome.getWidth()): if Util.randomFlipCoin(args["pmut"]): random_int = rand_randint(range_min, range_max) genome.setItem(i, j, random_int) mutations += 1 else: - for it in xrange(int(round(mutations))): + for it in range(int(round(mutations))): which_x = rand_randint(0, genome.getWidth() - 1) which_y = rand_randint(0, genome.getHeight() - 1) random_int = rand_randint(range_min, range_max) @@ -558,8 +558,8 @@ def G2DListMutatorIntegerGaussianGradient(genome, **args): if mutations < 1.0: mutations = 0 - for i in xrange(genome.getHeight()): - for j in xrange(genome.getWidth()): + for i in range(genome.getHeight()): + for j in range(genome.getWidth()): if Util.randomFlipCoin(args["pmut"]): final_value = int(genome[i][j] * abs(rand_gauss(mu, sigma))) @@ -570,7 +570,7 @@ def G2DListMutatorIntegerGaussianGradient(genome, **args): mutations += 1 else: - for it in xrange(int(round(mutations))): + for it in range(int(round(mutations))): which_x = rand_randint(0, genome.getWidth() - 1) which_y = rand_randint(0, genome.getHeight() - 1) @@ -610,8 +610,8 @@ def G2DListMutatorIntegerGaussian(genome, **args): if mutations < 1.0: mutations = 0 - for i in xrange(genome.getHeight()): - for j in xrange(genome.getWidth()): + for i in range(genome.getHeight()): + for j in range(genome.getWidth()): if Util.randomFlipCoin(args["pmut"]): final_value = genome[i][j] + int(rand_gauss(mu, sigma)) @@ -622,7 +622,7 @@ def G2DListMutatorIntegerGaussian(genome, **args): mutations += 1 else: - for it in xrange(int(round(mutations))): + for it in range(int(round(mutations))): which_x = rand_randint(0, genome.getWidth() - 1) which_y = rand_randint(0, genome.getHeight() - 1) @@ -660,14 +660,14 @@ def G2DListMutatorAllele(genome, **args): if mutations < 1.0: mutations = 0 - for i in xrange(genome.getHeight()): - for j in xrange(genome.getWidth()): + for i in range(genome.getHeight()): + for j in range(genome.getWidth()): if Util.randomFlipCoin(args["pmut"]): new_val = allele[0].getRandomAllele() genome.setItem(i, j, new_val) mutations += 1 else: - for it in xrange(int(round(mutations))): + for it in range(int(round(mutations))): which_x = rand_randint(0, genome.getHeight() - 1) which_y = rand_randint(0, genome.getWidth() - 1) @@ -704,8 +704,8 @@ def G2DListMutatorRealGaussian(genome, **args): if mutations < 1.0: mutations = 0 - for i in xrange(genome.getHeight()): - for j in xrange(genome.getWidth()): + for i in range(genome.getHeight()): + for j in range(genome.getWidth()): if Util.randomFlipCoin(args["pmut"]): final_value = genome[i][j] + rand_gauss(mu, sigma) @@ -716,7 +716,7 @@ def G2DListMutatorRealGaussian(genome, **args): mutations += 1 else: - for it in xrange(int(round(mutations))): + for it in range(int(round(mutations))): which_x = rand_randint(0, genome.getWidth() - 1) which_y = rand_randint(0, genome.getHeight() - 1) @@ -751,8 +751,8 @@ def G2DListMutatorRealGaussianGradient(genome, **args): if mutations < 1.0: mutations = 0 - for i in xrange(genome.getHeight()): - for j in xrange(genome.getWidth()): + for i in range(genome.getHeight()): + for j in range(genome.getWidth()): if Util.randomFlipCoin(args["pmut"]): final_value = genome[i][j] * abs(rand_gauss(mu, sigma)) @@ -763,7 +763,7 @@ def G2DListMutatorRealGaussianGradient(genome, **args): mutations += 1 else: - for it in xrange(int(round(mutations))): + for it in range(int(round(mutations))): which_x = rand_randint(0, genome.getWidth() - 1) which_y = rand_randint(0, genome.getHeight() - 1) @@ -796,14 +796,14 @@ def G2DBinaryStringMutatorSwap(genome, **args): if mutations < 1.0: mutations = 0 - for i in xrange(height): - for j in xrange(width): + for i in range(height): + for j in range(width): if Util.randomFlipCoin(args["pmut"]): index_b = (rand_randint(0, height - 1), rand_randint(0, width - 1)) Util.list2DSwapElement(genome.genomeString, (i, j), index_b) mutations += 1 else: - for it in xrange(int(round(mutations))): + for it in range(int(round(mutations))): index_a = (rand_randint(0, height - 1), rand_randint(0, width - 1)) index_b = (rand_randint(0, height - 1), rand_randint(0, width - 1)) Util.list2DSwapElement(genome.genomeString, index_a, index_b) @@ -827,8 +827,8 @@ def G2DBinaryStringMutatorFlip(genome, **args): if mutations < 1.0: mutations = 0 - for i in xrange(genome.getHeight()): - for j in xrange(genome.getWidth()): + for i in range(genome.getHeight()): + for j in range(genome.getWidth()): if Util.randomFlipCoin(args["pmut"]): if genome[i][j] == 0: genome.setItem(i, j, 1) @@ -837,7 +837,7 @@ def G2DBinaryStringMutatorFlip(genome, **args): mutations += 1 else: - for it in xrange(int(round(mutations))): + for it in range(int(round(mutations))): which_x = rand_randint(0, genome.getWidth() - 1) which_y = rand_randint(0, genome.getHeight() - 1) @@ -864,14 +864,14 @@ def GTreeMutatorSwap(genome, **args): if mutations < 1.0: mutations = 0 - for i in xrange(len(genome)): + for i in range(len(genome)): if Util.randomFlipCoin(args["pmut"]): mutations += 1 nodeOne = genome.getRandomNode() nodeTwo = genome.getRandomNode() nodeOne.swapNodeData(nodeTwo) else: - for it in xrange(int(round(mutations))): + for it in range(int(round(mutations))): nodeOne = genome.getRandomNode() nodeTwo = genome.getRandomNode() nodeOne.swapNodeData(nodeTwo) @@ -897,7 +897,7 @@ def GTreeMutatorIntegerRange(genome, **args): if mutations < 1.0: mutations = 0 - for i in xrange(len(genome)): + for i in range(len(genome)): if Util.randomFlipCoin(args["pmut"]): mutations += 1 rand_node = genome.getRandomNode() @@ -905,7 +905,7 @@ def GTreeMutatorIntegerRange(genome, **args): rand_node.setData(random_int) else: - for it in xrange(int(round(mutations))): + for it in range(int(round(mutations))): rand_node = genome.getRandomNode() random_int = rand_randint(range_min, range_max) rand_node.setData(random_int) @@ -931,7 +931,7 @@ def GTreeMutatorRealRange(genome, **args): if mutations < 1.0: mutations = 0 - for i in xrange(len(genome)): + for i in range(len(genome)): if Util.randomFlipCoin(args["pmut"]): mutations += 1 rand_node = genome.getRandomNode() @@ -939,7 +939,7 @@ def GTreeMutatorRealRange(genome, **args): rand_node.setData(random_real) else: - for it in xrange(int(round(mutations))): + for it in range(int(round(mutations))): rand_node = genome.getRandomNode() random_real = rand_uniform(range_min, range_max) rand_node.setData(random_real) @@ -965,7 +965,7 @@ def GTreeMutatorIntegerGaussian(genome, **args): if mutations < 1.0: mutations = 0 - for i in xrange(len(genome)): + for i in range(len(genome)): if Util.randomFlipCoin(args["pmut"]): mutations += 1 rand_node = genome.getRandomNode() @@ -974,7 +974,7 @@ def GTreeMutatorIntegerGaussian(genome, **args): final_value = max(final_value, genome.getParam("rangemin", Consts.CDefRangeMin)) rand_node.setData(final_value) else: - for it in xrange(int(round(mutations))): + for it in range(int(round(mutations))): rand_node = genome.getRandomNode() final_value = rand_node.getData() + int(rand_gauss(mu, sigma)) final_value = min(final_value, genome.getParam("rangemax", Consts.CDefRangeMax)) @@ -1002,7 +1002,7 @@ def GTreeMutatorRealGaussian(genome, **args): if mutations < 1.0: mutations = 0 - for i in xrange(len(genome)): + for i in range(len(genome)): if Util.randomFlipCoin(args["pmut"]): mutations += 1 rand_node = genome.getRandomNode() @@ -1011,7 +1011,7 @@ def GTreeMutatorRealGaussian(genome, **args): final_value = max(final_value, genome.getParam("rangemin", Consts.CDefRangeMin)) rand_node.setData(final_value) else: - for it in xrange(int(round(mutations))): + for it in range(int(round(mutations))): rand_node = genome.getRandomNode() final_value = rand_node.getData() + rand_gauss(mu, sigma) final_value = min(final_value, genome.getParam("rangemax", Consts.CDefRangeMax)) @@ -1045,7 +1045,7 @@ def GTreeGPMutatorOperation(genome, **args): if mutations < 1.0: mutations = 0 - for i in xrange(len(genome)): + for i in range(len(genome)): if Util.randomFlipCoin(args["pmut"]): mutations += 1 rand_node = genome.getRandomNode() @@ -1055,7 +1055,7 @@ def GTreeGPMutatorOperation(genome, **args): else: op_len = gp_function_set[rand_node.getData()] fun_candidates = [] - for o, l in gp_function_set.items(): + for o, l in list(gp_function_set.items()): if l == op_len: fun_candidates.append(o) @@ -1065,7 +1065,7 @@ def GTreeGPMutatorOperation(genome, **args): term_operator = rand_choice(fun_candidates) rand_node.setData(term_operator) else: - for it in xrange(int(round(mutations))): + for it in range(int(round(mutations))): rand_node = genome.getRandomNode() assert rand_node is not None if rand_node.getType() == Consts.nodeType["TERMINAL"]: @@ -1073,7 +1073,7 @@ def GTreeGPMutatorOperation(genome, **args): else: op_len = gp_function_set[rand_node.getData()] fun_candidates = [] - for o, l in gp_function_set.items(): + for o, l in list(gp_function_set.items()): if l == op_len: fun_candidates.append(o) @@ -1110,7 +1110,7 @@ def GTreeGPMutatorSubtree(genome, **args): branch_list = genome.nodes_branch elements = len(branch_list) - for i in xrange(elements): + for i in range(elements): node = branch_list[i] assert node is not None diff --git a/pyevolve/Network.py b/pyevolve/Network.py index 726c82e..09c43e4 100644 --- a/pyevolve/Network.py +++ b/pyevolve/Network.py @@ -9,13 +9,13 @@ The *Network* module. """ -from __future__ import with_statement + import threading import socket import time import sys -import Util -import cPickle +from . import Util +import pickle try: import zlib @@ -23,7 +23,7 @@ except ImportError: ZLIB_SUPPORT = False -import Consts +from . import Consts import logging def getMachineIP(): @@ -393,7 +393,7 @@ def pickleAndCompress(obj, level=9): and -1 is to not compress """ - pickled = cPickle.dumps(obj) + pickled = pickle.dumps(obj) if level < 0: return pickled else: @@ -413,7 +413,7 @@ def unpickleAndDecompress(obj_dump, decompress=True): obj_decompress = zlib.decompress(obj_dump) else: obj_decompress = obj_dump - return cPickle.loads(obj_decompress) + return pickle.loads(obj_decompress) if __name__ == "__main__": arg = sys.argv[1] @@ -424,21 +424,21 @@ def unpickleAndDecompress(obj_dump, decompress=True): s.start() while True: - print ".", + print(".", end=' ') time.sleep(10) if s.isReady(): item = s.popPool() - print item + print(item) time.sleep(4) s.shutdown() break elif arg == "client": - print "Binding on %s..." % myself[0] + print("Binding on %s..." % myself[0]) s = UDPThreadUnicastClient(myself[0], 1500) s.setData("dsfssdfsfddf") s.setTargetHost(myself[0], 666) s.start() s.join() - print s.getSentBytes() + print(s.getSentBytes()) - print "end..." + print("end...") diff --git a/pyevolve/Scaling.py b/pyevolve/Scaling.py index a169dbf..bcc8c18 100644 --- a/pyevolve/Scaling.py +++ b/pyevolve/Scaling.py @@ -6,8 +6,8 @@ This module have the *scaling schemes* like Linear scaling, etc. """ -import Consts -import Util +from . import Consts +from . import Util import math import logging @@ -38,7 +38,7 @@ def LinearScaling(pop): a = pop_rawAve / delta b = -pop_rawMin * pop_rawAve / delta - for i in xrange(len(pop)): + for i in range(len(pop)): f = pop[i].score if f < 0.0: Util.raiseException("Score %r is negative, linear scaling not supported !" % (f,), ValueError) @@ -54,7 +54,7 @@ def SigmaTruncScaling(pop): c = Consts.CDefScaleSigmaTruncMultiplier pop_rawAve = pop.stats["rawAve"] pop_rawDev = pop.stats["rawDev"] - for i in xrange(len(pop)): + for i in range(len(pop)): f = pop[i].score - pop_rawAve f += c * pop_rawDev if f < 0: @@ -69,7 +69,7 @@ def PowerLawScaling(pop): """ logging.debug("Running power law scaling.") k = Consts.CDefScalePowerLawFactor - for i in xrange(len(pop)): + for i in range(len(pop)): f = pop[i].score if f < 0.0: Util.raiseException("Score %r is negative, power law scaling not supported !" % (f,), ValueError) @@ -99,14 +99,14 @@ def BoltzmannScaling(pop): boltz_e = [] avg = 0.0 - for i in xrange(len(pop)): + for i in range(len(pop)): val = math.exp(pop[i].score / boltz_temperature) boltz_e.append(val) avg += val avg /= len(pop) - for i in xrange(len(pop)): + for i in range(len(pop)): pop[i].fitness = boltz_e[i] / avg def ExponentialScaling(pop): @@ -115,7 +115,7 @@ def ExponentialScaling(pop): .. versionadded: 0.6 The `ExponentialScaling` function. """ - for i in xrange(len(pop)): + for i in range(len(pop)): score = pop[i].score pop[i].fitness = math.exp(score) @@ -125,6 +125,6 @@ def SaturatedScaling(pop): .. versionadded: 0.6 The `SaturatedScaling` function. """ - for i in xrange(len(pop)): + for i in range(len(pop)): score = pop[i].score pop[i].fitness = 1.0 - math.exp(score) diff --git a/pyevolve/Selectors.py b/pyevolve/Selectors.py index 9ee11f1..aa096a0 100644 --- a/pyevolve/Selectors.py +++ b/pyevolve/Selectors.py @@ -8,7 +8,7 @@ """ import random -import Consts +from . import Consts def GRankSelector(population, **args): """ The Rank Selector - This selector will pick the best individual of @@ -19,12 +19,12 @@ def GRankSelector(population, **args): if args["popID"] != GRankSelector.cachePopID: if population.sortType == Consts.sortType["scaled"]: best_fitness = population.bestFitness().fitness - for index in xrange(1, len(population.internalPop)): + for index in range(1, len(population.internalPop)): if population[index].fitness == best_fitness: count += 1 else: best_raw = population.bestRaw().score - for index in xrange(1, len(population.internalPop)): + for index in range(1, len(population.internalPop)): if population[index].score == best_raw: count += 1 @@ -62,7 +62,7 @@ def GTournamentSelector(population, **args): minimax_operator = min if should_minimize else max poolSize = population.getParam("tournamentPool", Consts.CDefTournamentPoolSize) - tournament_pool = [GRouletteWheel(population, **args) for i in xrange(poolSize)] + tournament_pool = [GRouletteWheel(population, **args) for i in range(poolSize)] if population.sortType == Consts.sortType["scaled"]: choosen = minimax_operator(tournament_pool, key=lambda ind: ind.fitness) @@ -86,7 +86,7 @@ def GTournamentSelectorAlternative(population, **args): len_pop = len(population) should_minimize = population.minimax == Consts.minimaxType["minimize"] minimax_operator = min if should_minimize else max - tournament_pool = [population[random.randint(0, len_pop - 1)] for i in xrange(pool_size)] + tournament_pool = [population[random.randint(0, len_pop - 1)] for i in range(pool_size)] if population.sortType == Consts.sortType["scaled"]: choosen = minimax_operator(tournament_pool, key=lambda ind: ind.fitness) @@ -128,7 +128,7 @@ def GRouletteWheel_PrepareWheel(population): len_pop = len(population) - psum = [i for i in xrange(len_pop)] + psum = [i for i in range(len_pop)] population.statistics() @@ -137,43 +137,43 @@ def GRouletteWheel_PrepareWheel(population): pop_fitMin = population.stats["fitMin"] if pop_fitMax == pop_fitMin: - for index in xrange(len_pop): + for index in range(len_pop): psum[index] = (index + 1) / float(len_pop) elif (pop_fitMax > 0 and pop_fitMin >= 0) or (pop_fitMax <= 0 and pop_fitMin < 0): population.sort() if population.minimax == Consts.minimaxType["maximize"]: psum[0] = population[0].fitness - for i in xrange(1, len_pop): + for i in range(1, len_pop): psum[i] = population[i].fitness + psum[i - 1] - for i in xrange(len_pop): + for i in range(len_pop): psum[i] /= float(psum[len_pop - 1]) else: psum[0] = -population[0].fitness + pop_fitMax + pop_fitMin - for i in xrange(1, len_pop): + for i in range(1, len_pop): psum[i] = -population[i].fitness + pop_fitMax + pop_fitMin + psum[i - 1] - for i in xrange(len_pop): + for i in range(len_pop): psum[i] /= float(psum[len_pop - 1]) else: pop_rawMax = population.stats["rawMax"] pop_rawMin = population.stats["rawMin"] if pop_rawMax == pop_rawMin: - for index in xrange(len_pop): + for index in range(len_pop): psum[index] = (index + 1) / float(len_pop) elif (pop_rawMax > 0 and pop_rawMin >= 0) or (pop_rawMax <= 0 and pop_rawMin < 0): population.sort() if population.minimax == Consts.minimaxType["maximize"]: psum[0] = population[0].score - for i in xrange(1, len_pop): + for i in range(1, len_pop): psum[i] = population[i].score + psum[i - 1] - for i in xrange(len_pop): + for i in range(len_pop): psum[i] /= float(psum[len_pop - 1]) else: psum[0] = - population[0].score + pop_rawMax + pop_rawMin - for i in xrange(1, len_pop): + for i in range(1, len_pop): psum[i] = - population[i].score + pop_rawMax + pop_rawMin + psum[i - 1] - for i in xrange(len_pop): + for i in range(len_pop): psum[i] /= float(psum[len_pop - 1]) return psum diff --git a/pyevolve/Statistics.py b/pyevolve/Statistics.py index a6f1188..abb01a0 100644 --- a/pyevolve/Statistics.py +++ b/pyevolve/Statistics.py @@ -73,7 +73,7 @@ def __len__(self): def __repr__(self): """ Return a string representation of the statistics """ strBuff = "- Statistics\n" - for k, v in self.internalDict.items(): + for k, v in list(self.internalDict.items()): strBuff += "\t%-45s = %.2f\n" % (self.descriptions.get(k, k), v) return strBuff @@ -83,12 +83,12 @@ def asTuple(self): def clear(self): """ Set all statistics to zero """ - for k in self.internalDict.keys(): + for k in list(self.internalDict.keys()): self.internalDict[k] = 0 def items(self): """ Return a tuple (name, value) for all stored statistics """ - return self.internalDict.items() + return list(self.internalDict.items()) def clone(self): """ Instantiate a new Statistic class with the same contents """ diff --git a/pyevolve/Util.py b/pyevolve/Util.py index 4674797..421d356 100644 --- a/pyevolve/Util.py +++ b/pyevolve/Util.py @@ -11,7 +11,7 @@ from random import random as rand_random from math import sqrt as math_sqrt import logging -import Consts +from . import Consts def randomFlipCoin(p): @@ -88,7 +88,7 @@ def raiseException(message, expt=None): if expt is None: raise Exception(message) else: - raise (expt, message) + raise expt def cmp_individual_raw(a, b): @@ -274,7 +274,7 @@ def getNodes(self): :rtype: the list of nodes """ - return self.adjacent.keys() + return list(self.adjacent.keys()) def reset(self): """ Deletes all nodes of the graph """ @@ -285,11 +285,11 @@ def getNeighbors(self, node): :param node: the node """ - return self.adjacent[node].keys() + return list(self.adjacent[node].keys()) def __getitem__(self, node): """ Returns the adjacent nodes of the node """ - return self.adjacent[node].keys() + return list(self.adjacent[node].keys()) def __repr__(self): ret = "- Graph\n" @@ -319,7 +319,7 @@ def G1DListGetEdges(individual): """ edg = {} ind_list = individual.getInternalList() - for i in xrange(len(ind_list)): + for i in range(len(ind_list)): a, b = ind_list[i], ind_list[i - 1] if a not in edg: @@ -342,7 +342,7 @@ def G1DListMergeEdges(eda, edb): :rtype: the merged dictionary """ edges = {} - for value, near in eda.items(): + for value, near in list(eda.items()): for adj in near: if (value in edb) and (adj in edb[value]): edges.setdefault(value, []).append(adj) From 94b1d1a88d3ec651df0fd38c674cf4c8c3189182 Mon Sep 17 00:00:00 2001 From: yugangzhang Date: Fri, 6 Jul 2018 17:42:45 -0400 Subject: [PATCH 02/10] Update to python3.3.6 --- pyevolve_graph.py | 46 +++++++++++++++++++++++----------------------- 1 file changed, 23 insertions(+), 23 deletions(-) diff --git a/pyevolve_graph.py b/pyevolve_graph.py index 7956331..8241b03 100755 --- a/pyevolve_graph.py +++ b/pyevolve_graph.py @@ -15,7 +15,7 @@ def graph_pop_heatmap_raw(pop, minimize, colormap="jet", filesave=None): if filesave: pylab.savefig(filesave) - print "Graph saved to %s file !" % (filesave,) + print("Graph saved to %s file !" % (filesave,)) else: pylab.show() @@ -29,7 +29,7 @@ def graph_pop_heatmap_fitness(pop, minimize, colormap="jet", filesave=None): if filesave: pylab.savefig(filesave) - print "Graph saved to %s file !" % (filesave,) + print("Graph saved to %s file !" % (filesave,)) else: pylab.show() @@ -90,7 +90,7 @@ def graph_diff_raw(pop, minimize, filesave=None): if filesave: pylab.savefig(filesave) - print "Graph saved to %s file !" % (filesave,) + print("Graph saved to %s file !" % (filesave,)) else: pylab.show() @@ -160,7 +160,7 @@ def graph_maxmin_raw(pop, minimize, filesave=None): if filesave: pylab.savefig(filesave) - print "Graph saved to %s file !" % (filesave,) + print("Graph saved to %s file !" % (filesave,)) else: pylab.show() @@ -207,7 +207,7 @@ def graph_maxmin_fitness(pop, minimize, filesave=None): if filesave: pylab.savefig(filesave) - print "Graph saved to %s file !" % (filesave,) + print("Graph saved to %s file !" % (filesave,)) else: pylab.show() @@ -235,7 +235,7 @@ def graph_errorbars_raw(pop, minimize, filesave=None): if filesave: pylab.savefig(filesave) - print "Graph saved to %s file !" % (filesave,) + print("Graph saved to %s file !" % (filesave,)) else: pylab.show() @@ -264,7 +264,7 @@ def graph_errorbars_fitness(pop, minimize, filesave=None): if filesave: pylab.savefig(filesave) - print "Graph saved to %s file !" % (filesave,) + print("Graph saved to %s file !" % (filesave,)) else: pylab.show() @@ -304,7 +304,7 @@ def graph_compare_raw(pop, minimize, id_list, filesave=None): if filesave: pylab.savefig(filesave) - print "Graph saved to %s file !" % (filesave,) + print("Graph saved to %s file !" % (filesave,)) else: pylab.show() @@ -343,7 +343,7 @@ def graph_compare_fitness(pop, minimize, id_list, filesave=None): if filesave: pylab.savefig(filesave) - print "Graph saved to %s file !" % (filesave,) + print("Graph saved to %s file !" % (filesave,)) else: pylab.show() @@ -354,8 +354,8 @@ def graph_compare_fitness(pop, minimize, id_list, filesave=None): popGraph = False - print "Pyevolve %s - Graph Plot Tool" % (pyevolve_version,) - print "By %s\n" % (pyevolve_author,) + print("Pyevolve %s - Graph Plot Tool" % (pyevolve_version,)) + print("By %s\n" % (pyevolve_author,)) parser = OptionParser() parser.add_option("-f", "--file", dest="dbfile", @@ -424,11 +424,11 @@ def graph_compare_fitness(pop, minimize, id_list, filesave=None): parser.print_help() exit() - print "Loading modules...." + print("Loading modules....") import os.path if not os.path.exists(options.dbfile): - print "Database file '%s' not found !" % (options.dbfile, ) + print("Database file '%s' not found !" % (options.dbfile, )) exit() import pylab @@ -438,10 +438,10 @@ def graph_compare_fitness(pop, minimize, id_list, filesave=None): import math import os - print "Loading database and creating graph..." + print("Loading database and creating graph...") identify_list = options.identify.split(",") - identify_list = map(str.strip, identify_list) + identify_list = list(map(str.strip, identify_list)) pop = None @@ -458,7 +458,7 @@ def graph_compare_fitness(pop, minimize, id_list, filesave=None): generations = ret.fetchall() if len(generations) <= 0: - print "No generation data found for the identify '%s' !" % (options.identify,) + print("No generation data found for the identify '%s' !" % (options.identify,)) exit() pop = [] @@ -492,10 +492,10 @@ def graph_compare_fitness(pop, minimize, id_list, filesave=None): conn.close() if len(pop) <= 0: - print "No statistic data found for the identify '%s' !" % (options.identify,) + print("No statistic data found for the identify '%s' !" % (options.identify,)) exit() - print "%d generations found !" % (len(pop),) + print("%d generations found !" % (len(pop),)) popGraph = True @@ -520,10 +520,10 @@ def graph_compare_fitness(pop, minimize, id_list, filesave=None): conn.close() if len(pop) <= 0: - print "No statistic data found for the identify '%s' !" % (options.identify,) + print("No statistic data found for the identify '%s' !" % (options.identify,)) exit() - print "%d generations found !" % (len(pop),) + print("%d generations found !" % (len(pop),)) elif len(identify_list) > 1 and not popGraph: pop = [] @@ -547,10 +547,10 @@ def graph_compare_fitness(pop, minimize, id_list, filesave=None): conn.close() if len(pop) <= 0: - print "No statistic data found for the identify list '%s' !" % (options.identify,) + print("No statistic data found for the identify list '%s' !" % (options.identify,)) exit() - print "%d identify found !" % (len(pop),) + print("%d identify found !" % (len(pop),)) if options.errorbars_raw: if options.outfile: graph_errorbars_raw(pop, options.minimize, options.outfile + "." + options.extension) @@ -588,7 +588,7 @@ def graph_compare_fitness(pop, minimize, id_list, filesave=None): filename += "." + options.extension graph(pop, options.minimize, filename) - print "\n\tDone ! The graphs was saved in the directory '%s'" % (dirname) + print("\n\tDone ! The graphs was saved in the directory '%s'" % (dirname)) if options.compare_raw: if options.outfile: graph_compare_raw(pop, options.minimize, identify_list, options.outfile + "." + options.extension) From 5ac1ed578c0762479d86aedc7a18d9d70f5a9f34 Mon Sep 17 00:00:00 2001 From: yugangzhang Date: Fri, 6 Jul 2018 17:43:17 -0400 Subject: [PATCH 03/10] Old python2 --- pyevolve/Consts.py.bak | 536 +++++++++++++++ pyevolve/Crossovers.py.bak | 800 ++++++++++++++++++++++ pyevolve/DBAdapters.py.bak | 790 +++++++++++++++++++++ pyevolve/FunctionSlot.py.bak | 202 ++++++ pyevolve/G1DBinaryString.py.bak | 169 +++++ pyevolve/G1DList.py.bak | 165 +++++ pyevolve/G2DBinaryString.py.bak | 196 ++++++ pyevolve/G2DList.py.bak | 228 +++++++ pyevolve/GAllele.py.bak | 284 ++++++++ pyevolve/GPopulation.py.bak | 491 +++++++++++++ pyevolve/GSimpleGA.py.bak | 889 ++++++++++++++++++++++++ pyevolve/GTree.py.bak | 721 ++++++++++++++++++++ pyevolve/GenomeBase.py.bak | 607 +++++++++++++++++ pyevolve/Initializators.py.bak | 274 ++++++++ pyevolve/Interaction.py.bak | 84 +++ pyevolve/Migration.py.bak | 341 ++++++++++ pyevolve/Mutators.py.bak | 1134 +++++++++++++++++++++++++++++++ pyevolve/Network.py.bak | 444 ++++++++++++ pyevolve/Scaling.py.bak | 130 ++++ pyevolve/Selectors.py.bak | 179 +++++ pyevolve/Statistics.py.bak | 106 +++ pyevolve/Util.py.bak | 349 ++++++++++ 22 files changed, 9119 insertions(+) create mode 100644 pyevolve/Consts.py.bak create mode 100644 pyevolve/Crossovers.py.bak create mode 100644 pyevolve/DBAdapters.py.bak create mode 100644 pyevolve/FunctionSlot.py.bak create mode 100644 pyevolve/G1DBinaryString.py.bak create mode 100644 pyevolve/G1DList.py.bak create mode 100644 pyevolve/G2DBinaryString.py.bak create mode 100644 pyevolve/G2DList.py.bak create mode 100644 pyevolve/GAllele.py.bak create mode 100644 pyevolve/GPopulation.py.bak create mode 100644 pyevolve/GSimpleGA.py.bak create mode 100644 pyevolve/GTree.py.bak create mode 100644 pyevolve/GenomeBase.py.bak create mode 100644 pyevolve/Initializators.py.bak create mode 100644 pyevolve/Interaction.py.bak create mode 100644 pyevolve/Migration.py.bak create mode 100644 pyevolve/Mutators.py.bak create mode 100644 pyevolve/Network.py.bak create mode 100644 pyevolve/Scaling.py.bak create mode 100644 pyevolve/Selectors.py.bak create mode 100644 pyevolve/Statistics.py.bak create mode 100644 pyevolve/Util.py.bak diff --git a/pyevolve/Consts.py.bak b/pyevolve/Consts.py.bak new file mode 100644 index 0000000..f1442cd --- /dev/null +++ b/pyevolve/Consts.py.bak @@ -0,0 +1,536 @@ +""" + +:mod:`Consts` -- constants module +============================================================================ + +Pyevolve have defaults in all genetic operators, settings and etc, this is an issue to helps the user in the API use and minimize the source code needed to make simple things. In the module :mod:`Consts`, you will find those defaults settings. You are encouraged to see the constants, but not to change directly on the module, there are methods for this. + +General constants +---------------------------------------------------------------------------- + +.. attribute:: CDefPythonRequire + + The mininum version required to run Pyevolve. + +.. attribute:: CDefLogFile + + The default log filename. + +.. attribute:: CDefLogLevel + + Default log level. + +.. attribute:: sortType + + Sort type, raw or scaled. + + Example: + >>> sort_type = Consts.sortType["raw"] + >>> sort_type = Consts.sortType["scaled"] + +.. attribute:: minimaxType + + The Min/Max type, maximize or minimize the evaluation function. + + Example: + >>> minmax = Consts.minimaxType["minimize"] + >>> minmax = Consts.minimaxType["maximize"] + +.. attribute:: CDefESCKey + + The ESC key ASCII code. Used to start Interactive Mode. + +.. attribute:: CDefRangeMin + + Minimum range. This constant is used as integer and real max/min. + +.. attribute:: CDefRangeMax + + Maximum range. This constant is used as integer and real max/min. + +.. attribute:: CDefBroadcastAddress + + The broadcast address for UDP, 255.255.255.255 + +.. attribute:: CDefImportList + + The import list and messages + +.. attribute:: nodeType + + The genetic programming node types, can be "TERMINAL":0 or "NONTERMINAL":1 + +.. attribute:: CDefGPGenomes + + The classes which are used in Genetic Programming, used to detected the + correct mode when starting the evolution + +Selection methods constants (:mod:`Selectors`) +---------------------------------------------------------------------------- + +.. attribute:: CDefTournamentPoolSize + + The default pool size for the Tournament Selector (:func:`Selectors.GTournamentSelector`). + +Scaling scheme constants (:mod:`Scaling`) +---------------------------------------------------------------------------- + +.. attribute:: CDefScaleLinearMultiplier + + The multiplier of the Linear (:func:`Scaling.LinearScaling`) scaling scheme. + +.. attribute:: CDefScaleSigmaTruncMultiplier + + The default Sigma Truncation (:func:`Scaling.SigmaTruncScaling`) scaling scheme. + +.. attribute:: CDefScalePowerLawFactor + + The default Power Law (:func:`Scaling.PowerLawScaling`) scaling scheme factor. + +.. attribute:: CDefScaleBoltzMinTemp + + The default mininum temperature of the (:func:`Scaling.BoltzmannScaling`) scaling scheme factor. + +.. attribute:: CDefScaleBoltzFactor + + The default Boltzmann Factor of (:func:`Scaling.BoltzmannScaling`) scaling scheme factor. + This is the factor that the temperature will be subtracted. + +.. attribute:: CDefScaleBoltzStart + + The default Boltzmann start temperature (:func:`Scaling.BoltzmannScaling`). + If you don't set the start temperature parameter, this will be the default initial + temperature for the Boltzmann scaling scheme. + +Population constants (:class:`GPopulation.GPopulation`) +---------------------------------------------------------------------------- + +.. attribute:: CDefPopSortType + + Default sort type parameter. + +.. attribute:: CDefPopMinimax + + Default min/max parameter. + +.. attribute:: CDefPopScale + + Default scaling scheme. + + +1D Binary String Defaults (:class:`G1DBinaryString.G1DBinaryString`) +---------------------------------------------------------------------------- + +.. attribute:: CDefG1DBinaryStringMutator + + The default mutator for the 1D Binary String (:class:`G1DBinaryString.G1DBinaryString`) chromosome. + +.. attribute:: CDefG1DBinaryStringCrossover + + The default crossover method for the 1D Binary String (:class:`G1DBinaryString.G1DBinaryString`) chromosome. + +.. attribute:: CDefG1DBinaryStringInit + + The default initializator for the 1D Binary String (:class:`G1DBinaryString.G1DBinaryString`) chromosome. + +.. attribute:: CDefG1DBinaryStringUniformProb + + The default uniform probability used for some uniform genetic operators for the 1D Binary String (:class:`G1DBinaryString.G1DBinaryString`) chromosome. + + +2D Binary String Defaults (:class:`G2DBinaryString.G2DBinaryString`) +---------------------------------------------------------------------------- + +.. attribute:: CDefG2DBinaryStringMutator + + The default mutator for the 2D Binary String (:class:`G2DBinaryString.G2DBinaryString`) chromosome. + +.. attribute:: CDefG2DBinaryStringCrossover + + The default crossover method for the 2D Binary String (:class:`G2DBinaryString.G2DBinaryString`) chromosome. + +.. attribute:: CDefG2DBinaryStringInit + + The default initializator for the 2D Binary String (:class:`G2DBinaryString.G2DBinaryString`) chromosome. + +.. attribute:: CDefG2DBinaryStringUniformProb + + The default uniform probability used for some uniform genetic operators for the 2D Binary String (:class:`G2DBinaryString.G2DBinaryString`) chromosome. + + +1D List chromosome constants (:class:`G1DList.G1DList`) +---------------------------------------------------------------------------- + +.. attribute:: CDefG1DListMutIntMU + + Default *mu* value of the 1D List Gaussian Integer Mutator (:func:`Mutators.G1DListMutatorIntegerGaussian`), the *mu* represents the mean of the distribution. + +.. attribute:: CDefG1DListMutIntSIGMA + + Default *sigma* value of the 1D List Gaussian Integer Mutator (:func:`Mutators.G1DListMutatorIntegerGaussian`), the *sigma* represents the standard deviation of the distribution. + +.. attribute:: CDefG1DListMutRealMU + + Default *mu* value of the 1D List Gaussian Real Mutator (:func:`Mutators.G1DListMutatorRealGaussian`), the *mu* represents the mean of the distribution. + +.. attribute:: CDefG1DListMutRealSIGMA + + Default *sigma* value of the 1D List Gaussian Real Mutator (:func:`Mutators.G1DListMutatorRealGaussian`), the *sigma* represents the mean of the distribution. + + +Tree chromosome constants (:class:`GTree.GTree`) +---------------------------------------------------------------------------- + +.. attribute:: CDefGTreeInit + + Default initializator of the tree chromosome. + +.. attribute:: CDefGGTreeMutator + + Default mutator of the tree chromosome. + +.. attribute:: CDefGTreeCrossover + + Default crossover of the tree chromosome. + + +2D List chromosome constants (:class:`G2DList.G2DList`) +---------------------------------------------------------------------------- + +.. attribute:: CDefG2DListMutRealMU + + Default *mu* value of the 2D List Gaussian Real Mutator (:func:`Mutators.G2DListMutatorRealGaussian`), the *mu* represents the mean of the distribution. + +.. attribute:: CDefG2DListMutRealSIGMA + + Default *sigma* value of the 2D List Gaussian Real Mutator (:func:`Mutators.G2DListMutatorRealGaussian`), the *sigma* represents the mean of the distribution. + +.. attribute:: CDefG2DListMutIntMU + + Default *mu* value of the 2D List Gaussian Integer Mutator (:func:`Mutators.G2DListMutatorIntegerGaussian`), the *mu* represents the mean of the distribution. + +.. attribute:: CDefG2DListMutIntSIGMA + + Default *sigma* value of the 2D List Gaussian Integer Mutator (:func:`Mutators.G2DListMutatorIntegerGaussian`), the *sigma* represents the mean of the distribution. + +.. attribute:: CDefG2DListMutator + + Default mutator for the 2D List chromosome. + +.. attribute:: CDefG2DListCrossover + + Default crossover method for the 2D List chromosome. + +.. attribute:: CDefG2DListInit + + Default initializator for the 2D List chromosome. + +.. attribute:: CDefG2DListCrossUniformProb + + Default uniform probability for the 2D List Uniform Crossover method (:func:`Crossovers.G2DListCrossoverUniform`). + + +GA Engine constants (:class:`GSimpleGA.GSimpleGA`) +---------------------------------------------------------------------------- + +.. attribute:: CDefGAGenerations + + Default number of generations. + +.. attribute:: CDefGAMutationRate + + Default mutation rate. + +.. attribute:: CDefGACrossoverRate + + Default crossover rate. + +.. attribute:: CDefGAPopulationSize + + Default population size. + +.. attribute:: CDefGASelector + + Default selector method. + +DB Adapters constants (:mod:`DBAdapters`) +---------------------------------------------------------------------------- +Constants for the DB Adapters + + +SQLite3 DB Adapter Constants (:class:`DBAdapters.DBSQLite`) +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +.. attribute:: CDefSQLiteDBName + + Default database filename. + +.. attribute:: CDefSQLiteDBTable + + Default statistical table name. + +.. attribute:: CDefSQLiteDBTablePop + + Default population statistical table name. + +.. attribute:: CDefSQLiteStatsGenFreq + + Default generational frequency for dump statistics. + +.. attribute:: CDefSQLiteStatsCommitFreq + + Default commit frequency. + + +MySQL DB Adapter Constants (:class:`DBAdapters.DBMySQLAdapter`) +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +.. attribute:: CDefMySQLDBName + + Default database name. + +.. attribute:: CDefMySQLDBTable + + Default statistical table name. + +.. attribute:: CDefMySQLDBTablePop + + Default population statistical table name. + +.. attribute:: CDefMySQLStatsGenFreq + + Default generational frequency for dump statistics. + +.. attribute:: CDefMySQLStatsCommitFreq + + Default commit frequency. + +.. attribute:: CDefMySQLDBHost + + Default MySQL connection host. + +.. attribute:: CDefMySQLDBPort + + Default MySQL connection TCP port. + + +URL Post DB Adapter Constants (:class:`DBAdapters.DBURLPost`) +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +.. attribute:: CDefURLPostStatsGenFreq + + Default generational frequency for dump statistics. + + +CSV File DB Adapter Constants (:class:`DBAdapters.DBFileCSV`) +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +.. attribute:: CDefCSVFileName + + The default CSV filename to dump statistics. + +.. attribute:: CDefCSVFileStatsGenFreq + + Default generational frequency for dump statistics. + + +XMP RPC DB Adapter Constants (:class:`DBAdapters.DBXMLRPC`) +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +.. attribute:: CDefXMLRPCStatsGenFreq + + Default generational frequency for dump statistics. + +Migration Constants (:mod:`Migration`) +---------------------------------------------------------------------------- +.. attribute:: CDefGenMigrationRate + + The default generations supposed to migrate and receive individuals + +.. attribute:: CDefMigrationNIndividuals + + The default number of individuals that will migrate at the *CDefGenMigrationRate* + interval + +.. attribute:: CDefNetworkIndividual + + A migration code for network individual data + +.. attribute:: CDefNetworkInfo + + A migration code for network info data + +.. attribute:: CDefGenMigrationReplacement + + The default number of individuals to be replaced at the migration stage + + +""" +import Scaling +import Selectors +import Initializators +import Mutators +import Crossovers +import logging +from GTree import GTreeGP + +# Required python version 2.5+ +CDefPythonRequire = (2, 5) + +# Logging system +CDefLogFile = "pyevolve.log" +CDefLogLevel = logging.DEBUG + +# Types of sort +# - raw: uses the "score" attribute +# - scaled: uses the "fitness" attribute +sortType = { + "raw": 0, + "scaled": 1 +} + +# Optimization type +# - Minimize or Maximize the Evaluator Function +minimaxType = {"minimize": 0, + "maximize": 1 + } + +CDefESCKey = 27 + +CDefImportList = {"visual.graph": "you must install VPython !", + "csv": "csv module not found !", + "urllib": "urllib module not found !", + "sqlite3": "sqlite3 module not found, are you using Jython or IronPython ?", + "xmlrpclib": "xmlrpclib module not found !", + "MySQLdb": "MySQLdb module not found, you must install mysql-python !", + "pydot": "Pydot module not found, you must install Pydot to plot graphs !"} + +#################### +# Defaults section # +#################### + +# - Tournament selector +CDefTournamentPoolSize = 2 + +# - Scale methods defaults +CDefScaleLinearMultiplier = 1.2 +CDefScaleSigmaTruncMultiplier = 2.0 +CDefScalePowerLawFactor = 1.0005 +CDefScaleBoltzMinTemp = 1.0 +CDefScaleBoltzFactor = 0.05 +# 40 temp. = 500 generations +CDefScaleBoltzStart = 40.0 + +# - Population Defaults +CDefPopSortType = sortType["scaled"] +CDefPopMinimax = minimaxType["maximize"] +CDefPopScale = Scaling.LinearScaling + +# - GA Engine defaults +CDefGAGenerations = 100 +CDefGAMutationRate = 0.02 +CDefGACrossoverRate = 0.9 +CDefGAPopulationSize = 80 +CDefGASelector = Selectors.GRankSelector +CDefGAElitismReplacement = 1 + +# - This is general used by integer/real ranges defaults +CDefRangeMin = 0 +CDefRangeMax = 100 + +# - G1DBinaryString defaults +CDefG1DBinaryStringMutator = Mutators.G1DBinaryStringMutatorFlip +CDefG1DBinaryStringCrossover = Crossovers.G1DBinaryStringXSinglePoint +CDefG1DBinaryStringInit = Initializators.G1DBinaryStringInitializator +CDefG1DBinaryStringUniformProb = 0.5 + +# - G2DBinaryString defaults +CDefG2DBinaryStringMutator = Mutators.G2DBinaryStringMutatorFlip +CDefG2DBinaryStringCrossover = Crossovers.G2DBinaryStringXUniform +CDefG2DBinaryStringInit = Initializators.G2DBinaryStringInitializator +CDefG2DBinaryStringUniformProb = 0.5 + +# - GTree defaults +CDefGTreeInit = Initializators.GTreeInitializatorInteger +CDefGGTreeMutator = Mutators.GTreeMutatorIntegerRange +CDefGTreeCrossover = Crossovers.GTreeCrossoverSinglePointStrict + +# - GTreeGP defaults +CDefGTreeGPInit = Initializators.GTreeGPInitializator +CDefGGTreeGPMutator = Mutators.GTreeGPMutatorSubtree +CDefGTreeGPCrossover = Crossovers.GTreeGPCrossoverSinglePoint + +# - G1DList defaults +CDefG1DListMutIntMU = 2 +CDefG1DListMutIntSIGMA = 10 + +CDefG1DListMutRealMU = 0 +CDefG1DListMutRealSIGMA = 1 + +CDefG1DListMutator = Mutators.G1DListMutatorSwap +CDefG1DListCrossover = Crossovers.G1DListCrossoverSinglePoint +CDefG1DListInit = Initializators.G1DListInitializatorInteger +CDefG1DListCrossUniformProb = 0.5 + +# SBX Crossover defaults +# Crossover distribution index for SBX +# Larger Etac = similar to parents +# Smaller Etac = far away from parents +CDefG1DListSBXEtac = 10 +CDefG1DListSBXEPS = 1.0e-14 + +# - G2DList defaults +CDefG2DListMutIntMU = 2 +CDefG2DListMutIntSIGMA = 10 + +CDefG2DListMutRealMU = 0 +CDefG2DListMutRealSIGMA = 1 + +CDefG2DListMutator = Mutators.G2DListMutatorSwap +CDefG2DListCrossover = Crossovers.G2DListCrossoverUniform +CDefG2DListInit = Initializators.G2DListInitializatorInteger +CDefG2DListCrossUniformProb = 0.5 + +# Gaussian Gradient +CDefGaussianGradientMU = 1.0 +CDefGaussianGradientSIGMA = (1.0 / 3.0) # approx. +/- 3-sigma is +/- 10% + +# - DB Adapters SQLite defaults +CDefSQLiteDBName = "pyevolve.db" +CDefSQLiteDBTable = "statistics" +CDefSQLiteDBTablePop = "population" +CDefSQLiteStatsGenFreq = 1 +CDefSQLiteStatsCommitFreq = 300 + +# - DB Adapters MySQL defaults +CDefMySQLDBName = "pyevolve" +CDefMySQLDBTable = "statistics" +CDefMySQLDBTablePop = "population" +CDefMySQLDBHost = "localhost" +CDefMySQLDBPort = 3306 +CDefMySQLStatsGenFreq = 1 +CDefMySQLStatsCommitFreq = 300 + +# - DB Adapters URL Post defaults +CDefURLPostStatsGenFreq = 100 + +# - DB Adapters CSV File defaults +CDefCSVFileName = "pyevolve.csv" +CDefCSVFileStatsGenFreq = 1 + +# - DB Adapter XML RPC +CDefXMLRPCStatsGenFreq = 20 + +# Util Consts +CDefBroadcastAddress = "255.255.255.255" +nodeType = {"TERMINAL": 0, "NONTERMINAL": 1} + +CDefGPGenomes = [GTreeGP] + +# Migration Consts +CDefGenMigrationRate = 20 +CDefMigrationNIndividuals = 3 +CDefGenMigrationReplacement = 3 + +CDefNetworkIndividual = 1 +CDefNetworkInfo = 2 diff --git a/pyevolve/Crossovers.py.bak b/pyevolve/Crossovers.py.bak new file mode 100644 index 0000000..7584a00 --- /dev/null +++ b/pyevolve/Crossovers.py.bak @@ -0,0 +1,800 @@ +""" + +:mod:`Crossovers` -- crossover methods module +===================================================================== + +In this module we have the genetic operators of crossover (or recombination) for each chromosome representation. + +""" + +from random import randint as rand_randint, choice as rand_choice +from random import random as rand_random +import math +import Util +import Consts + +############################# +## 1D Binary String ## +############################# + +def G1DBinaryStringXSinglePoint(genome, **args): + """ The crossover of 1D Binary String, Single Point + + .. warning:: You can't use this crossover method for binary strings with length of 1. + + """ + sister = None + brother = None + gMom = args["mom"] + gDad = args["dad"] + + if len(gMom) == 1: + Util.raiseException("The Binary String have one element, can't use the Single Point Crossover method !", TypeError) + + cut = rand_randint(1, len(gMom) - 1) + + if args["count"] >= 1: + sister = gMom.clone() + sister.resetStats() + sister[cut:] = gDad[cut:] + + if args["count"] == 2: + brother = gDad.clone() + brother.resetStats() + brother[cut:] = gMom[cut:] + + return (sister, brother) + +def G1DBinaryStringXTwoPoint(genome, **args): + """ The 1D Binary String crossover, Two Point + + .. warning:: You can't use this crossover method for binary strings with length of 1. + + """ + sister = None + brother = None + gMom = args["mom"] + gDad = args["dad"] + + if len(gMom) == 1: + Util.raiseException("The Binary String have one element, can't use the Two Point Crossover method !", TypeError) + + cuts = [rand_randint(1, len(gMom) - 1), rand_randint(1, len(gMom) - 1)] + + if cuts[0] > cuts[1]: + Util.listSwapElement(cuts, 0, 1) + + if args["count"] >= 1: + sister = gMom.clone() + sister.resetStats() + sister[cuts[0]:cuts[1]] = gDad[cuts[0]:cuts[1]] + + if args["count"] == 2: + brother = gDad.clone() + brother.resetStats() + brother[cuts[0]:cuts[1]] = gMom[cuts[0]:cuts[1]] + + return (sister, brother) + +def G1DBinaryStringXUniform(genome, **args): + """ The G1DList Uniform Crossover """ + sister = None + brother = None + gMom = args["mom"] + gDad = args["dad"] + + sister = gMom.clone() + brother = gDad.clone() + sister.resetStats() + brother.resetStats() + + for i in xrange(len(gMom)): + if Util.randomFlipCoin(Consts.CDefG1DBinaryStringUniformProb): + temp = sister[i] + sister[i] = brother[i] + brother[i] = temp + + return (sister, brother) + +#################### +## 1D List ## +#################### + +def G1DListCrossoverSinglePoint(genome, **args): + """ The crossover of G1DList, Single Point + + .. warning:: You can't use this crossover method for lists with just one element. + + """ + sister = None + brother = None + gMom = args["mom"] + gDad = args["dad"] + + if len(gMom) == 1: + Util.raiseException("The 1D List have one element, can't use the Single Point Crossover method !", TypeError) + + cut = rand_randint(1, len(gMom) - 1) + + if args["count"] >= 1: + sister = gMom.clone() + sister.resetStats() + sister[cut:] = gDad[cut:] + + if args["count"] == 2: + brother = gDad.clone() + brother.resetStats() + brother[cut:] = gMom[cut:] + + return (sister, brother) + +def G1DListCrossoverTwoPoint(genome, **args): + """ The G1DList crossover, Two Point + + .. warning:: You can't use this crossover method for lists with just one element. + + """ + sister = None + brother = None + gMom = args["mom"] + gDad = args["dad"] + + if len(gMom) == 1: + Util.raiseException("The 1D List have one element, can't use the Two Point Crossover method !", TypeError) + + cuts = [rand_randint(1, len(gMom) - 1), rand_randint(1, len(gMom) - 1)] + + if cuts[0] > cuts[1]: + Util.listSwapElement(cuts, 0, 1) + + if args["count"] >= 1: + sister = gMom.clone() + sister.resetStats() + sister[cuts[0]:cuts[1]] = gDad[cuts[0]:cuts[1]] + + if args["count"] == 2: + brother = gDad.clone() + brother.resetStats() + brother[cuts[0]:cuts[1]] = gMom[cuts[0]:cuts[1]] + + return (sister, brother) + +def G1DListCrossoverUniform(genome, **args): + """ The G1DList Uniform Crossover + + Each gene has a 50% chance of being swapped between mom and dad + + """ + sister = None + brother = None + gMom = args["mom"] + gDad = args["dad"] + + sister = gMom.clone() + brother = gDad.clone() + sister.resetStats() + brother.resetStats() + + for i in xrange(len(gMom)): + if Util.randomFlipCoin(Consts.CDefG1DListCrossUniformProb): + temp = sister[i] + sister[i] = brother[i] + brother[i] = temp + + return (sister, brother) + +def G1DListCrossoverOX(genome, **args): + """ The OX Crossover for G1DList (order crossover) """ + sister = None + brother = None + gMom = args["mom"] + gDad = args["dad"] + listSize = len(gMom) + + c1, c2 = [rand_randint(1, len(gMom) - 1), rand_randint(1, len(gMom) - 1)] + + while c1 == c2: + c2 = rand_randint(1, len(gMom) - 1) + + if c1 > c2: + h = c1 + c1 = c2 + c2 = h + + if args["count"] >= 1: + sister = gMom.clone() + sister.resetStats() + P1 = [c for c in gMom[c2:] + gMom[:c2] if c not in gDad[c1:c2]] + sister.genomeList = P1[listSize - c2:] + gDad[c1:c2] + P1[:listSize - c2] + + if args["count"] == 2: + brother = gDad.clone() + brother.resetStats() + P2 = [c for c in gDad[c2:] + gDad[:c2] if c not in gMom[c1:c2]] + brother.genomeList = P2[listSize - c2:] + gMom[c1:c2] + P2[:listSize - c2] + + assert listSize == len(sister) + assert listSize == len(brother) + + return (sister, brother) + +def G1DListCrossoverEdge(genome, **args): + """ THe Edge Recombination crossover for G1DList (widely used for TSP problem) + + See more information in the `Edge Recombination Operator `_ + Wikipedia entry. + """ + gMom, sisterl = args["mom"], [] + gDad, brotherl = args["dad"], [] + + mom_edges, dad_edges, merge_edges = Util.G1DListGetEdgesComposite(gMom, gDad) + + for c, u in (sisterl, set(gMom)), (brotherl, set(gDad)): + curr = None + for i in xrange(len(gMom)): + curr = rand_choice(tuple(u)) if not curr else curr + c.append(curr) + u.remove(curr) + d = [v for v in merge_edges.get(curr, []) if v in u] + if d: + curr = rand_choice(d) + else: + s = [v for v in mom_edges.get(curr, []) if v in u] + s += [v for v in dad_edges.get(curr, []) if v in u] + curr = rand_choice(s) if s else None + + sister = gMom.clone() + brother = gDad.clone() + sister.resetStats() + brother.resetStats() + + sister.genomeList = sisterl + brother.genomeList = brotherl + + return (sister, brother) + +def G1DListCrossoverCutCrossfill(genome, **args): + """ The crossover of G1DList, Cut and crossfill, for permutations + """ + sister = None + brother = None + gMom = args["mom"] + gDad = args["dad"] + + if len(gMom) == 1: + Util.raiseException("The 1D List have one element, can't use the Single Point Crossover method !", TypeError) + + cut = rand_randint(1, len(gMom) - 1) + + if args["count"] >= 1: + sister = gMom.clone() + mother_part = gMom[0:cut] + sister.resetStats() + i = (len(sister) - cut) + x = 0 + for v in gDad: + if v in mother_part: + continue + if x >= i: + break + sister[cut + x] = v + x += 1 + + if args["count"] == 2: + brother = gDad.clone() + father_part = gDad[0:cut] + brother.resetStats() + i = (len(brother) - cut) + x = 0 + for v in gMom: + if v in father_part: + continue + if x >= i: + break + brother[cut + x] = v + x += 1 + + return (sister, brother) + +def G1DListCrossoverRealSBX(genome, **args): + """ Experimental SBX Implementation - Follows the implementation in NSGA-II (Deb, et.al) + + Some implementation `reference `_. + And another reference to the `Simulated Binary Crossover `_. + + .. warning:: This crossover method is Data Type Dependent, which means that + must be used for 1D genome of real values. + """ + EPS = Consts.CDefG1DListSBXEPS + # Crossover distribution index + eta_c = Consts.CDefG1DListSBXEtac + + gMom = args["mom"] + gDad = args["dad"] + + # Get the variable bounds ('gDad' could have been used; but I love Mom:-)) + lb = gMom.getParam("rangemin", Consts.CDefRangeMin) + ub = gMom.getParam("rangemax", Consts.CDefRangeMax) + + sister = gMom.clone() + brother = gDad.clone() + + sister.resetStats() + brother.resetStats() + + for i in range(0, len(gMom)): + if math.fabs(gMom[i] - gDad[i]) > EPS: + if gMom[i] > gDad[i]: + #swap + temp = gMom[i] + gMom[i] = gDad[i] + gDad[i] = temp + + #random number betwn. 0 & 1 + u = rand_random() + + beta = 1.0 + 2 * (gMom[i] - lb) / (1.0 * (gDad[i] - gMom[i])) + alpha = 2.0 - beta ** (-(eta_c + 1.0)) + + if u <= (1.0 / alpha): + beta_q = (u * alpha) ** (1.0 / ((eta_c + 1.0) * 1.0)) + else: + beta_q = (1.0 / (2.0 - u * alpha)) ** (1.0 / (1.0 * (eta_c + 1.0))) + + brother[i] = 0.5 * ((gMom[i] + gDad[i]) - beta_q * (gDad[i] - gMom[i])) + + beta = 1.0 + 2.0 * (ub - gDad[i]) / (1.0 * (gDad[i] - gMom[i])) + alpha = 2.0 - beta ** (-(eta_c + 1.0)) + + if u <= (1.0 / alpha): + beta_q = (u * alpha) ** (1.0 / ((eta_c + 1) * 1.0)) + else: + beta_q = (1.0 / (2.0 - u * alpha)) ** (1.0 / (1.0 * (eta_c + 1.0))) + + sister[i] = 0.5 * ((gMom[i] + gDad[i]) + beta_q * (gDad[i] - gMom[i])) + + if brother[i] > ub: + brother[i] = ub + if brother[i] < lb: + brother[i] = lb + + if sister[i] > ub: + sister[i] = ub + if sister[i] < lb: + sister[i] = lb + + if rand_random() > 0.5: + # Swap + temp = sister[i] + sister[i] = brother[i] + brother[i] = temp + else: + sister[i] = gMom[i] + brother[i] = gDad[i] + + return (sister, brother) + + +#################### +## 2D List ## +#################### + +def G2DListCrossoverUniform(genome, **args): + """ The G2DList Uniform Crossover """ + sister = None + brother = None + gMom = args["mom"] + gDad = args["dad"] + + sister = gMom.clone() + brother = gDad.clone() + sister.resetStats() + brother.resetStats() + + h, w = gMom.getSize() + + for i in xrange(h): + for j in xrange(w): + if Util.randomFlipCoin(Consts.CDefG2DListCrossUniformProb): + temp = sister.getItem(i, j) + sister.setItem(i, j, brother.getItem(i, j)) + brother.setItem(i, j, temp) + + return (sister, brother) + + +def G2DListCrossoverSingleVPoint(genome, **args): + """ The crossover of G2DList, Single Vertical Point """ + sister = None + brother = None + gMom = args["mom"] + gDad = args["dad"] + + cut = rand_randint(1, gMom.getWidth() - 1) + + if args["count"] >= 1: + sister = gMom.clone() + sister.resetStats() + for i in xrange(sister.getHeight()): + sister[i][cut:] = gDad[i][cut:] + + if args["count"] == 2: + brother = gDad.clone() + brother.resetStats() + for i in xrange(brother.getHeight()): + brother[i][cut:] = gMom[i][cut:] + + return (sister, brother) + +def G2DListCrossoverSingleHPoint(genome, **args): + """ The crossover of G2DList, Single Horizontal Point """ + sister = None + brother = None + gMom = args["mom"] + gDad = args["dad"] + + cut = rand_randint(1, gMom.getHeight() - 1) + + if args["count"] >= 1: + sister = gMom.clone() + sister.resetStats() + for i in xrange(cut, sister.getHeight()): + sister[i][:] = gDad[i][:] + + if args["count"] == 2: + brother = gDad.clone() + brother.resetStats() + for i in xrange(brother.getHeight()): + brother[i][:] = gMom[i][:] + + return (sister, brother) + + +############################# +## 2D Binary String ## +############################# + + +def G2DBinaryStringXUniform(genome, **args): + """ The G2DBinaryString Uniform Crossover + + .. versionadded:: 0.6 + The *G2DBinaryStringXUniform* function + """ + sister = None + brother = None + gMom = args["mom"] + gDad = args["dad"] + + sister = gMom.clone() + brother = gDad.clone() + sister.resetStats() + brother.resetStats() + + h, w = gMom.getSize() + + for i in xrange(h): + for j in xrange(w): + if Util.randomFlipCoin(Consts.CDefG2DBinaryStringUniformProb): + temp = sister.getItem(i, j) + sister.setItem(i, j, brother.getItem(i, j)) + brother.setItem(i, j, temp) + + return (sister, brother) + + +def G2DBinaryStringXSingleVPoint(genome, **args): + """ The crossover of G2DBinaryString, Single Vertical Point + + .. versionadded:: 0.6 + The *G2DBinaryStringXSingleVPoint* function + """ + sister = None + brother = None + gMom = args["mom"] + gDad = args["dad"] + + cut = rand_randint(1, gMom.getWidth() - 1) + + if args["count"] >= 1: + sister = gMom.clone() + sister.resetStats() + for i in xrange(sister.getHeight()): + sister[i][cut:] = gDad[i][cut:] + + if args["count"] == 2: + brother = gDad.clone() + brother.resetStats() + for i in xrange(brother.getHeight()): + brother[i][cut:] = gMom[i][cut:] + + return (sister, brother) + +def G2DBinaryStringXSingleHPoint(genome, **args): + """ The crossover of G2DBinaryString, Single Horizontal Point + + .. versionadded:: 0.6 + The *G2DBinaryStringXSingleHPoint* function + + """ + sister = None + brother = None + gMom = args["mom"] + gDad = args["dad"] + + cut = rand_randint(1, gMom.getHeight() - 1) + + if args["count"] >= 1: + sister = gMom.clone() + sister.resetStats() + for i in xrange(cut, sister.getHeight()): + sister[i][:] = gDad[i][:] + + if args["count"] == 2: + brother = gDad.clone() + brother.resetStats() + for i in xrange(brother.getHeight()): + brother[i][:] = gMom[i][:] + + return (sister, brother) + +############################# +## Tree ## +############################# + + +def GTreeCrossoverSinglePoint(genome, **args): + """ The crossover for GTree, Single Point """ + sister = None + brother = None + gMom = args["mom"].clone() + gDad = args["dad"].clone() + + gMom.resetStats() + gDad.resetStats() + + node_mom_stack = [] + all_mom_nodes = [] + node_mom_tmp = None + + node_dad_stack = [] + all_dad_nodes = [] + node_dad_tmp = None + + node_mom_stack.append(gMom.getRoot()) + node_dad_stack.append(gDad.getRoot()) + + while (len(node_mom_stack) > 0) and (len(node_dad_stack) > 0): + node_mom_tmp = node_mom_stack.pop() + node_dad_tmp = node_dad_stack.pop() + + if node_mom_tmp != gMom.getRoot(): + all_mom_nodes.append(node_mom_tmp) + all_dad_nodes.append(node_dad_tmp) + + node_mom_stack.extend(node_mom_tmp.getChilds()) + node_dad_stack.extend(node_dad_tmp.getChilds()) + + if len(all_mom_nodes) == 0 or len(all_dad_nodes) == 0: + return (gMom, gDad) + + if len(all_dad_nodes) == 1: + nodeDad = all_dad_nodes[0] + else: + nodeDad = rand_choice(all_dad_nodes) + + if len(all_mom_nodes) == 1: + nodeMom = all_mom_nodes[0] + else: + nodeMom = rand_choice(all_mom_nodes) + + nodeMom_parent = nodeMom.getParent() + nodeDad_parent = nodeDad.getParent() + + # Sister + if args["count"] >= 1: + sister = gMom + nodeDad.setParent(nodeMom_parent) + nodeMom_parent.replaceChild(nodeMom, nodeDad) + sister.processNodes() + + # Brother + if args["count"] == 2: + brother = gDad + nodeMom.setParent(nodeDad_parent) + nodeDad_parent.replaceChild(nodeDad, nodeMom) + brother.processNodes() + + return (sister, brother) + +def GTreeCrossoverSinglePointStrict(genome, **args): + """ The crossover of Tree, Strict Single Point + + ..note:: This crossover method creates offspring with restriction of the + *max_depth* parameter. + + Accepts the *max_attempt* parameter, *max_depth* (required), and + the distr_leaft (>= 0.0 and <= 1.0), which represents the probability + of leaf selection when findin random nodes for crossover. + + """ + sister = None + brother = None + + gMom = args["mom"].clone() + gDad = args["dad"].clone() + + gMom.resetStats() + gDad.resetStats() + + max_depth = gMom.getParam("max_depth", None) + max_attempt = gMom.getParam("max_attempt", 10) + distr_leaf = gMom.getParam("distr_leaf", None) + + if max_depth is None: + Util.raiseException("You must specify the max_depth genome parameter !", ValueError) + + if max_depth < 0: + Util.raiseException("The max_depth must be >= 1, if you want to use GTreeCrossoverSinglePointStrict crossover !", ValueError) + + momRandom = None + dadRandom = None + + for i in xrange(max_attempt): + + if distr_leaf is None: + dadRandom = gDad.getRandomNode() + momRandom = gMom.getRandomNode() + else: + if Util.randomFlipCoin(distr_leaf): + momRandom = gMom.getRandomNode(1) + else: + momRandom = gMom.getRandomNode(2) + + if Util.randomFlipCoin(distr_leaf): + dadRandom = gDad.getRandomNode(1) + else: + dadRandom = gDad.getRandomNode(2) + + assert momRandom is not None + assert dadRandom is not None + + # Optimize here + mH = gMom.getNodeHeight(momRandom) + dH = gDad.getNodeHeight(dadRandom) + + mD = gMom.getNodeDepth(momRandom) + dD = gDad.getNodeDepth(dadRandom) + + # The depth of the crossover is greater than the max_depth + if (dD + mH <= max_depth) and (mD + dH <= max_depth): + break + + if i == (max_attempt - 1): + assert gMom.getHeight() <= max_depth + return (gMom, gDad) + else: + nodeMom, nodeDad = momRandom, dadRandom + + nodeMom_parent = nodeMom.getParent() + nodeDad_parent = nodeDad.getParent() + + # Sister + if args["count"] >= 1: + sister = gMom + nodeDad.setParent(nodeMom_parent) + + if nodeMom_parent is None: + sister.setRoot(nodeDad) + else: + nodeMom_parent.replaceChild(nodeMom, nodeDad) + sister.processNodes() + assert sister.getHeight() <= max_depth + + # Brother + if args["count"] == 2: + brother = gDad + nodeMom.setParent(nodeDad_parent) + + if nodeDad_parent is None: + brother.setRoot(nodeMom) + else: + nodeDad_parent.replaceChild(nodeDad, nodeMom) + brother.processNodes() + assert brother.getHeight() <= max_depth + + return (sister, brother) + +############################################################################# +################# GTreeGP Crossovers ###################################### +############################################################################# + +def GTreeGPCrossoverSinglePoint(genome, **args): + """ The crossover of the GTreeGP, Single Point for Genetic Programming + + ..note:: This crossover method creates offspring with restriction of the + *max_depth* parameter. + + Accepts the *max_attempt* parameter, *max_depth* (required). + """ + sister = None + brother = None + + gMom = args["mom"].clone() + gDad = args["dad"].clone() + + gMom.resetStats() + gDad.resetStats() + + max_depth = gMom.getParam("max_depth", None) + max_attempt = gMom.getParam("max_attempt", 15) + + if max_depth is None: + Util.raiseException("You must specify the max_depth genome parameter !", ValueError) + + if max_depth < 0: + Util.raiseException("The max_depth must be >= 1, if you want to use GTreeCrossoverSinglePointStrict crossover !", ValueError) + + momRandom = None + dadRandom = None + + for i in xrange(max_attempt): + + dadRandom = gDad.getRandomNode() + + if dadRandom.getType() == Consts.nodeType["TERMINAL"]: + momRandom = gMom.getRandomNode(1) + elif dadRandom.getType() == Consts.nodeType["NONTERMINAL"]: + momRandom = gMom.getRandomNode(2) + + mD = gMom.getNodeDepth(momRandom) + dD = gDad.getNodeDepth(dadRandom) + + # Two nodes are root + if mD == 0 and dD == 0: + continue + + mH = gMom.getNodeHeight(momRandom) + if dD + mH > max_depth: + continue + + dH = gDad.getNodeHeight(dadRandom) + if mD + dH > max_depth: + continue + + break + + if i == (max_attempt - 1): + assert gMom.getHeight() <= max_depth + return (gMom, gDad) + else: + nodeMom, nodeDad = momRandom, dadRandom + + nodeMom_parent = nodeMom.getParent() + nodeDad_parent = nodeDad.getParent() + + # Sister + if args["count"] >= 1: + sister = gMom + nodeDad.setParent(nodeMom_parent) + + if nodeMom_parent is None: + sister.setRoot(nodeDad) + else: + nodeMom_parent.replaceChild(nodeMom, nodeDad) + sister.processNodes() + assert sister.getHeight() <= max_depth + + # Brother + if args["count"] == 2: + brother = gDad + nodeMom.setParent(nodeDad_parent) + + if nodeDad_parent is None: + brother.setRoot(nodeMom) + else: + nodeDad_parent.replaceChild(nodeDad, nodeMom) + brother.processNodes() + assert brother.getHeight() <= max_depth + + return (sister, brother) diff --git a/pyevolve/DBAdapters.py.bak b/pyevolve/DBAdapters.py.bak new file mode 100644 index 0000000..63a4a35 --- /dev/null +++ b/pyevolve/DBAdapters.py.bak @@ -0,0 +1,790 @@ +""" +:mod:`DBAdapters` -- database adapters for statistics +===================================================================== + +.. warning:: the use the of a DB Adapter can reduce the performance of the + Genetic Algorithm. + +Pyevolve have a feature in which you can save the statistics of every +generation in a database, file or call an URL with the statistics as param. +You can use the database to plot evolution statistics graphs later. In this +module, you'll find the adapters above cited. + +.. seealso:: + + Method :meth:`GSimpleGA.GSimpleGA.setDBAdapter` + DB Adapters are set in the GSimpleGA Class. + +""" + +from pyevolve import __version__ +import Consts +import Util +import logging +import types +import datetime +import Statistics + + +class DBBaseAdapter(object): + """ DBBaseAdapter Class - The base class for all DB Adapters + + If you want to create your own DB Adapter, you must subclass this + class. + + :param frequency: the the generational dump frequency + + .. versionadded:: 0.6 + Added the :class:`DBBaseAdapter` class. + """ + def __init__(self, frequency, identify): + """ The class constructor """ + self.statsGenFreq = frequency + + if identify is None: + self.identify = datetime.datetime.strftime(datetime.datetime.now(), "%d/%m/%y-%H:%M") + else: + self.identify = identify + + def setIdentify(self, identify): + """ Sets the identify of the statistics + + :param identify: the id string + """ + if identify is None: + self.identify = datetime.datetime.strftime(datetime.datetime.now(), "%d/%m/%y-%H:%M") + else: + self.identify = identify + + def getIdentify(self): + """ Return the statistics identify + + :rtype: identify string + """ + return self.identify + + def getStatsGenFreq(self): + """ Returns the frequency of statistical dump + + :rtype: the generation interval of statistical dump + """ + return self.statsGenFreq + + def setStatsGenFreq(self, statsGenFreq): + """ Set the frequency of statistical dump + + :param statsGenFreq: the generation interval of statistical dump + """ + self.statsGenFreq = statsGenFreq + + def open(self, ga_engine): + """ This method is called one time to do the initialization of + the DB Adapter + + :param ga_engine: the GA Engine + """ + pass + + def commitAndClose(self): + """ This method is called at the end of the evolution, to closes the + DB Adapter and commit the changes """ + pass + + def insert(self, ga_engine): + """ Insert the stats + + :param ga_engine: the GA Engine + """ + Util.raiseException("This method is not implemented on the ABC", NotImplementedError) + +class DBFileCSV(DBBaseAdapter): + """ DBFileCSV Class - Adapter to dump statistics in CSV format + + Inheritance diagram for :class:`DBAdapters.DBFileCSV`: + + .. inheritance-diagram:: DBAdapters.DBFileCSV + + Example: + >>> adapter = DBFileCSV(filename="file.csv", identify="run_01", + frequency = 1, reset = True) + + :param filename: the CSV filename + :param identify: the identify of the run + :param frequency: the generational dump frequency + :param reset: if True, the file old data will be overwrite with the new + + .. versionadded:: 0.6 + Removed the stub methods and subclassed the :class:`DBBaseAdapter` class. + + """ + def __init__(self, filename=Consts.CDefCSVFileName, identify=None, + frequency=Consts.CDefCSVFileStatsGenFreq, reset=True): + """ The creator of DBFileCSV Class """ + + super(DBFileCSV, self).__init__(frequency, identify) + + self.csvmod = None + + self.filename = filename + self.csvWriter = None + self.fHandle = None + self.reset = reset + + def __repr__(self): + """ The string representation of adapter """ + ret = "DBFileCSV DB Adapter [File='%s', identify='%s']" % (self.filename, self.getIdentify()) + return ret + + def open(self, ga_engine): + """ Open the CSV file or creates a new file + + :param ga_engine: the GA Engine + + .. versionchanged:: 0.6 + The method now receives the *ga_engine* parameter. + """ + if self.csvmod is None: + logging.debug("Loading the csv module...") + self.csvmod = Util.importSpecial("csv") + + logging.debug("Opening the CSV file to dump statistics [%s]", self.filename) + open_mode = 'w' if self.reset else 'a' + self.fHandle = open(self.filename, open_mode) + self.csvWriter = self.csvmod.writer(self.fHandle, delimiter=';') + + def close(self): + """ Closes the CSV file handle """ + logging.debug("Closing the CSV file [%s]", self.filename) + if self.fHandle: + self.fHandle.close() + + def commitAndClose(self): + """ Commits and closes """ + self.close() + + def insert(self, ga_engine): + """ Inserts the stats into the CSV file + + :param ga_engine: the GA Engine + + .. versionchanged:: 0.6 + The method now receives the *ga_engine* parameter. + """ + stats = ga_engine.getStatistics() + generation = ga_engine.getCurrentGeneration() + line = [self.getIdentify(), generation] + line.extend(stats.asTuple()) + self.csvWriter.writerow(line) + +class DBURLPost(DBBaseAdapter): + """ DBURLPost Class - Adapter to call an URL with statistics + + Inheritance diagram for :class:`DBAdapters.DBURLPost`: + + .. inheritance-diagram:: DBAdapters.DBURLPost + + Example: + >>> dbadapter = DBURLPost(url="http://localhost/post.py", identify="test") + + The parameters that will be sent is all the statistics described in the :class:`Statistics.Statistics` + class, and the parameters: + + **generation** + The generation of the statistics + + **identify** + The id specified by user + + .. note:: see the :class:`Statistics.Statistics` documentation. + + :param url: the URL to be used + :param identify: the identify of the run + :param frequency: the generational dump frequency + :param post: if True, the POST method will be used, otherwise GET will be used. + + .. versionadded:: 0.6 + Removed the stub methods and subclassed the :class:`DBBaseAdapter` class. + """ + + def __init__(self, url, identify=None, + frequency=Consts.CDefURLPostStatsGenFreq, post=True): + """ The creator of the DBURLPost Class. """ + + super(DBURLPost, self).__init__(frequency, identify) + self.urllibmod = None + + self.url = url + self.post = post + + def __repr__(self): + """ The string representation of adapter """ + ret = "DBURLPost DB Adapter [URL='%s', identify='%s']" % (self.url, self.getIdentify()) + return ret + + def open(self, ga_engine): + """ Load the modules needed + + :param ga_engine: the GA Engine + + .. versionchanged:: 0.6 + The method now receives the *ga_engine* parameter. + """ + if self.urllibmod is None: + logging.debug("Loading urllib module...") + self.urllibmod = Util.importSpecial("urllib") + + def insert(self, ga_engine): + """ Sends the data to the URL using POST or GET + + :param ga_engine: the GA Engine + + .. versionchanged:: 0.6 + The method now receives the *ga_engine* parameter. + """ + logging.debug("Sending http request to %s.", self.url) + stats = ga_engine.getStatistics() + response = None + params = stats.internalDict.copy() + params["generation"] = ga_engine.getCurrentGeneration() + params["identify"] = self.getIdentify() + if self.post: # POST + response = self.urllibmod.urlopen(self.url, self.urllibmod.urlencode(params)) + else: # GET + response = self.urllibmod.urlopen(self.url + "?%s" % (self.urllibmod.urlencode(params))) + if response: + response.close() + +class DBSQLite(DBBaseAdapter): + """ DBSQLite Class - Adapter to dump data in SQLite3 database format + + Inheritance diagram for :class:`DBAdapters.DBSQLite`: + + .. inheritance-diagram:: DBAdapters.DBSQLite + + Example: + >>> dbadapter = DBSQLite(identify="test") + + When you run some GA for the first time, you need to create the database, for this, you + must use the *resetDB* parameter: + + >>> dbadapter = DBSQLite(identify="test", resetDB=True) + + This parameter will erase all the database tables and will create the new ones. + The *resetDB* parameter is different from the *resetIdentify* parameter, the *resetIdentify* + only erases the rows with the same "identify" name. + + :param dbname: the database filename + :param identify: the identify if the run + :param resetDB: if True, the database structure will be recreated + :param resetIdentify: if True, the identify with the same name will be overwrite with new data + :param frequency: the generational dump frequency + :param commit_freq: the commit frequency + """ + + def __init__(self, dbname=Consts.CDefSQLiteDBName, identify=None, resetDB=False, + resetIdentify=True, frequency=Consts.CDefSQLiteStatsGenFreq, + commit_freq=Consts.CDefSQLiteStatsCommitFreq): + """ The creator of the DBSQLite Class """ + + super(DBSQLite, self).__init__(frequency, identify) + + self.sqlite3mod = None + self.connection = None + self.resetDB = resetDB + self.resetIdentify = resetIdentify + self.dbName = dbname + self.typeDict = {types.FloatType: "real"} + self.cursorPool = None + self.commitFreq = commit_freq + + def __repr__(self): + """ The string representation of adapter """ + ret = "DBSQLite DB Adapter [File='%s', identify='%s']" % (self.dbName, self.getIdentify()) + return ret + + def open(self, ga_engine): + """ Open the database connection + + :param ga_engine: the GA Engine + + .. versionchanged:: 0.6 + The method now receives the *ga_engine* parameter. + """ + if self.sqlite3mod is None: + logging.debug("Loading sqlite3 module...") + self.sqlite3mod = Util.importSpecial("sqlite3") + + logging.debug("Opening database, dbname=%s", self.dbName) + self.connection = self.sqlite3mod.connect(self.dbName) + + temp_stats = Statistics.Statistics() + + if self.resetDB: + self.resetStructure(Statistics.Statistics()) + + self.createStructure(temp_stats) + + if self.resetIdentify: + self.resetTableIdentify() + + def commitAndClose(self): + """ Commit changes on database and closes connection """ + self.commit() + self.close() + + def close(self): + """ Close the database connection """ + logging.debug("Closing database.") + if self.cursorPool: + self.cursorPool.close() + self.cursorPool = None + self.connection.close() + + def commit(self): + """ Commit changes to database """ + logging.debug("Commiting changes to database.") + self.connection.commit() + + def getCursor(self): + """ Return a cursor from the pool + + :rtype: the cursor + + """ + if not self.cursorPool: + logging.debug("Creating new cursor for database...") + self.cursorPool = self.connection.cursor() + return self.cursorPool + else: + return self.cursorPool + + def createStructure(self, stats): + """ Create table using the Statistics class structure + + :param stats: the statistics object + + """ + c = self.getCursor() + pstmt = "create table if not exists %s(identify text, generation integer, " % (Consts.CDefSQLiteDBTable) + for k, v in stats.items(): + pstmt += "%s %s, " % (k, self.typeDict[type(v)]) + pstmt = pstmt[:-2] + ")" + logging.debug("Creating table %s: %s.", Consts.CDefSQLiteDBTable, pstmt) + c.execute(pstmt) + + pstmt = """create table if not exists %s(identify text, generation integer, + individual integer, fitness real, raw real)""" % (Consts.CDefSQLiteDBTablePop) + logging.debug("Creating table %s: %s.", Consts.CDefSQLiteDBTablePop, pstmt) + c.execute(pstmt) + self.commit() + + def resetTableIdentify(self): + """ Delete all records on the table with the same Identify """ + c = self.getCursor() + stmt = "delete from %s where identify = ?" % (Consts.CDefSQLiteDBTable) + stmt2 = "delete from %s where identify = ?" % (Consts.CDefSQLiteDBTablePop) + + logging.debug("Erasing data from the tables with the identify = %s", self.getIdentify()) + try: + c.execute(stmt, (self.getIdentify(),)) + c.execute(stmt2, (self.getIdentify(),)) + except self.sqlite3mod.OperationalError, expt: + if str(expt).find("no such table") >= 0: + print "\n ## The DB Adapter can't find the tables ! Consider enable the parameter resetDB ! ##\n" + + self.commit() + + def resetStructure(self, stats): + """ Deletes de current structure and calls createStructure + + :param stats: the statistics object + + """ + logging.debug("Reseting structure, droping table and creating new empty table.") + c = self.getCursor() + c.execute("drop table if exists %s" % (Consts.CDefSQLiteDBTable,)) + c.execute("drop table if exists %s" % (Consts.CDefSQLiteDBTablePop,)) + self.commit() + self.createStructure(stats) + + def insert(self, ga_engine): + """ Inserts the statistics data to database + + :param ga_engine: the GA Engine + + .. versionchanged:: 0.6 + The method now receives the *ga_engine* parameter. + """ + stats = ga_engine.getStatistics() + population = ga_engine.getPopulation() + generation = ga_engine.getCurrentGeneration() + + c = self.getCursor() + pstmt = "insert into %s values (?, ?, " % (Consts.CDefSQLiteDBTable) + for i in xrange(len(stats)): + pstmt += "?, " + pstmt = pstmt[:-2] + ")" + c.execute(pstmt, (self.getIdentify(), generation) + stats.asTuple()) + + pstmt = "insert into %s values(?, ?, ?, ?, ?)" % (Consts.CDefSQLiteDBTablePop,) + tups = [] + for i in xrange(len(population)): + ind = population[i] + tups.append((self.getIdentify(), generation, i, ind.fitness, ind.score)) + + c.executemany(pstmt, tups) + if (generation % self.commitFreq == 0): + self.commit() + +class DBXMLRPC(DBBaseAdapter): + """ DBXMLRPC Class - Adapter to dump statistics to a XML Remote Procedure Call + + Inheritance diagram for :class:`DBAdapters.DBXMLRPC`: + + .. inheritance-diagram:: DBAdapters.DBXMLRPC + + Example: + >>> adapter = DBXMLRPC(url="http://localhost:8000/", identify="run_01", + frequency = 1) + + :param url: the URL of the XML RPC + :param identify: the identify of the run + :param frequency: the generational dump frequency + + + .. note:: The XML RPC Server must implement the *insert* method, wich receives + a python dictionary as argument. + + Example of an server in Python: :: + + import xmlrpclib + from SimpleXMLRPCServer import SimpleXMLRPCServer + + def insert(l): + print "Received statistics: %s" % l + + server = SimpleXMLRPCServer(("localhost", 8000), allow_none=True) + print "Listening on port 8000..." + server.register_function(insert, "insert") + server.serve_forever() + + .. versionadded:: 0.6 + The :class:`DBXMLRPC` class. + + """ + def __init__(self, url, identify=None, frequency=Consts.CDefXMLRPCStatsGenFreq): + """ The creator of DBXMLRPC Class """ + + super(DBXMLRPC, self).__init__(frequency, identify) + self.xmlrpclibmod = None + + self.url = url + self.proxy = None + + def __repr__(self): + """ The string representation of adapter """ + ret = "DBXMLRPC DB Adapter [URL='%s', identify='%s']" % (self.url, self.getIdentify()) + return ret + + def open(self, ga_engine): + """ Open the XML RPC Server proxy + + :param ga_engine: the GA Engine + + .. versionchanged:: 0.6 + The method now receives the *ga_engine* parameter. + """ + if self.xmlrpclibmod is None: + logging.debug("Loding the xmlrpclib module...") + self.xmlrpclibmod = Util.importSpecial("xmlrpclib") + + logging.debug("Opening the XML RPC Server Proxy on %s", self.url) + self.proxy = self.xmlrpclibmod.ServerProxy(self.url, allow_none=True) + + def insert(self, ga_engine): + """ Calls the XML RPC procedure + + :param ga_engine: the GA Engine + + .. versionchanged:: 0.6 + The method now receives the *ga_engine* parameter. + """ + stats = ga_engine.getStatistics() + generation = ga_engine.getCurrentGeneration() + di = stats.internalDict.copy() + di.update({"identify": self.getIdentify(), "generation": generation}) + self.proxy.insert(di) + +class DBVPythonGraph(DBBaseAdapter): + """ The DBVPythonGraph Class - A DB Adapter for real-time visualization using VPython + + Inheritance diagram for :class:`DBAdapters.DBVPythonGraph`: + + .. inheritance-diagram:: DBAdapters.DBVPythonGraph + + .. note:: to use this DB Adapter, you **must** install VPython first. + + Example: + >>> adapter = DBAdapters.DBVPythonGraph(identify="run_01", frequency = 1) + >>> ga_engine.setDBAdapter(adapter) + + :param identify: the identify of the run + :param genmax: use the generations as max value for x-axis, default False + :param frequency: the generational dump frequency + + .. versionadded:: 0.6 + The *DBVPythonGraph* class. + """ + + def __init__(self, identify=None, frequency=20, genmax=False): + super(DBVPythonGraph, self).__init__(frequency, identify) + self.genmax = genmax + self.vtkGraph = None + self.curveMin = None + self.curveMax = None + self.curveDev = None + self.curveAvg = None + + def makeDisplay(self, title_sec, x, y, ga_engine): + """ Used internally to create a new display for VPython. + + :param title_sec: the title of the window + :param x: the x position of the window + :param y: the y position of the window + :param ga_engine: the GA Engine + + :rtype: the window (the return of gdisplay call) + """ + title = "Pyevolve v.%s - %s - id [%s]" % (__version__, title_sec, self.identify) + if self.genmax: + disp = self.vtkGraph.gdisplay(title=title, xtitle='Generation', ytitle=title_sec, + xmax=ga_engine.getGenerations(), xmin=0., width=500, + height=250, x=x, y=y) + else: + disp = self.vtkGraph.gdisplay(title=title, xtitle='Generation', ytitle=title_sec, + xmin=0., width=500, height=250, x=x, y=y) + return disp + + def open(self, ga_engine): + """ Imports the VPython module and creates the four graph windows + + :param ga_engine: the GA Engine + """ + logging.debug("Loading visual.graph (VPython) module...") + if self.vtkGraph is None: + self.vtkGraph = Util.importSpecial("visual.graph").graph + + display_rawmin = self.makeDisplay("Raw Score (min)", 0, 0, ga_engine) + display_rawmax = self.makeDisplay("Raw Score (max)", 0, 250, ga_engine) + display_rawdev = self.makeDisplay("Raw Score (std. dev.)", 500, 0, ga_engine) + display_rawavg = self.makeDisplay("Raw Score (avg)", 500, 250, ga_engine) + + self.curveMin = self.vtkGraph.gcurve(color=self.vtkGraph.color.red, gdisplay=display_rawmin) + self.curveMax = self.vtkGraph.gcurve(color=self.vtkGraph.color.green, gdisplay=display_rawmax) + self.curveDev = self.vtkGraph.gcurve(color=self.vtkGraph.color.blue, gdisplay=display_rawdev) + self.curveAvg = self.vtkGraph.gcurve(color=self.vtkGraph.color.orange, gdisplay=display_rawavg) + + def insert(self, ga_engine): + """ Plot the current statistics to the graphs + + :param ga_engine: the GA Engine + """ + stats = ga_engine.getStatistics() + generation = ga_engine.getCurrentGeneration() + + self.curveMin.plot(pos=(generation, stats["rawMin"])) + self.curveMax.plot(pos=(generation, stats["rawMax"])) + self.curveDev.plot(pos=(generation, stats["rawDev"])) + self.curveAvg.plot(pos=(generation, stats["rawAve"])) + +class DBMySQLAdapter(DBBaseAdapter): + """ DBMySQLAdapter Class - Adapter to dump data in MySql database server + + Inheritance diagram for :class:`DBAdapters.DBMySQLAdapter`: + + .. inheritance-diagram:: DBAdapters.DBMySQLAdapter + + Example: + >>> dbadapter = DBMySQLAdapter("pyevolve_username", "password", identify="run1") + + or + + >>> dbadapter = DBMySQLAdapter(user="username", passwd="password", + ... host="mysqlserver.com.br", port=3306, db="pyevolve_db") + + When you run some GA for the first time, you need to create the database, for this, you + must use the *resetDB* parameter as True. + + This parameter will erase all the database tables and will create the new ones. + The *resetDB* parameter is different from the *resetIdentify* parameter, the *resetIdentify* + only erases the rows with the same "identify" name, and *resetDB* will drop and recreate + the tables. + + :param user: mysql username (must have permission to create, drop, insert, etc.. on tables + :param passwd: the user password on MySQL server + :param host: the hostname, default is "localhost" + :param port: the port, default is 3306 + :param db: the database name, default is "pyevolve" + :param identify: the identify if the run + :param resetDB: if True, the database structure will be recreated + :param resetIdentify: if True, the identify with the same name will be overwrite with new data + :param frequency: the generational dump frequency + :param commit_freq: the commit frequency + """ + + def __init__(self, user, passwd, host=Consts.CDefMySQLDBHost, port=Consts.CDefMySQLDBPort, + db=Consts.CDefMySQLDBName, identify=None, resetDB=False, resetIdentify=True, + frequency=Consts.CDefMySQLStatsGenFreq, commit_freq=Consts.CDefMySQLStatsCommitFreq): + """ The creator of the DBSQLite Class """ + + super(DBMySQLAdapter, self).__init__(frequency, identify) + + self.mysqldbmod = None + self.connection = None + self.resetDB = resetDB + self.resetIdentify = resetIdentify + self.db = db + self.host = host + self.port = port + self.user = user + self.passwd = passwd + self.typeDict = {types.FloatType: "DOUBLE(14,6)"} + self.cursorPool = None + self.commitFreq = commit_freq + + def __repr__(self): + """ The string representation of adapter """ + ret = "DBMySQLAdapter DB Adapter [identify='%s', host='%s', username='%s', db='%s']" % (self.getIdentify(), + self.host, self.user, self.db) + return ret + + def open(self, ga_engine): + """ Open the database connection + + :param ga_engine: the GA Engine + + .. versionchanged:: 0.6 + The method now receives the *ga_engine* parameter. + """ + if self.mysqldbmod is None: + logging.debug("Loading MySQLdb module...") + self.mysqldbmod = Util.importSpecial("MySQLdb") + + logging.debug("Opening database, host=%s", self.host) + self.connection = self.mysqldbmod.connect(host=self.host, user=self.user, + passwd=self.passwd, db=self.db, + port=self.port) + temp_stats = Statistics.Statistics() + self.createStructure(temp_stats) + + if self.resetDB: + self.resetStructure(Statistics.Statistics()) + + if self.resetIdentify: + self.resetTableIdentify() + + def commitAndClose(self): + """ Commit changes on database and closes connection """ + self.commit() + self.close() + + def close(self): + """ Close the database connection """ + logging.debug("Closing database.") + if self.cursorPool: + self.cursorPool.close() + self.cursorPool = None + self.connection.close() + + def commit(self): + """ Commit changes to database """ + logging.debug("Commiting changes to database.") + self.connection.commit() + + def getCursor(self): + """ Return a cursor from the pool + + :rtype: the cursor + + """ + if not self.cursorPool: + logging.debug("Creating new cursor for database...") + self.cursorPool = self.connection.cursor() + return self.cursorPool + else: + return self.cursorPool + + def createStructure(self, stats): + """ Create table using the Statistics class structure + + :param stats: the statistics object + + """ + c = self.getCursor() + pstmt = "create table if not exists %s(identify VARCHAR(80), generation INTEGER, " % (Consts.CDefMySQLDBTable) + for k, v in stats.items(): + pstmt += "%s %s, " % (k, self.typeDict[type(v)]) + pstmt = pstmt[:-2] + ")" + logging.debug("Creating table %s: %s.", Consts.CDefSQLiteDBTable, pstmt) + c.execute(pstmt) + + pstmt = """create table if not exists %s(identify VARCHAR(80), generation INTEGER, + individual INTEGER, fitness DOUBLE(14,6), raw DOUBLE(14,6))""" % (Consts.CDefMySQLDBTablePop) + logging.debug("Creating table %s: %s.", Consts.CDefMySQLDBTablePop, pstmt) + c.execute(pstmt) + self.commit() + + def resetTableIdentify(self): + """ Delete all records on the table with the same Identify """ + c = self.getCursor() + stmt = "delete from %s where identify = '%s'" % (Consts.CDefMySQLDBTable, self.getIdentify()) + stmt2 = "delete from %s where identify = '%s'" % (Consts.CDefMySQLDBTablePop, self.getIdentify()) + + logging.debug("Erasing data from the tables with the identify = %s", self.getIdentify()) + c.execute(stmt) + c.execute(stmt2) + + self.commit() + + def resetStructure(self, stats): + """ Deletes de current structure and calls createStructure + + :param stats: the statistics object + + """ + logging.debug("Reseting structure, droping table and creating new empty table.") + c = self.getCursor() + c.execute("drop table if exists %s" % (Consts.CDefMySQLDBTable,)) + c.execute("drop table if exists %s" % (Consts.CDefMySQLDBTablePop,)) + self.commit() + self.createStructure(stats) + + def insert(self, ga_engine): + """ Inserts the statistics data to database + + :param ga_engine: the GA Engine + + .. versionchanged:: 0.6 + The method now receives the *ga_engine* parameter. + """ + stats = ga_engine.getStatistics() + population = ga_engine.getPopulation() + generation = ga_engine.getCurrentGeneration() + + c = self.getCursor() + pstmt = "insert into " + Consts.CDefMySQLDBTable + " values (%s, %s, " + for i in xrange(len(stats)): + pstmt += "%s, " + pstmt = pstmt[:-2] + ")" + c.execute(pstmt, (self.getIdentify(), generation) + stats.asTuple()) + + pstmt = "insert into " + Consts.CDefMySQLDBTablePop + " values(%s, %s, %s, %s, %s)" + + tups = [] + for i in xrange(len(population)): + ind = population[i] + tups.append((self.getIdentify(), generation, i, ind.fitness, ind.score)) + + c.executemany(pstmt, tups) + if (generation % self.commitFreq == 0): + self.commit() diff --git a/pyevolve/FunctionSlot.py.bak b/pyevolve/FunctionSlot.py.bak new file mode 100644 index 0000000..e5145e0 --- /dev/null +++ b/pyevolve/FunctionSlot.py.bak @@ -0,0 +1,202 @@ +""" +:mod:`FunctionSlot` -- function slots module +================================================================== + +The *function slot* concept is large used by Pyevolve, the idea +is simple, each genetic operator or any operator, can be assigned +to a slot, by this way, we can add more than simple one operator, +we can have for example, two or more mutator operators at same time, +two or more evaluation functions, etc. In this :mod:`FunctionSlot` module, +you'll find the class :class:`FunctionSlot.FunctionSlot`, which is the slot class. + +""" + +from random import uniform as rand_uniform +from types import BooleanType + +import Util + +class FunctionSlot(object): + """ FunctionSlot Class - The function slot + + Example: + >>> genome.evaluator.set(eval_func) + >>> genome.evaluator[0] + + >>> genome.evaluator + Slot [Evaluation Function] (Count: 1) + Name: eval_func + >>> genome.evaluator.clear() + >>> genome.evaluator + Slot [Evaluation Function] (Count: 0) + No function + + You can add weight to functions when using the `rand_apply` paramter: + >>> genome.evaluator.set(eval_main, 0.9) + >>> genome.evaluator.add(eval_sec, 0.3) + >>> genome.evaluator.setRandomApply() + + In the above example, the function *eval_main* will be called with 90% of + probability and the *eval_sec* will be called with 30% of probability. + + There are another way to add functions too: + >>> genome.evaluator += eval_func + + :param name: the slot name + :param rand_apply: if True, just one of the functions in the slot + will be applied, this function is randomly picked based + on the weight of the function added. + + """ + + def __init__(self, name="Anonymous Function", rand_apply=False): + """ The creator of the FunctionSlot Class """ + self.funcList = [] + self.funcWeights = [] + self.slotName = name + self.rand_apply = rand_apply + + def __typeCheck(self, func): + """ Used internally to check if a function passed to the + function slot is callable. Otherwise raises a TypeError exception. + + :param func: the function object + """ + if not callable(func): + Util.raiseException("The function must be a method or function", TypeError) + + def __iadd__(self, func): + """ To add more functions using the += operator + + .. versionadded:: 0.6 + The __iadd__ method. + """ + self.__typeCheck(func) + self.funcList.append(func) + return self + + def __getitem__(self, index): + """ Used to retrieve some slot function index """ + return self.funcList[index] + + def __setitem__(self, index, value): + """ Used to set the index slot function """ + self.__typeCheck(value) + self.funcList[index] = value + + def __iter__(self): + """ Return the function list iterator """ + return iter(self.funcList) + + def __len__(self): + """ Return the number of functions on the slot + + .. versionadded:: 0.6 + The *__len__* method + """ + return len(self.funcList) + + def setRandomApply(self, flag=True): + """ Sets the random function application, in this mode, the + function will randomly choose one slot to apply + + :param flag: True or False + + """ + if type(flag) != BooleanType: + Util.raiseException("Random option must be True or False", TypeError) + + self.rand_apply = flag + + def clear(self): + """ Used to clear the functions in the slot """ + if len(self.funcList) > 0: + del self.funcList[:] + del self.funcWeights[:] + + def add(self, func, weight=0.5): + """ Used to add a function to the slot + + :param func: the function to be added in the slot + :param weight: used when you enable the *random apply*, it's the weight + of the function for the random selection + + .. versionadded:: 0.6 + The `weight` parameter. + + """ + self.__typeCheck(func) + self.funcList.append(func) + self.funcWeights.append(weight) + + def isEmpty(self): + """ Return true if the function slot is empy """ + return (len(self.funcList) == 0) + + def set(self, func, weight=0.5): + """ Used to clear all functions in the slot and add one + + :param func: the function to be added in the slot + :param weight: used when you enable the *random apply*, it's the weight + of the function for the random selection + + .. versionadded:: 0.6 + The `weight` parameter. + + .. note:: the method *set* of the function slot remove all previous + functions added to the slot. + """ + self.clear() + self.__typeCheck(func) + self.add(func, weight) + + def apply(self, index, obj, **args): + """ Apply the index function + + :param index: the index of the function + :param obj: this object is passes as parameter to the function + :param args: this args dictionary is passed to the function + + """ + if len(self.funcList) <= 0: + raise Exception("No function defined: " + self.slotName) + return self.funcList[index](obj, **args) + + def applyFunctions(self, obj=None, **args): + """ Generator to apply all function slots in obj + + :param obj: this object is passes as parameter to the function + :param args: this args dictionary is passed to the function + + """ + if len(self.funcList) <= 0: + Util.raiseException("No function defined: " + self.slotName) + + if not self.rand_apply: + for f in self.funcList: + yield f(obj, **args) + else: + v = rand_uniform(0, 1) + fobj = None + for func, weight in zip(self.funcList, self.funcWeights): + fobj = func + if v < weight: + break + v = v - weight + + yield fobj(obj, **args) + + def __repr__(self): + """ String representation of FunctionSlot """ + strRet = "Slot [%s] (Count: %d)\n" % (self.slotName, len(self.funcList)) + + if len(self.funcList) <= 0: + strRet += "\t\tNo function\n" + return strRet + + for f, w in zip(self.funcList, self.funcWeights): + strRet += "\t\tName: %s - Weight: %.2f\n" % (f.func_name, w) + if f.func_doc: + strRet += "\t\tDoc: " + f.func_doc + "\n" + + return strRet diff --git a/pyevolve/G1DBinaryString.py.bak b/pyevolve/G1DBinaryString.py.bak new file mode 100644 index 0000000..a1fb683 --- /dev/null +++ b/pyevolve/G1DBinaryString.py.bak @@ -0,0 +1,169 @@ +""" +:mod:`G1DBinaryString` -- the classical binary string chromosome +===================================================================== + +This is the classical chromosome representation on GAs, it is the 1D +Binary String. This string looks like "00011101010". + + +Default Parameters +------------------------------------------------------------- + +*Initializator* + + :func:`Initializators.G1DBinaryStringInitializator` + + The Binatry String Initializator for G1DBinaryString + +*Mutator* + + :func:`Mutators.G1DBinaryStringMutatorFlip` + + The Flip Mutator for G1DBinaryString + +*Crossover* + + :func:`Crossovers.G1DBinaryStringXSinglePoint` + + The Single Point Crossover for G1DBinaryString + + +Class +------------------------------------------------------------- + + +""" + +from GenomeBase import GenomeBase, G1DBase +import Consts +import Util + +class G1DBinaryString(G1DBase): + """ G1DBinaryString Class - The 1D Binary String chromosome + + Inheritance diagram for :class:`G1DBinaryString.G1DBinaryString`: + + .. inheritance-diagram:: G1DBinaryString.G1DBinaryString + + This chromosome class extends the :class:`GenomeBase.G1DBase` class. + + Example: + >>> genome = G1DBinaryString.G1DBinaryString(5) + + :param length: the 1D Binary String size + + """ + __slots__ = ["stringLength"] + + def __init__(self, length=10): + """ The initializator of G1DList representation """ + super(G1DBinaryString, self).__init__(length) + self.genomeList = [] + self.stringLength = length + self.initializator.set(Consts.CDefG1DBinaryStringInit) + self.mutator.set(Consts.CDefG1DBinaryStringMutator) + self.crossover.set(Consts.CDefG1DBinaryStringCrossover) + + def __setitem__(self, key, value): + """ Set the specified value for an gene of List + + >>> g = G1DBinaryString(5) + >>> for i in xrange(len(g)): + ... g.append(1) + >>> g[4] = 0 + >>> g[4] + 0 + + """ + if value not in (0, 1): + Util.raiseException("The value must be zero (0) or one (1), used (%s)" % value, ValueError) + G1DBase.__setitem__(self, key, value) + + def __repr__(self): + """ Return a string representation of Genome """ + ret = GenomeBase.__repr__(self) + ret += "- G1DBinaryString\n" + ret += "\tString length:\t %s\n" % (self.getListSize(),) + ret += "\tString:\t\t %s\n\n" % (self.getBinary(),) + return ret + + def getDecimal(self): + """ Converts the binary string to decimal representation + + Example: + >>> g = G1DBinaryString(5) + >>> for i in xrange(len(g)): + ... g.append(0) + >>> g[3] = 1 + >>> g.getDecimal() + 2 + + :rtype: decimal value + + """ + return int(self.getBinary(), 2) + + def getBinary(self): + """ Returns the binary string representation + + Example: + >>> g = G1DBinaryString(2) + >>> g.append(0) + >>> g.append(1) + >>> g.getBinary() + '01' + + :rtype: the binary string + + """ + return "".join(map(str, self)) + + def append(self, value): + """ Appends an item to the list + + Example: + >>> g = G1DBinaryString(2) + >>> g.append(0) + + :param value: value to be added, 0 or 1 + + """ + if value not in [0, 1]: + Util.raiseException("The value must be 0 or 1", ValueError) + G1DBase.append(self, value) + + def copy(self, g): + """ Copy genome to 'g' + + Example: + >>> g1 = G1DBinaryString(2) + >>> g1.append(0) + >>> g1.append(1) + >>> g2 = G1DBinaryString(2) + >>> g1.copy(g2) + >>> g2[1] + 1 + + :param g: the destination genome + + """ + GenomeBase.copy(self, g) + G1DBase.copy(self, g) + + def clone(self): + """ Return a new instace copy of the genome + + Example: + >>> g = G1DBinaryString(5) + >>> for i in xrange(len(g)): + ... g.append(1) + >>> clone = g.clone() + >>> clone[0] + 1 + + :rtype: the G1DBinaryString instance clone + + """ + newcopy = G1DBinaryString(self.getListSize()) + self.copy(newcopy) + return newcopy diff --git a/pyevolve/G1DList.py.bak b/pyevolve/G1DList.py.bak new file mode 100644 index 0000000..62e487b --- /dev/null +++ b/pyevolve/G1DList.py.bak @@ -0,0 +1,165 @@ +""" + +:mod:`G1DList` -- the 1D list chromosome +============================================================= + +This is the 1D List representation, this list can carry real +numbers or integers or any kind of object, by default, we have +genetic operators for integer and real lists, which can be found +on the respective modules. + +Default Parameters +------------------------------------------------------------- + +*Initializator* + + :func:`Initializators.G1DListInitializatorInteger` + + The Integer Initializator for G1DList + +*Mutator* + + :func:`Mutators.G1DListMutatorSwap` + + The Swap Mutator for G1DList + +*Crossover* + + :func:`Crossovers.G1DListCrossoverSinglePoint` + + The Single Point Crossover for G1DList + + +Class +------------------------------------------------------------- + +""" +from GenomeBase import GenomeBase, G1DBase +import Consts + + +class G1DList(G1DBase): + """ G1DList Class - The 1D List chromosome representation + + Inheritance diagram for :class:`G1DList.G1DList`: + + .. inheritance-diagram:: G1DList.G1DList + + This chromosome class extends the :class:`GenomeBase.GenomeBase` class. + + **Examples** + + The instantiation + >>> g = G1DList(10) + + Compare + >>> genome2 = genome1.clone() + >>> genome2 == genome1 + True + + Multiply + >>> genome = population[0] + >>> genome + (...) + [1, 2, 3, 4] + >>> genome_result = genome * 2 + >>> genome_result + (...) + [2, 2, 6, 8] + + Add + >>> genome + (...) + [1, 2, 3, 4] + >>> genome_result = genome + 2 + (...) + [3, 4, 5, 6] + + Iteration + >>> for i in genome: + >>> print i + 1 + 2 + 3 + 4 + + Size, slice, get/set, append + >>> len(genome) + 4 + >>> genome + (...) + [1, 2, 3, 4] + >>> genome[0:1] + [1, 2] + >>> genome[1] = 666 + >>> genome + (...) + [1, 666, 3, 4] + >>> genome.append(99) + >>> genome + (...) + [1, 666, 3, 4, 99] + + :param size: the 1D list size + + """ + + def __init__(self, size=10, cloning=False): + """ The initializator of G1DList representation, + size parameter must be specified """ + super(G1DList, self).__init__(size) + if not cloning: + self.initializator.set(Consts.CDefG1DListInit) + self.mutator.set(Consts.CDefG1DListMutator) + self.crossover.set(Consts.CDefG1DListCrossover) + + def __mul__(self, other): + """ Multiply every element of G1DList by "other" """ + newObj = self.clone() + for i in xrange(len(newObj)): + newObj[i] *= other + return newObj + + def __add__(self, other): + """ Plus every element of G1DList by "other" """ + newObj = self.clone() + for i in xrange(len(newObj)): + newObj[i] += other + return newObj + + def __sub__(self, other): + """ Plus every element of G1DList by "other" """ + newObj = self.clone() + for i in xrange(len(newObj)): + newObj[i] -= other + return newObj + + def __repr__(self): + """ Return a string representation of Genome """ + ret = GenomeBase.__repr__(self) + ret += "- G1DList\n" + ret += "\tList size:\t %s\n" % (self.getListSize(),) + ret += "\tList:\t\t %s\n\n" % (self.genomeList,) + return ret + + def copy(self, g): + """ Copy genome to 'g' + + Example: + >>> genome_origin.copy(genome_destination) + + :param g: the destination G1DList instance + + """ + GenomeBase.copy(self, g) + G1DBase.copy(self, g) + + def clone(self): + """ Return a new instace copy of the genome + + :rtype: the G1DList clone instance + + """ + newcopy = G1DList(self.genomeSize, True) + self.copy(newcopy) + return newcopy diff --git a/pyevolve/G2DBinaryString.py.bak b/pyevolve/G2DBinaryString.py.bak new file mode 100644 index 0000000..2b2bdab --- /dev/null +++ b/pyevolve/G2DBinaryString.py.bak @@ -0,0 +1,196 @@ +""" +:mod:`G2DBinaryString` -- the classical binary string chromosome +===================================================================== + +This representation is a 2D Binary String, the string looks like +this matrix: + +00101101010 +00100011010 +00101101010 +10100101000 + +Default Parameters +------------------------------------------------------------- + +*Initializator* + + :func:`Initializators.G2DBinaryStringInitializator` + + The Binatry String Initializator for G2DBinaryString + +*Mutator* + + :func:`Mutators.G2DBinaryStringMutatorFlip` + + The Flip Mutator for G2DBinaryString + +*Crossover* + + :func:`Crossovers.G2DBinaryStringXSinglePoint` + + The Single Point Crossover for G2DBinaryString + +.. versionadded:: 0.6 + Added the module :mod:`G2DBinaryString` + +Class +------------------------------------------------------------- +""" + +from GenomeBase import GenomeBase +import Consts +import Util + + +class G2DBinaryString(GenomeBase): + """ G3DBinaryString Class - The 2D Binary String chromosome + + Inheritance diagram for :class:`G2DBinaryString.G2DBinaryString`: + + .. inheritance-diagram:: G2DBinaryString.G2DBinaryString + + Example: + >>> genome = G2DBinaryString.G2DBinaryString(10, 12) + + + :param height: the number of rows + :param width: the number of columns + + """ + __slots__ = ["height", "width", "genomeString"] + + def __init__(self, height, width): + """ The initializator of G2DBinaryString representation, + height and width must be specified """ + super(G2DBinaryString, self).__init__() + self.height = height + self.width = width + + self.genomeString = [None] * height + for i in xrange(height): + self.genomeString[i] = [None] * width + + self.initializator.set(Consts.CDefG2DBinaryStringInit) + self.mutator.set(Consts.CDefG2DBinaryStringMutator) + self.crossover.set(Consts.CDefG2DBinaryStringCrossover) + + def __eq__(self, other): + """ Compares one chromosome with another """ + cond1 = (self.genomeString == other.genomeString) + cond2 = (self.height == other.height) + cond3 = (self.width == other.width) + return True if cond1 and cond2 and cond3 else False + + def getItem(self, x, y): + """ Return the specified gene of List + + Example: + >>> genome.getItem(3, 1) + 0 + + :param x: the x index, the column + :param y: the y index, the row + :rtype: the item at x,y position + + """ + return self.genomeString[x][y] + + def setItem(self, x, y, value): + """ Set the specified gene of List + + Example: + >>> genome.setItem(3, 1, 0) + + :param x: the x index, the column + :param y: the y index, the row + :param value: the value (integers 0 or 1) + + """ + if value not in [0, 1]: + Util.raiseException("The item value must be 0 or 1 in the G2DBinaryString chromosome", ValueError) + self.genomeString[x][y] = value + + def __getitem__(self, key): + """ Return the specified gene of List """ + return self.genomeString[key] + + def __iter__(self): + """ Iterator support to the list """ + return iter(self.genomeString) + + def getHeight(self): + """ Return the height (lines) of the List """ + return self.height + + def getWidth(self): + """ Return the width (lines) of the List """ + return self.width + + def getSize(self): + """ Returns a tuple (height, widht) + + Example: + >>> genome.getSize() + (3, 2) + + """ + return self.getHeight(), self.getWidth() + + def __repr__(self): + """ Return a string representation of Genome """ + ret = GenomeBase.__repr__(self) + ret += "- G2DBinaryString\n" + ret += "\tList size:\t %s\n" % (self.getSize(),) + ret += "\tList:\n" + for line in self.genomeString: + ret += "\t\t\t" + for item in line: + ret += "[%s] " % (item) + ret += "\n" + ret += "\n" + return ret + + def resumeString(self): + """ Returns a resumed string representation of the Genome + + """ + ret = "" + for line in self.genomeString: + for item in line: + ret += "[%s] " % (item) + ret += "\n" + return ret + + def clearString(self): + """ Remove all genes from Genome """ + del self.genomeString[:] + + self.genomeString = [None] * self.height + for i in xrange(self.height): + self.genomeString[i] = [None] * self.width + + def copy(self, g): + """ Copy genome to 'g' + + Example: + >>> genome_origin.copy(genome_destination) + + :param g: the destination G2DBinaryString instance + + """ + GenomeBase.copy(self, g) + g.height = self.height + g.width = self.width + for i in xrange(self.height): + g.genomeString[i] = self.genomeString[i][:] + + def clone(self): + """ Return a new instace copy of the genome + + :rtype: the G2DBinaryString clone instance + + """ + newcopy = G2DBinaryString(self.height, self.width) + self.copy(newcopy) + return newcopy diff --git a/pyevolve/G2DList.py.bak b/pyevolve/G2DList.py.bak new file mode 100644 index 0000000..6c864e3 --- /dev/null +++ b/pyevolve/G2DList.py.bak @@ -0,0 +1,228 @@ +""" +:mod:`G2DList` -- the 2D list chromosome +================================================================ + +This is the 2D List representation, this list can carry real numbers or +integers or any kind of object, by default, we have genetic operators +for integer and real lists, which can be found on the respective modules. +This chromosome class extends the :class:`GenomeBase.GenomeBase`. + +Default Parameters +------------------------------------------------------------- + +*Initializator* + + :func:`Initializators.G2DListInitializatorInteger` + + The Integer Initializator for G2DList + +*Mutator* + + :func:`Mutators.G2DListMutatorSwap` + + The Swap Mutator for G2DList + +*Crossover* + + :func:`Crossovers.G2DListCrossoverUniform` + + The Uniform Crossover for G2DList + + +Class +------------------------------------------------------------- + + +""" + +from GenomeBase import GenomeBase +import Consts + + +class G2DList(GenomeBase): + """ G2DList Class - The 2D List chromosome representation + + Inheritance diagram for :class:`G2DList.G2DList`: + + .. inheritance-diagram:: G2DList.G2DList + + **Examples** + + The instantiation + >>> genome = G2DList.G2DList(10, 10) + + Compare + >>> genome2 = genome1.clone() + >>> genome2 == genome1 + True + + Iteration + >>> for row in genome: + >>> print row + [1, 3, 4, 1] + [7, 5, 3, 4] + [9, 0, 1, 2] + + Size, slice, get/set, append + >>> len(genome) + 3 + >>> genome + (...) + [1, 3, 4, 1] + [7, 5, 3, 4] + [9, 0, 1, 2] + >>> genome[1][2] + 3 + >>> genome[1] = [666, 666, 666, 666] + >>> genome + (...) + [1, 3, 4, 1] + [666, 666, 666, 666] + [9, 0, 1, 2] + >>> genome[1][1] = 2 + (...) + + :param height: the number of rows + :param width: the number of columns + + """ + + __slots__ = ["height", "width", "genomeList"] + + def __init__(self, height, width, cloning=False): + """ The initializator of G2DList representation, + height and width must be specified """ + super(G2DList, self).__init__() + self.height = height + self.width = width + + self.genomeList = [None] * height + for i in xrange(height): + self.genomeList[i] = [None] * width + + if not cloning: + self.initializator.set(Consts.CDefG2DListInit) + self.mutator.set(Consts.CDefG2DListMutator) + self.crossover.set(Consts.CDefG2DListCrossover) + + def __eq__(self, other): + """ Compares one chromosome with another """ + cond1 = (self.genomeList == other.genomeList) + cond2 = (self.height == other.height) + cond3 = (self.width == other.width) + return True if cond1 and cond2 and cond3 else False + + def getItem(self, x, y): + """ Return the specified gene of List + + Example: + >>> genome.getItem(3, 1) + 666 + >>> genome[3][1] + + :param x: the x index, the column + :param y: the y index, the row + :rtype: the item at x,y position + + """ + return self.genomeList[x][y] + + def setItem(self, x, y, value): + """ Set the specified gene of List + + Example: + >>> genome.setItem(3, 1, 666) + >>> genome[3][1] = 666 + + :param x: the x index, the column + :param y: the y index, the row + :param value: the value + + """ + self.genomeList[x][y] = value + + def __getitem__(self, key): + """ Return the specified gene of List """ + return self.genomeList[key] + + def __iter__(self): + """ Iterator support to the list """ + return iter(self.genomeList) + + def getHeight(self): + """ Return the height (lines) of the List """ + return self.height + + def getWidth(self): + """ Return the width (lines) of the List """ + return self.width + + def getSize(self): + """ Returns a tuple (height, widht) + + Example: + >>> genome.getSize() + (3, 2) + + """ + return self.getHeight(), self.getWidth() + + def __repr__(self): + """ Return a string representation of Genome """ + ret = GenomeBase.__repr__(self) + ret += "- G2DList\n" + ret += "\tList size:\t %s\n" % (self.getSize(),) + ret += "\tList:\n" + for line in self.genomeList: + ret += "\t\t\t" + for item in line: + ret += "[%s] " % (item) + ret += "\n" + ret += "\n" + return ret + + def resumeString(self): + """ Returns a resumed string representation of the Genome + + .. versionadded:: 0.6 + The *resumeString* method. + """ + ret = "" + for line in self.genomeList: + for item in line: + ret += "[%s] " % item + ret += "\n" + return ret + + def clearList(self): + """ Remove all genes from Genome """ + del self.genomeList[:] + + self.genomeList = [None] * self.height + for i in xrange(self.height): + self.genomeList[i] = [None] * self.width + + def copy(self, g): + """ Copy genome to 'g' + + Example: + >>> genome_origin.copy(genome_destination) + + :param g: the destination G2DList instance + + """ + GenomeBase.copy(self, g) + g.height = self.height + g.width = self.width + for i in xrange(self.height): + g.genomeList[i] = self.genomeList[i][:] + + def clone(self): + """ Return a new instace copy of the genome + + :rtype: the G2DList clone instance + + """ + newcopy = G2DList(self.height, self.width, True) + self.copy(newcopy) + return newcopy diff --git a/pyevolve/GAllele.py.bak b/pyevolve/GAllele.py.bak new file mode 100644 index 0000000..2012568 --- /dev/null +++ b/pyevolve/GAllele.py.bak @@ -0,0 +1,284 @@ +""" + +:mod:`GAllele` -- the genome alleles module +=========================================================== + +In this module, there are the :class:`GAllele.GAlleles` class (which is the +class that holds the allele types) and all the +allele types to use with the supported chromosomes. + +""" +import random +import Consts +import Util + +class GAlleles(object): + """ GAlleles Class - The set of alleles + + Example: + >>> alleles = GAlleles() + >>> choices = [1,2,3,4] + >>> lst = GAlleleList(choices) + >>> alleles.add(lst) + >>> alleles[0].getRandomAllele() in lst + True + + :param allele_list: the list of alleles + :param homogeneous: if True, all the alleles will be use only the first added + + """ + + def __init__(self, allele_list=None, homogeneous=False): + """ The constructor of GAlleles class """ + self.allele_list = [] + if allele_list is not None: + self.allele_list.extend(allele_list) + self.homogeneous = homogeneous + + def __iadd__(self, allele): + """ To add more alleles using the += operator + + .. versionadded:: 0.6 + The __iadd__ method. + """ + self.add(allele) + return self + + def add(self, allele): + """ Appends one allele to the alleles list + + :param allele: allele to be added + + """ + self.allele_list.append(allele) + + def __getslice__(self, a, b): + """ Returns the slice part of alleles list """ + return self.allele_list[a:b] + + def __getitem__(self, index): + """ Returns the index allele of the alleles list """ + if self.homogeneous: + return self.allele_list[0] + try: + val = self.allele_list[index] + except IndexError: + Util.raiseException( + """An error was occurred while finding allele for the %d position of chromosome. + You may consider use the 'homogeneous' parameter of the GAlleles class. + """ % (index,)) + return val + + def __setitem__(self, index, value): + """ Sets the index allele of the alleles list """ + if self.homogeneous: + self.allele_list[0] = value + self.allele_list[index] = value + + def __iter__(self): + """ Return the list iterator """ + if self.homogeneous: + oneList = [self.allele_list[0]] + return iter(oneList) + return iter(self.allele_list) + + def __len__(self): + """ Returns the length of the alleles list """ + if self.homogeneous: + return 1 + return len(self.allele_list) + + def __repr__(self): + """ Return a string representation of the allele """ + ret = "- GAlleles\n" + ret += "\tHomogeneous:\t %s\n" % (self.homogeneous,) + ret += "\tList size:\t %s\n" % (len(self),) + ret += "\tAlleles:\n\n" + if self.homogeneous: + ret += "Allele for position 0:\n" + ret += self.allele_list[0].__repr__() + else: + for i in xrange(len(self)): + ret += "Allele for position %d:\n" % (i,) + ret += self.allele_list[i].__repr__() + return ret + + +class GAlleleList(object): + """ GAlleleList Class - The list allele type + + Example: + >>> alleles = GAlleles() + >>> choices = [1,2,3,4] + >>> lst = GAlleleList(choices) + >>> alleles.add(lst) + >>> alleles[0].getRandomAllele() in lst + True + + """ + + def __init__(self, options=None): + """ The constructor of GAlleleList class """ + self.options = [] + if options is not None: + self.options.extend(options) + + def clear(self): + """ Removes all the allele options from the list """ + del self.options[:] + + def getRandomAllele(self): + """ Returns one random choice from the options list """ + return random.choice(self.options) + + def add(self, option): + """ Appends one option to the options list + + :param option: option to be added in the list + + """ + self.options.append(option) + + def __getslice__(self, a, b): + """ Returns the slice part of options """ + return self.options[a:b] + + def __getitem__(self, index): + """ Returns the index option from the options list """ + return self.options[index] + + def __setitem__(self, index, value): + """ Sets the index option of the list """ + self.options[index] = value + + def __iter__(self): + """ Return the list iterator """ + return iter(self.options) + + def __len__(self): + """ Returns the length of the options list """ + return len(self.options) + + def remove(self, option): + """ Removes the option from list + + :param option: remove the option from the list + + """ + self.options.remove(option) + + def __repr__(self): + """ Return a string representation of the allele """ + ret = "- GAlleleList\n" + ret += "\tList size:\t %s\n" % (len(self),) + ret += "\tAllele Options:\t %s\n\n" % (self.options,) + return ret + +class GAlleleRange(object): + """ GAlleleRange Class - The range allele type + + Example: + >>> ranges = GAlleleRange(0,100) + >>> ranges.getRandomAllele() >= 0 and ranges.getRandomAllele() <= 100 + True + + :param begin: the begin of the range + :param end: the end of the range + :param real: if True, the range will be of real values + + """ + + def __init__(self, begin=Consts.CDefRangeMin, + end=Consts.CDefRangeMax, real=False): + """ The constructor of GAlleleRange class """ + self.beginEnd = [(begin, end)] + self.real = real + self.minimum = None + self.maximum = None + self.__processMinMax() + + def __processMinMax(self): + """ Process the mininum and maximum of the Allele """ + self.minimum = min([x for x, y in self.beginEnd]) + self.maximum = max([y for x, y in self.beginEnd]) + + def add(self, begin, end): + """ Add a new range + + :param begin: the begin of range + :param end: the end of the range + + """ + if begin > end: + Util.raiseException('Wrong value, the end of the range (%s) is greater than the begin (%s) !' % (end, begin), ValueError) + self.beginEnd.append((begin, end)) + self.__processMinMax() + + def __getitem__(self, index): + return self.beginEnd[index] + + def __setitem__(self, index, value): + if value[0] > value[1]: + Util.raiseException('Wrong value, the end of the range is greater than the begin ! %s' % value, ValueError) + self.beginEnd[index] = value + self.__processMinMax() + + def __iter__(self): + return iter(self.beginEnd) + + def getMaximum(self): + """ Return the maximum of all the ranges + + :rtype: the maximum value + """ + return self.maximum + + def getMinimum(self): + """ Return the minimum of all the ranges + + :rtype: the minimum value + """ + return self.minimum + + def clear(self): + """ Removes all ranges """ + del self.beginEnd[:] + self.minimum = None + self.maximum = None + + def getRandomAllele(self): + """ Returns one random choice between the range """ + rand_func = random.uniform if self.real else random.randint + + if len(self.beginEnd) <= 1: + choice = 0 + else: + choice = random.randint(0, len(self.beginEnd) - 1) + return rand_func(self.beginEnd[choice][0], self.beginEnd[choice][1]) + + def setReal(self, flag=True): + """ Pass in True if the range is real or False if integer + + :param flag: True or False + + """ + self.real = flag + + def getReal(self): + """ Returns True if the range is real or False if it is integer """ + return self.real + + def __len__(self): + """ Returns the ranges in the allele """ + return len(self.beginEnd) + + def __repr__(self): + """ Return a string representation of the allele """ + ret = "- GAlleleRange\n" + ret += "\tReal:\t\t %s\n" % (self.real,) + ret += "\tRanges Count:\t %s\n" % (len(self),) + ret += "\tRange List:\n" + for beg, end in self.beginEnd: + ret += "\t\t\t Range from [%s] to [%s]\n" % (beg, end) + ret += "\n" + return ret diff --git a/pyevolve/GPopulation.py.bak b/pyevolve/GPopulation.py.bak new file mode 100644 index 0000000..919ad18 --- /dev/null +++ b/pyevolve/GPopulation.py.bak @@ -0,0 +1,491 @@ +""" +:mod:`GPopulation` -- the population module +================================================================ + +This module contains the :class:`GPopulation.GPopulation` class, which is reponsible +to keep the population and the statistics. + +Default Parameters +------------------------------------------------------------- + +*Sort Type* + + >>> Consts.sortType["scaled"] + + The scaled sort type + +*Minimax* + + >>> Consts.minimaxType["maximize"] + + Maximize the evaluation function + +*Scale Method* + + :func:`Scaling.LinearScaling` + + The Linear Scaling scheme + +Class +------------------------------------------------------------- + + +""" + +import Consts +import Util +from FunctionSlot import FunctionSlot +from Statistics import Statistics +from math import sqrt as math_sqrt +import logging + +try: + from multiprocessing import cpu_count, Pool + CPU_COUNT = cpu_count() + MULTI_PROCESSING = True if CPU_COUNT > 1 else False + logging.debug("You have %d CPU cores, so the multiprocessing state is %s", CPU_COUNT, MULTI_PROCESSING) +except ImportError: + MULTI_PROCESSING = False + logging.debug("You don't have multiprocessing support for your Python version !") + + +def key_raw_score(individual): + """ A key function to return raw score + + :param individual: the individual instance + :rtype: the individual raw score + + .. note:: this function is used by the max()/min() python functions + + """ + return individual.score + +def key_fitness_score(individual): + """ A key function to return fitness score, used by max()/min() + + :param individual: the individual instance + :rtype: the individual fitness score + + .. note:: this function is used by the max()/min() python functions + + """ + return individual.fitness + + +def multiprocessing_eval(ind): + """ Internal used by the multiprocessing """ + ind.evaluate() + return ind.score + +def multiprocessing_eval_full(ind): + """ Internal used by the multiprocessing (full copy)""" + ind.evaluate() + return ind + + +class GPopulation(object): + """ GPopulation Class - The container for the population + + **Examples** + Get the population from the :class:`GSimpleGA.GSimpleGA` (GA Engine) instance + >>> pop = ga_engine.getPopulation() + + Get the best fitness individual + >>> bestIndividual = pop.bestFitness() + + Get the best raw individual + >>> bestIndividual = pop.bestRaw() + + Get the statistics from the :class:`Statistics.Statistics` instance + >>> stats = pop.getStatistics() + >>> print stats["rawMax"] + 10.4 + + Iterate, get/set individuals + >>> for ind in pop: + >>> print ind + (...) + + >>> for i in xrange(len(pop)): + >>> print pop[i] + (...) + + >>> pop[10] = newGenome + >>> pop[10].fitness + 12.5 + + :param genome: the :term:`Sample genome`, or a GPopulation object, when cloning. + + """ + + def __init__(self, genome): + """ The GPopulation Class creator """ + + if isinstance(genome, GPopulation): + self.oneSelfGenome = genome.oneSelfGenome + self.internalPop = [] + self.internalPopRaw = [] + self.popSize = genome.popSize + self.sortType = genome.sortType + self.sorted = False + self.minimax = genome.minimax + self.scaleMethod = genome.scaleMethod + self.allSlots = [self.scaleMethod] + + self.internalParams = genome.internalParams + self.multiProcessing = genome.multiProcessing + + self.statted = False + self.stats = Statistics() + return + + logging.debug("New population instance, %s class genomes.", genome.__class__.__name__) + self.oneSelfGenome = genome + self.internalPop = [] + self.internalPopRaw = [] + self.popSize = 0 + self.sortType = Consts.CDefPopSortType + self.sorted = False + self.minimax = Consts.CDefPopMinimax + self.scaleMethod = FunctionSlot("Scale Method") + self.scaleMethod.set(Consts.CDefPopScale) + self.allSlots = [self.scaleMethod] + + self.internalParams = {} + self.multiProcessing = (False, False, None) + + # Statistics + self.statted = False + self.stats = Statistics() + + def setMultiProcessing(self, flag=True, full_copy=False, max_processes=None): + """ Sets the flag to enable/disable the use of python multiprocessing module. + Use this option when you have more than one core on your CPU and when your + evaluation function is very slow. + The parameter "full_copy" defines where the individual data should be copied back + after the evaluation or not. This parameter is useful when you change the + individual in the evaluation function. + + :param flag: True (default) or False + :param full_copy: True or False (default) + :param max_processes: None (default) or an integer value + + .. warning:: Use this option only when your evaluation function is slow, se you + will get a good tradeoff between the process communication speed and the + parallel evaluation. + + .. versionadded:: 0.6 + The `setMultiProcessing` method. + + """ + self.multiProcessing = (flag, full_copy, max_processes) + + def setMinimax(self, minimax): + """ Sets the population minimax + + Example: + >>> pop.setMinimax(Consts.minimaxType["maximize"]) + + :param minimax: the minimax type + + """ + self.minimax = minimax + + def __repr__(self): + """ Returns the string representation of the population """ + ret = "- GPopulation\n" + ret += "\tPopulation Size:\t %d\n" % (self.popSize,) + ret += "\tSort Type:\t\t %s\n" % (Consts.sortType.keys()[Consts.sortType.values().index(self.sortType)].capitalize(),) + ret += "\tMinimax Type:\t\t %s\n" % (Consts.minimaxType.keys()[Consts.minimaxType.values().index(self.minimax)].capitalize(),) + for slot in self.allSlots: + ret += "\t" + slot.__repr__() + ret += "\n" + ret += self.stats.__repr__() + return ret + + def __len__(self): + """ Return the length of population """ + return len(self.internalPop) + + def __getitem__(self, key): + """ Returns the specified individual from population """ + return self.internalPop[key] + + def __iter__(self): + """ Returns the iterator of the population """ + return iter(self.internalPop) + + def __setitem__(self, key, value): + """ Set an individual of population """ + self.internalPop[key] = value + self.clearFlags() + + def clearFlags(self): + """ Clear the sorted and statted internal flags """ + self.sorted = False + self.statted = False + + def getStatistics(self): + """ Return a Statistics class for statistics + + :rtype: the :class:`Statistics.Statistics` instance + + """ + self.statistics() + return self.stats + + def statistics(self): + """ Do statistical analysis of population and set 'statted' to True """ + if self.statted: + return + logging.debug("Running statistical calculations") + raw_sum = 0 + + len_pop = len(self) + for ind in xrange(len_pop): + raw_sum += self[ind].score + + self.stats["rawMax"] = max(self, key=key_raw_score).score + self.stats["rawMin"] = min(self, key=key_raw_score).score + self.stats["rawAve"] = raw_sum / float(len_pop) + + tmpvar = 0.0 + for ind in xrange(len_pop): + s = self[ind].score - self.stats["rawAve"] + s *= s + tmpvar += s + + tmpvar /= float((len(self) - 1)) + try: + self.stats["rawDev"] = math_sqrt(tmpvar) + except: + self.stats["rawDev"] = 0.0 + + self.stats["rawVar"] = tmpvar + + self.statted = True + + def bestFitness(self, index=0): + """ Return the best scaled fitness individual of population + + :param index: the *index* best individual + :rtype: the individual + + """ + self.sort() + return self.internalPop[index] + + def worstFitness(self): + """ Return the worst scaled fitness individual of the population + + :rtype: the individual + + """ + self.sort() + return self.internalPop[-1] + + def bestRaw(self, index=0): + """ Return the best raw score individual of population + + :param index: the *index* best raw individual + :rtype: the individual + + .. versionadded:: 0.6 + The parameter `index`. + + """ + if self.sortType == Consts.sortType["raw"]: + return self.internalPop[index] + else: + self.sort() + return self.internalPopRaw[index] + + def worstRaw(self): + """ Return the worst raw score individual of population + + :rtype: the individual + + .. versionadded:: 0.6 + The parameter `index`. + + """ + if self.sortType == Consts.sortType["raw"]: + return self.internalPop[-1] + else: + self.sort() + return self.internalPopRaw[-1] + + def sort(self): + """ Sort the population """ + if self.sorted: + return + rev = (self.minimax == Consts.minimaxType["maximize"]) + + if self.sortType == Consts.sortType["raw"]: + self.internalPop.sort(cmp=Util.cmp_individual_raw, reverse=rev) + else: + self.scale() + self.internalPop.sort(cmp=Util.cmp_individual_scaled, reverse=rev) + self.internalPopRaw = self.internalPop[:] + self.internalPopRaw.sort(cmp=Util.cmp_individual_raw, reverse=rev) + + self.sorted = True + + def setPopulationSize(self, size): + """ Set the population size + + :param size: the population size + + """ + self.popSize = size + + def setSortType(self, sort_type): + """ Sets the sort type + + Example: + >>> pop.setSortType(Consts.sortType["scaled"]) + + :param sort_type: the Sort Type + + """ + self.sortType = sort_type + + def create(self, **args): + """ Clone the example genome to fill the population """ + self.minimax = args["minimax"] + self.internalPop = [self.oneSelfGenome.clone() for i in xrange(self.popSize)] + self.clearFlags() + + def __findIndividual(self, individual, end): + for i in xrange(end): + if individual.compare(self.internalPop[i]) == 0: + return True + + def initialize(self, **args): + """ Initialize all individuals of population, + this calls the initialize() of individuals """ + logging.debug("Initializing the population") + + if self.oneSelfGenome.getParam("full_diversity", True) and hasattr(self.oneSelfGenome, "compare"): + for i in xrange(len(self.internalPop)): + curr = self.internalPop[i] + curr.initialize(**args) + while self.__findIndividual(curr, i): + curr.initialize(**args) + else: + for gen in self.internalPop: + gen.initialize(**args) + self.clearFlags() + + def evaluate(self, **args): + """ Evaluate all individuals in population, calls the evaluate() method of individuals + + :param args: this params are passed to the evaluation function + + """ + # We have multiprocessing + if self.multiProcessing[0] and MULTI_PROCESSING: + logging.debug("Evaluating the population using the multiprocessing method") + proc_pool = Pool(processes=self.multiProcessing[2]) + + # Multiprocessing full_copy parameter + if self.multiProcessing[1]: + results = proc_pool.map(multiprocessing_eval_full, self.internalPop) + proc_pool.close() + proc_pool.join() + for i in xrange(len(self.internalPop)): + self.internalPop[i] = results[i] + else: + results = proc_pool.map(multiprocessing_eval, self.internalPop) + proc_pool.close() + proc_pool.join() + for individual, score in zip(self.internalPop, results): + individual.score = score + else: + for ind in self.internalPop: + ind.evaluate(**args) + + self.clearFlags() + + def scale(self, **args): + """ Scale the population using the scaling method + + :param args: this parameter is passed to the scale method + + """ + for it in self.scaleMethod.applyFunctions(self, **args): + pass + + fit_sum = 0 + for ind in xrange(len(self)): + fit_sum += self[ind].fitness + + self.stats["fitMax"] = max(self, key=key_fitness_score).fitness + self.stats["fitMin"] = min(self, key=key_fitness_score).fitness + self.stats["fitAve"] = fit_sum / float(len(self)) + + self.sorted = False + + def printStats(self): + """ Print statistics of the current population """ + message = "" + if self.sortType == Consts.sortType["scaled"]: + message = "Max/Min/Avg Fitness(Raw) [%(fitMax).2f(%(rawMax).2f)/%(fitMin).2f(%(rawMin).2f)/%(fitAve).2f(%(rawAve).2f)]" % self.stats + else: + message = "Max/Min/Avg Raw [%(rawMax).2f/%(rawMin).2f/%(rawAve).2f]" % self.stats + logging.info(message) + print message + return message + + def copy(self, pop): + """ Copy current population to 'pop' + + :param pop: the destination population + + .. warning:: this method do not copy the individuals, only the population logic + + """ + pop.popSize = self.popSize + pop.sortType = self.sortType + pop.minimax = self.minimax + pop.scaleMethod = self.scaleMethod + pop.internalParams = self.internalParams + pop.multiProcessing = self.multiProcessing + + def getParam(self, key, nvl=None): + """ Gets an internal parameter + + Example: + >>> population.getParam("tournamentPool") + 5 + + :param key: the key of param + :param nvl: if the key doesn't exist, the nvl will be returned + + """ + return self.internalParams.get(key, nvl) + + def setParams(self, **args): + """ Gets an internal parameter + + Example: + >>> population.setParams(tournamentPool=5) + + :param args: parameters to set + + .. versionadded:: 0.6 + The `setParams` method. + """ + self.internalParams.update(args) + + def clear(self): + """ Remove all individuals from population """ + del self.internalPop[:] + del self.internalPopRaw[:] + self.clearFlags() + + def clone(self): + """ Return a brand-new cloned population """ + newpop = GPopulation(self.oneSelfGenome) + self.copy(newpop) + return newpop diff --git a/pyevolve/GSimpleGA.py.bak b/pyevolve/GSimpleGA.py.bak new file mode 100644 index 0000000..44775d5 --- /dev/null +++ b/pyevolve/GSimpleGA.py.bak @@ -0,0 +1,889 @@ +""" + +:mod:`GSimpleGA` -- the genetic algorithm by itself +===================================================================== + +This module contains the GA Engine, the GA Engine class is responsible +for all the evolutionary process. It contains the GA Engine related +funtions, like the Termination Criteria functions for convergence analysis, etc. + +Default Parameters +------------------------------------------------------------- + +*Number of Generations* + + Default is 100 generations + +*Mutation Rate* + + Default is 0.02, which represents 2% + +*Crossover Rate* + + Default is 0.9, which represents 90% + +*Elitism Replacement* + + Default is 1 individual + +*Population Size* + + Default is 80 individuals + +*Minimax* + + >>> Consts.minimaxType["maximize"] + + Maximize the evaluation function + +*DB Adapter* + + Default is **None** + +*Migration Adapter* + + Default is **None** + +*Interactive Mode* + + Default is **True** + +*Selector (Selection Method)* + + :func:`Selectors.GRankSelector` + + The Rank Selection method + +Class +------------------------------------------------------------- + +""" +import random +import logging +from time import time +from types import BooleanType +from sys import platform as sys_platform +from sys import stdout as sys_stdout +import code + +from GPopulation import GPopulation +from FunctionSlot import FunctionSlot +from GenomeBase import GenomeBase +from DBAdapters import DBBaseAdapter +import Consts +import Util +import pyevolve + +# Platform dependant code for the Interactive Mode +if sys_platform[:3] == "win": + import msvcrt + + +def RawScoreCriteria(ga_engine): + """ Terminate the evolution using the **bestrawscore** and **rounddecimal** + parameter obtained from the individual + + Example: + >>> genome.setParams(bestrawscore=0.00, rounddecimal=2) + (...) + >>> ga_engine.terminationCriteria.set(GSimpleGA.RawScoreCriteria) + + """ + ind = ga_engine.bestIndividual() + bestRawScore = ind.getParam("bestrawscore") + roundDecimal = ind.getParam("rounddecimal") + + if bestRawScore is None: + Util.raiseException("you must specify the bestrawscore parameter", ValueError) + + if ga_engine.getMinimax() == Consts.minimaxType["maximize"]: + if roundDecimal is not None: + return round(bestRawScore, roundDecimal) <= round(ind.score, roundDecimal) + else: + return bestRawScore <= ind.score + else: + if roundDecimal is not None: + return round(bestRawScore, roundDecimal) >= round(ind.score, roundDecimal) + else: + return bestRawScore >= ind.score + + +def ConvergenceCriteria(ga_engine): + """ Terminate the evolution when the population have converged + + Example: + >>> ga_engine.terminationCriteria.set(GSimpleGA.ConvergenceCriteria) + + """ + pop = ga_engine.getPopulation() + return pop[0] == pop[len(pop) - 1] + + +def RawStatsCriteria(ga_engine): + """ Terminate the evolution based on the raw stats + + Example: + >>> ga_engine.terminationCriteria.set(GSimpleGA.RawStatsCriteria) + + """ + stats = ga_engine.getStatistics() + if stats["rawMax"] == stats["rawMin"]: + if stats["rawAve"] == stats["rawMax"]: + return True + return False + + +def FitnessStatsCriteria(ga_engine): + """ Terminate the evoltion based on the fitness stats + + Example: + >>> ga_engine.terminationCriteria.set(GSimpleGA.FitnessStatsCriteria) + + + """ + stats = ga_engine.getStatistics() + if stats["fitMax"] == stats["fitMin"]: + if stats["fitAve"] == stats["fitMax"]: + return True + return False + + +class GSimpleGA(object): + """ GA Engine Class - The Genetic Algorithm Core + + Example: + >>> ga = GSimpleGA.GSimpleGA(genome) + >>> ga.selector.set(Selectors.GRouletteWheel) + >>> ga.setGenerations(120) + >>> ga.terminationCriteria.set(GSimpleGA.ConvergenceCriteria) + + :param genome: the :term:`Sample Genome` + :param interactiveMode: this flag enables the Interactive Mode, the default is True + :param seed: the random seed value + + .. note:: if you use the same random seed, all the runs of algorithm will be the same + + """ + + selector = None + """ This is the function slot for the selection method + if you want to change the default selector, you must do this: :: + + ga_engine.selector.set(Selectors.GRouletteWheel) """ + + stepCallback = None + """ This is the :term:`step callback function` slot, + if you want to set the function, you must do this: :: + + def your_func(ga_engine): + # Here you have access to the GA Engine + return False + + ga_engine.stepCallback.set(your_func) + + now *"your_func"* will be called every generation. + When this function returns True, the GA Engine will stop the evolution and show + a warning, if False, the evolution continues. + """ + + terminationCriteria = None + """ This is the termination criteria slot, if you want to set one + termination criteria, you must do this: :: + + ga_engine.terminationCriteria.set(GSimpleGA.ConvergenceCriteria) + + Now, when you run your GA, it will stop when the population converges. + + There are those termination criteria functions: :func:`GSimpleGA.RawScoreCriteria`, + :func:`GSimpleGA.ConvergenceCriteria`, :func:`GSimpleGA.RawStatsCriteria`, :func:`GSimpleGA.FitnessStatsCriteria` + + But you can create your own termination function, this function receives + one parameter which is the GA Engine, follows an example: :: + + def ConvergenceCriteria(ga_engine): + pop = ga_engine.getPopulation() + return pop[0] == pop[len(pop)-1] + + When this function returns True, the GA Engine will stop the evolution and show + a warning, if False, the evolution continues, this function is called every + generation. + """ + + def __init__(self, genome, seed=None, interactiveMode=True): + """ Initializator of GSimpleGA """ + if seed: + random.seed(seed) + + if type(interactiveMode) != BooleanType: + Util.raiseException("Interactive Mode option must be True or False", TypeError) + + if not isinstance(genome, GenomeBase): + Util.raiseException("The genome must be a GenomeBase subclass", TypeError) + + self.internalPop = GPopulation(genome) + self.nGenerations = Consts.CDefGAGenerations + self.pMutation = Consts.CDefGAMutationRate + self.pCrossover = Consts.CDefGACrossoverRate + self.nElitismReplacement = Consts.CDefGAElitismReplacement + self.setPopulationSize(Consts.CDefGAPopulationSize) + self.minimax = Consts.minimaxType["maximize"] + self.elitism = True + + # Adapters + self.dbAdapter = None + self.migrationAdapter = None + + self.time_init = None + self.max_time = None + self.interactiveMode = interactiveMode + self.interactiveGen = -1 + self.GPMode = False + + self.selector = FunctionSlot("Selector") + self.stepCallback = FunctionSlot("Generation Step Callback") + self.terminationCriteria = FunctionSlot("Termination Criteria") + self.selector.set(Consts.CDefGASelector) + self.allSlots = (self.selector, self.stepCallback, self.terminationCriteria) + + self.internalParams = {} + + self.currentGeneration = 0 + + # GP Testing + for classes in Consts.CDefGPGenomes: + if isinstance(self.internalPop.oneSelfGenome, classes): + self.setGPMode(True) + break + + logging.debug("A GA Engine was created, nGenerations=%d", self.nGenerations) + + def setGPMode(self, bool_value): + """ Sets the Genetic Programming mode of the GA Engine + + :param bool_value: True or False + """ + self.GPMode = bool_value + + def getGPMode(self): + """ Get the Genetic Programming mode of the GA Engine + + :rtype: True or False + """ + return self.GPMode + + def __call__(self, *args, **kwargs): + """ A method to implement a callable object + + Example: + >>> ga_engine(freq_stats=10) + + .. versionadded:: 0.6 + The callable method. + """ + if kwargs.get("freq_stats", None): + return self.evolve(kwargs.get("freq_stats")) + else: + return self.evolve() + + def setParams(self, **args): + """ Set the internal params + + Example: + >>> ga.setParams(gp_terminals=['x', 'y']) + + + :param args: params to save + + ..versionaddd:: 0.6 + Added the *setParams* method. + """ + self.internalParams.update(args) + + def getParam(self, key, nvl=None): + """ Gets an internal parameter + + Example: + >>> ga.getParam("gp_terminals") + ['x', 'y'] + + :param key: the key of param + :param nvl: if the key doesn't exist, the nvl will be returned + + ..versionaddd:: 0.6 + Added the *getParam* method. + """ + return self.internalParams.get(key, nvl) + + def setInteractiveGeneration(self, generation): + """ Sets the generation in which the GA must enter in the + Interactive Mode + + :param generation: the generation number, use "-1" to disable + + .. versionadded::0.6 + The *setInteractiveGeneration* method. + """ + if generation < -1: + Util.raiseException("Generation must be >= -1", ValueError) + self.interactiveGen = generation + + def getInteractiveGeneration(self): + """ returns the generation in which the GA must enter in the + Interactive Mode + + :rtype: the generation number or -1 if not set + + .. versionadded::0.6 + The *getInteractiveGeneration* method. + """ + return self.interactiveGen + + def setElitismReplacement(self, numreplace): + """ Set the number of best individuals to copy to the next generation on the elitism + + :param numreplace: the number of individuals + + .. versionadded:: 0.6 + The *setElitismReplacement* method. + + """ + if numreplace < 1: + Util.raiseException("Replacement number must be >= 1", ValueError) + self.nElitismReplacement = numreplace + + def setInteractiveMode(self, flag=True): + """ Enable/disable the interactive mode + + :param flag: True or False + + .. versionadded: 0.6 + The *setInteractiveMode* method. + + """ + if type(flag) != BooleanType: + Util.raiseException("Interactive Mode option must be True or False", TypeError) + self.interactiveMode = flag + + def __repr__(self): + """ The string representation of the GA Engine """ + minimax_type = Consts.minimaxType.keys()[Consts.minimaxType.values().index(self.minimax)] + ret = "- GSimpleGA\n" + ret += "\tGP Mode:\t\t %s\n" % self.getGPMode() + ret += "\tPopulation Size:\t %d\n" % self.internalPop.popSize + ret += "\tGenerations:\t\t %d\n" % self.nGenerations + ret += "\tCurrent Generation:\t %d\n" % self.currentGeneration + ret += "\tMutation Rate:\t\t %.2f\n" % self.pMutation + ret += "\tCrossover Rate:\t\t %.2f\n" % self.pCrossover + ret += "\tMinimax Type:\t\t %s\n" % minimax_type.capitalize() + ret += "\tElitism:\t\t %s\n" % self.elitism + ret += "\tElitism Replacement:\t %d\n" % self.nElitismReplacement + ret += "\tDB Adapter:\t\t %s\n" % self.dbAdapter + for slot in self.allSlots: + ret += "\t" + slot.__repr__() + ret += "\n" + return ret + + def setMultiProcessing(self, flag=True, full_copy=False, max_processes=None): + """ Sets the flag to enable/disable the use of python multiprocessing module. + Use this option when you have more than one core on your CPU and when your + evaluation function is very slow. + + Pyevolve will automaticly check if your Python version has **multiprocessing** + support and if you have more than one single CPU core. If you don't have support + or have just only one core, Pyevolve will not use the **multiprocessing** + feature. + + Pyevolve uses the **multiprocessing** to execute the evaluation function over + the individuals, so the use of this feature will make sense if you have a + truly slow evaluation function (which is commom in GAs). + + The parameter "full_copy" defines where the individual data should be copied back + after the evaluation or not. This parameter is useful when you change the + individual in the evaluation function. + + :param flag: True (default) or False + :param full_copy: True or False (default) + :param max_processes: None (default) or an integer value + + .. warning:: Use this option only when your evaluation function is slow, so you'll + get a good tradeoff between the process communication speed and the + parallel evaluation. The use of the **multiprocessing** doesn't means + always a better performance. + + .. note:: To enable the multiprocessing option, you **MUST** add the *__main__* check + on your application, otherwise, it will result in errors. See more on the + `Python Docs `__ + site. + + .. versionadded:: 0.6 + The `setMultiProcessing` method. + + """ + if type(flag) != BooleanType: + Util.raiseException("Multiprocessing option must be True or False", TypeError) + + if type(full_copy) != BooleanType: + Util.raiseException("Multiprocessing 'full_copy' option must be True or False", TypeError) + + self.internalPop.setMultiProcessing(flag, full_copy, max_processes) + + def setMigrationAdapter(self, migration_adapter=None): + """ Sets the Migration Adapter + + .. versionadded:: 0.6 + The `setMigrationAdapter` method. + """ + + self.migrationAdapter = migration_adapter + if self.migrationAdapter is not None: + self.migrationAdapter.setGAEngine(self) + + def setDBAdapter(self, dbadapter=None): + """ Sets the DB Adapter of the GA Engine + + :param dbadapter: one of the :mod:`DBAdapters` classes instance + + .. warning:: the use the of a DB Adapter can reduce the speed performance of the + Genetic Algorithm. + """ + if (dbadapter is not None) and (not isinstance(dbadapter, DBBaseAdapter)): + Util.raiseException("The DB Adapter must be a DBBaseAdapter subclass", TypeError) + self.dbAdapter = dbadapter + + def setPopulationSize(self, size): + """ Sets the population size, calls setPopulationSize() of GPopulation + + :param size: the population size + + .. note:: the population size must be >= 2 + + """ + if size < 2: + Util.raiseException("population size must be >= 2", ValueError) + self.internalPop.setPopulationSize(size) + + def setSortType(self, sort_type): + """ Sets the sort type, Consts.sortType["raw"]/Consts.sortType["scaled"] + + Example: + >>> ga_engine.setSortType(Consts.sortType["scaled"]) + + :param sort_type: the Sort Type + + """ + if sort_type not in Consts.sortType.values(): + Util.raiseException("sort type must be a Consts.sortType type", TypeError) + self.internalPop.sortType = sort_type + + def setMutationRate(self, rate): + """ Sets the mutation rate, between 0.0 and 1.0 + + :param rate: the rate, between 0.0 and 1.0 + + """ + if (rate > 1.0) or (rate < 0.0): + Util.raiseException("Mutation rate must be >= 0.0 and <= 1.0", ValueError) + self.pMutation = rate + + def setCrossoverRate(self, rate): + """ Sets the crossover rate, between 0.0 and 1.0 + + :param rate: the rate, between 0.0 and 1.0 + + """ + if (rate > 1.0) or (rate < 0.0): + Util.raiseException("Crossover rate must be >= 0.0 and <= 1.0", ValueError) + self.pCrossover = rate + + def setGenerations(self, num_gens): + """ Sets the number of generations to evolve + + :param num_gens: the number of generations + + """ + if num_gens < 1: + Util.raiseException("Number of generations must be >= 1", ValueError) + self.nGenerations = num_gens + + def getGenerations(self): + """ Return the number of generations to evolve + + :rtype: the number of generations + + .. versionadded:: 0.6 + Added the *getGenerations* method + """ + return self.nGenerations + + def getMinimax(self): + """ Gets the minimize/maximize mode + + :rtype: the Consts.minimaxType type + + """ + return self.minimax + + def setMinimax(self, mtype): + """ Sets the minimize/maximize mode, use Consts.minimaxType + + :param mtype: the minimax mode, from Consts.minimaxType + + """ + if mtype not in Consts.minimaxType.values(): + Util.raiseException("Minimax must be maximize or minimize", TypeError) + self.minimax = mtype + + def getCurrentGeneration(self): + """ Gets the current generation + + :rtype: the current generation + + """ + return self.currentGeneration + + def setElitism(self, flag): + """ Sets the elitism option, True or False + + :param flag: True or False + + """ + if type(flag) != BooleanType: + Util.raiseException("Elitism option must be True or False", TypeError) + self.elitism = flag + + def getDBAdapter(self): + """ Gets the DB Adapter of the GA Engine + + :rtype: a instance from one of the :mod:`DBAdapters` classes + + """ + return self.dbAdapter + + def setMaxTime(self, seconds): + """ Sets the maximun evolve time of the GA Engine + + :param seconds: maximum time in seconds + """ + self.max_time = seconds + + def getMaxTime(self): + """ Get the maximun evolve time of the GA Engine + + :rtype: True or False + """ + return self.max_time + + def bestIndividual(self): + """ Returns the population best individual + + :rtype: the best individual + + """ + return self.internalPop.bestRaw() + + def worstIndividual(self): + """ Returns the population worst individual + + :rtype: the best individual + + """ + return self.internalPop.worstRaw() + + def __gp_catch_functions(self, prefix): + """ Internally used to catch functions with some specific prefix + as non-terminals of the GP core """ + import __main__ as mod_main + + function_set = {} + + main_dict = mod_main.__dict__ + for obj, addr in main_dict.items(): + if obj[0:len(prefix)] == prefix: + try: + op_len = addr.func_code.co_argcount + except: + continue + function_set[obj] = op_len + + if len(function_set) <= 0: + Util.raiseException("No function set found using function prefix '%s' !" % prefix, ValueError) + + self.setParams(gp_function_set=function_set) + + def initialize(self): + """ Initializes the GA Engine. Create and initialize population """ + self.internalPop.create(minimax=self.minimax) + self.internalPop.initialize(ga_engine=self) + logging.debug("The GA Engine was initialized !") + + def getPopulation(self): + """ Return the internal population of GA Engine + + :rtype: the population (:class:`GPopulation.GPopulation`) + + """ + return self.internalPop + + def getStatistics(self): + """ Gets the Statistics class instance of current generation + + :rtype: the statistics instance (:class:`Statistics.Statistics`) + + """ + return self.internalPop.getStatistics() + + def step(self): + """ Just do one step in evolution, one generation """ + newPop = GPopulation(self.internalPop) + logging.debug("Population was cloned.") + + size_iterate = len(self.internalPop) + + # Odd population size + if size_iterate % 2 != 0: + size_iterate -= 1 + + crossover_empty = self.select(popID=self.currentGeneration).crossover.isEmpty() + + for i in xrange(0, size_iterate, 2): + genomeMom = self.select(popID=self.currentGeneration) + genomeDad = self.select(popID=self.currentGeneration) + + if not crossover_empty and self.pCrossover >= 1.0: + for it in genomeMom.crossover.applyFunctions(mom=genomeMom, dad=genomeDad, count=2): + (sister, brother) = it + else: + if not crossover_empty and Util.randomFlipCoin(self.pCrossover): + for it in genomeMom.crossover.applyFunctions(mom=genomeMom, dad=genomeDad, count=2): + (sister, brother) = it + else: + sister = genomeMom.clone() + brother = genomeDad.clone() + + sister.mutate(pmut=self.pMutation, ga_engine=self) + brother.mutate(pmut=self.pMutation, ga_engine=self) + + newPop.internalPop.append(sister) + newPop.internalPop.append(brother) + + if len(self.internalPop) % 2 != 0: + genomeMom = self.select(popID=self.currentGeneration) + genomeDad = self.select(popID=self.currentGeneration) + + if Util.randomFlipCoin(self.pCrossover): + for it in genomeMom.crossover.applyFunctions(mom=genomeMom, dad=genomeDad, count=1): + (sister, brother) = it + else: + sister = random.choice([genomeMom, genomeDad]) + sister = sister.clone() + sister.mutate(pmut=self.pMutation, ga_engine=self) + + newPop.internalPop.append(sister) + + logging.debug("Evaluating the new created population.") + newPop.evaluate() + + if self.elitism: + logging.debug("Doing elitism.") + if self.getMinimax() == Consts.minimaxType["maximize"]: + for i in xrange(self.nElitismReplacement): + #re-evaluate before being sure this is the best + self.internalPop.bestRaw(i).evaluate() + if self.internalPop.bestRaw(i).score > newPop.bestRaw(i).score: + newPop[len(newPop) - 1 - i] = self.internalPop.bestRaw(i) + elif self.getMinimax() == Consts.minimaxType["minimize"]: + for i in xrange(self.nElitismReplacement): + #re-evaluate before being sure this is the best + self.internalPop.bestRaw(i).evaluate() + if self.internalPop.bestRaw(i).score < newPop.bestRaw(i).score: + newPop[len(newPop) - 1 - i] = self.internalPop.bestRaw(i) + + self.internalPop = newPop + self.internalPop.sort() + + logging.debug("The generation %d was finished.", self.currentGeneration) + + self.currentGeneration += 1 + + if self.max_time: + total_time = time() - self.time_init + if total_time > self.max_time: + return True + return self.currentGeneration == self.nGenerations + + def printStats(self): + """ Print generation statistics + + :rtype: the printed statistics as string + + .. versionchanged:: 0.6 + The return of *printStats* method. + """ + percent = self.currentGeneration * 100 / float(self.nGenerations) + message = "Gen. %d (%.2f%%):" % (self.currentGeneration, percent) + logging.info(message) + print message, + sys_stdout.flush() + self.internalPop.statistics() + stat_ret = self.internalPop.printStats() + return message + stat_ret + + def printTimeElapsed(self): + """ Shows the time elapsed since the begin of evolution """ + total_time = time() - self.time_init + print "Total time elapsed: %.3f seconds." % total_time + return total_time + + def dumpStatsDB(self): + """ Dumps the current statistics to database adapter """ + logging.debug("Dumping stats to the DB Adapter") + self.internalPop.statistics() + self.dbAdapter.insert(self) + + def evolve(self, freq_stats=0): + """ Do all the generations until the termination criteria, accepts + the freq_stats (default is 0) to dump statistics at n-generation + + Example: + >>> ga_engine.evolve(freq_stats=10) + (...) + + :param freq_stats: if greater than 0, the statistics will be + printed every freq_stats generation. + :rtype: returns the best individual of the evolution + + .. versionadded:: 0.6 + the return of the best individual + + """ + + stopFlagCallback = False + stopFlagTerminationCriteria = False + + self.time_init = time() + + logging.debug("Starting the DB Adapter and the Migration Adapter if any") + if self.dbAdapter: + self.dbAdapter.open(self) + if self.migrationAdapter: + self.migrationAdapter.start() + + if self.getGPMode(): + gp_function_prefix = self.getParam("gp_function_prefix") + if gp_function_prefix is not None: + self.__gp_catch_functions(gp_function_prefix) + + self.initialize() + self.internalPop.evaluate() + self.internalPop.sort() + logging.debug("Starting loop over evolutionary algorithm.") + + try: + while True: + if self.migrationAdapter: + logging.debug("Migration adapter: exchange") + self.migrationAdapter.exchange() + self.internalPop.clearFlags() + self.internalPop.sort() + + if not self.stepCallback.isEmpty(): + for it in self.stepCallback.applyFunctions(self): + stopFlagCallback = it + + if not self.terminationCriteria.isEmpty(): + for it in self.terminationCriteria.applyFunctions(self): + stopFlagTerminationCriteria = it + + if freq_stats: + if (self.currentGeneration % freq_stats == 0) or (self.getCurrentGeneration() == 0): + self.printStats() + + if self.dbAdapter: + if self.currentGeneration % self.dbAdapter.getStatsGenFreq() == 0: + self.dumpStatsDB() + + if stopFlagTerminationCriteria: + logging.debug("Evolution stopped by the Termination Criteria !") + if freq_stats: + print "\n\tEvolution stopped by Termination Criteria function !\n" + break + + if stopFlagCallback: + logging.debug("Evolution stopped by Step Callback function !") + if freq_stats: + print "\n\tEvolution stopped by Step Callback function !\n" + break + + if self.interactiveMode: + if sys_platform[:3] == "win": + if msvcrt.kbhit(): + if ord(msvcrt.getch()) == Consts.CDefESCKey: + print "Loading modules for Interactive Mode...", + logging.debug( + "Windows Interactive Mode key detected ! generation=%d", + self.getCurrentGeneration() + ) + from pyevolve import Interaction + print " done !" + interact_banner = "## Pyevolve v.%s - Interactive Mode ##\n" \ + "Press CTRL-Z to quit interactive mode." % (pyevolve.__version__,) + session_locals = { + "ga_engine": self, + "population": self.getPopulation(), + "pyevolve": pyevolve, + "it": Interaction, + } + print + code.interact(interact_banner, local=session_locals) + + is_interactive_generation = self.getInteractiveGeneration() == self.getCurrentGeneration() + if self.getInteractiveGeneration() >= 0 and is_interactive_generation: + print "Loading modules for Interactive Mode...", + logging.debug( + "Manual Interactive Mode key detected ! generation=%d", + self.getCurrentGeneration() + ) + from pyevolve import Interaction + print " done !" + interact_banner = "## Pyevolve v.%s - Interactive Mode ##" % (pyevolve.__version__,) + session_locals = { + "ga_engine": self, + "population": self.getPopulation(), + "pyevolve": pyevolve, + "it": Interaction + } + print + code.interact(interact_banner, local=session_locals) + + if self.step(): + break + + except KeyboardInterrupt: + logging.debug("CTRL-C detected, finishing evolution.") + if freq_stats: + print "\n\tA break was detected, you have interrupted the evolution !\n" + + if freq_stats != 0: + self.printStats() + self.printTimeElapsed() + + if self.dbAdapter: + logging.debug("Closing the DB Adapter") + if not (self.currentGeneration % self.dbAdapter.getStatsGenFreq() == 0): + self.dumpStatsDB() + self.dbAdapter.commitAndClose() + + if self.migrationAdapter: + logging.debug("Closing the Migration Adapter") + self.migrationAdapter.stop() + + return self.bestIndividual() + + def select(self, **args): + """ Select one individual from population + + :param args: this parameters will be sent to the selector + + """ + for it in self.selector.applyFunctions(self.internalPop, **args): + return it diff --git a/pyevolve/GTree.py.bak b/pyevolve/GTree.py.bak new file mode 100644 index 0000000..381580d --- /dev/null +++ b/pyevolve/GTree.py.bak @@ -0,0 +1,721 @@ +""" + +:mod:`GTree` and GTreeGP -- the tree chromosomes +============================================================= + +This is the rooted tree representation, this chromosome representation +can carry any data-type. + +Default Parameters +------------------------------------------------------------- + +*Initializator* + + :func:`Initializators.GTreeInitializatorInteger` + + The Integer Initializator for GTree + +*Mutator* + + :func:`Mutators.GTreeMutatorIntegerRange` + + The Integer Range mutator for GTree + +*Crossover* + + :func:`Crossovers.GTreeCrossoverSinglePointStrict` + + The Strict Single Point crossover for GTree + +.. versionadded:: 0.6 + The *GTree* module. + +Classes +------------------------------------------------------------- +""" +import random +from GenomeBase import GenomeBase, GTreeBase, GTreeNodeBase +import Consts +import Util + +try: + import pydot + HAVE_PYDOT = True +except ImportError: + HAVE_PYDOT = False + +################################# +# GTree # +################################# + + +class GTree(GTreeBase): + """ The GTree class - The tree chromosome representation + + Inheritance diagram for :class:`GTree.GTree`: + + .. inheritance-diagram:: GTree.GTree + + :param root_node: the root node of the tree + """ + + def __init__(self, root_node=None): + super(GTree, self).__init__(root_node) + self.initializator.set(Consts.CDefGTreeInit) + self.mutator.set(Consts.CDefGGTreeMutator) + self.crossover.set(Consts.CDefGTreeCrossover) + + def __repr__(self): + """ Return a string representation of Genome """ + ret = GenomeBase.__repr__(self) + ret += GTreeBase.__repr__(self) + return ret + + def copy(self, g): + """ Copy the contents to the destination g + + :param g: the GTree genome destination + """ + GenomeBase.copy(self, g) + GTreeBase.copy(self, g) + + def clone(self): + """ Return a new instance of the genome + + :rtype: new GTree instance + """ + newcopy = GTree() + self.copy(newcopy) + newcopy.processNodes(True) + return newcopy + + +class GTreeNode(GTreeNodeBase): + """ The GTreeNode class - The node representation + + Inheritance diagram for :class:`GTree.GTreeNode`: + + .. inheritance-diagram:: GTree.GTreeNode + + :param data: the root node of the tree + :param parent: the parent node, if root, this + must be *None* + """ + __slots__ = ["node_data"] + + def __init__(self, data, parent=None): + super(GTreeNode, self).__init__(parent) + self.node_data = data + + def __repr__(self): + str_repr = GTreeNodeBase.__repr__(self) + str_repr += " - [%s]" % self.node_data + return str_repr + + def setData(self, data): + """ Sets the data of the node + + :param data: the data of the node + """ + self.node_data = data + + def getData(self): + """ Return the data of the node + + :rtype: the data of the node + """ + return self.node_data + + def newNode(self, data): + """ Created a new child node + + :param data: the data of the new created node + """ + node = GTreeNode(data, self) + self.addChild(node) + return node + + def swapNodeData(self, node): + """ Swaps the node data with another node + + :param node: the node to do the data swap + """ + tmp_data = self.node_data + self.setData(node.getData()) + node.setData(tmp_data) + + def copy(self, g): + """ Copy the contents to the destination g + + :param g: the GTreeNode genome destination + """ + GTreeNodeBase.copy(self, g) + g.node_data = self.node_data + + def clone(self): + """ Return a new instance of the genome + + :rtype: new GTree instance + """ + newcopy = GTreeNode(None) + self.copy(newcopy) + return newcopy + +################################# +# Tree Utility Functions # +################################# + + +def buildGTreeGrow(depth, value_callback, max_siblings, max_depth): + """ Random generates a Tree structure using the value_callback + for data generation and the method "Grow" + + :param depth: the initial depth, zero + :param value_callback: the function which generates the random + values for nodes + :param max_siblings: the maximum number of sisters of a node + :param max_depth: the maximum depth of the tree + + :rtype: the root node of created tree + """ + + random_value = value_callback() + n = GTreeNode(random_value) + + if depth == max_depth: + return n + + for i in xrange(random.randint(0, abs(max_siblings))): + child = buildGTreeGrow(depth + 1, value_callback, max_siblings, max_depth) + child.setParent(n) + n.addChild(child) + return n + + +def buildGTreeFull(depth, value_callback, max_siblings, max_depth): + """ Random generates a Tree structure using the value_callback + for data generation and the method "Full" + + :param depth: the initial depth, zero + :param value_callback: the function which generates the random + values for nodes + :param max_siblings: the maximum number of sisters of a node + :param max_depth: the maximum depth of the tree + + :rtype: the root node of created tree + """ + + random_value = value_callback() + n = GTreeNode(random_value) + + if depth == max_depth: + return n + + if max_siblings < 0: + range_val = abs(max_siblings) + else: + range_val = random.randint(1, abs(max_siblings)) + + for i in xrange(range_val): + child = buildGTreeFull(depth + 1, value_callback, max_siblings, max_depth) + child.setParent(n) + n.addChild(child) + return n + +################################# +# GTree GP # +################################# + + +class GTreeNodeGP(GTreeNodeBase): + """ The GTreeNodeGP Class - The Genetic Programming Node representation + + Inheritance diagram for :class:`GTree.GTreeNodeGP`: + + .. inheritance-diagram:: GTree.GTreeNodeGP + + :param data: the node data + :param type: the node type + :param parent: the node parent + + """ + __slots__ = ["node_type", "node_data"] + + def __init__(self, data, node_type=0, parent=None): + super(GTreeNodeGP, self).__init__(parent) + self.node_type = node_type + self.node_data = data + + def __repr__(self): + str_repr = GTreeNodeBase.__repr__(self) + str_repr += " - [%s]" % self.node_data + return str_repr + + def compare(self, other): + """ Compare this node with other + + :param other: the other GTreeNodeGP + """ + if not isinstance(other, GTreeNodeGP): + Util.raiseException("The other node used to compare is not a GTreeNodeGP class", TypeError) + + if other.node_type == self.node_type: + if other.node_data == self.node_data: + return 0 + return -1 + + def setData(self, data): + """Sets the node internal data + + :param data: the internal data + """ + self.node_data = data + + def getData(self): + """Gets the node internal data + + :rtype: the internal data + """ + return self.node_data + + def setType(self, node_type): + """Sets the node type + + :param node_type: the node type is type of Consts.nodeType + """ + self.node_type = node_type + + def getType(self): + """Get the node type + + :rtype: the node type is type of Consts.nodeType + """ + return self.node_type + + def newNode(self, data): + """Creates a new node and adds this + node as children of current node + + :param data: the internal node data + """ + node = GTreeNodeGP(data, self) + self.addChild(node) + return node + + def swapNodeData(self, node): + """Swaps the node data and type with another node + + :param node: the node + """ + tmp_data = self.node_data + tmp_type = self.node_type + self.setData(node.getData()) + self.setType(node.getType()) + node.setData(tmp_data) + node.setType(tmp_type) + + def copy(self, g): + """ Copy the contents to the destination g + + :param g: the GTreeNodeGP genome destination + """ + GTreeNodeBase.copy(self, g) + g.node_data = self.node_data + g.node_type = self.node_type + + def clone(self): + """ Return a new copy of the node + + :rtype: the new GTreeNodeGP instance + """ + newcopy = GTreeNodeGP(None) + self.copy(newcopy) + return newcopy + + +class GTreeGP(GTreeBase): + """ The GTreeGP Class - The Genetic Programming Tree representation + + Inheritance diagram for :class:`GTree.GTreeGP`: + + .. inheritance-diagram:: GTree.GTreeGP + + :param root_node: the Root node of the GP Tree + """ + def __init__(self, root_node=None, cloning=False): + super(GTreeGP, self).__init__(root_node) + if not cloning: + self.initializator.set(Consts.CDefGTreeGPInit) + self.mutator.set(Consts.CDefGGTreeGPMutator) + self.crossover.set(Consts.CDefGTreeGPCrossover) + + def __repr__(self): + """ Return a string representation of Genome """ + ret = GenomeBase.__repr__(self) + ret += GTreeBase.__repr__(self) + ret += "\n- GTreeGP\n" + ret += "\tExpression: %s\n" % self.getPreOrderExpression() + return ret + + def writeDotImage(self, filename): + """ Writes a image representation of the individual + + :param filename: the output file image + """ + if not HAVE_PYDOT: + Util.raiseException("You must install Pydot to use this feature !") + + graph = pydot.Dot() + self.writeDotGraph(graph) + graph.write_jpeg(filename, prog='dot') + + def writeDotRaw(self, filename): + """ Writes the raw dot file (text-file used by dot/neato) with the + representation of the individual + + :param filename: the output file, ex: individual.dot + """ + if not HAVE_PYDOT: + Util.raiseException("You must install Pydot to use this feature !") + + graph = pydot.Dot(graph_type="digraph") + self.writeDotGraph(graph) + graph.write(filename, prog='dot', format="raw") + + def writeDotGraph(self, graph, startNode=0): + """ Write a graph to the pydot Graph instance + + :param graph: the pydot Graph instance + :param startNode: used to plot more than one individual + """ + if not HAVE_PYDOT: + print "You must install Pydot to use this feature !" + return + + count = startNode + node_stack = [] + nodes_dict = {} + import __main__ as main_module + + for i in xrange(len(self.nodes_list)): + newnode = pydot.Node(str(count), style="filled") + count += 1 + + if self.nodes_list[i].getType() == Consts.nodeType["TERMINAL"]: + newnode.set_color("lightblue2") + else: + newnode.set_color("goldenrod2") + + if self.nodes_list[i].getType() == Consts.nodeType["NONTERMINAL"]: + func = getattr(main_module, self.nodes_list[i].getData()) + + if hasattr(func, "shape"): + newnode.set_shape(func.shape) + + if hasattr(func, "representation"): + newnode.set_label(func.representation) + else: + newnode.set_label(self.nodes_list[i].getData()) + if hasattr(func, "color"): + newnode.set_color(func.color) + + else: + newnode.set_label(self.nodes_list[i].getData()) + + nodes_dict.update({self.nodes_list[i]: newnode}) + graph.add_node(newnode) + + node_stack.append(self.getRoot()) + while len(node_stack) > 0: + tmp = node_stack.pop() + + parent = tmp.getParent() + if parent is not None: + parent_node = nodes_dict[parent] + child_node = nodes_dict[tmp] + + newedge = pydot.Edge(parent_node, child_node) + graph.add_edge(newedge) + + rev_childs = tmp.getChilds()[:] + rev_childs.reverse() + node_stack.extend(rev_childs) + + return count + + def getSExpression(self, start_node=None): + """ Returns a tree-formated string (s-expression) of the tree. + + :rtype: a S-Expression representing the tree + """ + str_buff = "" + if start_node is None: + start_node = self.getRoot() + str_buff += "%s " % start_node.getData() + + is_leaf = start_node.isLeaf() + if not is_leaf: + str_buff += "( " + + for child_node in start_node.getChilds(): + str_buff += "%s " % child_node.getData() + str_buff += self.getSExpression(child_node) + + if not is_leaf: + str_buff += " )" + return str_buff + + def getPreOrderExpression(self, start_node=None): + """ Return the pre order expression string of the Tree, used + to python *eval*. + + :rtype: the expression string + """ + if start_node is None: + start_node = self.getRoot() + + str_buff = start_node.getData() + + if not start_node.isLeaf(): + all_childs = start_node.getChilds() + str_buff += "(" + self.getPreOrderExpression(all_childs[0]) + + for index in xrange(1, len(all_childs)): + child = all_childs[index] + str_buff += ", " + self.getPreOrderExpression(child) + str_buff += ")" + + return str_buff + + def getCompiledCode(self): + """ Get the compiled code for the Tree expression + After getting the compiled code object, you just need to evaluate it using + the :func:`eval` native Python method. + + :rtype: compiled python code + """ + expr = self.getPreOrderExpression() + return compile(expr, "", "eval") + + def copy(self, g): + """ Copy the contents to the destination g + + :param g: the GTreeGP genome destination + """ + GenomeBase.copy(self, g) + GTreeBase.copy(self, g) + + def clone(self): + """ Return a new instance of the genome + + :rtype: the new GTreeGP instance + """ + newcopy = GTreeGP(cloning=True) + self.copy(newcopy) + newcopy.processNodes(True) + return newcopy + + def compare(self, other): + """ This method will compare the currently tree with another one + + :param other: the other GTreeGP to compare + """ + if not isinstance(other, GTreeGP): + Util.raiseException("The other tree used to compare is not a GTreeGP class", TypeError) + + stack_self = [] + stack_other = [] + + stack_self.append(self.getRoot()) + stack_other.append(other.getRoot()) + + while len(stack_self) > 0: + + if (len(stack_self) <= 0) or (len(stack_other) <= 0): + return -1 + + tmp_self, tmp_other = stack_self.pop(), stack_other.pop() + if tmp_self.compare(tmp_other) != 0: + return -1 + + stack_self.extend(tmp_self.getChilds()) + stack_other.extend(tmp_other.getChilds()) + + return 0 + + @staticmethod + def writePopulationDot(ga_engine, filename, format="jpeg", start=0, end=0): + """ Writes to a graphical file using pydot, the population of trees + + Example: + >>> GTreeGP.writePopulationDot(ga_engine, "pop.jpg", "jpeg", 0, 10) + + This example will draw the first ten individuals of the population into + the file called "pop.jpg". + + :param ga_engine: the GA Engine + :param filename: the filename, ie. population.jpg + :param start: the start index of individuals + :param end: the end index of individuals + """ + if not HAVE_PYDOT: + Util.raiseException("You must install Pydot to use this feature !") + + pop = ga_engine.getPopulation() + graph = pydot.Dot(graph_type="digraph") + + if not isinstance(pop[0], GTreeGP): + Util.raiseException("The population must have individuals of the GTreeGP chromosome !") + + n = 0 + end_index = len(pop) if end == 0 else end + for i in xrange(start, end_index): + ind = pop[i] + subg = pydot.Cluster( + "cluster_%d" % i, + label="\"Ind. #%d - Score Raw/Fit.: %.4f/%.4f\"" % (i, ind.getRawScore(), ind.getFitnessScore()) + ) + n = ind.writeDotGraph(subg, n) + graph.add_subgraph(subg) + + graph.write(filename, prog='dot', format=format) + + @staticmethod + def writePopulationDotRaw(ga_engine, filename, start=0, end=0): + """ Writes to a raw dot file using pydot, the population of trees + + Example: + >>> GTreeGP.writePopulationDotRaw(ga_engine, "pop.dot", 0, 10) + + This example will draw the first ten individuals of the population into + the file called "pop.dot". + + :param ga_engine: the GA Engine + :param filename: the filename, ie. population.dot + :param start: the start index of individuals + :param end: the end index of individuals + """ + if not HAVE_PYDOT: + Util.raiseException("You must install Pydot to use this feature !") + + pop = ga_engine.getPopulation() + graph = pydot.Dot(graph_type="digraph") + + if not isinstance(pop[0], GTreeGP): + Util.raiseException("The population must have individuals of the GTreeGP chromosome !") + + n = 0 + end_index = len(pop) if end == 0 else end + for i in xrange(start, end_index): + ind = pop[i] + subg = pydot.Cluster( + "cluster_%d" % i, + label="\"Ind. #%d - Score Raw/Fit.: %.4f/%.4f\"" % (i, ind.getRawScore(), ind.getFitnessScore()) + ) + n = ind.writeDotGraph(subg, n) + graph.add_subgraph(subg) + + graph.write(filename, prog='dot', format="raw") + + +################################# +# Tree GP Utility Functions # +################################# + +def gpdec(**kwds): + """ This is a decorator to use with genetic programming non-terminals + + It currently accepts the attributes: shape, color and representation. + """ + def decorate(f): + for k in kwds: + setattr(f, k, kwds[k]) + return f + return decorate + + +def checkTerminal(terminal): + """ Do some check on the terminal, to evaluate ephemeral constants + + :param terminal: the terminal string + """ + if terminal.startswith("ephemeral:"): + splited = terminal.split(":") + ephemeral_constant = eval(splited[1]) + return str(ephemeral_constant) + else: + return terminal + + +def buildGTreeGPGrow(ga_engine, depth, max_depth): + """ Creates a new random GTreeGP root node with subtrees using + the "Grow" method. + + :param ga_engine: the GA Core + :param depth: the initial depth + :max_depth: the maximum depth of the tree + :rtype: the root node + """ + + gp_terminals = ga_engine.getParam("gp_terminals") + assert gp_terminals is not None + + gp_function_set = ga_engine.getParam("gp_function_set") + assert gp_function_set is not None + + if depth == max_depth: + random_terminal = checkTerminal(random.choice(gp_terminals)) + n = GTreeNodeGP(random_terminal, Consts.nodeType["TERMINAL"]) + return n + else: + # Do not generate degenerative trees + if depth == 0: + random_node = random.choice(gp_function_set.keys()) + else: + fchoice = random.choice([gp_function_set.keys(), gp_terminals]) + random_node = random.choice(fchoice) + + if random_node in gp_terminals: + n = GTreeNodeGP(checkTerminal(random_node), Consts.nodeType["TERMINAL"]) + else: + n = GTreeNodeGP(random_node, Consts.nodeType["NONTERMINAL"]) + + if n.getType() == Consts.nodeType["NONTERMINAL"]: + for i in xrange(gp_function_set[n.getData()]): + child = buildGTreeGPGrow(ga_engine, depth + 1, max_depth) + child.setParent(n) + n.addChild(child) + + return n + + +def buildGTreeGPFull(ga_engine, depth, max_depth): + """ Creates a new random GTreeGP root node with subtrees using + the "Full" method. + + :param ga_engine: the GA Core + :param depth: the initial depth + :max_depth: the maximum depth of the tree + :rtype: the root node + """ + gp_terminals = ga_engine.getParam("gp_terminals") + assert gp_terminals is not None + + gp_function_set = ga_engine.getParam("gp_function_set") + assert gp_function_set is not None + + if depth == max_depth: + random_terminal = checkTerminal(random.choice(gp_terminals)) + n = GTreeNodeGP(random_terminal, Consts.nodeType["TERMINAL"]) + return n + else: + random_oper = random.choice(gp_function_set.keys()) + n = GTreeNodeGP(random_oper, Consts.nodeType["NONTERMINAL"]) + + if n.getType() == Consts.nodeType["NONTERMINAL"]: + for i in xrange(gp_function_set[n.getData()]): + child = buildGTreeGPFull(ga_engine, depth + 1, max_depth) + child.setParent(n) + n.addChild(child) + + return n diff --git a/pyevolve/GenomeBase.py.bak b/pyevolve/GenomeBase.py.bak new file mode 100644 index 0000000..f22b1cf --- /dev/null +++ b/pyevolve/GenomeBase.py.bak @@ -0,0 +1,607 @@ +""" + +:mod:`GenomeBase` -- the genomes base module +================================================================ + +This module have the class which every representation extends, +if you are planning to create a new representation, you must +take a inside look into this module. + +""" +from random import choice as rand_choice +import inspect + +from FunctionSlot import FunctionSlot +import Util + +class GenomeBase(object): + """ GenomeBase Class - The base of all chromosome representation """ + __slots__ = ["evaluator", "initializator", "mutator", "crossover", "internalParams", "score", "fitness"] + + def __init__(self): + """Genome Constructor""" + self.evaluator = FunctionSlot("Evaluator") + self.initializator = FunctionSlot("Initializator") + self.mutator = FunctionSlot("Mutator") + self.crossover = FunctionSlot("Crossover") + + self.internalParams = {} + self.score = 0.0 + self.fitness = 0.0 + + def getRawScore(self): + """ Get the Raw Score of the genome + + :rtype: genome raw score + + """ + return self.score + + def getFitnessScore(self): + """ Get the Fitness Score of the genome + + :rtype: genome fitness score + + """ + return self.fitness + + def __repr__(self): + """String representation of Genome""" + allSlots = [self.evaluator, self.initializator, self.mutator, + self.crossover] + + ret = "- GenomeBase\n" + ret += "\tScore:\t\t\t %.6f\n" % (self.score,) + ret += "\tFitness:\t\t %.6f\n\n" % (self.fitness,) + ret += "\tParams:\t\t %s\n\n" % (self.internalParams,) + + for slot in allSlots: + ret += "\t" + slot.__repr__() + ret += "\n" + + return ret + + def setParams(self, **args): + """ Set the internal params + + Example: + >>> genome.setParams(rangemin=0, rangemax=100, gauss_mu=0, gauss_sigma=1) + + .. note:: All the individuals of the population shares this parameters and uses + the same instance of this dict. + + :param args: this params will saved in every chromosome for genetic op. use + + """ + self.internalParams.update(args) + + def getParam(self, key, nvl=None): + """ Gets an internal parameter + + Example: + >>> genome.getParam("rangemax") + 100 + + .. note:: All the individuals of the population shares this parameters and uses + the same instance of this dict. + + :param key: the key of param + :param nvl: if the key doesn't exist, the nvl will be returned + + """ + return self.internalParams.get(key, nvl) + + def resetStats(self): + """ Clear score and fitness of genome """ + self.score = 0.0 + self.fitness = 0.0 + + def evaluate(self, **args): + """ Called to evaluate genome + + :param args: this parameters will be passes to the evaluator + + """ + self.resetStats() + for it in self.evaluator.applyFunctions(self, **args): + self.score += it + + def initialize(self, **args): + """ Called to initialize genome + + :param args: this parameters will be passed to the initializator + + """ + for it in self.initializator.applyFunctions(self, **args): + pass + + def mutate(self, **args): + """ Called to mutate the genome + + :param args: this parameters will be passed to the mutator + :rtype: the number of mutations returned by mutation operator + + """ + nmuts = 0 + for it in self.mutator.applyFunctions(self, **args): + nmuts += it + return nmuts + + def copy(self, g): + """ Copy the current GenomeBase to 'g' + + :param g: the destination genome + + .. note:: If you are planning to create a new chromosome representation, you + **must** implement this method on your class. + + """ + g.score = self.score + g.fitness = self.fitness + g.evaluator = self.evaluator + g.initializator = self.initializator + g.mutator = self.mutator + g.crossover = self.crossover + g.internalParams = self.internalParams + + def clone(self): + """ Clone this GenomeBase + + :rtype: the clone genome + + .. note:: If you are planning to create a new chromosome representation, you + **must** implement this method on your class. + """ + newcopy = GenomeBase() + self.copy(newcopy) + return newcopy + +class G1DBase(GenomeBase): + """ G1DBase Class - The base class for 1D chromosomes + + This chromosome class extends the :class:`GenomeBase` classes. + + :param size: the 1D list size + + .. versionadded:: 0.6 + Added the *G1DBase* class + """ + __slots__ = ["genomeSize", "genomeList"] + + def __init__(self, size): + super(G1DBase, self).__init__() + self.genomeSize = size + self.genomeList = [] + + def __iadd__(self, item): + """ To add more items using the += operator """ + self.genomeList.append(item) + return self + + def __eq__(self, other): + """ Compares one chromosome with another """ + cond1 = (self.genomeList == other.genomeList) + cond2 = (self.genomeSize == other.genomeSize) + return True if cond1 and cond2 else False + + def __contains__(self, value): + """ Used on: *value in genome* """ + return value in self.genomeList + + def __getslice__(self, a, b): + """ Return the sliced part of chromosome """ + return self.genomeList[a:b] + + def __setslice__(self, a, b, val): + """ Sets the slice part of chromosome """ + self.genomeList[a:b] = val + + def __getitem__(self, key): + """ Return the specified gene of List """ + return self.genomeList[key] + + def __setitem__(self, key, value): + """ Set the specified value for an gene of List """ + self.genomeList[key] = value + + def __iter__(self): + """ Iterator support to the list """ + return iter(self.genomeList) + + def __len__(self): + """ Return the size of the List """ + return len(self.genomeList) + + def getListSize(self): + """ Returns the list supposed size + + .. warning:: this is different from what the len(obj) returns + """ + return self.genomeSize + + def resumeString(self): + """ Returns a resumed string representation of the Genome """ + return str(self.genomeList) + + def append(self, value): + """ Appends an item to the end of the list + + Example: + >>> genome.append(44) + + :param value: value to be added + + """ + self.genomeList.append(value) + + def remove(self, value): + """ Removes an item from the list + + Example: + >>> genome.remove(44) + + :param value: value to be added + + """ + self.genomeList.remove(value) + + def clearList(self): + """ Remove all genes from Genome """ + del self.genomeList[:] + + def copy(self, g): + """ Copy genome to 'g' + + Example: + >>> genome_origin.copy(genome_destination) + + :param g: the destination instance + + """ + g.genomeSize = self.genomeSize + g.genomeList = self.genomeList[:] + + def getInternalList(self): + """ Returns the internal list of the genome + + ... note:: this method was created to solve performance issues + :rtype: the internal list + """ + return self.genomeList + + def setInternalList(self, lst): + """ Assigns a list to the internal list of the chromosome + + :param lst: the list to assign the internal list of the chromosome + """ + self.genomeList = lst + +class GTreeNodeBase(object): + """ GTreeNodeBase Class - The base class for the node tree genomes + + :param parent: the parent node of the node + :param childs: the childs of the node, must be a list of nodes + + .. versionadded:: 0.6 + Added the *GTreeNodeBase* class + """ + __slots__ = ["parent", "childs"] + + def __init__(self, parent, childs=None): + self.parent = parent + self.childs = [] + + if childs is not None: + if type(childs) != list: + Util.raiseException("Childs must be a list of nodes", TypeError) + typecheck_list = filter(lambda x: not isinstance(x, GTreeNodeBase), childs) + if len(typecheck_list) > 0: + Util.raiseException("Childs must be a list of nodes", TypeError) + self.childs += childs + + def isLeaf(self): + """ Return True if the node is a leaf + + :rtype: True or False + """ + return len(self.childs) == 0 + + def getChild(self, index): + """ Returns the index-child of the node + + :rtype: child node + """ + return self.childs[index] + + def getChilds(self): + """ Return the childs of the node + + .. warning :: use .getChilds()[:] if you'll change the list itself, like using childs.reverse(), + otherwise the original genome child order will be changed. + + :rtype: a list of nodes + """ + return self.childs + + def addChild(self, child): + """ Adds a child to the node + + :param child: the node to be added + """ + if type(child) == list: + self.childs.extend(child) + else: + if not isinstance(child, GTreeNodeBase): + Util.raiseException("The child must be a node", TypeError) + self.childs.append(child) + + def replaceChild(self, older, newer): + """ Replaces a child of the node + + :param older: the child to be replaces + :param newer: the new child which replaces the older + """ + index = self.childs.index(older) + self.childs[index] = newer + + def setParent(self, parent): + """ Sets the parent of the node + + :param parent: the parent node + """ + self.parent = parent + + def getParent(self): + """ Get the parent node of the node + + :rtype: the parent node + """ + return self.parent + + def __repr__(self): + str_repr = "GTreeNodeBase [Childs=%d]" % len(self) + return str_repr + + def __len__(self): + return len(self.childs) + + def copy(self, g): + """ Copy the current contents GTreeNodeBase to 'g' + + :param g: the destination node + + .. note:: If you are planning to create a new chromosome representation, you + **must** implement this method on your class. + """ + g.parent = self.parent + g.childs = self.childs[:] + + def clone(self): + """ Clone this GenomeBase + + :rtype: the clone genome + + .. note:: If you are planning to create a new chromosome representation, you + **must** implement this method on your class. + """ + newcopy = GTreeNodeBase(None) + self.copy(newcopy) + return newcopy + + +class GTreeBase(GenomeBase): + """ GTreeBase Class - The base class for the tree genomes + + This chromosome class extends the :class:`GenomeBase` classes. + + :param root_node: the root node of the tree + + .. versionadded:: 0.6 + Added the *GTreeBase* class + """ + __slots__ = ["root_node", "tree_height", "nodes_list", "nodes_leaf", "nodes_branch"] + + def __init__(self, root_node): + super(GTreeBase, self).__init__() + self.root_node = root_node + self.tree_height = None + self.nodes_list = None + + def processNodes(self, cloning=False): + """ Creates a *cache* on the tree, this method must be called + every time you change the shape of the tree. It updates the + internal nodes list and the internal nodes properties such as + depth and height. + """ + if self.root_node is None: + return + self.nodes_list = self.getAllNodes() + self.nodes_leaf = filter(lambda n: n.isLeaf(), self.nodes_list) + self.nodes_branch = filter(lambda n: n.isLeaf() is False, self.nodes_list) + + if not cloning: + self.tree_height = self.getNodeHeight(self.getRoot()) + + def getRoot(self): + """ Return the tree root node + + :rtype: the tree root node + """ + return self.root_node + + def setRoot(self, root): + """ Sets the root of the tree + + :param root: the tree root node + """ + if not isinstance(root, GTreeNodeBase): + Util.raiseException("The root must be a node", TypeError) + self.root_node = root + + def getNodeDepth(self, node): + """ Returns the depth of a node + + :rtype: the depth of the node, the depth of root node is 0 + """ + if node == self.getRoot(): + return 0 + else: + return 1 + self.getNodeDepth(node.getParent()) + + def getNodeHeight(self, node): + """ Returns the height of a node + + .. note:: If the node has no childs, the height will be 0. + + :rtype: the height of the node + """ + height = 0 + if len(node) <= 0: + return 0 + for child in node.getChilds(): + h_inner = self.getNodeHeight(child) + 1 + if h_inner > height: + height = h_inner + return height + + def getHeight(self): + """ Return the tree height + + :rtype: the tree height + """ + return self.tree_height + + def getNodesCount(self, start_node=None): + """ Return the number of the nodes on the tree + starting at the *start_node*, if *start_node* is None, + then the method will count all the tree nodes. + + :rtype: the number of nodes + """ + count = 1 + if start_node is None: + start_node = self.getRoot() + for i in start_node.getChilds(): + count += self.getNodesCount(i) + return count + + def getTraversalString(self, start_node=None, spc=0): + """ Returns a tree-formated string of the tree. This + method is used by the __repr__ method of the tree + + :rtype: a string representing the tree + """ + str_buff = "" + if start_node is None: + start_node = self.getRoot() + str_buff += "%s\n" % start_node + spaces = spc + 2 + for child_node in start_node.getChilds(): + str_buff += "%s%s\n" % (" " * spaces, child_node) + str_buff += self.getTraversalString(child_node, spaces) + return str_buff + + def traversal(self, callback, start_node=None): + """ Traversal the tree, this method will call the + user-defined callback function for each node on the tree + + :param callback: a function + :param start_node: the start node to begin the traversal + """ + if not inspect.isfunction(callback): + Util.raiseException("The callback for the tree traversal must be a function", TypeError) + + if start_node is None: + start_node = self.getRoot() + callback(start_node) + for child_node in start_node.getChilds(): + callback(child_node) + self.traversal(callback, child_node) + + def getRandomNode(self, node_type=0): + """ Returns a random node from the Tree + + :param node_type: 0 = Any, 1 = Leaf, 2 = Branch + :rtype: random node + """ + lists = (self.nodes_list, self.nodes_leaf, self.nodes_branch) + cho = lists[node_type] + if len(cho) <= 0: + return None + return rand_choice(cho) + + def getAllNodes(self): + """ Return a new list with all nodes + + :rtype: the list with all nodes + """ + node_stack = [] + all_nodes = [] + tmp = None + + node_stack.append(self.getRoot()) + while len(node_stack) > 0: + tmp = node_stack.pop() + all_nodes.append(tmp) + childs = tmp.getChilds() + node_stack.extend(childs) + + return all_nodes + + def __repr__(self): + str_buff = "- GTree\n" + str_buff += "\tHeight:\t\t\t%d\n" % self.getHeight() + str_buff += "\tNodes:\t\t\t%d\n" % self.getNodesCount() + str_buff += "\n" + self.getTraversalString() + + return str_buff + + def __len__(self): + return len(self.nodes_list) + + def __getitem__(self, index): + return self.nodes_list[index] + + def __iter__(self): + return iter(self.nodes_list) + + def copy(self, g, node=None, node_parent=None): + """ Copy the current contents GTreeBase to 'g' + + :param g: the destination GTreeBase tree + + .. note:: If you are planning to create a new chromosome representation, you + **must** implement this method on your class. + """ + if node is None: + g.tree_height = self.tree_height + node = self.root_node + + if node is None: + return None + + newnode = node.clone() + + if node_parent is None: + g.setRoot(newnode) + else: + newnode.setParent(node_parent) + node_parent.replaceChild(node, newnode) + + for ci in xrange(len(newnode)): + GTreeBase.copy(self, g, newnode.getChild(ci), newnode) + + return newnode + + def clone(self): + """ Clone this GenomeBase + + :rtype: the clone genome + + .. note:: If you are planning to create a new chromosome representation, you + **must** implement this method on your class. + """ + newcopy = GTreeBase(None) + self.copy(newcopy) + newcopy.processNodes() + return newcopy diff --git a/pyevolve/Initializators.py.bak b/pyevolve/Initializators.py.bak new file mode 100644 index 0000000..ff99c8b --- /dev/null +++ b/pyevolve/Initializators.py.bak @@ -0,0 +1,274 @@ +""" + +:mod:`Initializators` -- initialization methods module +=================================================================== + +In this module we have the genetic operators of initialization for each +chromosome representation, the most part of initialization is done by +choosing random data. + +.. note:: In Pyevolve, the Initializator defines the data type that will + be used on the chromosome, for example, the :func:`G1DListInitializatorInteger` + will initialize the G1DList with Integers. + + +""" + +from random import randint as rand_randint, uniform as rand_uniform, choice as rand_choice +import GTree +import Util + + +############################# +## 1D Binary String ## +############################# + +def G1DBinaryStringInitializator(genome, **args): + """ 1D Binary String initializator """ + genome.genomeList = [rand_choice((0, 1)) for _ in xrange(genome.getListSize())] + + +############################# +## 2D Binary String ## +############################# + +def G2DBinaryStringInitializator(genome, **args): + """ Integer initialization function of 2D Binary String + + .. versionadded:: 0.6 + The *G2DBinaryStringInitializator* function + """ + genome.clearString() + + for i in xrange(genome.getHeight()): + for j in xrange(genome.getWidth()): + random_gene = rand_choice((0, 1)) + genome.setItem(i, j, random_gene) + + +#################### +## 1D List ## +#################### + +def G1DListInitializatorAllele(genome, **args): + """ Allele initialization function of G1DList + + To use this initializator, you must specify the *allele* genome parameter with the + :class:`GAllele.GAlleles` instance. + + """ + + allele = genome.getParam("allele", None) + if allele is None: + Util.raiseException("to use the G1DListInitializatorAllele, you must specify the 'allele' parameter") + + genome.genomeList = [allele[i].getRandomAllele() for i in xrange(genome.getListSize())] + + +def G1DListInitializatorInteger(genome, **args): + """ Integer initialization function of G1DList + + This initializator accepts the *rangemin* and *rangemax* genome parameters. + + """ + range_min = genome.getParam("rangemin", 0) + range_max = genome.getParam("rangemax", 100) + + genome.genomeList = [rand_randint(range_min, range_max) for i in xrange(genome.getListSize())] + + +def G1DListInitializatorReal(genome, **args): + """ Real initialization function of G1DList + + This initializator accepts the *rangemin* and *rangemax* genome parameters. + + """ + range_min = genome.getParam("rangemin", 0) + range_max = genome.getParam("rangemax", 100) + + genome.genomeList = [rand_uniform(range_min, range_max) for i in xrange(genome.getListSize())] + + +#################### +## 2D List ## +#################### + +def G2DListInitializatorInteger(genome, **args): + """ Integer initialization function of G2DList + + This initializator accepts the *rangemin* and *rangemax* genome parameters. + + """ + genome.clearList() + + for i in xrange(genome.getHeight()): + for j in xrange(genome.getWidth()): + randomInteger = rand_randint(genome.getParam("rangemin", 0), + genome.getParam("rangemax", 100)) + genome.setItem(i, j, randomInteger) + + +def G2DListInitializatorReal(genome, **args): + """ Integer initialization function of G2DList + + This initializator accepts the *rangemin* and *rangemax* genome parameters. + + """ + genome.clearList() + + for i in xrange(genome.getHeight()): + for j in xrange(genome.getWidth()): + randomReal = rand_uniform(genome.getParam("rangemin", 0), + genome.getParam("rangemax", 100)) + genome.setItem(i, j, randomReal) + + +def G2DListInitializatorAllele(genome, **args): + """ Allele initialization function of G2DList + + To use this initializator, you must specify the *allele* genome parameter with the + :class:`GAllele.GAlleles` instance. + + .. warning:: the :class:`GAllele.GAlleles` instance must have the homogeneous flag enabled + + """ + + allele = genome.getParam("allele", None) + if allele is None: + Util.raiseException("to use the G2DListInitializatorAllele, you must specify the 'allele' parameter") + + if not allele.homogeneous: + Util.raiseException("to use the G2DListInitializatorAllele, the 'allele' must be homogeneous") + + genome.clearList() + + for i in xrange(genome.getHeight()): + for j in xrange(genome.getWidth()): + random_allele = allele[0].getRandomAllele() + genome.setItem(i, j, random_allele) + + +#################### +## Tree ## +#################### + +def GTreeInitializatorInteger(genome, **args): + """ Integer initialization function of GTree + + This initializator accepts the *rangemin* and *rangemax* genome parameters. + It accepts the following parameters too: + + *max_depth* + The max depth of the tree + + *max_siblings* + The number of maximum siblings of an node + + *method* + The method, accepts "grow", "full" or "ramped". + + .. versionadded:: 0.6 + The *GTreeInitializatorInteger* function. + """ + max_depth = genome.getParam("max_depth", 5) + max_siblings = genome.getParam("max_siblings", 2) + + range_min = genome.getParam("rangemin", 0) + range_max = genome.getParam("rangemax", 100) + + lambda_generator = lambda: rand_randint(range_min, range_max) + + method = genome.getParam("method", "grow") + + if method == "grow": + root = GTree.buildGTreeGrow(0, lambda_generator, max_siblings, max_depth) + elif method == "full": + root = GTree.buildGTreeFull(0, lambda_generator, max_siblings, max_depth) + elif method == "ramped": + if Util.randomFlipCoin(0.5): + root = GTree.buildGTreeGrow(0, lambda_generator, max_siblings, max_depth) + else: + root = GTree.buildGTreeFull(0, lambda_generator, max_siblings, max_depth) + else: + Util.raiseException("Unknown tree initialization method [%s] !" % method) + + genome.setRoot(root) + genome.processNodes() + assert genome.getHeight() <= max_depth + + +def GTreeInitializatorAllele(genome, **args): + """ Allele initialization function of GTree + + To use this initializator, you must specify the *allele* genome parameter with the + :class:`GAllele.GAlleles` instance. + + .. warning:: the :class:`GAllele.GAlleles` instance **must** have the homogeneous flag enabled + + .. versionadded:: 0.6 + The *GTreeInitializatorAllele* function. + """ + max_depth = genome.getParam("max_depth", 5) + max_siblings = genome.getParam("max_siblings", 2) + method = genome.getParam("method", "grow") + + allele = genome.getParam("allele", None) + if allele is None: + Util.raiseException("to use the GTreeInitializatorAllele, you must specify the 'allele' parameter") + + if not allele.homogeneous: + Util.raiseException("to use the GTreeInitializatorAllele, the 'allele' must be homogeneous") + + if method == "grow": + root = GTree.buildGTreeGrow(0, allele[0].getRandomAllele, max_siblings, max_depth) + elif method == "full": + root = GTree.buildGTreeFull(0, allele[0].getRandomAllele, max_siblings, max_depth) + elif method == "ramped": + if Util.randomFlipCoin(0.5): + root = GTree.buildGTreeGrow(0, allele[0].getRandomAllele, max_siblings, max_depth) + else: + root = GTree.buildGTreeFull(0, allele[0].getRandomAllele, max_siblings, max_depth) + else: + Util.raiseException("Unknown tree initialization method [%s] !" % method) + + genome.setRoot(root) + genome.processNodes() + assert genome.getHeight() <= max_depth + + +#################### +## Tree GP ## +#################### + +def GTreeGPInitializator(genome, **args): + """This initializator accepts the follow parameters: + + *max_depth* + The max depth of the tree + + *method* + The method, accepts "grow", "full" or "ramped" + + .. versionadded:: 0.6 + The *GTreeGPInitializator* function. + """ + + max_depth = genome.getParam("max_depth", 5) + method = genome.getParam("method", "grow") + ga_engine = args["ga_engine"] + + if method == "grow": + root = GTree.buildGTreeGPGrow(ga_engine, 0, max_depth) + elif method == "full": + root = GTree.buildGTreeGPFull(ga_engine, 0, max_depth) + elif method == "ramped": + if Util.randomFlipCoin(0.5): + root = GTree.buildGTreeGPFull(ga_engine, 0, max_depth) + else: + root = GTree.buildGTreeGPGrow(ga_engine, 0, max_depth) + else: + Util.raiseException("Unknown tree initialization method [%s] !" % method) + + genome.setRoot(root) + genome.processNodes() + assert genome.getHeight() <= max_depth diff --git a/pyevolve/Interaction.py.bak b/pyevolve/Interaction.py.bak new file mode 100644 index 0000000..e1f5774 --- /dev/null +++ b/pyevolve/Interaction.py.bak @@ -0,0 +1,84 @@ +""" + +:mod:`Interaction` -- interaction module +========================================================================== + +In this module, you will find the funcionality for the :term:`Interactive mode`. +When you enter in the Interactive Mode, Pyevolve will automatic import this module +and exposes to you in the name space called "it". + +To use this mode, the parameter *interactiveMode* must be enabled in the +:class:`GSimpleGA.GSimpleGA`. + +You can use the manual method to enter in the Interactive Mode at specific +generation using the :meth:`GSimpleGA.GSimpleGA.setInteractiveGeneration` method. + +""" +import logging + +try: + import pylab +except: + logging.debug("cannot import Matplotlib ! Plots will not be available !") + print "Warning: cannot import Matplotlib ! Plots will not be available !" + +try: + import numpy +except: + logging.debug("cannot import Numpy ! Some functions will not be available !") + print "Warning: cannot import Numpy ! Some functions will not be available !" + +def getPopScores(population, fitness=False): + """ Returns a list of population scores + + Example: + >>> lst = Interaction.getPopScores(population) + + :param population: population object (:class:`GPopulation.GPopulation`) + :param fitness: if True, the fitness score will be used, otherwise, the raw. + :rtype: list of population scores + + """ + score_list = [] + for individual in population: + score_list.append(individual.fitness if fitness else individual.score) + return score_list + +def plotPopScore(population, fitness=False): + """ Plot the population score distribution + + Example: + >>> Interaction.plotPopScore(population) + + :param population: population object (:class:`GPopulation.GPopulation`) + :param fitness: if True, the fitness score will be used, otherwise, the raw. + :rtype: None + + """ + score_list = getPopScores(population, fitness) + pylab.plot(score_list, 'o') + pylab.title("Plot of population score distribution") + pylab.xlabel('Individual') + pylab.ylabel('Score') + pylab.grid(True) + pylab.show() + +def plotHistPopScore(population, fitness=False): + """ Population score distribution histogram + + Example: + >>> Interaction.plotHistPopScore(population) + + :param population: population object (:class:`GPopulation.GPopulation`) + :param fitness: if True, the fitness score will be used, otherwise, the raw. + :rtype: None + + """ + score_list = getPopScores(population, fitness) + n, bins, patches = pylab.hist(score_list, 50, facecolor='green', alpha=0.75, normed=1) + pylab.plot(bins, pylab.normpdf(bins, numpy.mean(score_list), numpy.std(score_list)), 'r--') + pylab.xlabel('Score') + pylab.ylabel('Frequency') + pylab.grid(True) + pylab.title("Plot of population score distribution") + pylab.show() diff --git a/pyevolve/Migration.py.bak b/pyevolve/Migration.py.bak new file mode 100644 index 0000000..3f566c9 --- /dev/null +++ b/pyevolve/Migration.py.bak @@ -0,0 +1,341 @@ +""" +:mod:`Migration` -- the migration schemes, distributed GA +===================================================================== + +This module contains all the migration schemes and the distributed +GA related functions. + +.. versionadded:: 0.6 + The :mod:`Migration` module. + +""" + +import Util +from random import randint as rand_randint, choice as rand_choice +import Network +import Consts +from FunctionSlot import FunctionSlot +import logging + +try: + from mpi4py import MPI + HAS_MPI4PY = True +except ImportError: + HAS_MPI4PY = False + +class MigrationScheme(object): + """ This is the base class for all migration schemes """ + + selector = None + """ This is the function slot for the selection method + if you want to change the default selector, you must do this: :: + + migration_scheme.selector.set(Selectors.GRouletteWheel) """ + + def __init__(self): + self.selector = FunctionSlot("Selector") + self.GAEngine = None + self.nMigrationRate = Consts.CDefGenMigrationRate + self.nIndividuals = Consts.CDefMigrationNIndividuals + self.nReplacement = Consts.CDefGenMigrationReplacement + self.networkCompression = 9 + + def isReady(self): + """ Returns true if is time to migrate """ + return True if self.GAEngine.getCurrentGeneration() % self.nMigrationRate == 0 else False + + def getCompressionLevel(self): + """ Get the zlib compression level of network data + + The values are in the interval described on the :func:`Network.pickleAndCompress` + """ + return self.networkCompression + + def setCompressionLevel(self, level): + """ Set the zlib compression level of network data + + The values are in the interval described on the :func:`Network.pickleAndCompress` + + :param level: the zlib compression level + """ + self.networkCompression = level + + def getNumReplacement(self): + """ Return the number of individuals that will be + replaced in the migration process """ + return self.nReplacement + + def setNumReplacement(self, num_individuals): + """ Return the number of individuals that will be + replaced in the migration process + + :param num_individuals: the number of individuals to be replaced + """ + self.nReplacement = num_individuals + + def getNumIndividuals(self): + """ Return the number of individuals that will migrate + + :rtype: the number of individuals to be replaced + """ + return self.nIndividuals + + def setNumIndividuals(self, num_individuals): + """ Set the number of individuals that will migrate + + :param num_individuals: the number of individuals + """ + self.nIndividuals = num_individuals + + def setMigrationRate(self, generations): + """ Sets the generation frequency supposed to migrate + and receive individuals. + + :param generations: the number of generations + """ + self.nMigrationRate = generations + + def getMigrationRate(self): + """ Return the the generation frequency supposed to migrate + and receive individuals + + :rtype: the number of generations + """ + return self.nMigrationRate + + def setGAEngine(self, ga_engine): + """ Sets the GA Engine handler """ + self.GAEngine = ga_engine + + def start(self): + """ Initializes the migration scheme """ + pass + + def stop(self): + """ Stops the migration engine """ + pass + + def select(self): + """ Picks an individual from population using specific selection method + + :rtype: an individual object + """ + if self.selector.isEmpty(): + return self.GAEngine.select(popID=self.GAEngine.currentGeneration) + else: + for it in self.selector.applyFunctions(self.GAEngine.internalPop, + popID=self.GAEngine.currentGeneration): + return it + + def selectPool(self, num_individuals): + """ Select num_individuals number of individuals and return a pool + + :param num_individuals: the number of individuals to select + :rtype: list with individuals + """ + pool = [self.select() for i in xrange(num_individuals)] + return pool + + def exchange(self): + """ Exchange individuals """ + pass + + +class WANMigration(MigrationScheme): + """ This is the Simple Migration class for distributed GA + + Example: + >>> mig = WANMigration("192.168.0.1", "10000", "group1") + + :param host: the source hostname + :param port: the source port number + :param group_name: the group name + """ + + selector = None + """ This is the function slot for the selection method + if you want to change the default selector, you must do this: :: + + migration_scheme.selector.set(Selectors.GRouletteWheel) """ + + def __init__(self, host, port, group_name): + super(WANMigration, self).__init__() + self.setMyself(host, port) + self.setGroupName(group_name) + self.topologyGraph = None + self.serverThread = Network.UDPThreadServer(host, port) + self.clientThread = Network.UDPThreadUnicastClient(self.myself[0], rand_randint(30000, 65534)) + + def setMyself(self, host, port): + """ Which interface you will use to send/receive data + + :param host: your hostname + :param port: your port + """ + self.myself = (host, port) + + def getGroupName(self): + """ Gets the group name + + .. note:: all islands of evolution which are supposed to exchange + individuals, must have the same group name. + """ + return self.groupName + + def setGroupName(self, name): + """ Sets the group name + + :param name: the group name + + .. note:: all islands of evolution which are supposed to exchange + individuals, must have the same group name. + """ + self.groupName = name + + def setTopology(self, graph): + """ Sets the topology of the migrations + + :param graph: the :class:`Util.Graph` instance + """ + self.topologyGraph = graph + + def start(self): + """ Start capture of packets and initialize the migration scheme """ + self.serverThread.start() + + if self.topologyGraph is None: + Util.raiseException("You must add a topology graph to the migration scheme !") + + targets = self.topologyGraph.getNeighbors(self.myself) + self.clientThread.setMultipleTargetHost(targets) + self.clientThread.start() + + def stop(self): + """ Stops the migration engine """ + self.serverThread.shutdown() + self.clientThread.shutdown() + server_timeout = self.serverThread.timeout + client_timeout = self.clientThread.timeout + + self.serverThread.join(server_timeout + 3) + self.clientThread.join(client_timeout + 3) + + if self.serverThread.isAlive(): + logging.warning("warning: server thread not joined !") + + if self.clientThread.isAlive(): + logging.warning("warning: client thread not joined !") + + def exchange(self): + """ This is the main method, is where the individuals + are exchanged """ + + if not self.isReady(): + return + + # Client section -------------------------------------- + # How many will migrate ? + pool = self.selectPool(self.getNumIndividuals()) + + for individual in pool: + # (code, group name, individual) + networkObject = (Consts.CDefNetworkIndividual, self.getGroupName(), individual) + networkData = Network.pickleAndCompress(networkObject, self.getCompressionLevel()) + # Send the individuals to the topology + self.clientThread.addData(networkData) + + # Server section -------------------------------------- + pool = [] + while self.serverThread.isReady(): + # (IP source, data) + networkData = self.serverThread.popPool() + networkObject = Network.unpickleAndDecompress(networkData[1]) + # (code, group name, individual) + pool.append(networkObject) + + # No individuals received + if len(pool) <= 0: + return + + population = self.GAEngine.getPopulation() + + for i in xrange(self.getNumReplacement()): + if len(pool) <= 0: + break + choice = rand_choice(pool) + pool.remove(choice) + + # replace the worst + population[len(population) - 1 - i] = choice[2] + + +class MPIMigration(MigrationScheme): + """ This is the MPIMigration """ + + def __init__(self): + # Delayed ImportError of mpi4py + if not HAS_MPI4PY: + raise ImportError("No module named mpi4py, you must install mpi4py to use MPIMIgration!") + + super(MPIMigration, self).__init__() + + self.comm = MPI.COMM_WORLD + self.pid = self.comm.rank + + if self.pid == 0: + self.source = self.comm.size - 1 + else: + self.source = self.comm.rank - 1 + + self.dest = (self.comm.rank + 1) % (self.comm.size) + + self.all_stars = None + + def isReady(self): + """ Returns true if is time to migrate """ + + if self.GAEngine.getCurrentGeneration() == 0: + return False + + if self.GAEngine.getCurrentGeneration() % self.nMigrationRate == 0: + return True + else: + return False + + def gather_bests(self): + ''' + Collect all the best individuals from the various populations. The + result is stored in process 0 + ''' + best_guy = self.select() + self.all_stars = self.comm.gather(sendobj=best_guy, root=0) + + def exchange(self): + """ This is the main method, is where the individuals + are exchanged """ + + if not self.isReady(): + return + + pool_to_send = self.selectPool(self.getNumIndividuals()) + pool_received = self.comm.sendrecv(sendobj=pool_to_send, + dest=self.dest, + sendtag=0, + recvobj=None, + source=self.source, + recvtag=0) + + population = self.GAEngine.getPopulation() + + pool = pool_received + for i in xrange(self.getNumReplacement()): + if len(pool) <= 0: + break + + choice = rand_choice(pool) + pool.remove(choice) + + # replace the worst + population[len(population) - 1 - i] = choice + + self.gather_bests() diff --git a/pyevolve/Mutators.py.bak b/pyevolve/Mutators.py.bak new file mode 100644 index 0000000..3c757df --- /dev/null +++ b/pyevolve/Mutators.py.bak @@ -0,0 +1,1134 @@ +""" + +:mod:`Mutators` -- mutation methods module +===================================================================== + +In this module we have the genetic operators of mutation for each chromosome representation. + +""" + +import Util +from random import randint as rand_randint, gauss as rand_gauss, uniform as rand_uniform +from random import choice as rand_choice +import Consts +import GTree + +############################# +## 1D Binary String ## +############################# + +def G1DBinaryStringMutatorSwap(genome, **args): + """ The 1D Binary String Swap Mutator """ + + if args["pmut"] <= 0.0: + return 0 + stringLength = len(genome) + mutations = args["pmut"] * (stringLength) + + if mutations < 1.0: + mutations = 0 + for it in xrange(stringLength): + if Util.randomFlipCoin(args["pmut"]): + Util.listSwapElement(genome, it, rand_randint(0, stringLength - 1)) + mutations += 1 + + else: + for it in xrange(int(round(mutations))): + Util.listSwapElement(genome, rand_randint(0, stringLength - 1), + rand_randint(0, stringLength - 1)) + + return int(mutations) + +def G1DBinaryStringMutatorFlip(genome, **args): + """ The classical flip mutator for binary strings """ + if args["pmut"] <= 0.0: + return 0 + stringLength = len(genome) + mutations = args["pmut"] * (stringLength) + + if mutations < 1.0: + mutations = 0 + for it in xrange(stringLength): + if Util.randomFlipCoin(args["pmut"]): + if genome[it] == 0: + genome[it] = 1 + else: + genome[it] = 0 + mutations += 1 + + else: + for it in xrange(int(round(mutations))): + which = rand_randint(0, stringLength - 1) + if genome[which] == 0: + genome[which] = 1 + else: + genome[which] = 0 + + return int(mutations) + +#################### +## 1D List ## +#################### + +def G1DListMutatorSwap(genome, **args): + """ The mutator of G1DList, Swap Mutator + + .. note:: this mutator is :term:`Data Type Independent` + + """ + if args["pmut"] <= 0.0: + return 0 + listSize = len(genome) + mutations = args["pmut"] * listSize + + if mutations < 1.0: + mutations = 0 + for it in xrange(listSize): + if Util.randomFlipCoin(args["pmut"]): + Util.listSwapElement(genome, it, rand_randint(0, listSize - 1)) + mutations += 1 + else: + for it in xrange(int(round(mutations))): + Util.listSwapElement(genome, rand_randint(0, listSize - 1), rand_randint(0, listSize - 1)) + + return int(mutations) + +def G1DListMutatorSIM(genome, **args): + """ The mutator of G1DList, Simple Inversion Mutation + + .. note:: this mutator is :term:`Data Type Independent` + + """ + mutations = 0 + if args["pmut"] <= 0.0: + return 0 + + cuts = [rand_randint(0, len(genome)), rand_randint(0, len(genome))] + + if cuts[0] > cuts[1]: + Util.listSwapElement(cuts, 0, 1) + + if (cuts[1] - cuts[0]) <= 0: + cuts[1] = rand_randint(cuts[0], len(genome)) + + if Util.randomFlipCoin(args["pmut"]): + part = genome[cuts[0]:cuts[1]] + if len(part) == 0: + return 0 + part.reverse() + genome[cuts[0]:cuts[1]] = part + mutations += 1 + + return mutations + +def G1DListMutatorIntegerRange(genome, **args): + """ Simple integer range mutator for G1DList + + Accepts the *rangemin* and *rangemax* genome parameters, both optional. + + """ + if args["pmut"] <= 0.0: + return 0 + listSize = len(genome) + mutations = args["pmut"] * listSize + + if mutations < 1.0: + mutations = 0 + for it in xrange(listSize): + if Util.randomFlipCoin(args["pmut"]): + genome[it] = rand_randint(genome.getParam("rangemin", Consts.CDefRangeMin), + genome.getParam("rangemax", Consts.CDefRangeMax)) + mutations += 1 + + else: + for it in xrange(int(round(mutations))): + which_gene = rand_randint(0, listSize - 1) + genome[which_gene] = rand_randint(genome.getParam("rangemin", Consts.CDefRangeMin), + genome.getParam("rangemax", Consts.CDefRangeMax)) + + return int(mutations) + + +def G1DListMutatorRealRange(genome, **args): + """ Simple real range mutator for G1DList + + Accepts the *rangemin* and *rangemax* genome parameters, both optional. + + """ + if args["pmut"] <= 0.0: + return 0 + listSize = len(genome) + mutations = args["pmut"] * (listSize) + + if mutations < 1.0: + mutations = 0 + for it in xrange(listSize): + if Util.randomFlipCoin(args["pmut"]): + genome[it] = rand_uniform(genome.getParam("rangemin", Consts.CDefRangeMin), + genome.getParam("rangemax", Consts.CDefRangeMax)) + mutations += 1 + + else: + for it in xrange(int(round(mutations))): + which_gene = rand_randint(0, listSize - 1) + genome[which_gene] = rand_uniform(genome.getParam("rangemin", Consts.CDefRangeMin), + genome.getParam("rangemax", Consts.CDefRangeMax)) + + return int(mutations) + +def G1DListMutatorIntegerGaussianGradient(genome, **args): + """ A gaussian mutator for G1DList of Integers + + Accepts the *rangemin* and *rangemax* genome parameters, both optional. The + random distribution is set with mu=1.0 and std=0.0333 + + Same as IntegerGaussian, except that this uses relative gradient rather than + absolute gaussian. A value is randomly generated about gauss(mu=1, sigma=.0333) + and multiplied by the gene to drift it up or down (depending on what side of + 1 the random value falls on) and cast to integer + + """ + if args["pmut"] <= 0.0: + return 0 + listSize = len(genome) + mutations = args["pmut"] * (listSize) + + mu = Consts.CDefGaussianGradientMU + sigma = Consts.CDefGaussianGradientSIGMA + + if mutations < 1.0: + mutations = 0 + for it in xrange(listSize): + if Util.randomFlipCoin(args["pmut"]): + final_value = int(genome[it] * abs(rand_gauss(mu, sigma))) + + final_value = min(final_value, genome.getParam("rangemax", Consts.CDefRangeMax)) + final_value = max(final_value, genome.getParam("rangemin", Consts.CDefRangeMin)) + + genome[it] = final_value + mutations += 1 + else: + for it in xrange(int(round(mutations))): + which_gene = rand_randint(0, listSize - 1) + final_value = int(genome[which_gene] * abs(rand_gauss(mu, sigma))) + + final_value = min(final_value, genome.getParam("rangemax", Consts.CDefRangeMax)) + final_value = max(final_value, genome.getParam("rangemin", Consts.CDefRangeMin)) + + genome[which_gene] = final_value + + return int(mutations) + +def G1DListMutatorIntegerGaussian(genome, **args): + """ A gaussian mutator for G1DList of Integers + + Accepts the *rangemin* and *rangemax* genome parameters, both optional. Also + accepts the parameter *gauss_mu* and the *gauss_sigma* which respectively + represents the mean and the std. dev. of the random distribution. + + """ + if args["pmut"] <= 0.0: + return 0 + listSize = len(genome) + mutations = args["pmut"] * (listSize) + + mu = genome.getParam("gauss_mu") + sigma = genome.getParam("gauss_sigma") + + if mu is None: + mu = Consts.CDefG1DListMutIntMU + + if sigma is None: + sigma = Consts.CDefG1DListMutIntSIGMA + + if mutations < 1.0: + mutations = 0 + for it in xrange(listSize): + if Util.randomFlipCoin(args["pmut"]): + final_value = genome[it] + int(rand_gauss(mu, sigma)) + + final_value = min(final_value, genome.getParam("rangemax", Consts.CDefRangeMax)) + final_value = max(final_value, genome.getParam("rangemin", Consts.CDefRangeMin)) + + genome[it] = final_value + mutations += 1 + else: + for it in xrange(int(round(mutations))): + which_gene = rand_randint(0, listSize - 1) + final_value = genome[which_gene] + int(rand_gauss(mu, sigma)) + + final_value = min(final_value, genome.getParam("rangemax", Consts.CDefRangeMax)) + final_value = max(final_value, genome.getParam("rangemin", Consts.CDefRangeMin)) + + genome[which_gene] = final_value + + return int(mutations) + + +def G1DListMutatorRealGaussian(genome, **args): + """ The mutator of G1DList, Gaussian Mutator + + Accepts the *rangemin* and *rangemax* genome parameters, both optional. Also + accepts the parameter *gauss_mu* and the *gauss_sigma* which respectively + represents the mean and the std. dev. of the random distribution. + + """ + if args["pmut"] <= 0.0: + return 0 + listSize = len(genome) + mutations = args["pmut"] * (listSize) + + mu = genome.getParam("gauss_mu") + sigma = genome.getParam("gauss_sigma") + + if mu is None: + mu = Consts.CDefG1DListMutRealMU + + if sigma is None: + sigma = Consts.CDefG1DListMutRealSIGMA + + if mutations < 1.0: + mutations = 0 + for it in xrange(listSize): + if Util.randomFlipCoin(args["pmut"]): + final_value = genome[it] + rand_gauss(mu, sigma) + + final_value = min(final_value, genome.getParam("rangemax", Consts.CDefRangeMax)) + final_value = max(final_value, genome.getParam("rangemin", Consts.CDefRangeMin)) + + genome[it] = final_value + mutations += 1 + else: + for it in xrange(int(round(mutations))): + which_gene = rand_randint(0, listSize - 1) + final_value = genome[which_gene] + rand_gauss(mu, sigma) + + final_value = min(final_value, genome.getParam("rangemax", Consts.CDefRangeMax)) + final_value = max(final_value, genome.getParam("rangemin", Consts.CDefRangeMin)) + + genome[which_gene] = final_value + + return int(mutations) + +def G1DListMutatorRealGaussianGradient(genome, **args): + """ The mutator of G1DList, Gaussian Gradient Mutator + + Accepts the *rangemin* and *rangemax* genome parameters, both optional. The + random distribution is set with mu=1.0 and std=0.0333 + + The difference between this routine and the normal Gaussian Real is that the + other function generates a gaussian value and adds it to the value. If the + mu is 0, and the std is 1, a typical value could be 1.8 or -0.5. These small + values are fine if your range is 0-10, but if your range is much larger, like + 0-100,000, a relative gradient makes sense. + + This routine generates a gaussian value with mu=1.0 and std=0.0333 and then + the gene is multiplied by this value. This will cause the gene to drift + no matter how large it is. + + """ + if args["pmut"] <= 0.0: + return 0 + listSize = len(genome) + mutations = args["pmut"] * (listSize) + + mu = Consts.CDefGaussianGradientMU + sigma = Consts.CDefGaussianGradientSIGMA + + if mutations < 1.0: + mutations = 0 + for it in xrange(listSize): + if Util.randomFlipCoin(args["pmut"]): + final_value = genome[it] * abs(rand_gauss(mu, sigma)) + + final_value = min(final_value, genome.getParam("rangemax", Consts.CDefRangeMax)) + final_value = max(final_value, genome.getParam("rangemin", Consts.CDefRangeMin)) + + genome[it] = final_value + mutations += 1 + else: + for it in xrange(int(round(mutations))): + which_gene = rand_randint(0, listSize - 1) + final_value = genome[which_gene] * abs(rand_gauss(mu, sigma)) + + final_value = min(final_value, genome.getParam("rangemax", Consts.CDefRangeMax)) + final_value = max(final_value, genome.getParam("rangemin", Consts.CDefRangeMin)) + + genome[which_gene] = final_value + + return int(mutations) + +def G1DListMutatorIntegerBinary(genome, **args): + """ The mutator of G1DList, the binary mutator + + This mutator will random change the 0 and 1 elements of the 1D List. + + """ + if args["pmut"] <= 0.0: + return 0 + listSize = len(genome) + mutations = args["pmut"] * (listSize) + + if mutations < 1.0: + mutations = 0 + for it in xrange(listSize): + if Util.randomFlipCoin(args["pmut"]): + if genome[it] == 0: + genome[it] = 1 + elif genome[it] == 1: + genome[it] = 0 + + mutations += 1 + else: + for it in xrange(int(round(mutations))): + which_gene = rand_randint(0, listSize - 1) + if genome[which_gene] == 0: + genome[which_gene] = 1 + elif genome[which_gene] == 1: + genome[which_gene] = 0 + + return int(mutations) + +def G1DListMutatorAllele(genome, **args): + """ The mutator of G1DList, Allele Mutator + + To use this mutator, you must specify the *allele* genome parameter with the + :class:`GAllele.GAlleles` instance. + + """ + if args["pmut"] <= 0.0: + return 0 + listSize = len(genome) + mutations = args["pmut"] * listSize + + allele = genome.getParam("allele", None) + if allele is None: + Util.raiseException("to use the G1DListMutatorAllele, you must specify the 'allele' parameter", TypeError) + + if mutations < 1.0: + mutations = 0 + for it in xrange(listSize): + if Util.randomFlipCoin(args["pmut"]): + new_val = allele[it].getRandomAllele() + genome[it] = new_val + mutations += 1 + else: + for it in xrange(int(round(mutations))): + which_gene = rand_randint(0, listSize - 1) + new_val = allele[which_gene].getRandomAllele() + genome[which_gene] = new_val + + return int(mutations) + +def G1DListMutatorAlleleGaussian(genome, **arguments): + """An allele-based mutator based on G1DListMutatorRealGaussian. + + Accepts the parameter *gauss_mu* and the *gauss_sigma* which + respectively represents the mean and the std. dev. of the random + distribution. + """ + if arguments["pmut"] <= 0.0: + return 0 + listSize = len(genome) + mutations = arguments["pmut"] * listSize + + mu = genome.getParam("gauss_mu") + sigma = genome.getParam("gauss_sigma") + if mu is None: + mu = Consts.CDefG1DListMutRealMU + if sigma is None: + sigma = Consts.CDefG1DListMutRealSIGMA + + allele = genome.getParam("allele", None) + if allele is None: + Util.raiseException("to use this mutator, you must specify the 'allele' parameter", TypeError) + + if mutations < 1.0: + mutations = 0 + for it in xrange(listSize): + if Util.randomFlipCoin(arguments["pmut"]): + final_value = genome[it] + rand_gauss(mu, sigma) + assert len(allele[it].beginEnd) == 1, "only single ranges are supported" + rangemin, rangemax = allele[it].beginEnd[0] + final_value = min(final_value, rangemax) + final_value = max(final_value, rangemin) + genome[it] = final_value + mutations += 1 + else: + for it in xrange(int(round(mutations))): + which_gene = rand_randint(0, listSize - 1) + final_value = genome[which_gene] + rand_gauss(mu, sigma) + assert len(allele[which_gene].beginEnd) == 1, "only single ranges are supported" + rangemin, rangemax = allele[which_gene].beginEnd[0] + final_value = min(final_value, rangemax) + final_value = max(final_value, rangemin) + genome[which_gene] = final_value + return int(mutations) + + +#################### +## 2D List ## +#################### + +def G2DListMutatorSwap(genome, **args): + """ The mutator of G1DList, Swap Mutator + + .. note:: this mutator is :term:`Data Type Independent` + + """ + + if args["pmut"] <= 0.0: + return 0 + height, width = genome.getSize() + elements = height * width + + mutations = args["pmut"] * elements + + if mutations < 1.0: + mutations = 0 + for i in xrange(height): + for j in xrange(width): + if Util.randomFlipCoin(args["pmut"]): + index_b = (rand_randint(0, height - 1), rand_randint(0, width - 1)) + Util.list2DSwapElement(genome.genomeList, (i, j), index_b) + mutations += 1 + else: + for it in xrange(int(round(mutations))): + index_a = (rand_randint(0, height - 1), rand_randint(0, width - 1)) + index_b = (rand_randint(0, height - 1), rand_randint(0, width - 1)) + Util.list2DSwapElement(genome.genomeList, index_a, index_b) + + return int(mutations) + +def G2DListMutatorIntegerRange(genome, **args): + """ Simple integer range mutator for G2DList + + Accepts the *rangemin* and *rangemax* genome parameters, both optional. + + """ + if args["pmut"] <= 0.0: + return 0 + height, width = genome.getSize() + elements = height * width + + mutations = args["pmut"] * elements + + range_min = genome.getParam("rangemin", Consts.CDefRangeMin) + range_max = genome.getParam("rangemax", Consts.CDefRangeMax) + + if mutations < 1.0: + mutations = 0 + for i in xrange(genome.getHeight()): + for j in xrange(genome.getWidth()): + if Util.randomFlipCoin(args["pmut"]): + random_int = rand_randint(range_min, range_max) + genome.setItem(i, j, random_int) + mutations += 1 + + else: + for it in xrange(int(round(mutations))): + which_x = rand_randint(0, genome.getWidth() - 1) + which_y = rand_randint(0, genome.getHeight() - 1) + random_int = rand_randint(range_min, range_max) + genome.setItem(which_y, which_x, random_int) + + return int(mutations) + + +def G2DListMutatorIntegerGaussianGradient(genome, **args): + """ A gaussian mutator for G2DList of Integers + + Accepts the *rangemin* and *rangemax* genome parameters, both optional. + + This routine generates a gaussian value with mu=1.0 and std=0.0333 and then + the gene is multiplied by this value. This will cause the gene to drift + no matter how large it is. + + """ + if args["pmut"] <= 0.0: + return 0 + height, width = genome.getSize() + elements = height * width + + mutations = args["pmut"] * elements + + mu = Consts.CDefGaussianGradientMU + sigma = Consts.CDefGaussianGradientSIGMA + + if mutations < 1.0: + mutations = 0 + + for i in xrange(genome.getHeight()): + for j in xrange(genome.getWidth()): + if Util.randomFlipCoin(args["pmut"]): + final_value = int(genome[i][j] * abs(rand_gauss(mu, sigma))) + + final_value = min(final_value, genome.getParam("rangemax", Consts.CDefRangeMax)) + final_value = max(final_value, genome.getParam("rangemin", Consts.CDefRangeMin)) + + genome.setItem(i, j, final_value) + mutations += 1 + else: + + for it in xrange(int(round(mutations))): + which_x = rand_randint(0, genome.getWidth() - 1) + which_y = rand_randint(0, genome.getHeight() - 1) + + final_value = int(genome[which_y][which_x] * abs(rand_gauss(mu, sigma))) + + final_value = min(final_value, genome.getParam("rangemax", Consts.CDefRangeMax)) + final_value = max(final_value, genome.getParam("rangemin", Consts.CDefRangeMin)) + + genome.setItem(which_y, which_x, final_value) + + return int(mutations) + +def G2DListMutatorIntegerGaussian(genome, **args): + """ A gaussian mutator for G2DList of Integers + + Accepts the *rangemin* and *rangemax* genome parameters, both optional. Also + accepts the parameter *gauss_mu* and the *gauss_sigma* which respectively + represents the mean and the std. dev. of the random distribution. + + """ + if args["pmut"] <= 0.0: + return 0 + height, width = genome.getSize() + elements = height * width + + mutations = args["pmut"] * elements + + mu = genome.getParam("gauss_mu") + sigma = genome.getParam("gauss_sigma") + + if mu is None: + mu = Consts.CDefG2DListMutIntMU + + if sigma is None: + sigma = Consts.CDefG2DListMutIntSIGMA + + if mutations < 1.0: + mutations = 0 + + for i in xrange(genome.getHeight()): + for j in xrange(genome.getWidth()): + if Util.randomFlipCoin(args["pmut"]): + final_value = genome[i][j] + int(rand_gauss(mu, sigma)) + + final_value = min(final_value, genome.getParam("rangemax", Consts.CDefRangeMax)) + final_value = max(final_value, genome.getParam("rangemin", Consts.CDefRangeMin)) + + genome.setItem(i, j, final_value) + mutations += 1 + else: + + for it in xrange(int(round(mutations))): + which_x = rand_randint(0, genome.getWidth() - 1) + which_y = rand_randint(0, genome.getHeight() - 1) + + final_value = genome[which_y][which_x] + int(rand_gauss(mu, sigma)) + + final_value = min(final_value, genome.getParam("rangemax", Consts.CDefRangeMax)) + final_value = max(final_value, genome.getParam("rangemin", Consts.CDefRangeMin)) + + genome.setItem(which_y, which_x, final_value) + + return int(mutations) + + +def G2DListMutatorAllele(genome, **args): + """ The mutator of G2DList, Allele Mutator + + To use this mutator, you must specify the *allele* genome parameter with the + :class:`GAllele.GAlleles` instance. + + .. warning:: the :class:`GAllele.GAlleles` instance must have the homogeneous flag enabled + + """ + if args["pmut"] <= 0.0: + return 0 + listSize = genome.getHeight() * genome.getWidth() - 1 + mutations = args["pmut"] * (listSize + 1) + + allele = genome.getParam("allele", None) + if allele is None: + Util.raiseException("to use the G2DListMutatorAllele, you must specify the 'allele' parameter", TypeError) + + if not allele.homogeneous: + Util.raiseException("to use the G2DListMutatorAllele, the 'allele' must be homogeneous") + + if mutations < 1.0: + mutations = 0 + + for i in xrange(genome.getHeight()): + for j in xrange(genome.getWidth()): + if Util.randomFlipCoin(args["pmut"]): + new_val = allele[0].getRandomAllele() + genome.setItem(i, j, new_val) + mutations += 1 + else: + for it in xrange(int(round(mutations))): + which_x = rand_randint(0, genome.getHeight() - 1) + which_y = rand_randint(0, genome.getWidth() - 1) + + new_val = allele[0].getRandomAllele() + genome.setItem(which_x, which_y, new_val) + + return int(mutations) + + +def G2DListMutatorRealGaussian(genome, **args): + """ A gaussian mutator for G2DList of Real + + Accepts the *rangemin* and *rangemax* genome parameters, both optional. Also + accepts the parameter *gauss_mu* and the *gauss_sigma* which respectively + represents the mean and the std. dev. of the random distribution. + + """ + if args["pmut"] <= 0.0: + return 0 + height, width = genome.getSize() + elements = height * width + + mutations = args["pmut"] * elements + + mu = genome.getParam("gauss_mu") + sigma = genome.getParam("gauss_sigma") + + if mu is None: + mu = Consts.CDefG2DListMutRealMU + + if sigma is None: + sigma = Consts.CDefG2DListMutRealSIGMA + + if mutations < 1.0: + mutations = 0 + + for i in xrange(genome.getHeight()): + for j in xrange(genome.getWidth()): + if Util.randomFlipCoin(args["pmut"]): + final_value = genome[i][j] + rand_gauss(mu, sigma) + + final_value = min(final_value, genome.getParam("rangemax", Consts.CDefRangeMax)) + final_value = max(final_value, genome.getParam("rangemin", Consts.CDefRangeMin)) + + genome.setItem(i, j, final_value) + mutations += 1 + else: + + for it in xrange(int(round(mutations))): + which_x = rand_randint(0, genome.getWidth() - 1) + which_y = rand_randint(0, genome.getHeight() - 1) + + final_value = genome[which_y][which_x] + rand_gauss(mu, sigma) + + final_value = min(final_value, genome.getParam("rangemax", Consts.CDefRangeMax)) + final_value = max(final_value, genome.getParam("rangemin", Consts.CDefRangeMin)) + + genome.setItem(which_y, which_x, final_value) + + return int(mutations) + +def G2DListMutatorRealGaussianGradient(genome, **args): + """ A gaussian gradient mutator for G2DList of Real + + Accepts the *rangemin* and *rangemax* genome parameters, both optional. + + The difference is that this multiplies the gene by gauss(1.0, 0.0333), allowing + for a smooth gradient drift about the value. + + """ + if args["pmut"] <= 0.0: + return 0 + height, width = genome.getSize() + elements = height * width + + mutations = args["pmut"] * elements + + mu = Consts.CDefGaussianGradientMU + sigma = Consts.CDefGaussianGradientSIGMA + + if mutations < 1.0: + mutations = 0 + + for i in xrange(genome.getHeight()): + for j in xrange(genome.getWidth()): + if Util.randomFlipCoin(args["pmut"]): + final_value = genome[i][j] * abs(rand_gauss(mu, sigma)) + + final_value = min(final_value, genome.getParam("rangemax", Consts.CDefRangeMax)) + final_value = max(final_value, genome.getParam("rangemin", Consts.CDefRangeMin)) + + genome.setItem(i, j, final_value) + mutations += 1 + else: + + for it in xrange(int(round(mutations))): + which_x = rand_randint(0, genome.getWidth() - 1) + which_y = rand_randint(0, genome.getHeight() - 1) + + final_value = genome[which_y][which_x] * abs(rand_gauss(mu, sigma)) + + final_value = min(final_value, genome.getParam("rangemax", Consts.CDefRangeMax)) + final_value = max(final_value, genome.getParam("rangemin", Consts.CDefRangeMin)) + + genome.setItem(which_y, which_x, final_value) + + return int(mutations) + +############################# +## 2D Binary String ## +############################# + +def G2DBinaryStringMutatorSwap(genome, **args): + """ The mutator of G2DBinaryString, Swap Mutator + + .. versionadded:: 0.6 + The *G2DBinaryStringMutatorSwap* function + """ + + if args["pmut"] <= 0.0: + return 0 + height, width = genome.getSize() + elements = height * width + + mutations = args["pmut"] * elements + + if mutations < 1.0: + mutations = 0 + for i in xrange(height): + for j in xrange(width): + if Util.randomFlipCoin(args["pmut"]): + index_b = (rand_randint(0, height - 1), rand_randint(0, width - 1)) + Util.list2DSwapElement(genome.genomeString, (i, j), index_b) + mutations += 1 + else: + for it in xrange(int(round(mutations))): + index_a = (rand_randint(0, height - 1), rand_randint(0, width - 1)) + index_b = (rand_randint(0, height - 1), rand_randint(0, width - 1)) + Util.list2DSwapElement(genome.genomeString, index_a, index_b) + + return int(mutations) + + +def G2DBinaryStringMutatorFlip(genome, **args): + """ A flip mutator for G2DBinaryString + + .. versionadded:: 0.6 + The *G2DBinaryStringMutatorFlip* function + """ + if args["pmut"] <= 0.0: + return 0 + height, width = genome.getSize() + elements = height * width + + mutations = args["pmut"] * elements + + if mutations < 1.0: + mutations = 0 + + for i in xrange(genome.getHeight()): + for j in xrange(genome.getWidth()): + if Util.randomFlipCoin(args["pmut"]): + if genome[i][j] == 0: + genome.setItem(i, j, 1) + else: + genome.setItem(i, j, 0) + mutations += 1 + else: + + for it in xrange(int(round(mutations))): + which_x = rand_randint(0, genome.getWidth() - 1) + which_y = rand_randint(0, genome.getHeight() - 1) + + if genome[i][j] == 0: + genome.setItem(which_y, which_x, 1) + else: + genome.setItem(which_y, which_x, 0) + + return int(mutations) + +################# +## Tree ## +################# +def GTreeMutatorSwap(genome, **args): + """ The mutator of GTree, Swap Mutator + + .. versionadded:: 0.6 + The *GTreeMutatorSwap* function + """ + if args["pmut"] <= 0.0: + return 0 + elements = len(genome) + mutations = args["pmut"] * elements + + if mutations < 1.0: + mutations = 0 + for i in xrange(len(genome)): + if Util.randomFlipCoin(args["pmut"]): + mutations += 1 + nodeOne = genome.getRandomNode() + nodeTwo = genome.getRandomNode() + nodeOne.swapNodeData(nodeTwo) + else: + for it in xrange(int(round(mutations))): + nodeOne = genome.getRandomNode() + nodeTwo = genome.getRandomNode() + nodeOne.swapNodeData(nodeTwo) + + return int(mutations) + + +def GTreeMutatorIntegerRange(genome, **args): + """ The mutator of GTree, Integer Range Mutator + + Accepts the *rangemin* and *rangemax* genome parameters, both optional. + + .. versionadded:: 0.6 + The *GTreeMutatorIntegerRange* function + """ + if args["pmut"] <= 0.0: + return 0 + elements = len(genome) + mutations = args["pmut"] * elements + + range_min = genome.getParam("rangemin", Consts.CDefRangeMin) + range_max = genome.getParam("rangemax", Consts.CDefRangeMax) + + if mutations < 1.0: + mutations = 0 + for i in xrange(len(genome)): + if Util.randomFlipCoin(args["pmut"]): + mutations += 1 + rand_node = genome.getRandomNode() + random_int = rand_randint(range_min, range_max) + rand_node.setData(random_int) + + else: + for it in xrange(int(round(mutations))): + rand_node = genome.getRandomNode() + random_int = rand_randint(range_min, range_max) + rand_node.setData(random_int) + + return int(mutations) + + +def GTreeMutatorRealRange(genome, **args): + """ The mutator of GTree, Real Range Mutator + + Accepts the *rangemin* and *rangemax* genome parameters, both optional. + + .. versionadded:: 0.6 + The *GTreeMutatorRealRange* function + """ + if args["pmut"] <= 0.0: + return 0 + elements = len(genome) + mutations = args["pmut"] * elements + + range_min = genome.getParam("rangemin", Consts.CDefRangeMin) + range_max = genome.getParam("rangemax", Consts.CDefRangeMax) + + if mutations < 1.0: + mutations = 0 + for i in xrange(len(genome)): + if Util.randomFlipCoin(args["pmut"]): + mutations += 1 + rand_node = genome.getRandomNode() + random_real = rand_uniform(range_min, range_max) + rand_node.setData(random_real) + + else: + for it in xrange(int(round(mutations))): + rand_node = genome.getRandomNode() + random_real = rand_uniform(range_min, range_max) + rand_node.setData(random_real) + + return int(mutations) + + +def GTreeMutatorIntegerGaussian(genome, **args): + """ A gaussian mutator for GTree of Integers + + Accepts the *rangemin* and *rangemax* genome parameters, both optional. Also + accepts the parameter *gauss_mu* and the *gauss_sigma* which respectively + represents the mean and the std. dev. of the random distribution. + + """ + if args["pmut"] <= 0.0: + return 0 + elements = len(genome) + mutations = args["pmut"] * elements + + mu = genome.getParam("gauss_mu", Consts.CDefG1DListMutIntMU) + sigma = genome.getParam("gauss_sigma", Consts.CDefG1DListMutIntSIGMA) + + if mutations < 1.0: + mutations = 0 + for i in xrange(len(genome)): + if Util.randomFlipCoin(args["pmut"]): + mutations += 1 + rand_node = genome.getRandomNode() + final_value = rand_node.getData() + int(rand_gauss(mu, sigma)) + final_value = min(final_value, genome.getParam("rangemax", Consts.CDefRangeMax)) + final_value = max(final_value, genome.getParam("rangemin", Consts.CDefRangeMin)) + rand_node.setData(final_value) + else: + for it in xrange(int(round(mutations))): + rand_node = genome.getRandomNode() + final_value = rand_node.getData() + int(rand_gauss(mu, sigma)) + final_value = min(final_value, genome.getParam("rangemax", Consts.CDefRangeMax)) + final_value = max(final_value, genome.getParam("rangemin", Consts.CDefRangeMin)) + rand_node.setData(final_value) + + return int(mutations) + + +def GTreeMutatorRealGaussian(genome, **args): + """ A gaussian mutator for GTree of Real numbers + + Accepts the *rangemin* and *rangemax* genome parameters, both optional. Also + accepts the parameter *gauss_mu* and the *gauss_sigma* which respectively + represents the mean and the std. dev. of the random distribution. + + """ + if args["pmut"] <= 0.0: + return 0 + elements = len(genome) + mutations = args["pmut"] * elements + + mu = genome.getParam("gauss_mu", Consts.CDefG1DListMutRealMU) + sigma = genome.getParam("gauss_sigma", Consts.CDefG1DListMutRealSIGMA) + + if mutations < 1.0: + mutations = 0 + for i in xrange(len(genome)): + if Util.randomFlipCoin(args["pmut"]): + mutations += 1 + rand_node = genome.getRandomNode() + final_value = rand_node.getData() + rand_gauss(mu, sigma) + final_value = min(final_value, genome.getParam("rangemax", Consts.CDefRangeMax)) + final_value = max(final_value, genome.getParam("rangemin", Consts.CDefRangeMin)) + rand_node.setData(final_value) + else: + for it in xrange(int(round(mutations))): + rand_node = genome.getRandomNode() + final_value = rand_node.getData() + rand_gauss(mu, sigma) + final_value = min(final_value, genome.getParam("rangemax", Consts.CDefRangeMax)) + final_value = max(final_value, genome.getParam("rangemin", Consts.CDefRangeMin)) + rand_node.setData(final_value) + + return int(mutations) + +################### +## Tree GP ## +################### + +def GTreeGPMutatorOperation(genome, **args): + """ The mutator of GTreeGP, Operation Mutator + + .. versionadded:: 0.6 + The *GTreeGPMutatorOperation* function + """ + + if args["pmut"] <= 0.0: + return 0 + elements = len(genome) + mutations = args["pmut"] * elements + ga_engine = args["ga_engine"] + + gp_terminals = ga_engine.getParam("gp_terminals") + assert gp_terminals is not None + + gp_function_set = ga_engine.getParam("gp_function_set") + assert gp_function_set is not None + + if mutations < 1.0: + mutations = 0 + for i in xrange(len(genome)): + if Util.randomFlipCoin(args["pmut"]): + mutations += 1 + rand_node = genome.getRandomNode() + assert rand_node is not None + if rand_node.getType() == Consts.nodeType["TERMINAL"]: + term_operator = rand_choice(gp_terminals) + else: + op_len = gp_function_set[rand_node.getData()] + fun_candidates = [] + for o, l in gp_function_set.items(): + if l == op_len: + fun_candidates.append(o) + + if len(fun_candidates) <= 0: + continue + + term_operator = rand_choice(fun_candidates) + rand_node.setData(term_operator) + else: + for it in xrange(int(round(mutations))): + rand_node = genome.getRandomNode() + assert rand_node is not None + if rand_node.getType() == Consts.nodeType["TERMINAL"]: + term_operator = rand_choice(gp_terminals) + else: + op_len = gp_function_set[rand_node.getData()] + fun_candidates = [] + for o, l in gp_function_set.items(): + if l == op_len: + fun_candidates.append(o) + + if len(fun_candidates) <= 0: + continue + + term_operator = rand_choice(fun_candidates) + rand_node.setData(term_operator) + + return int(mutations) + + +def GTreeGPMutatorSubtree(genome, **args): + """ The mutator of GTreeGP, Subtree Mutator + + This mutator will recreate random subtree of the tree using the grow algorithm. + + .. versionadded:: 0.6 + The *GTreeGPMutatorSubtree* function + """ + + if args["pmut"] <= 0.0: + return 0 + ga_engine = args["ga_engine"] + max_depth = genome.getParam("max_depth", None) + mutations = 0 + + if max_depth is None: + Util.raiseException("You must specify the max_depth genome parameter !", ValueError) + + if max_depth < 0: + Util.raiseException("The max_depth must be >= 1, if you want to use GTreeGPMutatorSubtree crossover !", ValueError) + + branch_list = genome.nodes_branch + elements = len(branch_list) + + for i in xrange(elements): + + node = branch_list[i] + assert node is not None + + if Util.randomFlipCoin(args["pmut"]): + depth = genome.getNodeDepth(node) + mutations += 1 + + root_subtree = GTree.buildGTreeGPGrow(ga_engine, 0, max_depth - depth) + node_parent = node.getParent() + + if node_parent is None: + genome.setRoot(root_subtree) + genome.processNodes() + return mutations + else: + root_subtree.setParent(node_parent) + node_parent.replaceChild(node, root_subtree) + genome.processNodes() + + return int(mutations) diff --git a/pyevolve/Network.py.bak b/pyevolve/Network.py.bak new file mode 100644 index 0000000..726c82e --- /dev/null +++ b/pyevolve/Network.py.bak @@ -0,0 +1,444 @@ +""" + +:mod:`Network` -- network utility module +============================================================================ + +In this module you'll find all the network related implementation + +.. versionadded:: 0.6 + The *Network* module. + +""" +from __future__ import with_statement +import threading +import socket +import time +import sys +import Util +import cPickle + +try: + import zlib + ZLIB_SUPPORT = True +except ImportError: + ZLIB_SUPPORT = False + +import Consts +import logging + +def getMachineIP(): + """ Return all the IPs from current machine. + + Example: + >>> Util.getMachineIP() + ['200.12.124.181', '192.168.0.1'] + + :rtype: a python list with the string IPs + + """ + hostname = socket.gethostname() + addresses = socket.getaddrinfo(hostname, None) + ips = [x[4][0] for x in addresses] + return ips + +class UDPThreadBroadcastClient(threading.Thread): + """ The Broadcast UDP client thread class. + + This class is a thread to serve as Pyevolve client on the UDP + datagrams, it is used to send data over network lan/wan. + + Example: + >>> s = Network.UDPThreadClient('192.168.0.2', 1500, 666) + >>> s.setData("Test data") + >>> s.start() + >>> s.join() + + :param host: the hostname to bind the socket on sender (this is NOT the target host) + :param port: the sender port (this is NOT the target port) + :param target_port: the destination port target + + """ + def __init__(self, host, port, target_port): + super(UDPThreadBroadcastClient, self).__init__() + self.host = host + self.port = port + self.targetPort = target_port + self.data = None + self.sentBytes = None + self.sentBytesLock = threading.Lock() + + self.sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) + self.sock.setsockopt(socket.SOL_SOCKET, socket.SO_BROADCAST, 1) + self.sock.bind((host, port)) + + def setData(self, data): + """ Set the data to send + + :param data: the data to send + + """ + self.data = data + + def getData(self): + """ Get the data to send + + :rtype: data to send + + """ + return self.data + + def close(self): + """ Close the internal socket """ + self.sock.close() + + def getSentBytes(self): + """ Returns the number of sent bytes. The use of this method makes sense + when you already have sent the data + + :rtype: sent bytes + + """ + sent = None + with self.sentBytesLock: + if self.sentBytes is None: + Util.raiseException('Bytes sent is None') + else: + sent = self.sentBytes + return sent + + def send(self): + """ Broadcasts the data """ + return self.sock.sendto(self.data, (Consts.CDefBroadcastAddress, self.targetPort)) + + def run(self): + """ Method called when you call *.start()* of the thread """ + if self.data is None: + Util.raiseException('You must set the data with setData method', ValueError) + + with self.sentBytesLock: + self.sentBytes = self.send() + self.close() + +class UDPThreadUnicastClient(threading.Thread): + """ The Unicast UDP client thread class. + + This class is a thread to serve as Pyevolve client on the UDP + datagrams, it is used to send data over network lan/wan. + + Example: + >>> s = Network.UDPThreadClient('192.168.0.2', 1500) + >>> s.setData("Test data") + >>> s.setTargetHost('192.168.0.50', 666) + >>> s.start() + >>> s.join() + + :param host: the hostname to bind the socket on sender (this is not the target host) + :param port: the sender port (this is not the target port) + :param pool_size: the size of send pool + :param timeout: the time interval to check if the client have data to send + + """ + def __init__(self, host, port, pool_size=10, timeout=0.5): + super(UDPThreadUnicastClient, self).__init__() + self.host = host + self.port = port + self.target = [] + self.sendPool = [] + self.poolSize = pool_size + self.sendPoolLock = threading.Lock() + self.timeout = timeout + + self.doshutdown = False + + self.sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) + self.sock.bind((host, port)) + + def poolLength(self): + """ Returns the size of the pool + + :rtype: integer + + """ + with self.sendPoolLock: + ret = len(self.sendPool) + return ret + + def popPool(self): + """ Return the last data received on the pool + + :rtype: object + + """ + with self.sendPoolLock: + ret = self.sendPool.pop() + return ret + + def isReady(self): + """ Returns True when there is data on the pool or False when not + + :rtype: boolean + + """ + with self.sendPoolLock: + ret = True if len(self.sendPool) >= 1 else False + return ret + + def shutdown(self): + """ Shutdown the server thread, when called, this method will stop + the thread on the next socket timeout """ + self.doshutdown = True + + def addData(self, data): + """ Set the data to send + + :param data: the data to send + + """ + if self.poolLength() >= self.poolSize: + logging.warning('the send pool is full, consider increasing the pool size or decreasing the timeout !') + return + + with self.sendPoolLock: + self.sendPool.append(data) + + def setTargetHost(self, host, port): + """ Set the host/port of the target, the destination + + :param host: the target host + :param port: the target port + + .. note:: the host will be ignored when using broadcast mode + """ + del self.target[:] + self.target.append((host, port)) + + def setMultipleTargetHost(self, address_list): + """ Sets multiple host/port targets, the destinations + + :param address_list: a list with tuples (ip, port) + """ + del self.target[:] + self.target = address_list[:] + + def close(self): + """ Close the internal socket """ + self.sock.close() + + def send(self, data): + """ Send the data + + :param data: the data to send + :rtype: bytes sent to each destination + """ + bytes = -1 + for destination in self.target: + bytes = self.sock.sendto(data, destination) + return bytes + + def run(self): + """ Method called when you call *.start()* of the thread """ + if len(self.target) <= 0: + Util.raiseException('You must set the target(s) before send data', ValueError) + + while True: + if self.doshutdown: + break + + while self.isReady(): + data = self.popPool() + self.send(data) + + time.sleep(self.timeout) + + self.close() + +class UDPThreadServer(threading.Thread): + """ The UDP server thread class. + + This class is a thread to serve as Pyevolve server on the UDP + datagrams, it is used to receive data from network lan/wan. + + Example: + >>> s = UDPThreadServer("192.168.0.2", 666, 10) + >>> s.start() + >>> s.shutdown() + + :param host: the host to bind the server + :param port: the server port to bind + :param poolSize: the size of the server pool + :param timeout: the socket timeout + + .. note:: this thread implements a pool to keep the received data, + the *poolSize* parameter specifies how much individuals + we must keep on the pool until the *popPool* method + is called; when the pool is full, the sever will + discard the received individuals. + + """ + def __init__(self, host, port, poolSize=10, timeout=3): + super(UDPThreadServer, self).__init__() + self.recvPool = [] + self.recvPoolLock = threading.Lock() + self.bufferSize = 4096 + self.host = host + self.port = port + self.timeout = timeout + self.doshutdown = False + self.poolSize = poolSize + + self.sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) + self.sock.bind((host, port)) + self.sock.settimeout(self.timeout) + + def shutdown(self): + """ Shutdown the server thread, when called, this method will stop + the thread on the next socket timeout """ + self.doshutdown = True + + def isReady(self): + """ Returns True when there is data on the pool or False when not + + :rtype: boolean + + """ + with self.recvPoolLock: + ret = True if len(self.recvPool) >= 1 else False + return ret + + def poolLength(self): + """ Returns the size of the pool + + :rtype: integer + + """ + with self.recvPoolLock: + ret = len(self.recvPool) + return ret + + def popPool(self): + """ Return the last data received on the pool + + :rtype: object + + """ + with self.recvPoolLock: + ret = self.recvPool.pop() + return ret + + def close(self): + """ Closes the internal socket """ + self.sock.close() + + def setBufferSize(self, size): + """ Sets the receive buffer size + + :param size: integer + + """ + self.bufferSize = size + + def getBufferSize(self): + """ Gets the current receive buffer size + + :rtype: integer + + """ + return self.bufferSize + + def getData(self): + """ Calls the socket *recvfrom* method and waits for the data, + when the data is received, the method will return a tuple + with the IP of the sender and the data received. When a timeout + exception occurs, the method return None. + + :rtype: tuple (sender ip, data) or None when timeout exception + + """ + try: + data, sender = self.sock.recvfrom(self.bufferSize) + except socket.timeout: + return None + return (sender[0], data) + + def run(self): + """ Called when the thread is started by the user. This method + is the main of the thread, when called, it will enter in loop + to wait data or shutdown when needed. + """ + while True: + # Get the data + data = self.getData() + # Shutdown called + if self.doshutdown: + break + # The pool is full + if self.poolLength() >= self.poolSize: + continue + # There is no data received + if data is None: + continue + # It's a packet from myself + if data[0] == self.host: + continue + with self.recvPoolLock: + self.recvPool.append(data) + + self.close() + +def pickleAndCompress(obj, level=9): + """ Pickles the object and compress the dumped string with zlib + + :param obj: the object to be pickled + :param level: the compression level, 9 is the best + and -1 is to not compress + + """ + pickled = cPickle.dumps(obj) + if level < 0: + return pickled + else: + if not ZLIB_SUPPORT: + Util.raiseException('zlib not found !', ImportError) + pickled_zlib = zlib.compress(pickled, level) + return pickled_zlib + +def unpickleAndDecompress(obj_dump, decompress=True): + """ Decompress a zlib compressed string and unpickle the data + + :param obj: the object to be decompressend and unpickled + """ + if decompress: + if not ZLIB_SUPPORT: + Util.raiseException('zlib not found !', ImportError) + obj_decompress = zlib.decompress(obj_dump) + else: + obj_decompress = obj_dump + return cPickle.loads(obj_decompress) + +if __name__ == "__main__": + arg = sys.argv[1] + myself = getMachineIP() + + if arg == "server": + s = UDPThreadServer(myself[0], 666) + s.start() + + while True: + print ".", + time.sleep(10) + if s.isReady(): + item = s.popPool() + print item + time.sleep(4) + s.shutdown() + break + elif arg == "client": + print "Binding on %s..." % myself[0] + s = UDPThreadUnicastClient(myself[0], 1500) + s.setData("dsfssdfsfddf") + s.setTargetHost(myself[0], 666) + s.start() + s.join() + print s.getSentBytes() + + print "end..." diff --git a/pyevolve/Scaling.py.bak b/pyevolve/Scaling.py.bak new file mode 100644 index 0000000..a169dbf --- /dev/null +++ b/pyevolve/Scaling.py.bak @@ -0,0 +1,130 @@ +""" + +:mod:`Scaling` -- scaling schemes module +=========================================================== + +This module have the *scaling schemes* like Linear scaling, etc. + +""" +import Consts +import Util +import math +import logging + +def LinearScaling(pop): + """ Linear Scaling scheme + + .. warning :: Linear Scaling is only for positive raw scores + + """ + logging.debug("Running linear scaling.") + pop.statistics() + c = Consts.CDefScaleLinearMultiplier + a = b = delta = 0.0 + + pop_rawAve = pop.stats["rawAve"] + pop_rawMax = pop.stats["rawMax"] + pop_rawMin = pop.stats["rawMin"] + + if pop_rawAve == pop_rawMax: + a = 1.0 + b = 0.0 + elif pop_rawMin > (c * pop_rawAve - pop_rawMax / c - 1.0): + delta = pop_rawMax - pop_rawAve + a = (c - 1.0) * pop_rawAve / delta + b = pop_rawAve * (pop_rawMax - (c * pop_rawAve)) / delta + else: + delta = pop_rawAve - pop_rawMin + a = pop_rawAve / delta + b = -pop_rawMin * pop_rawAve / delta + + for i in xrange(len(pop)): + f = pop[i].score + if f < 0.0: + Util.raiseException("Score %r is negative, linear scaling not supported !" % (f,), ValueError) + f = f * a + b + if f < 0: + f = 0.0 + pop[i].fitness = f + +def SigmaTruncScaling(pop): + """ Sigma Truncation scaling scheme, allows negative scores """ + logging.debug("Running sigma truncation scaling.") + pop.statistics() + c = Consts.CDefScaleSigmaTruncMultiplier + pop_rawAve = pop.stats["rawAve"] + pop_rawDev = pop.stats["rawDev"] + for i in xrange(len(pop)): + f = pop[i].score - pop_rawAve + f += c * pop_rawDev + if f < 0: + f = 0.0 + pop[i].fitness = f + +def PowerLawScaling(pop): + """ Power Law scaling scheme + + .. warning :: Power Law Scaling is only for positive raw scores + + """ + logging.debug("Running power law scaling.") + k = Consts.CDefScalePowerLawFactor + for i in xrange(len(pop)): + f = pop[i].score + if f < 0.0: + Util.raiseException("Score %r is negative, power law scaling not supported !" % (f,), ValueError) + f = math.pow(f, k) + pop[i].fitness = f + + +def BoltzmannScaling(pop): + """ Boltzmann scaling scheme. You can specify the **boltz_temperature** to the + population parameters, this parameter will set the start temperature. You + can specify the **boltz_factor** and the **boltz_min** parameters, the **boltz_factor** + is the value that the temperature will be subtracted and the **boltz_min** is the + mininum temperature of the scaling scheme. + + .. versionadded: 0.6 + The `BoltzmannScaling` function. + + """ + boltz_temperature = pop.getParam("boltz_temperature", Consts.CDefScaleBoltzStart) + boltz_factor = pop.getParam("boltz_factor", Consts.CDefScaleBoltzFactor) + boltz_min = pop.getParam("boltz_min", Consts.CDefScaleBoltzMinTemp) + + boltz_temperature -= boltz_factor + boltz_temperature = max(boltz_temperature, boltz_min) + pop.setParams(boltzTemperature=boltz_temperature) + + boltz_e = [] + avg = 0.0 + + for i in xrange(len(pop)): + val = math.exp(pop[i].score / boltz_temperature) + boltz_e.append(val) + avg += val + + avg /= len(pop) + + for i in xrange(len(pop)): + pop[i].fitness = boltz_e[i] / avg + +def ExponentialScaling(pop): + """ Exponential Scaling Scheme. The fitness will be the same as (e^score). + + .. versionadded: 0.6 + The `ExponentialScaling` function. + """ + for i in xrange(len(pop)): + score = pop[i].score + pop[i].fitness = math.exp(score) + +def SaturatedScaling(pop): + """ Saturated Scaling Scheme. The fitness will be the same as 1.0-(e^score) + + .. versionadded: 0.6 + The `SaturatedScaling` function. + """ + for i in xrange(len(pop)): + score = pop[i].score + pop[i].fitness = 1.0 - math.exp(score) diff --git a/pyevolve/Selectors.py.bak b/pyevolve/Selectors.py.bak new file mode 100644 index 0000000..9ee11f1 --- /dev/null +++ b/pyevolve/Selectors.py.bak @@ -0,0 +1,179 @@ +""" + +:mod:`Selectors` -- selection methods module +============================================================== + +This module have the *selection methods*, like roulette wheel, tournament, ranking, etc. + +""" + +import random +import Consts + +def GRankSelector(population, **args): + """ The Rank Selector - This selector will pick the best individual of + the population every time. + """ + count = 0 + + if args["popID"] != GRankSelector.cachePopID: + if population.sortType == Consts.sortType["scaled"]: + best_fitness = population.bestFitness().fitness + for index in xrange(1, len(population.internalPop)): + if population[index].fitness == best_fitness: + count += 1 + else: + best_raw = population.bestRaw().score + for index in xrange(1, len(population.internalPop)): + if population[index].score == best_raw: + count += 1 + + GRankSelector.cachePopID = args["popID"] + GRankSelector.cacheCount = count + + else: + count = GRankSelector.cacheCount + + return population[random.randint(0, count)] + +GRankSelector.cachePopID = None +GRankSelector.cacheCount = None + +def GUniformSelector(population, **args): + """ The Uniform Selector """ + return population[random.randint(0, len(population) - 1)] + +def GTournamentSelector(population, **args): + """ The Tournament Selector + + It accepts the *tournamentPool* population parameter. + + .. note:: + the Tournament Selector uses the Roulette Wheel to + pick individuals for the pool + + .. versionchanged:: 0.6 + Changed the parameter `poolSize` to the `tournamentPool`, now the selector + gets the pool size from the population. + + """ + choosen = None + should_minimize = population.minimax == Consts.minimaxType["minimize"] + minimax_operator = min if should_minimize else max + + poolSize = population.getParam("tournamentPool", Consts.CDefTournamentPoolSize) + tournament_pool = [GRouletteWheel(population, **args) for i in xrange(poolSize)] + + if population.sortType == Consts.sortType["scaled"]: + choosen = minimax_operator(tournament_pool, key=lambda ind: ind.fitness) + else: + choosen = minimax_operator(tournament_pool, key=lambda ind: ind.score) + + return choosen + +def GTournamentSelectorAlternative(population, **args): + """ The alternative Tournament Selector + + This Tournament Selector don't uses the Roulette Wheel + + It accepts the *tournamentPool* population parameter. + + .. versionadded: 0.6 + Added the GTournamentAlternative function. + + """ + pool_size = population.getParam("tournamentPool", Consts.CDefTournamentPoolSize) + len_pop = len(population) + should_minimize = population.minimax == Consts.minimaxType["minimize"] + minimax_operator = min if should_minimize else max + tournament_pool = [population[random.randint(0, len_pop - 1)] for i in xrange(pool_size)] + + if population.sortType == Consts.sortType["scaled"]: + choosen = minimax_operator(tournament_pool, key=lambda ind: ind.fitness) + else: + choosen = minimax_operator(tournament_pool, key=lambda ind: ind.score) + + return choosen + +def GRouletteWheel(population, **args): + """ The Roulette Wheel selector """ + psum = None + if args["popID"] != GRouletteWheel.cachePopID: + GRouletteWheel.cachePopID = args["popID"] + psum = GRouletteWheel_PrepareWheel(population) + GRouletteWheel.cacheWheel = psum + else: + psum = GRouletteWheel.cacheWheel + + cutoff = random.random() + lower = 0 + upper = len(population) - 1 + while(upper >= lower): + i = lower + ((upper - lower) / 2) + if psum[i] > cutoff: + upper = i - 1 + else: + lower = i + 1 + + lower = min(len(population) - 1, lower) + lower = max(0, lower) + + return population.bestFitness(lower) + +GRouletteWheel.cachePopID = None +GRouletteWheel.cacheWheel = None + +def GRouletteWheel_PrepareWheel(population): + """ A preparation for Roulette Wheel selection """ + + len_pop = len(population) + + psum = [i for i in xrange(len_pop)] + + population.statistics() + + if population.sortType == Consts.sortType["scaled"]: + pop_fitMax = population.stats["fitMax"] + pop_fitMin = population.stats["fitMin"] + + if pop_fitMax == pop_fitMin: + for index in xrange(len_pop): + psum[index] = (index + 1) / float(len_pop) + elif (pop_fitMax > 0 and pop_fitMin >= 0) or (pop_fitMax <= 0 and pop_fitMin < 0): + population.sort() + if population.minimax == Consts.minimaxType["maximize"]: + psum[0] = population[0].fitness + for i in xrange(1, len_pop): + psum[i] = population[i].fitness + psum[i - 1] + for i in xrange(len_pop): + psum[i] /= float(psum[len_pop - 1]) + else: + psum[0] = -population[0].fitness + pop_fitMax + pop_fitMin + for i in xrange(1, len_pop): + psum[i] = -population[i].fitness + pop_fitMax + pop_fitMin + psum[i - 1] + for i in xrange(len_pop): + psum[i] /= float(psum[len_pop - 1]) + else: + pop_rawMax = population.stats["rawMax"] + pop_rawMin = population.stats["rawMin"] + + if pop_rawMax == pop_rawMin: + for index in xrange(len_pop): + psum[index] = (index + 1) / float(len_pop) + + elif (pop_rawMax > 0 and pop_rawMin >= 0) or (pop_rawMax <= 0 and pop_rawMin < 0): + population.sort() + if population.minimax == Consts.minimaxType["maximize"]: + psum[0] = population[0].score + for i in xrange(1, len_pop): + psum[i] = population[i].score + psum[i - 1] + for i in xrange(len_pop): + psum[i] /= float(psum[len_pop - 1]) + else: + psum[0] = - population[0].score + pop_rawMax + pop_rawMin + for i in xrange(1, len_pop): + psum[i] = - population[i].score + pop_rawMax + pop_rawMin + psum[i - 1] + for i in xrange(len_pop): + psum[i] /= float(psum[len_pop - 1]) + + return psum diff --git a/pyevolve/Statistics.py.bak b/pyevolve/Statistics.py.bak new file mode 100644 index 0000000..a6f1188 --- /dev/null +++ b/pyevolve/Statistics.py.bak @@ -0,0 +1,106 @@ +""" + +:mod:`Statistics` -- statistical structure module +========================================================================== + +This module have the class which is reponsible to keep statistics of each +generation. This class is used by the adapters and other statistics dump objects. + +""" + + +class Statistics(object): + """ Statistics Class - A class bean-like to store the statistics + + The statistics hold by this class are: + + **rawMax, rawMin, rawAve** + Maximum, minimum and average of raw scores + + **rawDev, rawVar** + Standard Deviation and Variance of raw scores + + **fitMax, fitMin, fitAve** + Maximum, mininum and average of fitness scores + + **rawTot, fitTot** + The total (sum) of raw scores and the fitness scores + + Example: + >>> stats = ga_engine.getStatistics() + >>> st["rawMax"] + 10.2 + """ + + def __init__(self): + """ The Statistics Class creator """ + + # 'fit' means 'fitness' + self.internalDict = { + "rawMax": 0.0, + "rawMin": 0.0, + "rawAve": 0.0, + "rawDev": 0.0, + "rawVar": 0.0, + "fitMax": 0.0, + "fitMin": 0.0, + "fitAve": 0.0 + } + + self.descriptions = { + "rawMax": "Maximum raw score", + "rawMin": "Minimum raw score", + "rawAve": "Average of raw scores", + "rawDev": "Standard deviation of raw scores", + "rawVar": "Raw scores variance", + "fitMax": "Maximum fitness", + "fitMin": "Minimum fitness", + "fitAve": "Fitness average", + } + + def __getitem__(self, key): + """ Return the specific statistic by key """ + return self.internalDict[key] + + def __setitem__(self, key, value): + """ Set the statistic """ + self.internalDict[key] = value + + def __len__(self): + """ Return the length of internal stats dictionary """ + return len(self.internalDict) + + def __repr__(self): + """ Return a string representation of the statistics """ + strBuff = "- Statistics\n" + for k, v in self.internalDict.items(): + strBuff += "\t%-45s = %.2f\n" % (self.descriptions.get(k, k), v) + return strBuff + + def asTuple(self): + """ Returns the stats as a python tuple """ + return tuple(self.internalDict.values()) + + def clear(self): + """ Set all statistics to zero """ + for k in self.internalDict.keys(): + self.internalDict[k] = 0 + + def items(self): + """ Return a tuple (name, value) for all stored statistics """ + return self.internalDict.items() + + def clone(self): + """ Instantiate a new Statistic class with the same contents """ + clone_stat = Statistics() + self.copy(clone_stat) + return clone_stat + + def copy(self, obj): + """ Copy the values to the obj variable of the same class + + :param obj: the Statistics object destination + + """ + obj.internalDict = self.internalDict.copy() + obj.descriptions = self.descriptions.copy() diff --git a/pyevolve/Util.py.bak b/pyevolve/Util.py.bak new file mode 100644 index 0000000..4674797 --- /dev/null +++ b/pyevolve/Util.py.bak @@ -0,0 +1,349 @@ +""" + +:mod:`Util` -- utility module +============================================================================ + +This is the utility module, with some utility functions of general +use, like list item swap, random utilities and etc. + +""" + +from random import random as rand_random +from math import sqrt as math_sqrt +import logging +import Consts + + +def randomFlipCoin(p): + """Returns True with the *p* probability. If *p* is 1, the + function will always return True. If *p* is 0, the function will + return always False. + + Example: + >>> Util.randomFlipCoin(1.0) + True + + :param p: probability, between 0.0 and 1.0 + :rtype: True or False + + """ + if p == 1.0: + return True + if p == 0.0: + return False + + return rand_random() <= p + + +def listSwapElement(lst, indexa, indexb): + """ Swaps elements A and B in a list. + + Example: + >>> l = [1, 2, 3] + >>> Util.listSwapElement(l, 1, 2) + >>> l + [1, 3, 2] + + :param lst: the list + :param indexa: the swap element A + :param indexb: the swap element B + :rtype: None + + """ + lst[indexa], lst[indexb] = lst[indexb], lst[indexa] + + +def list2DSwapElement(lst, indexa, indexb): + """ Swaps elements A and B in a 2D list (matrix). + + Example: + >>> l = [ [1,2,3], [4,5,6] ] + >>> Util.list2DSwapElement(l, (0,1), (1,1) ) + >>> l + [[1, 5, 3], [4, 2, 6]] + + :param lst: the list + :param indexa: the swap element A + :param indexb: the swap element B + :rtype: None + + """ + temp = lst[indexa[0]][indexa[1]] + lst[indexa[0]][indexa[1]] = lst[indexb[0]][indexb[1]] + lst[indexb[0]][indexb[1]] = temp + + +def raiseException(message, expt=None): + """ Raise an exception and logs the message. + + Example: + >>> Util.raiseException('The value is not an integer', ValueError) + + :param message: the message of exception + :param expt: the exception class + :rtype: None + + """ + logging.critical(message) + if expt is None: + raise Exception(message) + else: + raise (expt, message) + + +def cmp_individual_raw(a, b): + """ Compares two individual raw scores + + Example: + >>> GPopulation.cmp_individual_raw(a, b) + + :param a: the A individual instance + :param b: the B individual instance + :rtype: 0 if the two individuals raw score are the same, + -1 if the B individual raw score is greater than A and + 1 if the A individual raw score is greater than B. + + .. note:: this function is used to sorte the population individuals + + """ + if a.score < b.score: + return -1 + if a.score > b.score: + return 1 + return 0 + + +def cmp_individual_scaled(a, b): + """ Compares two individual fitness scores, used for sorting population + + Example: + >>> GPopulation.cmp_individual_scaled(a, b) + + :param a: the A individual instance + :param b: the B individual instance + :rtype: 0 if the two individuals fitness score are the same, + -1 if the B individual fitness score is greater than A and + 1 if the A individual fitness score is greater than B. + + .. note:: this function is used to sorte the population individuals + + """ + if a.fitness < b.fitness: + return -1 + if a.fitness > b.fitness: + return 1 + return 0 + + +def importSpecial(name): + """ This function will import the *name* module, if fails, + it will raise an ImportError exception and a message + + :param name: the module name + :rtype: the module object + + .. versionadded:: 0.6 + The *import_special* function + """ + try: + imp_mod = __import__(name) + except ImportError: + raiseException("Cannot import module %s: %s" % (name, Consts.CDefImportList[name]), expt=ImportError) + return imp_mod + + +class ErrorAccumulator(object): + """ An accumulator for the Root Mean Square Error (RMSE) and the + Mean Square Error (MSE) + """ + def __init__(self): + self.acc = 0.0 + self.acc_square = 0.0 + self.acc_len = 0 + + def reset(self): + """ Reset the accumulator """ + self.acc_square = 0.0 + self.acc = 0.0 + self.acc_len = 0 + + def append(self, target, evaluated): + """ Add value to the accumulator + + :param target: the target value + :param evaluated: the evaluated value + """ + self.acc_square += (target - evaluated) ** 2 + self.acc += abs(target - evaluated) + self.acc_len += 1 + + def __iadd__(self, value): + """ The same as append, but you must pass a tuple """ + self.append(*value) + return self + + def getMean(self): + """ Return the mean of the non-squared accumulator """ + return self.acc / self.acc_len + + def getSquared(self): + """ Returns the squared accumulator """ + return self.acc_square + + def getNonSquared(self): + """ Returns the non-squared accumulator """ + return self.acc + + def getAdjusted(self): + """ Returns the adjusted fitness + This fitness is calculated as 1 / (1 + standardized fitness) + """ + return 1.0 / (1.0 + self.acc) + + def getRMSE(self): + """ Return the root mean square error + + :rtype: float RMSE + """ + return math_sqrt(self.acc_square / float(self.acc_len)) + + def getMSE(self): + """ Return the mean square error + + :rtype: float MSE + """ + return self.acc_square / float(self.acc_len) + + +class Graph(object): + """ The Graph class + + Example: + >>> g = Graph() + >>> g.addEdge("a", "b") + >>> g.addEdge("b", "c") + >>> for node in g: + ... print node + a + b + c + + .. versionadded:: 0.6 + The *Graph* class. + """ + + def __init__(self): + """ The constructor """ + self.adjacent = {} + + def __iter__(self): + """ Returns an iterator to the all graph elements """ + return iter(self.adjacent) + + def addNode(self, node): + """ Add the node + + :param node: the node to add + """ + if node not in self.adjacent: + self.adjacent[node] = {} + + def __iadd__(self, node): + """ Add a node using the += operator """ + self.addNode(node) + return self + + def addEdge(self, a, b): + """ Add an edge between two nodes, if the nodes + doesn't exists, they will be created + + :param a: the first node + :param b: the second node + """ + if a not in self.adjacent: + self.adjacent[a] = {} + + if b not in self.adjacent: + self.adjacent[b] = {} + + self.adjacent[a][b] = True + self.adjacent[b][a] = True + + def getNodes(self): + """ Returns all the current nodes on the graph + + :rtype: the list of nodes + """ + return self.adjacent.keys() + + def reset(self): + """ Deletes all nodes of the graph """ + self.adjacent.clear() + + def getNeighbors(self, node): + """ Returns the neighbors of the node + + :param node: the node + """ + return self.adjacent[node].keys() + + def __getitem__(self, node): + """ Returns the adjacent nodes of the node """ + return self.adjacent[node].keys() + + def __repr__(self): + ret = "- Graph\n" + ret += "\tNode list:\n" + for node in self: + ret += "\t\tNode [%s] = %s\n" % (node, self.getNeighbors(node)) + return ret + + +def G1DListGetEdgesComposite(mom, dad): + """ Get the edges and the merge between the edges of two G1DList individuals + + :param mom: the mom G1DList individual + :param dad: the dad G1DList individual + :rtype: a tuple (mom edges, dad edges, merge) + """ + mom_edges = G1DListGetEdges(mom) + dad_edges = G1DListGetEdges(dad) + return mom_edges, dad_edges, G1DListMergeEdges(mom_edges, dad_edges) + + +def G1DListGetEdges(individual): + """ Get the edges of a G1DList individual + + :param individual: the G1DList individual + :rtype: the edges dictionary + """ + edg = {} + ind_list = individual.getInternalList() + for i in xrange(len(ind_list)): + a, b = ind_list[i], ind_list[i - 1] + + if a not in edg: + edg[a] = [] + else: + edg[a].append(b) + + if b not in edg: + edg[b] = [] + else: + edg[b].append(a) + return edg + + +def G1DListMergeEdges(eda, edb): + """ Get the merge between the two individual edges + + :param eda: the edges of the first G1DList genome + :param edb: the edges of the second G1DList genome + :rtype: the merged dictionary + """ + edges = {} + for value, near in eda.items(): + for adj in near: + if (value in edb) and (adj in edb[value]): + edges.setdefault(value, []).append(adj) + return edges From 86f249410f8082b3641b5e3d9634a5b8cca92a82 Mon Sep 17 00:00:00 2001 From: yugangzhang Date: Fri, 6 Jul 2018 17:43:50 -0400 Subject: [PATCH 04/10] Old python2 --- pyevolve_graph.py.bak | 607 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 607 insertions(+) create mode 100755 pyevolve_graph.py.bak diff --git a/pyevolve_graph.py.bak b/pyevolve_graph.py.bak new file mode 100755 index 0000000..7956331 --- /dev/null +++ b/pyevolve_graph.py.bak @@ -0,0 +1,607 @@ +#!/usr/bin/python + +# This code is part of Pyevolve. +# It requires matplotlib v.0.98.5.0+ +from optparse import OptionParser +from optparse import OptionGroup + +def graph_pop_heatmap_raw(pop, minimize, colormap="jet", filesave=None): + pylab.imshow(pop, aspect="auto", interpolation="gaussian", cmap=matplotlib.cm.__dict__[colormap]) + pylab.title("Plot of pop. raw scores along the generations") + pylab.xlabel('Population') + pylab.ylabel('Generations') + pylab.grid(True) + pylab.colorbar() + + if filesave: + pylab.savefig(filesave) + print "Graph saved to %s file !" % (filesave,) + else: + pylab.show() + +def graph_pop_heatmap_fitness(pop, minimize, colormap="jet", filesave=None): + pylab.imshow(pop, aspect="equal", interpolation="gaussian", cmap=matplotlib.cm.__dict__[colormap]) + pylab.title("Plot of pop. fitness scores along the generations") + pylab.xlabel('Population') + pylab.ylabel('Generations') + pylab.grid(True) + pylab.colorbar() + + if filesave: + pylab.savefig(filesave) + print "Graph saved to %s file !" % (filesave,) + else: + pylab.show() + + +def graph_diff_raw(pop, minimize, filesave=None): + x = [] + + diff_raw_y = [] + diff_fit_y = [] + + for it in pop: + x.append(it["generation"]) + diff_raw_y.append(it["rawMax"] - it["rawMin"]) + diff_fit_y.append(it["fitMax"] - it["fitMin"]) + + pylab.figure() + pylab.subplot(211) + + pylab.plot(x, diff_raw_y, "g", label="Raw difference", linewidth=1.2) + pylab.fill_between(x, diff_raw_y, color="g", alpha=0.1) + + diff_raw_max= max(diff_raw_y) + gen_max_raw = x[diff_raw_y.index(diff_raw_max)] + + pylab.annotate("Maximum (%.2f)" % (diff_raw_max,), xy=(gen_max_raw, diff_raw_max), xycoords='data', + xytext=(-150, -20), textcoords='offset points', + arrowprops=dict(arrowstyle="->", + connectionstyle="arc"), + ) + + pylab.xlabel("Generation (#)") + pylab.ylabel("Raw difference") + pylab.title("Plot of evolution identified by '%s'" % (options.identify)) + + pylab.grid(True) + pylab.legend(prop=FontProperties(size="smaller")) + + pylab.subplot(212) + + pylab.plot(x, diff_fit_y, "b", label="Fitness difference", linewidth=1.2) + pylab.fill_between(x, diff_fit_y, color="b", alpha=0.1) + + + diff_fit_max= max(diff_fit_y) + gen_max_fit = x[diff_fit_y.index(diff_fit_max)] + + pylab.annotate("Maximum (%.2f)" % (diff_fit_max,), xy=(gen_max_fit, diff_fit_max), xycoords='data', + xytext=(-150, -20), textcoords='offset points', + arrowprops=dict(arrowstyle="->", + connectionstyle="arc"), + ) + + pylab.xlabel("Generation (#)") + pylab.ylabel("Fitness difference") + + pylab.grid(True) + pylab.legend(prop=FontProperties(size="smaller")) + + if filesave: + pylab.savefig(filesave) + print "Graph saved to %s file !" % (filesave,) + else: + pylab.show() + +def graph_maxmin_raw(pop, minimize, filesave=None): + x = [] + max_y = [] + min_y = [] + std_dev_y = [] + avg_y = [] + + for it in pop: + x.append(it["generation"]) + max_y.append(it["rawMax"]) + min_y.append(it["rawMin"]) + std_dev_y.append(it["rawDev"]) + avg_y.append(it["rawAve"]) + + pylab.figure() + + pylab.plot(x, max_y, "g", label="Max raw", linewidth=1.2) + pylab.plot(x, min_y, "r", label="Min raw", linewidth=1.2) + pylab.plot(x, avg_y, "b", label="Avg raw", linewidth=1.2) + pylab.plot(x, std_dev_y, "k", label="Std Dev raw", linewidth=1.2) + + pylab.fill_between(x, min_y, max_y, color="g", alpha=0.1, label="Diff max/min") + + if minimize: raw_max = min(min_y) + else: raw_max= max(max_y) + + if minimize: gen_max = x[min_y.index(raw_max)] + else: gen_max = x[max_y.index(raw_max)] + + min_std = min(std_dev_y) + gen_min_std = x[std_dev_y.index(min_std)] + + max_std = max(std_dev_y) + gen_max_std = x[std_dev_y.index(max_std)] + + if minimize: annot_label = "Minimum (%.2f)" % (raw_max,) + else: annot_label = "Maximum (%.2f)" % (raw_max,) + + + pylab.annotate(annot_label, xy=(gen_max, raw_max), xycoords='data', + xytext=(8, 15), textcoords='offset points', + arrowprops=dict(arrowstyle="->", + connectionstyle="arc"), + ) + + pylab.annotate("Min StdDev (%.2f)" % (min_std,), xy=(gen_min_std, min_std), xycoords='data', + xytext=(8, 15), textcoords='offset points', + arrowprops=dict(arrowstyle="->", + connectionstyle="arc"), + ) + + pylab.annotate("Max StdDev (%.2f)" % (max_std,), xy=(gen_max_std, max_std), xycoords='data', + xytext=(8, 15), textcoords='offset points', + arrowprops=dict(arrowstyle="->", + connectionstyle="arc"), + ) + + pylab.xlabel("Generation (#)") + pylab.ylabel("Raw score") + pylab.title("Plot of evolution identified by '%s' (raw scores)" % (options.identify)) + + pylab.grid(True) + pylab.legend(prop=FontProperties(size="smaller")) + + if filesave: + pylab.savefig(filesave) + print "Graph saved to %s file !" % (filesave,) + else: + pylab.show() + + +def graph_maxmin_fitness(pop, minimize, filesave=None): + x = [] + max_y = [] + min_y = [] + avg_y = [] + + for it in pop: + x.append(it["generation"]) + max_y.append(it["fitMax"]) + min_y.append(it["fitMin"]) + avg_y.append(it["fitAve"]) + + pylab.figure() + pylab.plot(x, max_y, "g", label="Max fitness") + pylab.plot(x, min_y, "r", label="Min fitness") + pylab.plot(x, avg_y, "b", label="Avg fitness") + + pylab.fill_between(x, min_y, max_y, color="g", alpha=0.1, label="Diff max/min") + + if minimize: raw_max = min(min_y) + else: raw_max = max(max_y) + + if minimize: gen_max = x[min_y.index(raw_max)] + else: gen_max = x[max_y.index(raw_max)] + + if minimize: annot_label = "Minimum (%.2f)" % (raw_max,) + else: annot_label = "Maximum (%.2f)" % (raw_max,) + + pylab.annotate(annot_label, xy=(gen_max, raw_max), xycoords='data', + xytext=(8, 15), textcoords='offset points', + arrowprops=dict(arrowstyle="->", + connectionstyle="arc"), + ) + + pylab.xlabel("Generation (#)") + pylab.ylabel("Fitness score") + pylab.title("Plot of evolution identified by '%s' (fitness scores)" % (options.identify)) + pylab.grid(True) + pylab.legend(prop=FontProperties(size="smaller")) + + if filesave: + pylab.savefig(filesave) + print "Graph saved to %s file !" % (filesave,) + else: + pylab.show() + +def graph_errorbars_raw(pop, minimize, filesave=None): + x = [] + y = [] + yerr_max = [] + yerr_min = [] + + for it in pop: + x.append(it["generation"]) + y.append(it["rawAve"]) + ymax = it["rawMax"] - it["rawAve"] + ymin = it["rawAve"] - it["rawMin"] + + yerr_max.append(ymax) + yerr_min.append(ymin) + + pylab.figure() + pylab.errorbar(x, y, [yerr_min, yerr_max], ecolor="g") + pylab.xlabel('Generation (#)') + pylab.ylabel('Raw score Min/Avg/Max') + pylab.title("Plot of evolution identified by '%s' (raw scores)" % (options.identify)) + pylab.grid(True) + + if filesave: + pylab.savefig(filesave) + print "Graph saved to %s file !" % (filesave,) + else: + pylab.show() + +def graph_errorbars_fitness(pop, minimize, filesave=None): + x = [] + y = [] + yerr_max = [] + yerr_min = [] + + for it in pop: + x.append(it["generation"]) + y.append(it["fitAve"]) + ymax = it["fitMax"] - it["fitAve"] + ymin = it["fitAve"] - it["fitMin"] + + yerr_max.append(ymax) + yerr_min.append(ymin) + + pylab.figure() + pylab.errorbar(x, y, [yerr_min, yerr_max], ecolor="g") + pylab.xlabel('Generation (#)') + pylab.ylabel('Fitness score Min/Avg/Max') + pylab.title("Plot of evolution identified by '%s' (fitness scores)" % (options.identify)) + + pylab.grid(True) + + if filesave: + pylab.savefig(filesave) + print "Graph saved to %s file !" % (filesave,) + else: + pylab.show() + +def graph_compare_raw(pop, minimize, id_list, filesave=None): + colors_list = ["g", "b", "r", "k", "m", "y"] + index = 0 + + pylab.figure() + + for it_out in pop: + x = [] + max_y = [] + min_y = [] + + for it in it_out: + x.append(it["generation"]) + max_y.append(it["rawMax"]) + min_y.append(it["rawMin"]) + + + if minimize: + pylab.plot(x, max_y, colors_list[index], linewidth=0.05) + pylab.plot(x, min_y, colors_list[index], label="Raw min (%s)" % (id_list[index],), linewidth=1.3) + else: + pylab.plot(x, max_y, colors_list[index], label="Raw max (%s)" % (id_list[index],), linewidth=1.3) + pylab.plot(x, min_y, colors_list[index], linewidth=0.05) + + pylab.fill_between(x, min_y, max_y, color=colors_list[index], alpha=0.06,) + + index += 1 + + pylab.xlabel("Generation (#)") + pylab.ylabel("Raw score") + pylab.title("Plot of evolution identified by '%s' (raw scores)" % ('many',)) + pylab.grid(True) + pylab.legend(prop=FontProperties(size="smaller")) + + if filesave: + pylab.savefig(filesave) + print "Graph saved to %s file !" % (filesave,) + else: + pylab.show() + +def graph_compare_fitness(pop, minimize, id_list, filesave=None): + colors_list = ["g", "b", "r", "k", "m", "y"] + index = 0 + + pylab.figure() + + for it_out in pop: + x = [] + max_y = [] + min_y = [] + + for it in it_out: + x.append(it["generation"]) + max_y.append(it["fitMax"]) + min_y.append(it["fitMin"]) + + if minimize: + pylab.plot(x, max_y, colors_list[index], linewidth=0.05) + pylab.plot(x, min_y, colors_list[index], label="Fitness min (%s)" % (id_list[index],), linewidth=1.3) + else: + pylab.plot(x, max_y, colors_list[index], label="Fitness max (%s)" % (id_list[index],), linewidth=1.3) + pylab.plot(x, min_y, colors_list[index], linewidth=0.05) + + pylab.fill_between(x, min_y, max_y, color=colors_list[index], alpha=0.06,) + + index += 1 + + pylab.xlabel("Generation (#)") + pylab.ylabel("Fitness score") + pylab.title("Plot of evolution identified by '%s' (fitness scores)" % ('many',)) + pylab.grid(True) + pylab.legend(prop=FontProperties(size="smaller")) + + if filesave: + pylab.savefig(filesave) + print "Graph saved to %s file !" % (filesave,) + else: + pylab.show() + + +if __name__ == "__main__": + from pyevolve import __version__ as pyevolve_version + from pyevolve import __author__ as pyevolve_author + + popGraph = False + + print "Pyevolve %s - Graph Plot Tool" % (pyevolve_version,) + print "By %s\n" % (pyevolve_author,) + parser = OptionParser() + + parser.add_option("-f", "--file", dest="dbfile", + help="Database file to read (default is 'pyevolve.db').", metavar="FILENAME", default="pyevolve.db") + + parser.add_option("-i", "--identify", dest="identify", + help="The identify of evolution.", metavar="IDENTIFY") + + parser.add_option("-o", "--outfile", dest="outfile", + help="""Write the graph image to a file (don't use extension, just the filename, default is png format, but you can change using --extension (-e) parameter).""", + metavar="OUTFILE") + + parser.add_option("-e", "--extension", dest="extension", + help="""Graph image file format. Supported options (formats) are: emf, eps, pdf, png, ps, raw, rgba, svg, svgz. Default is 'png'.""", + metavar="EXTENSION", default="png") + + parser.add_option("-g", "--genrange", dest="genrange", + help="""This is the generation range of the graph, ex: 1:30 (interval between 1 and 30).""", + metavar="GENRANGE") + + parser.add_option("-l", "--lindrange", dest="lindrange", + help="""This is the individual range of the graph, ex: 1:30 (individuals between 1 and 30), only applies to heatmaps.""", + metavar="LINDRANGE") + + parser.add_option("-c", "--colormap", dest="colormap", + help="""Sets the Color Map for the graph types 8 and 9. Some options are: summer, bone, gray, hot, jet, cooper, spectral. The default is 'jet'.""", + metavar="COLORMAP", default="jet") + + parser.add_option("-m", "--minimize", action="store_true", + help="Sets the 'Minimize' mode, default is the Maximize mode. This option makes sense if you are minimizing your evaluation function.", dest="minimize") + + group = OptionGroup(parser, "Graph types", "This is the supported graph types") + + group.add_option("-0", action="store_true", help="Write all graphs to files. Graph types: 1, 2, 3, 4 and 5.", dest="all_graphs") + + group.add_option("-1", action="store_true", help="Error bars graph (raw scores).", dest="errorbars_raw") + group.add_option("-2", action="store_true", help="Error bars graph (fitness scores).", dest="errorbars_fitness") + group.add_option("-3", action="store_true", help="Max/min/avg/std. dev. graph (raw scores).", dest="maxmin_raw") + group.add_option("-4", action="store_true", help="Max/min/avg graph (fitness scores).", dest="maxmin_fitness") + group.add_option("-5", action="store_true", help="Raw and Fitness min/max difference graph.", dest="diff_raw") + + group.add_option("-6", action="store_true", help="Compare best raw score of two or more evolutions (you must specify the identify comma-separed list with --identify (-i) parameter, like 'one, two, three'), the maximum is 6 items.", dest="compare_raw") + group.add_option("-7", action="store_true", help="Compare best fitness score of two or more evolutions (you must specify the identify comma-separed list with --identify (-i) parameter, like 'one, two, three'), the maximum is 6 items.", dest="compare_fitness") + + group.add_option("-8", action="store_true", help="Show a heat map of population raw score distribution between generations.", dest="pop_heatmap_raw") + group.add_option("-9", action="store_true", help="Show a heat map of population fitness score distribution between generations.", dest="pop_heatmap_fitness") + + + parser.add_option_group(group) + + (options, args) = parser.parse_args() + + if options.identify and (not options.errorbars_raw + and not options.errorbars_fitness + and not options.maxmin_raw + and not options.maxmin_fitness + and not options.diff_raw + and not options.all_graphs + and not options.compare_raw + and not options.pop_heatmap_raw + and not options.pop_heatmap_fitness + and not options.compare_fitness): + parser.error("You must choose one graph type !") + + if (not options.identify) or (not options.dbfile): + parser.print_help() + exit() + + print "Loading modules...." + + import os.path + if not os.path.exists(options.dbfile): + print "Database file '%s' not found !" % (options.dbfile, ) + exit() + + import pylab + from matplotlib.font_manager import FontProperties + import matplotlib.cm + import sqlite3 + import math + import os + + print "Loading database and creating graph..." + + identify_list = options.identify.split(",") + identify_list = map(str.strip, identify_list) + + pop = None + + if options.pop_heatmap_raw or options.pop_heatmap_fitness: + conn = sqlite3.connect(options.dbfile) + conn.row_factory = sqlite3.Row + c = conn.cursor() + + if options.genrange: + genrange = options.genrange.split(":") + ret = c.execute("select distinct generation from population where identify = ? and generation between ? and ?", (options.identify, genrange[0], genrange[1])) + else: + ret = c.execute("select distinct generation from population where identify = ?", (options.identify,)) + + generations = ret.fetchall() + if len(generations) <= 0: + print "No generation data found for the identify '%s' !" % (options.identify,) + exit() + + pop = [] + for gen in generations: + pop_tmp = [] + + if options.lindrange: + individual_range = options.lindrange.split(":") + ret = c.execute(""" + select * from population + where identify = ? + and generation = ? + and individual between ? and ? + """, (options.identify, gen[0], individual_range[0], individual_range[1])) + else: + ret = c.execute(""" + select * from population + where identify = ? + and generation = ? + """, (options.identify, gen[0])) + + ret_fetch = ret.fetchall() + for it in ret_fetch: + if options.pop_heatmap_raw: + pop_tmp.append(it["raw"]) + else: + pop_tmp.append(it["fitness"]) + pop.append(pop_tmp) + + ret.close() + conn.close() + + if len(pop) <= 0: + print "No statistic data found for the identify '%s' !" % (options.identify,) + exit() + + print "%d generations found !" % (len(pop),) + + popGraph = True + + + if len(identify_list) == 1 and not popGraph: + if options.compare_raw or options.compare_fitness: + parser.error("You can't use this graph type with only one identify !") + + conn = sqlite3.connect(options.dbfile) + conn.row_factory = sqlite3.Row + c = conn.cursor() + + if options.genrange: + genrange = options.genrange.split(":") + ret = c.execute("select * from statistics where identify = ? and generation between ? and ?", (options.identify, genrange[0], genrange[1])) + else: + ret = c.execute("select * from statistics where identify = ?", (options.identify,)) + + pop = ret.fetchall() + + ret.close() + conn.close() + + if len(pop) <= 0: + print "No statistic data found for the identify '%s' !" % (options.identify,) + exit() + + print "%d generations found !" % (len(pop),) + + elif len(identify_list) > 1 and not popGraph: + pop = [] + if (not options.compare_raw) and (not options.compare_fitness): + parser.error("You can't use many ids with this graph type !") + + conn = sqlite3.connect(options.dbfile) + conn.row_factory = sqlite3.Row + c = conn.cursor() + for item in identify_list: + if options.genrange: + genrange = options.genrange.split(":") + ret = c.execute("select * from statistics where identify = ? and generation between ? and ?", (item, genrange[0], genrange[1])) + else: + ret = c.execute("select * from statistics where identify = ?", (item,)) + fetchall = ret.fetchall() + if len(fetchall) > 0: + pop.append(fetchall) + + ret.close() + conn.close() + + if len(pop) <= 0: + print "No statistic data found for the identify list '%s' !" % (options.identify,) + exit() + + print "%d identify found !" % (len(pop),) + + if options.errorbars_raw: + if options.outfile: graph_errorbars_raw(pop, options.minimize, options.outfile + "." + options.extension) + else: graph_errorbars_raw(pop, options.minimize) + + if options.errorbars_fitness: + if options.outfile: graph_errorbars_fitness(pop, options.minimize, options.outfile + "." + options.extension) + else: graph_errorbars_fitness(pop, options.minimize) + + if options.maxmin_raw: + if options.outfile: graph_maxmin_raw(pop, options.minimize, options.outfile + "." + options.extension) + else: graph_maxmin_raw(pop, options.minimize) + + if options.maxmin_fitness: + if options.outfile: graph_maxmin_fitness(pop, options.minimize, options.outfile + "." + options.extension) + else: graph_maxmin_fitness(pop, options.minimize) + + if options.diff_raw: + if options.outfile: graph_diff_raw(pop, options.minimize, options.outfile + "." + options.extension) + else: graph_diff_raw(pop, options.minimize) + + if options.all_graphs: + all_graph_functions = [graph_errorbars_raw, graph_errorbars_fitness, graph_maxmin_raw, + graph_maxmin_fitness, graph_diff_raw] + if options.outfile: + parser.error("You can't specify one file to all graphs !") + + dirname = "graphs_" + options.identify + if not os.path.isdir(dirname): + os.mkdir(dirname) + + for graph in all_graph_functions: + filename = dirname + "/" + filename += options.identify + "_" + graph.__name__[6:] + filename += "." + options.extension + graph(pop, options.minimize, filename) + + print "\n\tDone ! The graphs was saved in the directory '%s'" % (dirname) + + if options.compare_raw: + if options.outfile: graph_compare_raw(pop, options.minimize, identify_list, options.outfile + "." + options.extension) + else: graph_compare_raw(pop, options.minimize, identify_list ) + + if options.compare_fitness: + if options.outfile: graph_compare_fitness(pop, options.minimize, identify_list, options.outfile + "." + options.extension) + else: graph_compare_fitness(pop, options.minimize, identify_list ) + + if options.pop_heatmap_raw: + if options.outfile: graph_pop_heatmap_raw(pop, options.minimize, options.colormap, options.outfile + "." + options.extension) + else: graph_pop_heatmap_raw(pop, options.minimize, options.colormap) + + if options.pop_heatmap_fitness: + if options.outfile: graph_pop_heatmap_fitness(pop, options.minimize, options.colormap, options.outfile + "." + options.extension) + else: graph_pop_heatmap_fitness(pop, options.minimize, options.colormap) From eaf9ca01c3406186f61f608f6ec6af2314d933cb Mon Sep 17 00:00:00 2001 From: yugangzhang Date: Fri, 6 Jul 2018 17:51:05 -0400 Subject: [PATCH 05/10] COR BooleanType into bool --- pyevolve/FunctionSlot.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pyevolve/FunctionSlot.py b/pyevolve/FunctionSlot.py index ccf4a5b..afab8ff 100644 --- a/pyevolve/FunctionSlot.py +++ b/pyevolve/FunctionSlot.py @@ -12,7 +12,7 @@ """ from random import uniform as rand_uniform -from types import BooleanType +#from types import BooleanType from . import Util @@ -103,7 +103,7 @@ def setRandomApply(self, flag=True): :param flag: True or False """ - if type(flag) != BooleanType: + if type(flag) != bool:#BooleanType: Util.raiseException("Random option must be True or False", TypeError) self.rand_apply = flag From 016217f2af37361820704d36bfddfeb00207dbee Mon Sep 17 00:00:00 2001 From: yugangzhang Date: Fri, 6 Jul 2018 17:53:37 -0400 Subject: [PATCH 06/10] COR BooleanType into bool --- pyevolve/GSimpleGA.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/pyevolve/GSimpleGA.py b/pyevolve/GSimpleGA.py index 447afb4..95047ab 100644 --- a/pyevolve/GSimpleGA.py +++ b/pyevolve/GSimpleGA.py @@ -61,7 +61,8 @@ import random import logging from time import time -from types import BooleanType +#from types import BooleanType +BooleanType = bool from sys import platform as sys_platform from sys import stdout as sys_stdout import code @@ -360,7 +361,7 @@ def setInteractiveMode(self, flag=True): The *setInteractiveMode* method. """ - if type(flag) != BooleanType: + if type(flag) != bool:#BooleanType: Util.raiseException("Interactive Mode option must be True or False", TypeError) self.interactiveMode = flag From ff6a9b970a7898fa24804ea6fb5dab4346cc2447 Mon Sep 17 00:00:00 2001 From: =yugang zhang Date: Fri, 6 Jul 2018 19:13:09 -0400 Subject: [PATCH 07/10] COR cmp to functool.cmp_to_key --- pyevolve/GPopulation.py | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/pyevolve/GPopulation.py b/pyevolve/GPopulation.py index 5daa41b..d50075e 100644 --- a/pyevolve/GPopulation.py +++ b/pyevolve/GPopulation.py @@ -38,7 +38,7 @@ from .Statistics import Statistics from math import sqrt as math_sqrt import logging - +import functools try: from multiprocessing import cpu_count, Pool CPU_COUNT = cpu_count() @@ -322,12 +322,16 @@ def sort(self): rev = (self.minimax == Consts.minimaxType["maximize"]) if self.sortType == Consts.sortType["raw"]: - self.internalPop.sort(cmp=Util.cmp_individual_raw, reverse=rev) + #self.internalPop.sort(cmp=Util.cmp_individual_raw, reverse=rev) + self.internalPop.sort( key= functools.cmp_to_key(cmp=Util.cmp_individual_raw), reverse=rev) else: - self.scale() - self.internalPop.sort(cmp=Util.cmp_individual_scaled, reverse=rev) - self.internalPopRaw = self.internalPop[:] - self.internalPopRaw.sort(cmp=Util.cmp_individual_raw, reverse=rev) + self.scale() + #self.internalPop.sort(cmp=Util.cmp_individual_scaled, reverse=rev) + #print( self.internalPop ) + self.internalPop.sort( key= functools.cmp_to_key( Util.cmp_individual_scaled), reverse=rev ) + self.internalPopRaw = self.internalPop[:] + #self.internalPopRaw.sort(cmp=Util.cmp_individual_raw, reverse=rev) + self.internalPopRaw.sort( key= functools.cmp_to_key( Util.cmp_individual_raw), reverse=rev ) self.sorted = True From d788227ce65432088555cd63fd9a0337610683a5 Mon Sep 17 00:00:00 2001 From: =yugang zhang Date: Sun, 8 Jul 2018 11:10:22 -0400 Subject: [PATCH 08/10] Cor url Add columns in CSV --- pyevolve/DBAdapters.py | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) diff --git a/pyevolve/DBAdapters.py b/pyevolve/DBAdapters.py index e5fcbf2..b4434fe 100644 --- a/pyevolve/DBAdapters.py +++ b/pyevolve/DBAdapters.py @@ -24,7 +24,8 @@ import types import datetime from . import Statistics - +import urllib.request as request +import urllib.parse as parse class DBBaseAdapter(object): """ DBBaseAdapter Class - The base class for all DB Adapters @@ -151,7 +152,11 @@ def open(self, ga_engine): open_mode = 'w' if self.reset else 'a' self.fHandle = open(self.filename, open_mode) self.csvWriter = self.csvmod.writer(self.fHandle, delimiter=';') - + line = ['identity', 'generation', 'Maximum_raw_score','Minimum_raw_score', + 'Average_of_raw_scores','Standard_deviation_of_raw_scores','Raw_scores_variance', + 'Maximum_fitness', 'Minimum_fitness','Fitness_average'] + self.csvWriter.writerow(line) + def close(self): """ Closes the CSV file handle """ logging.debug("Closing the CSV file [%s]", self.filename) @@ -248,12 +253,18 @@ def insert(self, ga_engine): params["generation"] = ga_engine.getCurrentGeneration() params["identify"] = self.getIdentify() if self.post: # POST - response = self.urllibmod.urlopen(self.url, self.urllibmod.urlencode(params)) + response = self.urllibmod.urlopen(self.url, self.urllibmod.urlencode(params)) else: # GET - response = self.urllibmod.urlopen(self.url + "?%s" % (self.urllibmod.urlencode(params))) + #print( self.urllibmod )#, self.urllibmod.urlencode(params) ) + #response = self.urllibmod.request.urlopen(self.url + "?%s" % (self.urllibmod.request.urlencode(params))) + response = request.urlopen(self.url + "?%s" % ( parse.urlencode(params))) if response: response.close() +#import urllib.request +#with urllib.request.urlopen("http://www.python.org") as url: +# s = url.read() + class DBSQLite(DBBaseAdapter): """ DBSQLite Class - Adapter to dump data in SQLite3 database format From 7c9437a2a99c39b1190aeb24a218d28e38895bb5 Mon Sep 17 00:00:00 2001 From: =yugang zhang Date: Sun, 8 Jul 2018 11:10:55 -0400 Subject: [PATCH 09/10] Cor bug for jpeg format --- pyevolve/GTree.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/pyevolve/GTree.py b/pyevolve/GTree.py index 366c7ff..6df999c 100644 --- a/pyevolve/GTree.py +++ b/pyevolve/GTree.py @@ -544,7 +544,8 @@ def compare(self, other): return 0 @staticmethod - def writePopulationDot(ga_engine, filename, format="jpeg", start=0, end=0): + #def writePopulationDot(ga_engine, filename, format="jpeg", start=0, end=0): + def writePopulationDot(ga_engine, filename, format="fig", start=0, end=0): """ Writes to a graphical file using pydot, the population of trees Example: From b718f31dc8e01252a9758ae8a78624c8ea34de6a Mon Sep 17 00:00:00 2001 From: =yugang zhang Date: Sun, 8 Jul 2018 11:11:28 -0400 Subject: [PATCH 10/10] Cor bug for non-integer index --- pyevolve/Selectors.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyevolve/Selectors.py b/pyevolve/Selectors.py index aa096a0..38bde71 100644 --- a/pyevolve/Selectors.py +++ b/pyevolve/Selectors.py @@ -109,7 +109,7 @@ def GRouletteWheel(population, **args): lower = 0 upper = len(population) - 1 while(upper >= lower): - i = lower + ((upper - lower) / 2) + i = int(lower + ((upper - lower) / 2)) if psum[i] > cutoff: upper = i - 1 else: