geneal


Namegeneal JSON
Version 0.7.1 PyPI version JSON
download
home_pagehttps://github.com/diogomatoschaves/geneal
SummaryPython Genetic Algorithm library
upload_time2024-02-22 02:31:17
maintainer
docs_urlNone
authorDiogo Matos Chaves
requires_python>=3.8
licenseMIT
keywords genetic algorithms ga optimization genetic programming
VCS
bugtrack_url
requirements No requirements were recorded.
Travis-CI No Travis.
coveralls test coverage No coveralls.
            # GeneAl

![build_badge](https://github.com/diogomatoschaves/geneal/workflows/build/badge.svg)
[![codecov](https://codecov.io/gh/diogomatoschaves/geneal/branch/master/graph/badge.svg)](https://codecov.io/gh/diogomatoschaves/geneal)
[![PyPI version](https://badge.fury.io/py/geneal.svg)](https://badge.fury.io/py/geneal)

`geneal` is a python library implementing genetic algorithms (GAs). It has functionality for both binary and continuous GA,
as well as specific use case applications such as a solver for the
[Travelling Salesman Problem](https://en.wikipedia.org/wiki/Travelling_salesman_problem). 

## Installation

```
$ pip install geneal
```

## Usage

`geneal` provides 2 main GA solver classes, `BinaryGenAlgSolver` and `ContinuousGenAlgSolver` 
for binary and continuous problem formulations respectively. The library is set up in such a way that all problems
have to be a maximization, and hence, the fitness functions need to be adjusted accordingly.

### Binary GA

The binary GA class can be customized by the input variables provided on its initialization. 
The minimum required arguments to provide at the initialization are the number of genes on each individual's
chromosome, and the fitness function to be maximized. 

An example is shown below.

```python

from geneal.genetic_algorithms import BinaryGenAlgSolver
from geneal.applications.fitness_functions.binary import fitness_functions_binary

solver = BinaryGenAlgSolver(
    n_genes=3, # number of variables defining the problem
    fitness_function=fitness_functions_binary(1), # fitness function to be maximized
)

solver.solve()

```

The above call will perform the optimization with the default parameters, which will most likely have to be adjusted for
each individual problem at hand. The algorithm parameters can be customized as shown below.

```python
from geneal.genetic_algorithms import BinaryGenAlgSolver
from geneal.applications.fitness_functions.binary import fitness_functions_binary

solver = BinaryGenAlgSolver(
    n_genes=3,
    fitness_function=fitness_functions_binary(1), 
    n_bits=1, # number of bits describing each gene (variable)
    pop_size=10, # population size (number of individuals)
    max_gen=500, # maximum number of generations
    mutation_rate=0.05, # mutation rate to apply to the population
    selection_rate=0.5, # percentage of the population to select for mating
    selection_strategy="roulette_wheel", # strategy to use for selection. see below for more details
    fitness_tolerance=(1E-4, 50)  # Loop will be exited if the best fitness value does not change more than
                                  # 1E-4 for 50 generations
)

solver.solve()

```

### Continuous GA

Following a similar pattern as the binary GA solver, the parameters of the continuous GA can be adjusted at initialization.
As a bare minimum, the number of variables and the fitness function to maximize must be provided, as shown below.

```python

from geneal.genetic_algorithms import ContinuousGenAlgSolver
from geneal.applications.fitness_functions.continuous import fitness_functions_continuous

solver = ContinuousGenAlgSolver(
    n_genes=4, # number of variables defining the problem
    fitness_function=fitness_functions_continuous(3), # fitness function to be maximized
)

solver.solve()

```

In order to customize the continuous GA solver further, more arguments can be passed at initialization.

```python

from geneal.genetic_algorithms import ContinuousGenAlgSolver
from geneal.applications.fitness_functions.continuous import fitness_functions_continuous

solver = ContinuousGenAlgSolver(
    n_genes=4,
    fitness_function=fitness_functions_continuous(3),
    pop_size=10, # population size (number of individuals)
    max_gen=200, # maximum number of generations
    mutation_rate=0.1, # mutation rate to apply to the population
    selection_rate=0.6, # percentage of the population to select for mating
    selection_strategy="roulette_wheel", # strategy to use for selection. see below for more details
    fitness_tolerance=(1E-5, 20)  # Loop will be exited if the best fitness value does not change more than
                                  # 1E-5 for 20 generations
)

solver.solve()

```

A notable difference to the binary GA solver is the fact that we can customize the input space of the problem
by defining if the problem is of type `int` or `float`, and defining an overall minimum and maximum values for each
variable (or for all at once).

```python

from geneal.genetic_algorithms import ContinuousGenAlgSolver
from geneal.applications.fitness_functions.continuous import fitness_functions_continuous

solver = ContinuousGenAlgSolver(
    n_genes=4, 
    fitness_function=fitness_functions_continuous(3),
    pop_size=10,
    max_gen=200,
    mutation_rate=0.1,
    selection_rate=0.6,
    selection_strategy="roulette_wheel",
    variables_type=float, # Defines the possible values as float numbers
    variables_limits=(-10, 10) # Defines the limits of all variables between -10 and 10. 
                               # Alternatively one can pass an array of tuples defining the limits
                               # for each variable: [(-10, 10), (0, 5), (0, 5), (-20, 20)]
)

solver.solve()

```

### selection strategy

It is possible to choose the selection strategy that the algorithm will use to select the parents that will 
be used for generating new offsprings for the next generation. The options are:

- `roulette_wheel`
- `random`
- `two_by_two`
- `tournament`

**roulette wheel**

This selection strategy orders the individuals in the selection pool by probability, with the fittest individuals
having higher odds of being selected. 

**random**

This selection procedure selects randomly individuals from the selection pool, following in essence a similar procedure
as the roulette wheel, but with the same probabilities for each individual.

**two_by_two**

This strategy groups the individuals in the mating pool 2 by 2, from top to bottom.

**tournament**

This strategy will select 3 individuals candidates for each parent position, which are then sorted by their fitness
and from which the fittest one is selected.

## Specific Applications

In the real world, there's usually the need to adapt a genetic algorithm implementation to each individual problem.
Thus, `geneal` offers the user a level of customization that aims to be both versatile and relatively simple. For that,
one just has to create a class which inherits from the `BinaryGenAlgSolver` or `ContinuousGenAlgSolver`
base classes, and on which some overriding methods are defined. This allows the user to control the main steps of a GA:

- fitness function
- population initialization
- mating between individuals (creation of offsprings)
- mutation of the population
 
A boilerplate template of such a class is shown below:

```python
from geneal.genetic_algorithms import ContinuousGenAlgSolver, BinaryGenAlgSolver


class TemplateChildClass(ContinuousGenAlgSolver, BinaryGenAlgSolver):
    def __init__(self, *args, **kwargs):
        BinaryGenAlgSolver.__init__(self, *args, **kwargs)
        ContinuousGenAlgSolver.__init__(self, *args, **kwargs)

    def fitness_function(self, chromosome):
        """
        Implements the logic that calculates the fitness
        measure of an individual.

        :param chromosome: chromosome of genes representing an individual
        :return: the fitness of the individual
        """
        pass

    def initialize_population(self):
        """
        Initializes the population of the problem

        :param pop_size: number of individuals in the population
        :param n_genes: number of genes representing the problem. In case of the binary
        solver, it represents the number of genes times the number of bits per gene
        :return: a numpy array with a randomized initialized population
        """
        pass

    def create_offspring(
        self, first_parent, sec_parent, crossover_pt, offspring_number
    ):
        """
        Creates an offspring from 2 parents. It uses the crossover point(s)
        to determine how to perform the crossover

        :param first_parent: first parent's chromosome
        :param sec_parent: second parent's chromosome
        :param crossover_pt: point(s) at which to perform the crossover
        :param offspring_number: whether it's the first or second offspring from a pair of parents.
        Important if there's different logic to be applied to each case.
        :return: the resulting offspring.
        """
        pass

    def mutate_population(self, population, n_mutations):
        """
        Mutates the population according to a given user defined rule.

        :param population: the population at a given iteration
        :param n_mutations: number of mutations to be performed. This number is 
        calculated according to mutation_rate, but can be adjusted as needed inside this function
        :return: the mutated population
        """
        pass

```

### Travelling Salesman Problem

One of the possible applications of genetic algorithms is to the 
[Travelling Salesman Problem](https://en.wikipedia.org/wiki/Travelling_salesman_problem). This problem is NP hard,
as the number of possible solutions grows with the factorial of the number of variables, and therefore, genetic algorithms 
are a good fit for approximating solutions to these problems.

As this particular problem has its own sets of constraints, a specific class adapted to this problem is provided
in `TravellingSalesmanProblemSolver`, which can be used out of the box to virtually
all problems of this kind. As a minimum input, this class requires the user to provide a 
[networkx](https://networkx.github.io/documentation/stable/) undirected graph containing all the nodes
representing the problem and with each node connected to every other node by edges with the respective 
associated cost (weight). To build this graph, one can use the `create_graph` method, as shown below:

```python
import turf

from geneal.applications.tsp.helpers import create_graph
from geneal.applications.tsp.examples.world_capitals import world_capitals_dict

G = create_graph(
    world_capitals_dict, # a python dictionary containing the nodes as keys
    turf.distance, # function to use to calculate distance between nodes
    lon=lambda x: x["CapitalLongitude"], # lambda function on how to retrieve the longitude
    lat=lambda x: x["CapitalLatitude"], # lambda function on how to retrieve the latitude
)

```

After having a built graph, one can pass it directly to `TravellingSalesmanProblemSolver`, and the number of genes
will be automatically retrieved from the number of nodes in the graph.

```python
from geneal.applications.tsp.travelling_salesman_problem import TravellingSalesmanProblemSolver
from geneal.applications.tsp.examples.world_capitals.graph import G

tsp_solver = TravellingSalesmanProblemSolver(graph=G)
```

Again, one can control the solver parameters as before, by providing them on the initialization:

```python
from geneal.applications.tsp.travelling_salesman_problem import TravellingSalesmanProblemSolver
from geneal.applications.tsp.examples.world_capitals.graph import G

tsp_solver = TravellingSalesmanProblemSolver(
    graph=G,
    pop_size=10, # population size (number of individuals)
    max_gen=500, # maximum number of generations
    mutation_rate=0.05, # mutation rate to apply to the population
    selection_rate=0.5, # percentage of the population to select for mating
    selection_strategy="tournament", # strategy to use for selection.
    mutation_strategy="random_inversion" # strategy to use for mutation. see below for more details.
)
```

**specific TSP parameters**

Being a particular use case for genetic algorithms, the Travelling Salesman Problem has also specific settings that
allow the user to control the convergence for each use case. One of such parameters is `mutation_strategy`, which 
can be one of the following:

- `2-opt`,
- `random_swap`,
- `random_inversion`,
- `random_gene_nearest_neighbour`,
- `worst_gene_random`,
- `worst_gene_nearest_neighbour`,
- `select_any_mutation`,

Below some brief explanation is given on each of the options:

**2-opt**

It performs a 2-opt mutation on a tour. It selects randomly 2 edges from the tour and combines the resulting sub tours
by swapping them. More details can be found [here](https://en.wikipedia.org/wiki/2-opt).

**random swap**

A random swap mutation will choose randomly 2 genes from a given tour and swap them around. This is the
kind of mutation that most closely resembles a typical genetic algorithm mutation.

**random inversion**

A random inversion swap will choose a consecutive subset from the tour and reverse it. The size of the subset is also
chosen randomly. 

**random gene nearest neighbour**

This is a knowledge-based mutation, where a randomly selected gene is shifted next to its closest neighbour. 
More details can be found in point [4.2.7](https://arxiv.org/pdf/1801.02827.pdf).

**worst gene random mutation**

This is again a knowledge-based mutation, where a randomly selected gene is swapped with the gene contributing 
most to the cost of the tour. More details can be found in point [4.2.3](https://arxiv.org/pdf/1801.02827.pdf).

**worst gene random mutation**

This is again a knowledge-based mutation, where gene contributing most to the total cost of the tour
is moved next to one of its neighbours. More details can be found in point [4.2.4](https://arxiv.org/pdf/1801.02827.pdf)


            

Raw data

            {
    "_id": null,
    "home_page": "https://github.com/diogomatoschaves/geneal",
    "name": "geneal",
    "maintainer": "",
    "docs_url": null,
    "requires_python": ">=3.8",
    "maintainer_email": "",
    "keywords": "genetic algorithms,ga,optimization,genetic programming",
    "author": "Diogo Matos Chaves",
    "author_email": "diogo_chaves@hotmail.com",
    "download_url": "https://files.pythonhosted.org/packages/51/84/2faaebb5538f1088c431f40d566f96668f74fd9390c152022e61daa5b498/geneal-0.7.1.tar.gz",
    "platform": null,
    "description": "# GeneAl\n\n![build_badge](https://github.com/diogomatoschaves/geneal/workflows/build/badge.svg)\n[![codecov](https://codecov.io/gh/diogomatoschaves/geneal/branch/master/graph/badge.svg)](https://codecov.io/gh/diogomatoschaves/geneal)\n[![PyPI version](https://badge.fury.io/py/geneal.svg)](https://badge.fury.io/py/geneal)\n\n`geneal` is a python library implementing genetic algorithms (GAs). It has functionality for both binary and continuous GA,\nas well as specific use case applications such as a solver for the\n[Travelling Salesman Problem](https://en.wikipedia.org/wiki/Travelling_salesman_problem). \n\n## Installation\n\n```\n$ pip install geneal\n```\n\n## Usage\n\n`geneal` provides 2 main GA solver classes, `BinaryGenAlgSolver` and `ContinuousGenAlgSolver` \nfor binary and continuous problem formulations respectively. The library is set up in such a way that all problems\nhave to be a maximization, and hence, the fitness functions need to be adjusted accordingly.\n\n### Binary GA\n\nThe binary GA class can be customized by the input variables provided on its initialization. \nThe minimum required arguments to provide at the initialization are the number of genes on each individual's\nchromosome, and the fitness function to be maximized. \n\nAn example is shown below.\n\n```python\n\nfrom geneal.genetic_algorithms import BinaryGenAlgSolver\nfrom geneal.applications.fitness_functions.binary import fitness_functions_binary\n\nsolver = BinaryGenAlgSolver(\n    n_genes=3, # number of variables defining the problem\n    fitness_function=fitness_functions_binary(1), # fitness function to be maximized\n)\n\nsolver.solve()\n\n```\n\nThe above call will perform the optimization with the default parameters, which will most likely have to be adjusted for\neach individual problem at hand. The algorithm parameters can be customized as shown below.\n\n```python\nfrom geneal.genetic_algorithms import BinaryGenAlgSolver\nfrom geneal.applications.fitness_functions.binary import fitness_functions_binary\n\nsolver = BinaryGenAlgSolver(\n    n_genes=3,\n    fitness_function=fitness_functions_binary(1), \n    n_bits=1, # number of bits describing each gene (variable)\n    pop_size=10, # population size (number of individuals)\n    max_gen=500, # maximum number of generations\n    mutation_rate=0.05, # mutation rate to apply to the population\n    selection_rate=0.5, # percentage of the population to select for mating\n    selection_strategy=\"roulette_wheel\", # strategy to use for selection. see below for more details\n    fitness_tolerance=(1E-4, 50)  # Loop will be exited if the best fitness value does not change more than\n                                  # 1E-4 for 50 generations\n)\n\nsolver.solve()\n\n```\n\n### Continuous GA\n\nFollowing a similar pattern as the binary GA solver, the parameters of the continuous GA can be adjusted at initialization.\nAs a bare minimum, the number of variables and the fitness function to maximize must be provided, as shown below.\n\n```python\n\nfrom geneal.genetic_algorithms import ContinuousGenAlgSolver\nfrom geneal.applications.fitness_functions.continuous import fitness_functions_continuous\n\nsolver = ContinuousGenAlgSolver(\n    n_genes=4, # number of variables defining the problem\n    fitness_function=fitness_functions_continuous(3), # fitness function to be maximized\n)\n\nsolver.solve()\n\n```\n\nIn order to customize the continuous GA solver further, more arguments can be passed at initialization.\n\n```python\n\nfrom geneal.genetic_algorithms import ContinuousGenAlgSolver\nfrom geneal.applications.fitness_functions.continuous import fitness_functions_continuous\n\nsolver = ContinuousGenAlgSolver(\n    n_genes=4,\n    fitness_function=fitness_functions_continuous(3),\n    pop_size=10, # population size (number of individuals)\n    max_gen=200, # maximum number of generations\n    mutation_rate=0.1, # mutation rate to apply to the population\n    selection_rate=0.6, # percentage of the population to select for mating\n    selection_strategy=\"roulette_wheel\", # strategy to use for selection. see below for more details\n    fitness_tolerance=(1E-5, 20)  # Loop will be exited if the best fitness value does not change more than\n                                  # 1E-5 for 20 generations\n)\n\nsolver.solve()\n\n```\n\nA notable difference to the binary GA solver is the fact that we can customize the input space of the problem\nby defining if the problem is of type `int` or `float`, and defining an overall minimum and maximum values for each\nvariable (or for all at once).\n\n```python\n\nfrom geneal.genetic_algorithms import ContinuousGenAlgSolver\nfrom geneal.applications.fitness_functions.continuous import fitness_functions_continuous\n\nsolver = ContinuousGenAlgSolver(\n    n_genes=4, \n    fitness_function=fitness_functions_continuous(3),\n    pop_size=10,\n    max_gen=200,\n    mutation_rate=0.1,\n    selection_rate=0.6,\n    selection_strategy=\"roulette_wheel\",\n    variables_type=float, # Defines the possible values as float numbers\n    variables_limits=(-10, 10) # Defines the limits of all variables between -10 and 10. \n                               # Alternatively one can pass an array of tuples defining the limits\n                               # for each variable: [(-10, 10), (0, 5), (0, 5), (-20, 20)]\n)\n\nsolver.solve()\n\n```\n\n### selection strategy\n\nIt is possible to choose the selection strategy that the algorithm will use to select the parents that will \nbe used for generating new offsprings for the next generation. The options are:\n\n- `roulette_wheel`\n- `random`\n- `two_by_two`\n- `tournament`\n\n**roulette wheel**\n\nThis selection strategy orders the individuals in the selection pool by probability, with the fittest individuals\nhaving higher odds of being selected. \n\n**random**\n\nThis selection procedure selects randomly individuals from the selection pool, following in essence a similar procedure\nas the roulette wheel, but with the same probabilities for each individual.\n\n**two_by_two**\n\nThis strategy groups the individuals in the mating pool 2 by 2, from top to bottom.\n\n**tournament**\n\nThis strategy will select 3 individuals candidates for each parent position, which are then sorted by their fitness\nand from which the fittest one is selected.\n\n## Specific Applications\n\nIn the real world, there's usually the need to adapt a genetic algorithm implementation to each individual problem.\nThus, `geneal` offers the user a level of customization that aims to be both versatile and relatively simple. For that,\none just has to create a class which inherits from the `BinaryGenAlgSolver` or `ContinuousGenAlgSolver`\nbase classes, and on which some overriding methods are defined. This allows the user to control the main steps of a GA:\n\n- fitness function\n- population initialization\n- mating between individuals (creation of offsprings)\n- mutation of the population\n \nA boilerplate template of such a class is shown below:\n\n```python\nfrom geneal.genetic_algorithms import ContinuousGenAlgSolver, BinaryGenAlgSolver\n\n\nclass TemplateChildClass(ContinuousGenAlgSolver, BinaryGenAlgSolver):\n    def __init__(self, *args, **kwargs):\n        BinaryGenAlgSolver.__init__(self, *args, **kwargs)\n        ContinuousGenAlgSolver.__init__(self, *args, **kwargs)\n\n    def fitness_function(self, chromosome):\n        \"\"\"\n        Implements the logic that calculates the fitness\n        measure of an individual.\n\n        :param chromosome: chromosome of genes representing an individual\n        :return: the fitness of the individual\n        \"\"\"\n        pass\n\n    def initialize_population(self):\n        \"\"\"\n        Initializes the population of the problem\n\n        :param pop_size: number of individuals in the population\n        :param n_genes: number of genes representing the problem. In case of the binary\n        solver, it represents the number of genes times the number of bits per gene\n        :return: a numpy array with a randomized initialized population\n        \"\"\"\n        pass\n\n    def create_offspring(\n        self, first_parent, sec_parent, crossover_pt, offspring_number\n    ):\n        \"\"\"\n        Creates an offspring from 2 parents. It uses the crossover point(s)\n        to determine how to perform the crossover\n\n        :param first_parent: first parent's chromosome\n        :param sec_parent: second parent's chromosome\n        :param crossover_pt: point(s) at which to perform the crossover\n        :param offspring_number: whether it's the first or second offspring from a pair of parents.\n        Important if there's different logic to be applied to each case.\n        :return: the resulting offspring.\n        \"\"\"\n        pass\n\n    def mutate_population(self, population, n_mutations):\n        \"\"\"\n        Mutates the population according to a given user defined rule.\n\n        :param population: the population at a given iteration\n        :param n_mutations: number of mutations to be performed. This number is \n        calculated according to mutation_rate, but can be adjusted as needed inside this function\n        :return: the mutated population\n        \"\"\"\n        pass\n\n```\n\n### Travelling Salesman Problem\n\nOne of the possible applications of genetic algorithms is to the \n[Travelling Salesman Problem](https://en.wikipedia.org/wiki/Travelling_salesman_problem). This problem is NP hard,\nas the number of possible solutions grows with the factorial of the number of variables, and therefore, genetic algorithms \nare a good fit for approximating solutions to these problems.\n\nAs this particular problem has its own sets of constraints, a specific class adapted to this problem is provided\nin `TravellingSalesmanProblemSolver`, which can be used out of the box to virtually\nall problems of this kind. As a minimum input, this class requires the user to provide a \n[networkx](https://networkx.github.io/documentation/stable/) undirected graph containing all the nodes\nrepresenting the problem and with each node connected to every other node by edges with the respective \nassociated cost (weight). To build this graph, one can use the `create_graph` method, as shown below:\n\n```python\nimport turf\n\nfrom geneal.applications.tsp.helpers import create_graph\nfrom geneal.applications.tsp.examples.world_capitals import world_capitals_dict\n\nG = create_graph(\n    world_capitals_dict, # a python dictionary containing the nodes as keys\n    turf.distance, # function to use to calculate distance between nodes\n    lon=lambda x: x[\"CapitalLongitude\"], # lambda function on how to retrieve the longitude\n    lat=lambda x: x[\"CapitalLatitude\"], # lambda function on how to retrieve the latitude\n)\n\n```\n\nAfter having a built graph, one can pass it directly to `TravellingSalesmanProblemSolver`, and the number of genes\nwill be automatically retrieved from the number of nodes in the graph.\n\n```python\nfrom geneal.applications.tsp.travelling_salesman_problem import TravellingSalesmanProblemSolver\nfrom geneal.applications.tsp.examples.world_capitals.graph import G\n\ntsp_solver = TravellingSalesmanProblemSolver(graph=G)\n```\n\nAgain, one can control the solver parameters as before, by providing them on the initialization:\n\n```python\nfrom geneal.applications.tsp.travelling_salesman_problem import TravellingSalesmanProblemSolver\nfrom geneal.applications.tsp.examples.world_capitals.graph import G\n\ntsp_solver = TravellingSalesmanProblemSolver(\n    graph=G,\n    pop_size=10, # population size (number of individuals)\n    max_gen=500, # maximum number of generations\n    mutation_rate=0.05, # mutation rate to apply to the population\n    selection_rate=0.5, # percentage of the population to select for mating\n    selection_strategy=\"tournament\", # strategy to use for selection.\n    mutation_strategy=\"random_inversion\" # strategy to use for mutation. see below for more details.\n)\n```\n\n**specific TSP parameters**\n\nBeing a particular use case for genetic algorithms, the Travelling Salesman Problem has also specific settings that\nallow the user to control the convergence for each use case. One of such parameters is `mutation_strategy`, which \ncan be one of the following:\n\n- `2-opt`,\n- `random_swap`,\n- `random_inversion`,\n- `random_gene_nearest_neighbour`,\n- `worst_gene_random`,\n- `worst_gene_nearest_neighbour`,\n- `select_any_mutation`,\n\nBelow some brief explanation is given on each of the options:\n\n**2-opt**\n\nIt performs a 2-opt mutation on a tour. It selects randomly 2 edges from the tour and combines the resulting sub tours\nby swapping them. More details can be found [here](https://en.wikipedia.org/wiki/2-opt).\n\n**random swap**\n\nA random swap mutation will choose randomly 2 genes from a given tour and swap them around. This is the\nkind of mutation that most closely resembles a typical genetic algorithm mutation.\n\n**random inversion**\n\nA random inversion swap will choose a consecutive subset from the tour and reverse it. The size of the subset is also\nchosen randomly. \n\n**random gene nearest neighbour**\n\nThis is a knowledge-based mutation, where a randomly selected gene is shifted next to its closest neighbour. \nMore details can be found in point [4.2.7](https://arxiv.org/pdf/1801.02827.pdf).\n\n**worst gene random mutation**\n\nThis is again a knowledge-based mutation, where a randomly selected gene is swapped with the gene contributing \nmost to the cost of the tour. More details can be found in point [4.2.3](https://arxiv.org/pdf/1801.02827.pdf).\n\n**worst gene random mutation**\n\nThis is again a knowledge-based mutation, where gene contributing most to the total cost of the tour\nis moved next to one of its neighbours. More details can be found in point [4.2.4](https://arxiv.org/pdf/1801.02827.pdf)\n\n",
    "bugtrack_url": null,
    "license": "MIT",
    "summary": "Python Genetic Algorithm library",
    "version": "0.7.1",
    "project_urls": {
        "Homepage": "https://github.com/diogomatoschaves/geneal",
        "Repository": "https://github.com/diogomatoschaves/geneal"
    },
    "split_keywords": [
        "genetic algorithms",
        "ga",
        "optimization",
        "genetic programming"
    ],
    "urls": [
        {
            "comment_text": "",
            "digests": {
                "blake2b_256": "e4e67afe76f18ad77de67377706d1c28947996355c00b510c0c3c072c77a9726",
                "md5": "af1e4eabb3137716f8309dbb77799d48",
                "sha256": "c83016a5a98d12e00a8ef2f9eda59ad518fe394ac01ae9e0c448e7da54c90342"
            },
            "downloads": -1,
            "filename": "geneal-0.7.1-py3-none-any.whl",
            "has_sig": false,
            "md5_digest": "af1e4eabb3137716f8309dbb77799d48",
            "packagetype": "bdist_wheel",
            "python_version": "py3",
            "requires_python": ">=3.8",
            "size": 27989,
            "upload_time": "2024-02-22T02:31:16",
            "upload_time_iso_8601": "2024-02-22T02:31:16.020574Z",
            "url": "https://files.pythonhosted.org/packages/e4/e6/7afe76f18ad77de67377706d1c28947996355c00b510c0c3c072c77a9726/geneal-0.7.1-py3-none-any.whl",
            "yanked": false,
            "yanked_reason": null
        },
        {
            "comment_text": "",
            "digests": {
                "blake2b_256": "51842faaebb5538f1088c431f40d566f96668f74fd9390c152022e61daa5b498",
                "md5": "dca5c86ab9becc809a6d2bc595530e1a",
                "sha256": "77c167be0fbb8d03b7dd36c18ddd1b87061c656897a6f1907bf16ba6b218f837"
            },
            "downloads": -1,
            "filename": "geneal-0.7.1.tar.gz",
            "has_sig": false,
            "md5_digest": "dca5c86ab9becc809a6d2bc595530e1a",
            "packagetype": "sdist",
            "python_version": "source",
            "requires_python": ">=3.8",
            "size": 21223,
            "upload_time": "2024-02-22T02:31:17",
            "upload_time_iso_8601": "2024-02-22T02:31:17.856610Z",
            "url": "https://files.pythonhosted.org/packages/51/84/2faaebb5538f1088c431f40d566f96668f74fd9390c152022e61daa5b498/geneal-0.7.1.tar.gz",
            "yanked": false,
            "yanked_reason": null
        }
    ],
    "upload_time": "2024-02-22 02:31:17",
    "github": true,
    "gitlab": false,
    "bitbucket": false,
    "codeberg": false,
    "github_user": "diogomatoschaves",
    "github_project": "geneal",
    "travis_ci": false,
    "coveralls": false,
    "github_actions": true,
    "lcname": "geneal"
}
        
Elapsed time: 0.18739s