Notice: This page requires JavaScript to function properly.
Please enable JavaScript in your browser settings or update your browser.
Impara Principi di Evoluzione e Adattamento | Fondamenti degli Algoritmi Bio-Ispirati
Algoritmi Bio-Ispirati

bookPrincipi di Evoluzione e Adattamento

La comprensione dei principi di evoluzione e adattamento è fondamentale nella progettazione di algoritmi bio-ispirati. In entrambi i sistemi naturali e computazionali, questi principi spiegano come i gruppi di individui cambiano e migliorano nel tempo. I concetti fondamentali includono:

  • Popolazione: L'insieme di tutte le soluzioni candidate o individui considerati in un dato momento;
  • Fitness: La misura di quanto bene ogni individuo si comporta rispetto all'obiettivo del problema;
  • Selezione: Il processo di scelta degli individui che produrranno la generazione successiva, spesso favorendo quelli con fitness più elevato;
  • Mutazione: L'introduzione di cambiamenti casuali negli individui, mantenendo la diversità e consentendo l'esplorazione di nuove soluzioni;
  • Crossover: La combinazione di parti di due o più individui per creare nuovi discendenti;
  • Adattamento: Il miglioramento continuo della popolazione in risposta a selezione, mutazione e crossover.

Ogni concetto sostiene lo sviluppo di soluzioni robuste imitando i processi che guidano l'adattamento e il successo in natura.

Popolazione

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 funzione create_population genera un gruppo di individui, dove ciascun individuo è rappresentato da una lista di numeri interi casuali. Ogni intero può essere considerato come un gene. È possibile specificare la dimensione della popolazione, la lunghezza di ciascun individuo e l'intervallo dei valori genetici.

Mantenere la diversità nella popolazione è essenziale. Una popolazione diversificata esplora una porzione più ampia dello spazio del problema, riducendo il rischio di rimanere bloccati in soluzioni di bassa qualità e aumentando la probabilità di trovare risposte di alto livello.

Fitness: Misurare la qualità della soluzione

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 fitness_function misura la qualità di una soluzione confrontandola con un valore target. Minore è la differenza, maggiore sarà il punteggio di fitness. Ad esempio, se la soluzione è 97 e il target è 100, il punteggio di fitness sarà più alto rispetto a una soluzione pari a 80.

Note
Nota

I punteggi di fitness vengono utilizzati per guidare la selezione, aiutando a identificare quali candidati hanno maggiori probabilità di produrre soluzioni migliori nella generazione successiva.

Selezione: scelta dei candidati più adatti

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 selezione a ruota della fortuna sceglie gli individui con una probabilità proporzionale ai loro punteggi di fitness. Questo significa che i candidati con fitness più elevato hanno maggiori probabilità di essere selezionati, ma anche gli individui con fitness inferiore possono essere scelti, contribuendo a mantenere la diversità nella popolazione.

Mutazione: Introduzione di Variazione

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 mutazione introduce cambiamenti casuali negli individui della popolazione. Questa casualità aiuta a mantenere la diversità, permettendo all'algoritmo di esplorare nuove soluzioni e riducendo il rischio di rimanere bloccati su soluzioni subottimali.

Crossover: Combinazione di tratti per nuove soluzioni

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

Questa funzione prende due individui genitori (liste di interi) e produce due discendenti scambiando materiale genetico in un punto scelto casualmente. Il punto di crossover viene selezionato in modo che ciascun discendente contenga geni da entrambi i genitori.

Esempio di utilizzo:

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

Vantaggi del crossover:

  • Combina tratti da soluzioni diverse, aumentando la probabilità di individuare candidati di alta qualità;
  • Favorisce l'esplorazione dello spazio delle soluzioni ricombinando caratteristiche di successo;
  • Aiuta a mantenere la diversità all'interno della popolazione, riducendo il rischio di convergenza prematura.

Adattamento: Come le popolazioni migliorano nel tempo

L'adattamento è l'effetto cumulativo di operazioni evolutive ripetute — selezione, crossover e mutazione. Con la ripetizione di questi processi, la popolazione diventa gradualmente più abile nel risolvere il problema, portando nel tempo a soluzioni di qualità superiore.

question mark

Quale affermazione descrive accuratamente lo scopo principale della mutazione negli algoritmi bio-ispirati?

Select the correct answer

Tutto è chiaro?

Come possiamo migliorarlo?

Grazie per i tuoi commenti!

Sezione 1. Capitolo 2

Chieda ad AI

expand

Chieda ad AI

ChatGPT

Chieda pure quello che desidera o provi una delle domande suggerite per iniziare la nostra conversazione

bookPrincipi di Evoluzione e Adattamento

Scorri per mostrare il menu

La comprensione dei principi di evoluzione e adattamento è fondamentale nella progettazione di algoritmi bio-ispirati. In entrambi i sistemi naturali e computazionali, questi principi spiegano come i gruppi di individui cambiano e migliorano nel tempo. I concetti fondamentali includono:

  • Popolazione: L'insieme di tutte le soluzioni candidate o individui considerati in un dato momento;
  • Fitness: La misura di quanto bene ogni individuo si comporta rispetto all'obiettivo del problema;
  • Selezione: Il processo di scelta degli individui che produrranno la generazione successiva, spesso favorendo quelli con fitness più elevato;
  • Mutazione: L'introduzione di cambiamenti casuali negli individui, mantenendo la diversità e consentendo l'esplorazione di nuove soluzioni;
  • Crossover: La combinazione di parti di due o più individui per creare nuovi discendenti;
  • Adattamento: Il miglioramento continuo della popolazione in risposta a selezione, mutazione e crossover.

Ogni concetto sostiene lo sviluppo di soluzioni robuste imitando i processi che guidano l'adattamento e il successo in natura.

Popolazione

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 funzione create_population genera un gruppo di individui, dove ciascun individuo è rappresentato da una lista di numeri interi casuali. Ogni intero può essere considerato come un gene. È possibile specificare la dimensione della popolazione, la lunghezza di ciascun individuo e l'intervallo dei valori genetici.

Mantenere la diversità nella popolazione è essenziale. Una popolazione diversificata esplora una porzione più ampia dello spazio del problema, riducendo il rischio di rimanere bloccati in soluzioni di bassa qualità e aumentando la probabilità di trovare risposte di alto livello.

Fitness: Misurare la qualità della soluzione

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 fitness_function misura la qualità di una soluzione confrontandola con un valore target. Minore è la differenza, maggiore sarà il punteggio di fitness. Ad esempio, se la soluzione è 97 e il target è 100, il punteggio di fitness sarà più alto rispetto a una soluzione pari a 80.

Note
Nota

I punteggi di fitness vengono utilizzati per guidare la selezione, aiutando a identificare quali candidati hanno maggiori probabilità di produrre soluzioni migliori nella generazione successiva.

Selezione: scelta dei candidati più adatti

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 selezione a ruota della fortuna sceglie gli individui con una probabilità proporzionale ai loro punteggi di fitness. Questo significa che i candidati con fitness più elevato hanno maggiori probabilità di essere selezionati, ma anche gli individui con fitness inferiore possono essere scelti, contribuendo a mantenere la diversità nella popolazione.

Mutazione: Introduzione di Variazione

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 mutazione introduce cambiamenti casuali negli individui della popolazione. Questa casualità aiuta a mantenere la diversità, permettendo all'algoritmo di esplorare nuove soluzioni e riducendo il rischio di rimanere bloccati su soluzioni subottimali.

Crossover: Combinazione di tratti per nuove soluzioni

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

Questa funzione prende due individui genitori (liste di interi) e produce due discendenti scambiando materiale genetico in un punto scelto casualmente. Il punto di crossover viene selezionato in modo che ciascun discendente contenga geni da entrambi i genitori.

Esempio di utilizzo:

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

Vantaggi del crossover:

  • Combina tratti da soluzioni diverse, aumentando la probabilità di individuare candidati di alta qualità;
  • Favorisce l'esplorazione dello spazio delle soluzioni ricombinando caratteristiche di successo;
  • Aiuta a mantenere la diversità all'interno della popolazione, riducendo il rischio di convergenza prematura.

Adattamento: Come le popolazioni migliorano nel tempo

L'adattamento è l'effetto cumulativo di operazioni evolutive ripetute — selezione, crossover e mutazione. Con la ripetizione di questi processi, la popolazione diventa gradualmente più abile nel risolvere il problema, portando nel tempo a soluzioni di qualità superiore.

question mark

Quale affermazione descrive accuratamente lo scopo principale della mutazione negli algoritmi bio-ispirati?

Select the correct answer

Tutto è chiaro?

Come possiamo migliorarlo?

Grazie per i tuoi commenti!

Sezione 1. Capitolo 2
some-alt