diff --git a/pyevolve/DBAdapters.py b/pyevolve/DBAdapters.py index 7c76f24..8bfa014 100644 --- a/pyevolve/DBAdapters.py +++ b/pyevolve/DBAdapters.py @@ -27,766 +27,808 @@ class DBBaseAdapter: - """ 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) + """ 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 + """ DBFileCSV Class - Adapter to dump statistics in CSV format - Inheritance diagram for :class:`DBAdapters.DBFileCSV`: + Inheritance diagram for :class:`DBAdapters.DBFileCSV`: - .. inheritance-diagram:: DBAdapters.DBFileCSV + .. inheritance-diagram:: DBAdapters.DBFileCSV - Example: - >>> adapter = DBFileCSV(filename="file.csv", identify="run_01", - frequency = 1, reset = True) + 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 is True, the file old data will be overwrite with the new + :param filename: the CSV filename + :param identify: the identify of the run + :param frequency: the generational dump frequency + :param reset: if is True, the file old data will be overwrite with the new - .. versionadded:: 0.6 - Removed the stub methods and subclassed the :class:`DBBaseAdapter` class. + .. 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 """ + """ + def __init__( + self, + filename=Consts.CDefCSVFileName, + identify=None, + frequency=Consts.CDefCSVFileStatsGenFreq, + reset=True + ): + """ The creator of DBFileCSV Class """ - DBBaseAdapter.__init__(self, frequency, identify) - - self.csvmod = None + DBBaseAdapter.__init__(self, frequency, identify) - self.filename = filename - self.csvWriter = None - self.fHandle = None - self.reset = reset + self.csvmod = None - def __repr__(self): - """ The string representation of adapter """ - ret = "DBFileCSV DB Adapter [File='%s', identify='%s']" % (self.filename, self.getIdentify()) - return ret + self.filename = filename + self.csvWriter = None + self.fHandle = None + self.reset = reset - def open(self, ga_engine): - """ Open the CSV file or creates a new file + def __repr__(self): + """ The string representation of adapter """ + ret = "DBFileCSV DB Adapter [File='%s', identify='%s']" % (self.filename, self.getIdentify()) + return ret - :param ga_engine: the GA Engine + def open(self, ga_engine): + """ Open the CSV file or creates a new file - .. 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") + :param ga_engine: the GA Engine - logging.debug("Opening the CSV file to dump statistics [%s]", self.filename) - if self.reset: open_mode = "w" - else: open_mode = "a" - self.fHandle = open(self.filename, open_mode) - self.csvWriter = self.csvmod.writer(self.fHandle, delimiter=';') + .. 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") - def close(self): - """ Closes the CSV file handle """ - logging.debug("Closing the CSV file [%s]", self.filename) - if self.fHandle: - self.fHandle.close() + logging.debug("Opening the CSV file to dump statistics [%s]", self.filename) + if self.reset: + open_mode = "w" + else: + open_mode = "a" + self.fHandle = open(self.filename, open_mode) + self.csvWriter = self.csvmod.writer(self.fHandle, delimiter=';') - def commitAndClose(self): - """ Commits and closes """ - self.close() + def close(self): + """ Closes the CSV file handle """ + logging.debug("Closing the CSV file [%s]", self.filename) + if self.fHandle: + self.fHandle.close() - def insert(self, ga_engine): - """ Inserts the stats into the CSV file + def commitAndClose(self): + """ Commits and closes """ + self.close() - :param ga_engine: the GA Engine + 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) - .. 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. """ - - DBBaseAdapter.__init__(self, 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() + """ 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. """ + + DBBaseAdapter.__init__(self, 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() + 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 + """ 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) - Example: - >>> dbadapter = DBSQLite(identify="test") + 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 """ + + DBBaseAdapter.__init__(self, 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 not generation % self.commitFreq: + self.commit() - 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 """ - - DBBaseAdapter.__init__(self, 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 + """ DBXMLRPC Class - Adapter to dump statistics to a XML Remote Procedure Call + + Inheritance diagram for :class:`DBAdapters.DBXMLRPC`: - Inheritance diagram for :class:`DBAdapters.DBXMLRPC`: + .. inheritance-diagram:: DBAdapters.DBXMLRPC - .. inheritance-diagram:: DBAdapters.DBXMLRPC + Example: + >>> adapter = DBXMLRPC(url="http://localhost:8000/", identify="run_01", + frequency = 1) - 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 - :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. - .. note:: The XML RPC Server must implement the *insert* method, wich receives - a python dictionary as argument. - - Example of an server in Python: :: + Example of an server in Python: :: - import xmlrpclib - from SimpleXMLRPCServer import SimpleXMLRPCServer + import xmlrpclib + from SimpleXMLRPCServer import SimpleXMLRPCServer - def insert(l): - print "Received statistics: %s" % l + 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() + 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. + .. versionadded:: 0.6 + The :class:`DBXMLRPC` class. - """ - def __init__(self, url, identify=None, frequency = Consts.CDefXMLRPCStatsGenFreq): - """ The creator of DBXMLRPC Class """ + """ + def __init__(self, url, identify=None, frequency = Consts.CDefXMLRPCStatsGenFreq): + """ The creator of DBXMLRPC Class """ - DBBaseAdapter.__init__(self, frequency, identify) - self.xmlrpclibmod = None + DBBaseAdapter.__init__(self, frequency, identify) + self.xmlrpclibmod = None - self.url = url - self.proxy = 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 __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 + def open(self, ga_engine): + """ Open the XML RPC Server proxy - :param ga_engine: the GA Engine + :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") + .. 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) + 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 + def insert(self, ga_engine): + """ Calls the XML RPC procedure - :param ga_engine: the GA Engine + :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) + .. 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): - DBBaseAdapter.__init__(self, 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"])) - + """ 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): + DBBaseAdapter.__init__(self, 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 """ - - DBBaseAdapter.__init__(self, 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() + """ 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 """ + + DBBaseAdapter.__init__(self, 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 not generation % self.commitFreq: + self.commit() diff --git a/pyevolve/FunctionSlot.py b/pyevolve/FunctionSlot.py index 20b2b94..040954f 100644 --- a/pyevolve/FunctionSlot.py +++ b/pyevolve/FunctionSlot.py @@ -12,194 +12,194 @@ """ from random import uniform as rand_uniform -import inspect from types import BooleanType import Util + class FunctionSlot: - """ 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[:] - - 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 __call__(self, *args): - # """ The callable method """ - - 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 + """ 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[:] + + 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 not bool(len(self.funcList)) + + #def __call__(self, *args): + # """ The callable method """ + + 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 b/pyevolve/G1DBinaryString.py index efe2c89..bc80e86 100644 --- a/pyevolve/G1DBinaryString.py +++ b/pyevolve/G1DBinaryString.py @@ -37,167 +37,167 @@ from GenomeBase import GenomeBase, G1DBase import Consts import Util - -class G1DBinaryString(GenomeBase, 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.GenomeBase` - and :class:`GenomeBase.G1DBase` classes. - - Example: - >>> genome = G1DBinaryString.G1DBinaryString(5) - :param length: the 1D Binary String size +class G1DBinaryString(GenomeBase, G1DBase): + """ G1DBinaryString Class - The 1D Binary String chromosome - """ + Inheritance diagram for :class:`G1DBinaryString.G1DBinaryString`: - evaluator = None - """ This is the :term:`evaluation function` slot, you can add - a function with the *set* method: :: + .. inheritance-diagram:: G1DBinaryString.G1DBinaryString - genome.evaluator.set(eval_func) - """ + This chromosome class extends the :class:`GenomeBase.GenomeBase` + and :class:`GenomeBase.G1DBase` classes. - initializator = None - """ This is the initialization function of the genome, you - can change the default initializator using the function slot: :: + Example: + >>> genome = G1DBinaryString.G1DBinaryString(5) - genome.initializator.set(Initializators.G1DBinaryStringInitializator) + :param length: the 1D Binary String size - In this example, the initializator :func:`Initializators.G1DBinaryStringInitializator` - will be used to create the initial population. - """ + """ - mutator = None - """ This is the mutator function slot, you can change the default - mutator using the slot *set* function: :: + evaluator = None + """ This is the :term:`evaluation function` slot, you can add + a function with the *set* method: :: - genome.mutator.set(Mutators.G1DBinaryStringMutatorSwap) + genome.evaluator.set(eval_func) + """ - """ + initializator = None + """ This is the initialization function of the genome, you + can change the default initializator using the function slot: :: - crossover = None - """ This is the reproduction function slot, the crossover. You - can change the default crossover method using: :: + genome.initializator.set(Initializators.G1DBinaryStringInitializator) - genome.crossover.set(Crossovers.G1DBinaryStringXUniform) - """ + In this example, the initializator :func:`Initializators.G1DBinaryStringInitializator` + will be used to create the initial population. + """ + mutator = None + """ This is the mutator function slot, you can change the default + mutator using the slot *set* function: :: - def __init__(self, length=10): - """ The initializator of G1DList representation """ - GenomeBase.__init__(self) - G1DBase.__init__(self, length) - self.genomeList = [] - self.stringLength = length - self.initializator.set(Consts.CDefG1DBinaryStringInit) - self.mutator.set(Consts.CDefG1DBinaryStringMutator) - self.crossover.set(Consts.CDefG1DBinaryStringCrossover) + genome.mutator.set(Mutators.G1DBinaryStringMutatorSwap) - 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 + crossover = None + """ This is the reproduction function slot, the crossover. You + can change the default crossover method using: :: - """ - 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) + genome.crossover.set(Crossovers.G1DBinaryStringXUniform) + """ - 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 __init__(self, length=10): + """ The initializator of G1DList representation """ + GenomeBase.__init__(self) + G1DBase.__init__(self, length) + self.genomeList = [] + self.stringLength = length + self.initializator.set(Consts.CDefG1DBinaryStringInit) + self.mutator.set(Consts.CDefG1DBinaryStringMutator) + self.crossover.set(Consts.CDefG1DBinaryStringCrossover) - def getDecimal(self): - """ Converts the binary string to decimal representation + def __setitem__(self, key, value): + """ Set the specified value for an gene of List - Example: - >>> g = G1DBinaryString(5) - >>> for i in xrange(len(g)): - ... g.append(0) - >>> g[3] = 1 - >>> g.getDecimal() - 2 + >>> g = G1DBinaryString(5) + >>> for i in xrange(len(g)): + ... g.append(1) + >>> g[4] = 0 + >>> g[4] + 0 - :rtype: decimal value + """ + 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) - """ - return int(self.getBinary(), 2) + 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 getBinary(self): - """ Returns the binary string representation + def getDecimal(self): + """ Converts the binary string to decimal representation - Example: - >>> g = G1DBinaryString(2) - >>> g.append(0) - >>> g.append(1) - >>> g.getBinary() - '01' + Example: + >>> g = G1DBinaryString(5) + >>> for i in xrange(len(g)): + ... g.append(0) + >>> g[3] = 1 + >>> g.getDecimal() + 2 - :rtype: the binary string + :rtype: decimal value - """ - return "".join(map(str, self)) + """ + return int(self.getBinary(), 2) - def append(self, value): - """ Appends an item to the list + def getBinary(self): + """ Returns the binary string representation - Example: - >>> g = G1DBinaryString(2) - >>> g.append(0) + Example: + >>> g = G1DBinaryString(2) + >>> g.append(0) + >>> g.append(1) + >>> g.getBinary() + '01' - :param value: value to be added, 0 or 1 + :rtype: the binary string - """ - if value not in [0, 1]: - Util.raiseException("The value must be 0 or 1", ValueError) - G1DBase.append(self, value) + """ + return "".join(map(str, self)) - 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 + 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