Examples
Optimizing a 1d test function
from dfmcontrol.Optimisation.DFM_opt_alg import genetic_algoritm
import dfmcontrol as dfmc
from dfmcontrol.Mathematical_functions.t_functions import tfx
import dfmcontrol.Helper.helper as dfmh
# Create a genetic algorithm object
ga = genetic_algoritm(bitsize=16)
ga.mode = "minimisation"
tfunc = tfx
# use the default bit2num function
ga.b2n = dfmh.ndbit2int
# The range of possible floats is now -10 to 10
ga.b2nkwargs = {"factor": 50}
# Initiate a population of 12 individuals with 1 gene each, confined to the range -50 to -30
ga.init_pop(dfmc.Utility.pop.uniform_bit_pop, shape=[12, 1], bitsize=ga.bitsize, factor=ga.b2nkwargs["factor"],
boundaries=[-50, -30])
# Initiate the log
ga.logdata(2)
# Set the target function
ga.target_func(tfunc)
# Set the selection, mutation and crossover functions
# Set the selection, mutation and crossover functions
ga.set_select(dfmc.Utility.selection.rank_tournament_selection) # Rank selection
ga.set_mutate(dfmc.Utility.mutation.mutate) # Mutate the full bit (do not use for IEEE 754 floats)
ga.set_cross(dfmc.Utility.crossover.equal_prob) # Crossover the full bit (do not use for IEEE 754 floats)
ga.elitism = 4 # Keep the 4 best individuals
# Run the genetic algorithm
# The runcond argument is a string that is evaluated as a condition for the algorithm to stop
# The string can use any of the attributes of the genetic algorithm object
runcond = r"np.min(np.abs(self.log.ranking.distancefx[-1])) > 0.1" # Stop when the minimum distance from the best solution to the mathematical is less than 0.1
# The verbosity argument is an integer that controls the amount of output
# 0: No output
# 1: Output the current generation, (best & group) distance to the best solution and the best fitness
verbosity = 2
# The muargs argument is a dictionary that is passed to the mutation function as the kwargs argument
muargs = {"mutate_coeff": 4}
# The selargs argument is a dictionary that is passed to the selection function as the kwargs argument
selargs = {"nbit2num": ga.b2n, "fitness_func": dfmc.Utility.selection.no_fitness,
"allow_duplicates": True}
ga.run(muargs=muargs, selargs=selargs, verbosity=verbosity, runcond=runcond)
# Save the results to a txt file
ga.log.ranking.save2txt("result", "results.txt")
Plotting the results
Due to the stoastic nature of the genetic algorithm, the results will vary from run to run. The following code plots the results from the previous run.
import numpy as np
from dfmcontrol.AdrianPackv402 import Fileread
from dfmcontrol.AdrianPackv402 import Aplot
data = Fileread.Fileread(r"results.txt", dtype=float)()
data = list(data.values())
datamat = np.array(data)
# calculate the average fitness
avgfit = np.average(datamat, axis=1)
# calculate the standard deviation
stdfit = np.std(datamat, axis=1)
# calculate the minimum fitness
minfit = np.min(datamat, axis=1)
# calculate the maximum fitness
maxfit = np.max(datamat, axis=1)
# plot the average fitness
plmin = Aplot.Default(np.arange(len(minfit)), minfit, colour="C1", data_label="Minimum fitness", legend_loc="upper right")
pl = Aplot.Default(np.arange(len(avgfit)), avgfit, colour="C0", data_label="Average fitness", add_mode=True)
plmax = Aplot.Default(np.arange(len(maxfit)), maxfit, colour="C2", data_label="Maximum fitness", add_mode=True)
plmin += pl
plmin += plmax
plmin()
This should produce a plot similar to the following:
When excluding the average and maximum fitness to focus on the “best” members of the population, the plot should look like this:
Optimizing Ackley’s function for 2 variables
Ackley’s function is defined in test functions. The following code finds the minimum of the function using the genetic algorithm.
from dfmcontrol.DFM_opt_alg import genetic_algoritm
import dfmcontrol as dfmc
from dfmcontrol.test_functions import ackley
import dfmcontrol.helper as dfmh
# Create a genetic algorithm object
ga = genetic_algoritm(bitsize=16)
tfunc = ackley
# use the default bit2num function
ga.b2n = dfmh.ndbit2int
# The range of possible floats is now -5 to 5
ga.b2nkwargs = {"factor": 20}
# Initiate a population of 16 individuals with 2 genes each
ga.init_pop("normal", shape=[40, 2], bitsize=ga.bitsize, factor=ga.b2nkwargs["factor"])
# Initiate the log
ga.logdata(2)
# Set the target function
ga.target_func(tfunc)
# Set the selection, mutation and crossover functions
ga.set_select(dfmc.selection_funcs.rank_tournament_selection) # Rank selection
ga.set_mutate(dfmc.mutation.mutate) # Mutate the full bit (do not use for IEEE 754 floats)
ga.set_cross(dfmc.cross_funcs.equal_prob) # Crossover the full bit (do not use for IEEE 754 floats)
ga.elitism = 4 # Keep the 4 best individuals
# Run the genetic algorithm
# The runcond argument is a string that is evaluated as a condition for the algorithm to stop
# The string can use any of the attributes of the genetic algorithm object
runcond = r"np.min(np.abs(self.log.ranking.distancefx[-1])) > 0.1" # Stop when the minimum distance from the best solution to the mathematical is less than 0.1
# The verbosity argument is an integer that controls the amount of output
# 0: No output
# 1: Output the current generation, (best & group) distance to the best solution and the best fitness
verbosity = 1
# The muargs argument is a dictionary that is passed to the mutation function as the kwargs argument
muargs = {"mutate_coeff": 2}
# The selargs argument is a dictionary that is passed to the selection function as the kwargs argument
selargs = {"nbit2num": ga.b2n, "fitness_func": dfmc.selection_funcs.no_fitness,
"allow_duplicates": True}
for i in range(1):
ga.run(muargs=muargs, selargs=selargs, verbosity=verbosity, runcond=runcond)
ga.reset(False)
# Save the log object to a .pickle file to be able to retrieve results later.
ga.save_log("log2.pickle")
Acquiring the results from a saved log
import numpy as np
from dfmcontrol.DFM_opt_alg import genetic_algoritm
import matplotlib.pyplot as plt
ga = genetic_algoritm(bitsize=16)
ga.load_log("log2.pickle")
log = ga.log
plt.plot(np.arange(len(log.ranking.result)), [np.average(i) for i in log.ranking.result], label="Group average")
plt.plot(np.arange(len(log.ranking.distancefx)), [np.min(i) for i in log.ranking.distancefx], label="Best result")
plt.xlabel("Generation")
plt.ylabel("Distance to the best solution")
plt.title("Result of the genetic algorithm")
plt.legend()
plt.show()
Which results in the following plot:
Note
Due to the stochastic nature of the genetic algorithm, the results will vary from run to run.
Optimizing the 39 dimensional Styblinski-Tang function
The Styblinski-Tang function is defined in test functions. The following code finds the minimum of the function using the genetic algorithm.
from dfmcontrol.DFM_opt_alg import genetic_algoritm
import dfmcontrol as dfmc
from dfmcontrol.test_functions import Styblinski_Tang
import dfmcontrol.helper as dfmh
# Create a genetic algorithm object
ga = genetic_algoritm(bitsize=16)
tfunc = Styblinski_Tang
# use the default bit2num function
ga.b2n = dfmh.ndbit2int
# The range of possible floats is now -5 to 5
ga.b2nkwargs = {"factor": 5}
# Initiate a population of 40 individuals with 39 genes each
ga.init_pop("normal", shape=[40, 39], bitsize=ga.bitsize, factor=ga.b2nkwargs["factor"])
# Initiate the log
ga.logdata(2)
# Set the target function
ga.target_func(tfunc)
# Set the selection, mutation and crossover functions
ga.set_select(dfmc.selection_funcs.rank_tournament_selection) # Rank selection
ga.set_mutate(dfmc.mutation.mutate) # Mutate the full bit (do not use for IEEE 754 floats)
ga.set_cross(dfmc.cross_funcs.equal_prob) # Crossover the full bit (do not use for IEEE 754 floats)
ga.elitism = 10 # Keep the 10 best individuals
# Run the genetic algorithm
# The runcond argument is a string that is evaluated as a condition for the algorithm to stop
# The string can use any of the attributes of the genetic algorithm object
runcond = r"np.min(np.abs(self.log.ranking.distancefx[-1])) > 0.1" # Stop when the minimum distance from the best solution to the mathematical is less than 0.1
# The verbosity argument is an integer that controls the amount of output
# 0: No output
# 1: Output the current generation, (best & group) distance to the best solution and the best fitness
verbosity = 1
# The muargs argument is a dictionary that is passed to the mutation function as the kwargs argument
muargs = {"mutate_coeff": 3}
# The selargs argument is a dictionary that is passed to the selection function as the kwargs argument
selargs = {"nbit2num": ga.b2n, "fitness_func": dfmc.selection_funcs.no_fitness,
"allow_duplicates": True}
ga.run(muargs=muargs, selargs=selargs, verbosity=verbosity, runcond=runcond)
# Save the log object to a .pickle file to be able to retrieve results later.
ga.save_log("log3.pickle")
The results are shown in the following plot:
The log object can also be used to extract data on the time / calculations required to find the minimum.
from dfmcontrol.AdrianPackv402.Aplot import Default
pl = Default(log.time.data, log.time.calculation, x_label="Time", y_label="Requests to the test function", degree=1,
marker="")
pl()