Genetic Algorithm

๐Ÿ”ฅ Vibe Prompt

"Evolve a bitstring to match '11111111...' (64 bits). Use tournament selection, 1-point crossover, mutation."

import random

def ga(target_len=64, pop_size=100, gens=100):
    target = [1] * target_len
    
    def fitness(ind): return sum(i == t for i, t in zip(ind, target))
    def create(): return [random.randint(0,1) for _ in range(target_len)]
    
    pop = [create() for _ in range(pop_size)]
    
    for gen in range(gens):
        scores = [(fitness(ind), ind) for ind in pop]
        scores.sort(reverse=True)
        
        if scores[0][0] == target_len:
            print(f"Perfect solution at gen {gen}!")
            break
        
        new_pop = [scores[0][1], scores[1][1]]  # Elitism
        
        while len(new_pop) < pop_size:
            parents = random.choices(pop, weights=[f + 1 for f, _ in scores], k=2)
            cross = random.randint(0, target_len)
            child = parents[0][:cross] + parents[1][cross:]
            if random.random() < 0.01:
                child[random.randint(0, target_len-1)] ^= 1
            new_pop.append(child)
        pop = new_pop
        
        if gen % 20 == 0:
            print(f"Gen {gen}: best fitness = {scores[0][0]}/{target_len}")

    return max(fitness(ind) for ind in pop)

result = ga()
print(f"Final fitness: {result}/64")

Applications

  • Neural architecture search
  • Financial trading strategies
  • Robot controller design
  • Feature selection

Key Points

  • Understand the core concepts thoroughly
  • Practice with hands-on code examples
  • Apply knowledge to real-world problems
  • Review and reinforce through exercises

Further Learning

  • Official documentation
  • Open source projects on GitHub
  • Community forums and discussions
  • Related courses and tutorials

What Is a Genetic Algorithm?

Genetic Algorithms (GA) are inspired by natural selection โ€” the fittest individuals survive and reproduce.

The GA Cycle

1. INITIALIZE โ†’ Create random population
       โ†“
2. EVALUATE โ†’ Calculate fitness for each individual
       โ†“
3. SELECT โ†’ Choose parents based on fitness
       โ†“
4. CROSSOVER โ†’ Combine parents to create offspring
       โ†“
5. MUTATE โ†’ Randomly modify offspring
       โ†“
6. REPLACE โ†’ New generation replaces old
       โ†“
   (repeat from step 2 until convergence)

Key Components

| Component | What It Does | Example | |-----------|-------------|---------| | Chromosome | Represents a solution | Binary string, permutation, real vector | | Gene | A single parameter | Bit, city index, weight value | | Fitness | How good the solution is | Cost function (lower = better) | | Population | Set of candidate solutions | 100 chromosomes | | Selection | Picks parents for breeding | Tournament, roulette wheel | | Crossover | Combines two parents | Single-point, uniform, PMX | | Mutation | Random changes to offspring | Bit flip, swap, Gaussian noise |

Python Implementation

import random

class GeneticAlgorithm:
    def __init__(self, pop_size=100, mutation_rate=0.01, crossover_rate=0.8):
        self.pop_size = pop_size
        self.mutation_rate = mutation_rate
        self.crossover_rate = crossover_rate
    
    def evolve(self, fitness_func, gene_pool, chrom_length, generations=100):
        """Evolve a population over multiple generations."""
        # Initialize random population
        population = [
            [random.choice(gene_pool) for _ in range(chrom_length)]
            for _ in range(self.pop_size)
        ]
        
        for gen in range(generations):
            # Evaluate fitness
            fitness = [fitness_func(ind) for ind in population]
            
            # Track best
            best_idx = fitness.index(min(fitness))
            best_fitness = fitness[best_idx]
            best_individual = population[best_idx].copy()
            
            if gen % 20 == 0:
                print(f"Generation {gen}: best fitness = {best_fitness:.4f}")
            
            # Create next generation
            new_population = []
            
            # Elitism: keep the best
            new_population.append(best_individual)
            
            while len(new_population) < self.pop_size:
                # Selection (tournament)
                parent1 = self._tournament_select(population, fitness)
                parent2 = self._tournament_select(population, fitness)
                
                # Crossover
                if random.random() < self.crossover_rate:
                    child1, child2 = self._crossover(parent1, parent2)
                else:
                    child1, child2 = parent1.copy(), parent2.copy()
                
                # Mutation
                self._mutate(child1)
                self._mutate(child2)
                
                new_population.extend([child1, child2])
            
            population = new_population[:self.pop_size]
        
        return best_individual, best_fitness
    
    def _tournament_select(self, pop, fitness, k=3):
        """Tournament selection: pick k random, return the best."""
        idx = random.sample(range(len(pop)), k)
        best = min(idx, key=lambda i: fitness[i])
        return pop[best].copy()
    
    def _crossover(self, p1, p2):
        """Single-point crossover."""
        point = random.randint(1, len(p1) - 1)
        c1 = p1[:point] + p2[point:]
        c2 = p2[:point] + p1[point:]
        return c1, c2
    
    def _mutate(self, chrom):
        """Bit-flip mutation for binary genes."""
        for i in range(len(chrom)):
            if random.random() < self.mutation_rate:
                chrom[i] = 1 - chrom[i]  # Flip 0โ†”1

# Example: Maximize sum of bits (MAX-ONE problem)
def fitness_max_one(chrom):
    return -sum(chrom)  # Negative because we minimize

ga = GeneticAlgorithm(pop_size=100, mutation_rate=0.01)
best, best_fit = ga.evolve(
    fitness_func=fitness_max_one,
    gene_pool=[0, 1],
    chrom_length=50,
    generations=200
)

print(f"\nBest: {best}")
print(f"Ones: {sum(best)} / 50")
print(f"Fitness: {best_fit}")

Selection Methods

| Method | How It Works | Best For | |--------|-------------|----------| | Tournament | Pick k random, keep the best | Simple, prevents premature convergence | | Roulette wheel | Probability proportional to fitness | When fitness is clearly ranked | | Rank-based | Probability based on rank, not raw fitness | Avoids domination by outliers |

Summary

Genetic Algorithms evolve solutions through selection, crossover, and mutation โ€” mimicking natural evolution.

Key takeaways: | GA cycle: initialize โ†’ evaluate โ†’ select โ†’ crossover โ†’ mutate โ†’ replace | | Chromosome = candidate solution; Fitness = how good it is | | Selection: tournament (k=3) is simple and effective | | Crossover (80% rate): combines two parents into two children | | Mutation (1% rate): random bit flips prevent premature convergence | | Elitism: keep the best individual from each generation | | MAX-ONE: maximize the number of 1s in a binary string | | GA works for any problem with a fitness function |

Next Chapter: PSO

The next chapter covers Particle Swarm Optimization.

Unlock Full Tutorial

This chapter is paid content. Join the project to unlock over 5000 words of deep analysis, including 10+ god-tier Prompts and real Source Code examples!