Total of weights must be greater than zero #python

I'm tried to follow a tutorial of making a genetic algorithm in python, but when I run the code below, i get the following errors: Traceback (most recent call last): File "C:\Users\Dani\PycharmProjects\FirstProject\main.py", line 343, in population, generations = run_evolution( File "C:\Users\Dani\PycharmProjects\FirstProject\main.py", line 325, in run_evolution parents = selection_func(population, fitness_func) File "C:\Users\Dani\PycharmProjects\FirstProject\main.py", line 274, in selection_pair return choices( File "C:\Users\Dani\AppData\Local\Programs\Python\Python39\lib\random.py", line 495, in choices raise ValueError('Total of weights must be greater than zero') ValueError: Total of weights must be greater than zero

The last one is the one that's bothering me the most because I don't really know what should I do in order to solve it.

Here is the code (sorry for the hardcoded part):

Genetic Algorithm

Genome = List[int] # this is line 98
Population = List[Genome]
FitnessFunc = Callable[[Genome], int]
PopulateFunc = Callable[[], Population]
SelectionFunc = Callable[[Population, FitnessFunc], Tuple[Genome, Genome]]
CrossoverFunc = Callable[[Genome, Genome], Tuple[Genome, Genome]]
MutationFunc = Callable[[Genome], Genome]

Champion = namedtuple('Champion', ['name', 'value', 'limit'])
champions = [
    Champion('Annie', 50, 1),
    Champion('Olaf', 47, 1),
    Champion('Galio', 46, 1),
    Champion('TwistedFate', 51, 1),
    Champion('XinZhao', 51, 1),
    Champion('Urgot', 48, 1),
    Champion('Leblanc', 46, 1),
    Champion('Vladimir', 49, 1),
    Champion('Fiddlesticks', 49, 1),
    Champion('Kayle', 50, 1),
    Champion('MasterYi', 50, 1),
    Champion('Alistar', 49, 1),
    Champion('Ryze', 40, 1),
    Champion('Sion', 49, 1),
    Champion('Sivir', 50, 1),
    Champion('Soraka', 52, 1),
    Champion('Teemo', 51, 1),
    Champion('Tristana', 51, 1),
    Champion('Warwick', 51, 1),
    Champion('Nunu', 49, 1),
    Champion('Ashe', 47, 1),
    Champion('Tryndamere', 52, 1),
    Champion('Jax', 50, 1),
    Champion('Morgana', 47, 1),
    Champion('Zilean', 49, 1),
    Champion('Singed', 53, 1),
    Champion('Evelynn', 47, 1),
    Champion('Twitch', 52, 1),
    Champion('Karthus', 51, 1),
    Champion('Anivia', 53, 1),
    Champion('Shaco', 49, 1),
    Champion('DrMundo', 49, 1),
    Champion('Sona', 54, 1),
    Champion('Kassadin', 49, 1),
    Champion('Irelia', 50, 1),
    Champion('Janna', 55, 1),
    Champion('Gangplank', 49, 1),
    Champion('Corki', 46, 1),
    Champion('Karma', 45, 1),
    Champion('Taric', 52, 1),
    Champion('Veigar', 49, 1),
    Champion('Trundle', 47, 1),
    Champion('Swain', 53, 1),
    Champion('Caitlyn', 46, 1),
    Champion('Blitzcrank', 51, 1),
    Champion('Malphite', 50, 1),
    Champion('Katarina', 50, 1),
    Champion('Nocturne', 51, 1),
    Champion('Maokai', 51, 1),
    Champion('Renekton', 50, 1),
    Champion('JarvanIV', 52, 1),
    Champion('Elise', 49, 1),
    Champion('Orianna', 50, 1),
    Champion('Wukong', 52, 1),
    Champion('Brand', 51, 1),
    Champion('LeeSin', 45, 1),
    Champion('Vayne', 51, 1),
    Champion('Rumble', 49, 1),
    Champion('Cassiopeia', 48, 1),
    Champion('Skarner', 48, 1),
    Champion('Heimerdinger', 48, 1),
    Champion('Nasus', 50, 1),
    Champion('Nidalee', 46, 1),
    Champion('Udyr', 49, 1),
    Champion('Poppy', 45, 1),
    Champion('Gragas', 49, 1),
    Champion('Pantheon', 50, 1),
    Champion('Ezreal', 46, 1),
    Champion('Mordekaiser', 51, 1),
    Champion('Yorick', 53, 1),
    Champion('Akali', 50, 1),
    Champion('Kennen', 47, 1),
    Champion('Garen', 53, 1),
    Champion('Leona', 51, 1),
    Champion('Malzahar', 52, 1),
    Champion('Talon', 50, 1),
    Champion('Riven', 49, 1),
    Champion('KogMaw', 50, 1),
    Champion('Shen', 48, 1),
    Champion('Lux', 49, 1),
    Champion('Xerath', 52, 1),
    Champion('Shyvana', 53, 1),
    Champion('Ahri', 52, 1),
    Champion('Graves', 47, 1),
    Champion('Fizz', 48, 1),
    Champion('Volibear', 49, 1),
    Champion('Rengar', 48, 1),
    Champion('Varus', 49, 1),
    Champion('Nautilus', 48, 1),
    Champion('Viktor', 47, 1),
    Champion('Sejuani', 53, 1),
    Champion('Fiora', 49, 1),
    Champion('Ziggs', 51, 1),
    Champion('Lulu', 50, 1),
    Champion('Draven', 50, 1),
    Champion('Hecarim', 50, 1),
    Champion('Khazix', 48, 1),
    Champion('Darius', 51, 1),
    Champion('Jayce', 50, 1),
    Champion('Lissandra', 46, 1),
    Champion('Diana', 51, 1),
    Champion('Quinn', 50, 1),
    Champion('Syndra', 46, 1),
    Champion('AurelionSol', 52, 1),
    Champion('Kayn', 48, 1),
    Champion('Zyra', 49, 1),
    Champion('Gnar', 49, 1),
    Champion('Zac', 49, 1),
    Champion('Yasuo', 50, 1),
    Champion('Velkoz', 51, 1),
    Champion('Taliyah', 47, 1),
    Champion('Camille', 48, 1),
    Champion('Braum', 51, 1),
    Champion('Jhin', 48, 1),
    Champion('Kindred', 48, 1),
    Champion('Jinx', 51, 1),
    Champion('TahmKench', 46, 1),
    Champion('Lucian', 47, 1),
    Champion('Zed', 49, 1),
    Champion('Kled', 51, 1),
    Champion('Ekko', 49, 1),
    Champion('Vi', 50, 1),
    Champion('Aatrox', 47, 1),
    Champion('Nami', 51, 1),
    Champion('Azir', 43, 1),
    Champion('Thresh', 47, 1),
    Champion('Illaoi', 48, 1),
    Champion('RekSai', 48, 1),
    Champion('Ivern', 46, 1),
    Champion('Kalista', 47, 1),
    Champion('Bard', 47, 1),
    Champion('Rakan', 50, 1),
    Champion('Xayah', 49, 1),
    Champion('Ornn', 41, 1),
]


def gen_genome(length: int) -> Genome:
    return choices([0, 1], k=length)


def gen_population(size: int, genome_length: int) -> Population:
    return [gen_genome(genome_length) for _ in range(size)]


def fitness(genome: Genome, champions: [Champion], team_limit: int) -> int:
    if len(genome) != len(champions):
        raise ValueError("Genome and champions must be of the same length")

    limit = 0
    value = 0

    for z, champion in enumerate(champions):
        if genome[z] == 1:
            limit += champion.limit
            value += champion.value

            if limit > team_limit:
                return 0

    return value

This is the problematic function

**def selection_pair(population: Population, fitness_func: FitnessFunc) -> Population:
    return choices(
        population=population,
        # limits=[fitness_func(gene) for gene in population],
        weights=[fitness_func(gene) for gene in population],
        k=2
    )**

Rest of the code

def single_point_crossover(a: Genome, b: Genome) -> Tuple[Genome, Genome]:
    if len(a) != len(b):
        raise ValueError("Genomes a and b must be of same length")

    length = len(a)
    if length < 2:
        return a, b

    p = randint(1, length -1)
    return a[0:p] + b[p:], b[0:p] + a[p:]


def mutation(genome: Genome, num: int = 1, probability: float = 0.5) -> Genome:
    for _ in range(num):
        index = randrange(len(genome))
        genome[index] = genome[index] if random() > probability else abs(genome[index] - 1)
    return genome


def run_evolution(
        populate_func: PopulateFunc,
        fitness_func: FitnessFunc,
        fitness_limit: int,
        selection_func: SelectionFunc = selection_pair,
        crossover_func: CrossoverFunc = single_point_crossover,
        mutation_func: MutationFunc = mutation,
        generation_limit: int = 100
) -> Tuple[Population, int]:
    population = populate_func()

    for r in range(generation_limit):
        population = sorted(
            population,
            key=lambda genome: fitness_func(genome),
            reverse=True
        )

        if fitness_func(population[0]) >= fitness_limit:
            break

        next_generation = population[0:2]

        for z in range(int(len(population) / 2) - 1):
            parents = selection_func(population, fitness_func)
            offspring_a, offspring_b = crossover_func(parents[0], parents[1])
            offspring_a = mutation_func(offspring_a)
            offspring_b = mutation_func(offspring_b)
            next_generation += [offspring_a, offspring_b]

        population = next_generation

    population = sorted(
        population,
        key=lambda genome: fitness_func(genome),
        reverse=True
    )

    return population, r


start = time.time()
population, generations = run_evolution(
    populate_func=partial(
        gen_population, size=10, genome_length=len(champions)
    ),
    fitness_func=partial(
        fitness, champions=champions, team_limit=5
    ),
    fitness_limit=300,
    generation_limit=100
)
end = time.time()


def genome_to_champions(genome: Genome, champions: [Champion]) -> [Champion]:
    result = []
    for z, champion in enumerate(champions):
        if genome[z] == 1:
            result += [champion.name]

    return result


print(f"number of generations: {generations}")
print(f"time: {end - start}s")
print(f"best solution: {genome_to_champions(population[0], champions)}")

The lines until 98 are just some for and if's, not affecting the algorithm The imports are:

import csv
import time
from collections import namedtuple
from functools import partial
from random import choices, randint, random, randrange
from typing import List, Callable, Tuple

Please help me, I have no ideas left...



Read more here: https://stackoverflow.com/questions/67394009/total-of-weights-must-be-greater-than-zero-python

Content Attribution

This content was originally published by Lanzin at Recent Questions - Stack Overflow, and is syndicated here via their RSS feed. You can read the original post over there.

%d bloggers like this: