Notice: This page requires JavaScript to function properly.
Please enable JavaScript in your browser settings or update your browser.
Aprende Principios de Evolución y Adaptación | Fundamentos de los Algoritmos Bioinspirados
Algoritmos Bioinspirados

bookPrincipios de Evolución y Adaptación

Dominar los principios de la evolución y la adaptación es fundamental al diseñar algoritmos bioinspirados. Tanto en sistemas naturales como computacionales, estos principios explican cómo los grupos de individuos cambian y mejoran con el tiempo. Los conceptos fundamentales incluyen:

  • Población: El conjunto de todas las soluciones candidatas o individuos considerados en un momento dado;
  • Aptitud: La medida de qué tan bien cada individuo cumple con el objetivo del problema;
  • Selección: El proceso de elegir individuos para producir la siguiente generación, a menudo favoreciendo a aquellos con mayor aptitud;
  • Mutación: La introducción de cambios aleatorios en los individuos, manteniendo la diversidad y permitiendo la exploración de nuevas soluciones;
  • Cruzamiento: La combinación de partes de dos o más individuos para crear nueva descendencia;
  • Adaptación: La mejora continua de la población en respuesta a la selección, mutación y cruzamiento.

Cada concepto respalda el desarrollo de soluciones robustas al imitar los procesos que impulsan la adaptación y el éxito en la naturaleza.

Población

import random

def create_population(size, length, value_range=(0, 100)):
    """
    Generates a population of individuals, each as a list of random integers.
    
    Args:
        size (int): Number of individuals in the population.
        length (int): Number of genes in each individual.
        value_range (tuple): Allowed range for gene values (inclusive).
    Returns:
        list: Population represented as a list of individuals.
    """
    return [[random.randint(value_range[0], value_range[1]) for _ in range(length)] for _ in range(size)]

# Example usage:
population = create_population(size=5, length=3, value_range=(0, 50))
print("Generated population:", population)

La función create_population genera un grupo de individuos, donde cada individuo está representado por una lista de números enteros aleatorios. Cada entero puede considerarse como un gen. Se especifica el tamaño de la población, la longitud de cada individuo y el rango de valores de los genes.

Mantener la diversidad en la población es esencial. Una población diversa explora más el espacio del problema, lo que reduce el riesgo de quedar atrapado en soluciones deficientes y aumenta la probabilidad de encontrar respuestas de alta calidad.

Aptitud: Medición de la calidad de la solución

def fitness_function(solution, target=100):
    """
    Calculates fitness based on how close the solution is to the target value.
    Higher fitness indicates a solution closer to the target.
    """
    return 1 / (1 + abs(target - solution))

# Example usage:
solution = 97
fitness = fitness_function(solution, target=100)
print(f"Fitness score: {fitness}")

La función fitness_function mide qué tan buena es una solución comparándola con un valor objetivo. Cuanto menor sea la diferencia, mayor será la puntuación de aptitud. Por ejemplo, si la solución es 97 y el objetivo es 100, la puntuación de aptitud será mayor que si la solución es 80.

Note
Nota

Las puntuaciones de aptitud se utilizan para guiar la selección, ayudando a identificar qué candidatos tienen más probabilidades de producir mejores soluciones en la siguiente generación.

Selección: Elegir los candidatos más aptos

import random

def roulette_wheel_selection(population, fitnesses, num_selected):
    """
    Selects individuals from the population using roulette wheel selection.
    Probability of selection is proportional to fitness.
    Handles the case where all fitness scores are zero by selecting randomly.
    """
    total_fitness = sum(fitnesses)
    if total_fitness == 0:
        # If all fitnesses are zero, select randomly
        return random.choices(population, k=num_selected)
    # Otherwise, select based on fitness weights
    return random.choices(population, weights=fitnesses, k=num_selected)

# Example usage:
population = [[1, 2, 3], [4, 5, 6], [7, 8, 9], [2, 4, 6]]
fitnesses = [10, 0, 30, 5]  # Higher fitness means higher chance of selection
selected = roulette_wheel_selection(population, fitnesses, num_selected=2)
print("Selected individuals:", selected)

La selección por ruleta elige individuos con una probabilidad proporcional a sus puntuaciones de aptitud. Esto significa que los candidatos con mayor aptitud tienen más probabilidad de ser seleccionados, pero los individuos con menor aptitud aún pueden ser elegidos, lo que ayuda a mantener la diversidad en la población.

Mutación: Introducción de variación

import random

def mutate_individual(individual, mutation_rate=0.2, value_range=(0, 100)):
    """
    Randomly changes each gene in an individual with a given probability.
    Returns a new individual with possible mutations.
    """
    return [random.randint(*value_range) if random.random() < mutation_rate else gene for gene in individual]

# Example: Mutating a single individual
original = [10, 20, 30, 40, 50]
mutated = mutate_individual(original, mutation_rate=0.4, value_range=(0, 100))
print("Original:", original)
print("Mutated:", mutated)

# Example: Mutating an entire population
population = [[5, 15, 25], [35, 45, 55], [65, 75, 85]]
mutated_population = [mutate_individual(ind, mutation_rate=0.3) for ind in population]
print("Original Population:", population)
print("Mutated Population:", mutated_population)

La mutación introduce cambios aleatorios en los individuos de la población. Esta aleatoriedad ayuda a mantener la diversidad, permitiendo que el algoritmo explore nuevas soluciones y reduciendo el riesgo de quedar atrapado en soluciones poco óptimas.

Cruce: Combinación de Rasgos para Nuevas Soluciones

def single_point_crossover(parent1, parent2):
    """
    Performs single-point crossover between two parent individuals.
    Each parent is a list of integers of the same length.
    Returns two offspring as lists.
    """
    import random
    if len(parent1) != len(parent2):
        raise ValueError("Parents must be of the same length.")
    if len(parent1) < 2:
        raise ValueError("Parent length must be at least 2 for crossover.")
    crossover_point = random.randint(1, len(parent1) - 1)
    offspring1 = parent1[:crossover_point] + parent2[crossover_point:]
    offspring2 = parent2[:crossover_point] + parent1[crossover_point:]
    return offspring1, offspring2

Esta función toma dos individuos padres (listas de enteros) y produce dos descendientes intercambiando material genético en un punto elegido aleatoriamente. El punto de cruce se selecciona de manera que cada descendiente contenga genes de ambos padres.

Ejemplo de uso:

import random
random.seed(42)  # For reproducible results
parent1 = [10, 20, 30, 40, 50]
parent2 = [1, 2, 3, 4, 5]
offspring1, offspring2 = single_point_crossover(parent1, parent2)
print("Offspring 1:", offspring1)
print("Offspring 2:", offspring2)
Note
Nota

Beneficios del Cruce:

  • Mezcla rasgos de diferentes soluciones, aumentando la probabilidad de descubrir candidatos de alta calidad;
  • Favorece la exploración del espacio de soluciones al recombinar características exitosas;
  • Ayuda a mantener la diversidad dentro de la población, reduciendo el riesgo de convergencia prematura.

Adaptación: Cómo mejoran las poblaciones con el tiempo

La adaptación es el efecto acumulativo de operaciones evolutivas repetidas — selección, cruce y mutación. A medida que estos procesos se repiten, la población mejora gradualmente en la resolución del problema, lo que conduce a soluciones de mayor calidad con el tiempo.

question mark

¿Cuál afirmación describe con precisión el propósito principal de la mutación en los algoritmos bioinspirados?

Select the correct answer

¿Todo estuvo claro?

¿Cómo podemos mejorarlo?

¡Gracias por tus comentarios!

Sección 1. Capítulo 2

Pregunte a AI

expand

Pregunte a AI

ChatGPT

Pregunte lo que quiera o pruebe una de las preguntas sugeridas para comenzar nuestra charla

Suggested prompts:

Can you explain how these evolutionary principles are applied in real-world algorithms?

What are some common challenges when implementing bio-inspired algorithms?

Can you give examples of problems that benefit from using these principles?

Awesome!

Completion rate improved to 6.25

bookPrincipios de Evolución y Adaptación

Desliza para mostrar el menú

Dominar los principios de la evolución y la adaptación es fundamental al diseñar algoritmos bioinspirados. Tanto en sistemas naturales como computacionales, estos principios explican cómo los grupos de individuos cambian y mejoran con el tiempo. Los conceptos fundamentales incluyen:

  • Población: El conjunto de todas las soluciones candidatas o individuos considerados en un momento dado;
  • Aptitud: La medida de qué tan bien cada individuo cumple con el objetivo del problema;
  • Selección: El proceso de elegir individuos para producir la siguiente generación, a menudo favoreciendo a aquellos con mayor aptitud;
  • Mutación: La introducción de cambios aleatorios en los individuos, manteniendo la diversidad y permitiendo la exploración de nuevas soluciones;
  • Cruzamiento: La combinación de partes de dos o más individuos para crear nueva descendencia;
  • Adaptación: La mejora continua de la población en respuesta a la selección, mutación y cruzamiento.

Cada concepto respalda el desarrollo de soluciones robustas al imitar los procesos que impulsan la adaptación y el éxito en la naturaleza.

Población

import random

def create_population(size, length, value_range=(0, 100)):
    """
    Generates a population of individuals, each as a list of random integers.
    
    Args:
        size (int): Number of individuals in the population.
        length (int): Number of genes in each individual.
        value_range (tuple): Allowed range for gene values (inclusive).
    Returns:
        list: Population represented as a list of individuals.
    """
    return [[random.randint(value_range[0], value_range[1]) for _ in range(length)] for _ in range(size)]

# Example usage:
population = create_population(size=5, length=3, value_range=(0, 50))
print("Generated population:", population)

La función create_population genera un grupo de individuos, donde cada individuo está representado por una lista de números enteros aleatorios. Cada entero puede considerarse como un gen. Se especifica el tamaño de la población, la longitud de cada individuo y el rango de valores de los genes.

Mantener la diversidad en la población es esencial. Una población diversa explora más el espacio del problema, lo que reduce el riesgo de quedar atrapado en soluciones deficientes y aumenta la probabilidad de encontrar respuestas de alta calidad.

Aptitud: Medición de la calidad de la solución

def fitness_function(solution, target=100):
    """
    Calculates fitness based on how close the solution is to the target value.
    Higher fitness indicates a solution closer to the target.
    """
    return 1 / (1 + abs(target - solution))

# Example usage:
solution = 97
fitness = fitness_function(solution, target=100)
print(f"Fitness score: {fitness}")

La función fitness_function mide qué tan buena es una solución comparándola con un valor objetivo. Cuanto menor sea la diferencia, mayor será la puntuación de aptitud. Por ejemplo, si la solución es 97 y el objetivo es 100, la puntuación de aptitud será mayor que si la solución es 80.

Note
Nota

Las puntuaciones de aptitud se utilizan para guiar la selección, ayudando a identificar qué candidatos tienen más probabilidades de producir mejores soluciones en la siguiente generación.

Selección: Elegir los candidatos más aptos

import random

def roulette_wheel_selection(population, fitnesses, num_selected):
    """
    Selects individuals from the population using roulette wheel selection.
    Probability of selection is proportional to fitness.
    Handles the case where all fitness scores are zero by selecting randomly.
    """
    total_fitness = sum(fitnesses)
    if total_fitness == 0:
        # If all fitnesses are zero, select randomly
        return random.choices(population, k=num_selected)
    # Otherwise, select based on fitness weights
    return random.choices(population, weights=fitnesses, k=num_selected)

# Example usage:
population = [[1, 2, 3], [4, 5, 6], [7, 8, 9], [2, 4, 6]]
fitnesses = [10, 0, 30, 5]  # Higher fitness means higher chance of selection
selected = roulette_wheel_selection(population, fitnesses, num_selected=2)
print("Selected individuals:", selected)

La selección por ruleta elige individuos con una probabilidad proporcional a sus puntuaciones de aptitud. Esto significa que los candidatos con mayor aptitud tienen más probabilidad de ser seleccionados, pero los individuos con menor aptitud aún pueden ser elegidos, lo que ayuda a mantener la diversidad en la población.

Mutación: Introducción de variación

import random

def mutate_individual(individual, mutation_rate=0.2, value_range=(0, 100)):
    """
    Randomly changes each gene in an individual with a given probability.
    Returns a new individual with possible mutations.
    """
    return [random.randint(*value_range) if random.random() < mutation_rate else gene for gene in individual]

# Example: Mutating a single individual
original = [10, 20, 30, 40, 50]
mutated = mutate_individual(original, mutation_rate=0.4, value_range=(0, 100))
print("Original:", original)
print("Mutated:", mutated)

# Example: Mutating an entire population
population = [[5, 15, 25], [35, 45, 55], [65, 75, 85]]
mutated_population = [mutate_individual(ind, mutation_rate=0.3) for ind in population]
print("Original Population:", population)
print("Mutated Population:", mutated_population)

La mutación introduce cambios aleatorios en los individuos de la población. Esta aleatoriedad ayuda a mantener la diversidad, permitiendo que el algoritmo explore nuevas soluciones y reduciendo el riesgo de quedar atrapado en soluciones poco óptimas.

Cruce: Combinación de Rasgos para Nuevas Soluciones

def single_point_crossover(parent1, parent2):
    """
    Performs single-point crossover between two parent individuals.
    Each parent is a list of integers of the same length.
    Returns two offspring as lists.
    """
    import random
    if len(parent1) != len(parent2):
        raise ValueError("Parents must be of the same length.")
    if len(parent1) < 2:
        raise ValueError("Parent length must be at least 2 for crossover.")
    crossover_point = random.randint(1, len(parent1) - 1)
    offspring1 = parent1[:crossover_point] + parent2[crossover_point:]
    offspring2 = parent2[:crossover_point] + parent1[crossover_point:]
    return offspring1, offspring2

Esta función toma dos individuos padres (listas de enteros) y produce dos descendientes intercambiando material genético en un punto elegido aleatoriamente. El punto de cruce se selecciona de manera que cada descendiente contenga genes de ambos padres.

Ejemplo de uso:

import random
random.seed(42)  # For reproducible results
parent1 = [10, 20, 30, 40, 50]
parent2 = [1, 2, 3, 4, 5]
offspring1, offspring2 = single_point_crossover(parent1, parent2)
print("Offspring 1:", offspring1)
print("Offspring 2:", offspring2)
Note
Nota

Beneficios del Cruce:

  • Mezcla rasgos de diferentes soluciones, aumentando la probabilidad de descubrir candidatos de alta calidad;
  • Favorece la exploración del espacio de soluciones al recombinar características exitosas;
  • Ayuda a mantener la diversidad dentro de la población, reduciendo el riesgo de convergencia prematura.

Adaptación: Cómo mejoran las poblaciones con el tiempo

La adaptación es el efecto acumulativo de operaciones evolutivas repetidas — selección, cruce y mutación. A medida que estos procesos se repiten, la población mejora gradualmente en la resolución del problema, lo que conduce a soluciones de mayor calidad con el tiempo.

question mark

¿Cuál afirmación describe con precisión el propósito principal de la mutación en los algoritmos bioinspirados?

Select the correct answer

¿Todo estuvo claro?

¿Cómo podemos mejorarlo?

¡Gracias por tus comentarios!

Sección 1. Capítulo 2
some-alt