Fix buggy database file creation. Change structure of config table. Updated all functions to work with new table style.

This commit is contained in:
danielwilczak
2021-01-20 03:04:49 -05:00
parent f50d5c2efa
commit 432a355ee9
2 changed files with 104 additions and 110 deletions

View File

@ -128,13 +128,14 @@ class Attributes:
Database = sql_database.SQL_Database, Database = sql_database.SQL_Database,
database_name = 'database.db', database_name = 'database.db',
sql_create_data_structure = """CREATE TABLE IF NOT EXISTS data ( sql_create_data_structure = f"""
id INTEGER PRIMARY KEY, CREATE TABLE IF NOT EXISTS data (
config_id INTEGER DEFAULT NULL, id INTEGER PRIMARY KEY,
generation INTEGER NOT NULL, config_id INTEGER DEFAULT NULL,
fitness REAL, generation INTEGER NOT NULL,
chromosome TEXT fitness REAL,
); """, chromosome TEXT
); """,
Graph = matplotlib_graph.Matplotlib_Graph, Graph = matplotlib_graph.Matplotlib_Graph,

View File

@ -7,12 +7,16 @@ class SQL_Database:
"""Main database class that controls all the functionality for input / """Main database class that controls all the functionality for input /
out of the database using SQLite3.""" out of the database using SQLite3."""
sql_type_list = [int, float, str]
def __init__(self): def __init__(self):
self.conn = None self.conn = None
self.config_id = None self.config_id = None
self._database_name = 'database.db' self._database_name = 'database.db'
self.config_structure = f"""
CREATE TABLE IF NOT EXISTS config (
config_id INTEGER,
attribute_name TEXT,
attribute_value TEXT)"""
#=====================================# #=====================================#
@ -23,14 +27,6 @@ class SQL_Database:
"""Create the database if it doenst exist and then the data and config """Create the database if it doenst exist and then the data and config
tables.""" tables."""
# if the database file already exists.
try:
self.config = self.get_current_config()
# If the database does not exist continue
except:
pass
# Create the database connection # Create the database connection
self.create_connection() self.create_connection()
@ -38,26 +34,78 @@ class SQL_Database:
# Create data table # Create data table
self.create_table(ga.sql_create_data_structure) self.create_table(ga.sql_create_data_structure)
# Creare config table # Creare config table
self.create_table(self.create_config_table_string(ga)) self.create_table(self.config_structure)
# Set the config id
self.config_id = self.get_current_config()
else: else:
raise Exception("Error! Cannot create the database connection.") raise Exception("Error! Cannot create the database connection.")
def insert_config(self,ga):
"""Insert the configuration attributes into the config."""
# Get the current config and add one for the new config key
self.config_id = self.get_current_config()
# Setting the config_id index if there is no file
if self.config_id == None:
self.config_id = 0
else:
self.config_id = self.config_id + 1
# Getting all the attributes from the attributes class
db_config_dict = (
(attr_name, getattr(ga, attr_name))
for attr_name
in dir(ga)
if attr_name[0] != '_'
if attr_name != 'population'
)
# Types supported in the database
sql_type_list = [int, float, str]
# Loop through all attributes
for name, value in db_config_dict:
# Inserting a function, do special stuff
if callable(value):
value = ""
# Not a function
else:
# Convert to the right type
if type(value) not in self.sql_type_list:
value = str(value)
# Insert into database
self.conn.execute(f"""
INSERT INTO config(config_id,attribute_name, attribute_value)
VALUES ('{self.config_id}', '{name}','{value}');""")
self.config_id = self.get_current_config()
#=====================================# #=====================================#
# Decorators: # # Decorators: #
#=====================================# #=====================================#
def default_config_id(method): def default_config_id(method):
"""Decorator used to set the default config_id""" """Decorator used to set the default config_id inside other functions."""
def new_method(self, config_id = None): def new_method(self, config_id = None):
input_id = self.config_id if config_id is None else config_id input_id = self.config_id if config_id is None else config_id
return method(self, input_id) return method(self, input_id)
return new_method return new_method
def format_query_data(method): def format_query_data(method):
"""Decorator used to format query data""" """Decorator used to format query data"""
@ -83,99 +131,74 @@ class SQL_Database:
def get_current_config(self): def get_current_config(self):
"""Get the current config_id from the config table.""" """Get the current config_id from the config table."""
return self.query_one_item("SELECT MAX(id) FROM config") return self.query_one_item("SELECT MAX(config_id) FROM config")
def past_runs(self): def past_runs(self):
"""Show a summerization of the past runs that the user has done.""" """Show a summerization of the past runs that the user has done."""
query_data = self.query_all(f"SELECT id,chromosome_length,population_size,generation_goal FROM config;") query_data = self.query_all(f"""
SELECT config_id,attribute_name,attribute_value
FROM config;""")
print( print(
tabulate( tabulate(
query_data, query_data,
headers = [ headers = [
'id', 'config_id',
'chromosome_length', 'attribute_name',
'population_size', 'attribute_value'
'generation_goal'
] ]
) )
) )
def get_most_recent_config_id(self):
"""Function to get the most recent config_id from the database."""
return self.query_one_item("SELECT max(config_id) FROM config")
@default_config_id @default_config_id
def get_generation_total_fitness(self, config_id): def get_generation_total_fitness(self, config_id):
"""Get each generations total fitness sum from the database """ """Get each generations total fitness sum from the database """
return self.query_all(f"SELECT SUM(fitness) FROM data WHERE config_id={config_id} GROUP BY generation;") return self.query_all(f"""
SELECT SUM(fitness)
FROM data
WHERE config_id={config_id}
GROUP BY generation;""")
@default_config_id @default_config_id
def get_total_generations(self, config_id): def get_total_generations(self, config_id):
"""Get the total generations from the database""" """Get the total generations from the database"""
return self.query_one_item(f"SELECT COUNT(DISTINCT generation) FROM data WHERE config_id={config_id};") return self.query_one_item(f"""
SELECT COUNT(DISTINCT generation)
FROM data
WHERE config_id={config_id};""")
@default_config_id @default_config_id
def get_highest_chromosome(self, config_id): def get_highest_chromosome(self, config_id):
"""Get the highest fitness of each generation""" """Get the highest fitness of each generation"""
return self.query_all(f"SELECT fitness, max(fitness) FROM data WHERE config_id={config_id} GROUP by generation;") return self.query_all(f"""
SELECT fitness, max(fitness)
FROM data
WHERE config_id={config_id}
GROUP by generation;""")
@default_config_id @default_config_id
def get_lowest_chromosome(self, config_id): def get_lowest_chromosome(self, config_id):
"""Get the lowest fitness of each generation""" """Get the lowest fitness of each generation"""
return self.query_all(f"SELECT fitness, min(fitness) FROM data WHERE config_id={config_id} GROUP by generation;") return self.query_all(f"""
SELECT fitness, min(fitness)
FROM data
WHERE config_id={config_id}
GROUP by generation;""")
#=====================================# #=====================================#
# Input information Queries: # # Input information Queries: #
#=====================================# #=====================================#
def insert_config(self,ga):
"""Insert the configuration attributes into the config."""
# Structure the insert data
db_config_list = list(ga.__dict__.values())
# Clean up so the sqlite database accepts the data structure
for i in range(len(db_config_list)):
if callable(db_config_list[i]):
db_config_list[i] = db_config_list[i].__name__
elif type(db_config_list[i]) not in self.sql_type_list:
db_config_list[i] = str(db_config_list[i])
# Create sql query structure
sql = "INSERT INTO config (" \
+ ",".join(self.get_var_names(ga)) \
+ ") VALUES(" \
+ ( ",?"*len(db_config_list) )[1:] \
+ ") "
# For some reason it has to be in var = array(tuple()) form
db_config_list = [tuple(db_config_list)]
# Execute sql query
cur = self.conn.cursor()
try:
cur.executemany(sql, db_config_list)
except:
self.remove_database()
cur = self.conn.cursor()
cur.executemany(sql, db_config_list)
self.conn.commit()
self.config_id = self.get_current_config()
return cur.lastrowid
def insert_chromosome(self, generation, chromosome): def insert_chromosome(self, generation, chromosome):
@ -190,15 +213,13 @@ class SQL_Database:
) )
# Create sql query structure # Create sql query structure
sql = ''' sql = """INSERT INTO data(config_id, generation, fitness, chromosome)
INSERT INTO data(config_id, generation, fitness, chromosome) VALUES(?,?,?,?)"""
VALUES(?,?,?,?)
'''
cur = self.conn.cursor() cur = self.conn.cursor()
cur.execute(sql, db_chromosome) cur.execute(sql, db_chromosome)
self.conn.commit() self.conn.commit()
return cur.lastrowid
def insert_current_population(self, ga): def insert_current_population(self, ga):
@ -217,15 +238,13 @@ class SQL_Database:
] ]
# Create sql query structure # Create sql query structure
sql = ''' sql = """INSERT INTO data(config_id, generation, fitness, chromosome)
INSERT INTO data(config_id, generation, fitness, chromosome) VALUES(?,?,?,?)"""
VALUES(?,?,?,?)
'''
cur = self.conn.cursor() cur = self.conn.cursor()
cur.executemany(sql, db_chromosome_list) cur.executemany(sql, db_chromosome_list)
self.conn.commit() self.conn.commit()
return cur.lastrowid
#=====================================# #=====================================#
@ -251,21 +270,6 @@ class SQL_Database:
except Error as e: except Error as e:
print(e) print(e)
def create_config_table_string(self,ga):
"""Automate the table creation sql statement so that it takes all the
attribute variables and adds them as columns in the database table config"""
# Structure the config table
sql = "CREATE TABLE IF NOT EXISTS config (id INTEGER PRIMARY KEY," \
+ ",".join(
var + ' ' + self.sql_type_of(var)
for var
in self.get_var_names(ga)
) + "); "
return sql
@format_query_data @format_query_data
def query_all(self, query): def query_all(self, query):
@ -275,6 +279,7 @@ class SQL_Database:
cur.execute(query) cur.execute(query)
return cur.fetchall() return cur.fetchall()
@format_query_data @format_query_data
def query_one_item(self, query): def query_one_item(self, query):
"""Query for single data point""" """Query for single data point"""
@ -283,20 +288,11 @@ class SQL_Database:
cur.execute(query) cur.execute(query)
return cur.fetchone() return cur.fetchone()
def remove_database(self): def remove_database(self):
"""Remove the current database file using the database_name attribute.""" """Remove the current database file using the database_name attribute."""
os.remove(self._database_name) os.remove(self._database_name)
def sql_type_of(self, obj):
"""Returns the sql type for the object"""
if isinstance(obj, int):
return 'INT'
elif isinstance(obj, float):
return 'REAL'
else:
return 'TEXT'
def get_var_names(self, ga): def get_var_names(self, ga):
"""Returns a list of the names of attributes of the ga.""" """Returns a list of the names of attributes of the ga."""
@ -308,7 +304,6 @@ class SQL_Database:
yield (var[1:] if (var[0] == '_') else var) yield (var[1:] if (var[0] == '_') else var)
#=====================================# #=====================================#
# Setters and Getters: # # Setters and Getters: #
#=====================================# #=====================================#
@ -340,8 +335,7 @@ class SQL_Database:
# If the connection doesnt exist then print error # If the connection doesnt exist then print error
except: except:
raise Exception("""You are required to run a ga before you raise Exception("""You are required to run a ga before you can connect to the database. Run ga.evolve() or ga.active()""")
can connect to the database. Run ga.evolve() or ga.active()""")
@conn.setter @conn.setter
@ -363,13 +357,12 @@ class SQL_Database:
# If the config_id has not been set yet # If the config_id has not been set yet
try: try:
# Check if you can connect to the database # Check if you can connect to the database
self._config_id = self.get_most_recent_config_id() self._config_id = self.get_current_config()
return self._config_id return self._config_id
# If the config_id doesnt exist then print error # If the config_id doesnt exist then print error
except: except:
raise Exception("""You are required to run a ga before you raise Exception("""You are required to run a ga before you can connect to the database. Run ga.evolve() or ga.active()""")
can connect to the database. Run ga.evolve() or ga.active()""")
@config_id.setter @config_id.setter