Uploaded by habiwap736

LAB 10 Genetic Algorithm with task

advertisement
LAB 10 Genetic Algorithm
Genetic Algorithm
A genetic algorithm is a search and optimization technique inspired by the process of natural selection.
It mimics the principles of genetics and evolution to solve complex problems. Here's a detailed
explanation of the genetic algorithm along with an example code implementation:
Initialization:
Define the size of the population, which consists of a set of individuals.
Each individual represents a potential solution to the problem and is encoded as a string of genes
(binary, integer, or real values).
Generate an initial population randomly or using some heuristics.
Fitness Evaluation:
Evaluate the fitness of each individual in the population.
The fitness function measures how well an individual solves the problem.
It assigns a numerical value (fitness score) indicating the quality of the solution.
Selection:
Select individuals from the population based on their fitness scores.
Individuals with higher fitness scores have a higher chance of being selected.
Selection methods include roulette wheel selection, tournament selection, or rank-based selection.
Reproduction:
Generate offspring by combining genetic material from selected individuals.
Common reproduction techniques are crossover and mutation:
Crossover: Randomly select two parents and exchange genetic information to create offspring.
Mutation: Randomly modify genes in an individual to introduce new variations.
Replacement:
Replace some individuals in the population with the newly created offspring.
The replacement can be based on the fitness scores of individuals or other criteria.
Termination:
Decide when to stop the algorithm based on a termination condition (e.g., a maximum number of
generations or a satisfactory solution).
If the termination condition is not met, go back to step 2 and repeat the process.
Genetic algorithms are usually used to identify optimal solutions to complex problems. This can clearly
be easily mapped to search methods, which are aiming toward a similar goal. Genetic algorithms can
thus be used to search for solutions to multi-value problems where the closeness of any attempted
solution to the actual solution (fitness) can be readily evaluated. In short, a population of possible
solutions (chromosomes) is generated, and a fitness value for each chromosome is determined. This
fitness is used to determine the likelihood that a given chromosome will survive to the next
generation, or reproduce. Reproduction is done by applying crossover to two (or more) chromosomes,
whereby features (genes) of each chromosome are combined together. Mutation is also applied,
which involves making random changes to particular genes.
Now, let's see an example implementation of the genetic algorithm in Python for a simple
optimization problem of finding the maximum value of a function.
import random
# Genetic Algorithm parameters
population_size = 100
chromosome_length = 20
mutation_rate = 0.01
num_generations = 50
# Define the fitness function
def fitness_function(chromosome):
# Convert binary chromosome to decimal value
value = int(''.join(map(str, chromosome)), 2)
# Evaluate the fitness (maximum value of a function)
fitness = value * value
return fitness
# Generate an initial population
def generate_population():
population = []
for _ in range(population_size):
chromosome = [random.randint(0, 1) for _ in
range(chromosome_length)]
population.append(chromosome)
return population
# Perform crossover between two parents
def crossover(parent1, parent2):
crossover_point = random.randint(0, chromosome_length - 1)
child = parent1[:crossover_point] + parent2[crossover_point:]
return child
# Perform mutation on an individual
def mutate(individual):
for i in range(chromosome_length):
if random.random() < mutation_rate:
individual[i] = 1 - individual[i]
# Flip the bit
# Genetic Algorithm main loop
def genetic_algorithm():
population = generate_population()
for generation in range(num_generations):
# Evaluate fitness of each individual
fitness_scores = [fitness_function(chromosome) for chromosome
in population]
# Select parents for reproduction
parents = random.choices(population, weights=fitness_scores,
k=2)
# Create offspring through crossover
offspring = [crossover(parents[0], parents[1]) for _ in
range(population_size)]
# Apply mutation to the offspring
for individual in offspring:
mutate(individual)
# Replace the old population with the offspring
population = offspring
# Find the best individual (maximum fitness)
best_individual = max(population, key=fitness_function)
best_fitness = fitness_function(best_individual)
return best_individual, best_fitness
# Run the genetic algorithm
best_solution, best_fitness = genetic_algorithm()
# Print the result
print("Best Solution:", best_solution)
print("Best Fitness:", best_fitness)
Here's a step-by-step description of the provided code:
Import the necessary modules:
import random
Define the parameters for the genetic algorithm:
population_size = 100 # Size of the population
chromosome_length = 20 # Length of each chromosome
mutation_rate = 0.01 # Probability of mutation
num_generations = 50 # Number of generations to run
Define the fitness function:
def fitness_function(chromosome):
value = int(''.join(map(str, chromosome)), 2) # Convert binary
chromosome to decimal value
fitness = value * value # Evaluate the fitness (maximum value of a
function)
return fitness
The fitness function takes a chromosome (individual) as input, converts it from binary to decimal
representation, evaluates its fitness (maximum value of a function), and returns the fitness score.
Generate an initial population:
def generate_population():
population = []
for _ in range(population_size):
chromosome = [random.randint(0, 1) for _ in
range(chromosome_length)] # Create a random binary chromosome
population.append(chromosome)
return population
The generate_population function creates a list of individuals (population) by generating random
binary chromosomes of a specified length.
Perform crossover between two parents:
def crossover(parent1, parent2):
crossover_point = random.randint(0, chromosome_length - 1) #
Select a random crossover point
child = parent1[:crossover_point] + parent2[crossover_point:]
Combine genetic information of parents to create a child
return child
#
The crossover function takes two parent chromosomes, selects a random crossover point, and
combines their genetic information to create a child chromosome.
Perform mutation on an individual:
def mutate(individual):
for i in range(chromosome_length):
if random.random() < mutation_rate:
individual[i] = 1 - individual[i]
(mutation)
# Flip the bit
The mutate function iterates through each gene of an individual's chromosome and with a certain
probability (mutation_rate), it flips the bit (mutation) to introduce variation.
Implement the main loop of the genetic algorithm:
def genetic_algorithm():
population = generate_population()
population
# Generate the initial
for generation in range(num_generations):
fitness_scores = [fitness_function(chromosome) for chromosome
in population] # Evaluate fitness of each individual
k=2)
parents = random.choices(population, weights=fitness_scores,
# Select parents for reproduction
offspring = [crossover(parents[0], parents[1]) for _ in
range(population_size)] # Create offspring through crossover
for individual in offspring:
mutate(individual) # Apply mutation to the offspring
population = offspring
offspring
# Replace the old population with the
best_individual = max(population, key=fitness_function) # Find the
best individual (maximum fitness)
best_fitness = fitness_function(best_individual) # Get the fitness
score of the best individual
return best_individual, best_fitness
The genetic_algorithm function implements the main loop of the genetic algorithm. It iterates
through a specified number of generations. In each generation, it evaluates the fitness of each
individual, selects parents for reproduction based on their fitness scores, creates offspring through
crossover, applies mutation to the offspring, and replaces the old population with the offspring.
Example to solve the Task 1 related problem by using genetic algorithm:
import random
# Define the fitness function
def fitness_function(x):
return (-x**2)/10 + 3*x
# Function to generate a random chromosome
def generate_chromosome():
return [random.randint(0, 1) for _ in range(5)]
# Function to decode chromosome to x value
def decode_chromosome(chromosome):
x = 0
for bit in chromosome:
x = (x << 1) | bit
return x
# Function to perform crossover between two chromosomes
def crossover(chromosome1, chromosome2):
crossover_point = random.randint(1, len(chromosome1) - 1)
new_chromosome1 = chromosome1[:crossover_point] +
chromosome2[crossover_point:]
new_chromosome2 = chromosome2[:crossover_point] +
chromosome1[crossover_point:]
return new_chromosome1, new_chromosome2
# Function to perform mutation on a chromosome
def mutate(chromosome):
mutation_point = random.randint(0, len(chromosome) - 1)
chromosome[mutation_point] = 1 - chromosome[mutation_point]
the bit
return chromosome
# Flip
# Initialize the population
population_size = 10
population = [generate_chromosome() for _ in range(population_size)]
# Main loop
generation = 1
while True:
# Calculate fitness values for each chromosome
fitness_values = [fitness_function(decode_chromosome(chromosome))
for chromosome in population]
# Check termination condition
best_fitness = max(fitness_values)
if best_fitness >= 0.9 * max(fitness_values):
break
# Selection - Roulette wheel selection
selection_probabilities = [fitness / sum(fitness_values) for
fitness in fitness_values]
selected_indices = random.choices(range(population_size),
weights=selection_probabilities, k=population_size)
# Create the new population through crossover and mutation
new_population = []
for i in range(0, population_size, 2):
chromosome1 = population[selected_indices[i]]
chromosome2 = population[selected_indices[i+1]]
chromosome1, chromosome2 = crossover(chromosome1, chromosome2)
if generation % 3 == 0: # Apply mutation every 3 generations
chromosome1 = mutate(chromosome1)
chromosome2 = mutate(chromosome2)
new_population.extend([chromosome1, chromosome2])
population = new_population
generation += 1
# Print the result
best_chromosome = population[fitness_values.index(max(fitness_values))]
best_x = decode_chromosome(best_chromosome)
best_fitness = fitness_function(best_x)
print("Best Chromosome:", best_chromosome)
print("Best x:", best_x)
print("Best Fitness:", best_fitness)
In this implementation:
➢ The fitness function is defined as fitness_function(x).
➢ The generate_chromosome() function generates a random chromosome of length 5.
➢ The decode_chromosome(chromosome) function decodes a chromosome to its
corresponding x value.
➢ The crossover(chromosome1, chromosome2) function performs crossover between
two chromosomes.
➢ The mutate(chromosome) function performs mutation on a chromosome by flipping
a random bit.
➢ The main loop continues until one of the candidate's fitness function value is greater
or equal to 90%.
➢ Within each generation, fitness values are calculated for each chromosome, and the
termination condition is checked.
➢ Roulette wheel selection is used to select chromosomes for the next generation.
➢ Crossover and mutation are applied to create the new population.
➢ The best chromosome, its corresponding x value, and fitness are printed as the
result.
Lab Tasks
Exercise 10.1.
Consider the problem of maximizing the function
𝑓(𝑥) =
−𝑥 2
+ 3𝑥
10
where 𝑥 is allowed to vary between 0 and 31. You must perform following tasks in the code.
a. Representation of states (solutions): To solve this using a genetic algorithm, we must encode the
possible values of 𝑥 as chromosomes. For this problem, we will encode 𝑥 as a binary integer of
length 5. Thus the chromosomes for our genetic algorithm will be sequences of 0's and 1's with a
length of 5 bits, and have a range from 0 (00000) to 31 (11111).
b. Fitness function:
The fitness function for it will be:
𝑓(𝑥) =
−𝑥 2
+ 3𝑥
10
To begin the algorithm, we select an initial population of 10 chromosomes at random. The
resulting initial population of chromosomes is shown in Table 1. Next we take the x-value that
each chromosome represents and test its fitness with the fitness function. The resulting fitness
values are recorded in the third column of Table 1.
Chromosome
Number
1
2
3
4
5
6
7
8
9
10
Initial
Population
01011
11010
00010
01110
01100
11110
10110
01001
00011
10001
𝒙-Value
Fitness Value 𝒇(𝒙)
Selection Probability
11
26
2
14
12
30
22
9
3
17
20.9
10.4
5.6
22.4
21.6
0
17.6
18.9
8.1
22.1
0.1416
0.0705
0.0379
0.1518
0.1463
0
0.1192
0.1280
0.0549
0.1497
c. Operators:
i.
Apply cross over in every generation.
ii.
Apply mutation after every 3 generations.
d. Termination criteria: Your loop should stop when the value of one of your candidate’s
fitness function is greater or equal to 90%.
Exercise 10.2. Travelling Salesman Problem
Suppose a TCS delivery boy has to deliver parcels from Head Office (MM Alam Road) to 7 different
locations in Lahore (Johar Town, Shahdara, DHA Phase 6, Wapda Town, Askari 10, Allama Iqbal Town,
Mall Road) and then return back to the Head Office. He wants to find the route with least travelling
distance. You helped him in finding the route using Hill Climbing Algorithm. Now use Genetic Algorithm
instead of Hill Climbing to solve this problem. Design choices should be as per class discussion. [You
can construct distance matrix using google maps OR you can take random values (between 0-50) for
distances between any two spots.]
Exercise 10.4.
n-Queen Problem using Genetic Algorithm.
Download