Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 11 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -15,3 +15,14 @@ __pycache__/
# =============================================================================
docs/build/
.venv-docs/

# =============================================================================
# Local virtual environment (setup_venv.sh).
# =============================================================================
.venv/

# =============================================================================
# IDE settings: JetBrains (PyCharm, IntelliJ, etc.) workspace files.
# These are personal to each developer and should not be committed.
# =============================================================================
.idea/
20 changes: 2 additions & 18 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,12 @@

[PyGAD](https://pypi.org/project/pygad) is an open-source easy-to-use Python 3 library for building the genetic algorithm and optimizing machine learning algorithms. It supports Keras and PyTorch. PyGAD supports optimizing both single-objective and multi-objective problems.

> Try the [Optimization Gadget](https://optimgadget.com), a free cloud-based tool powered by PyGAD. It makes optimization easier by reducing or removing the need for coding, and it shows helpful visualizations.
> Try [Vilvik](https://vilvik.com), a free cloud-based tool powered by PyGAD. It makes optimization easier by reducing or removing the need for coding, and it shows helpful visualizations.

Read the [PyGAD documentation](https://pygad.readthedocs.io/en/latest).

[![PyPI Downloads](https://pepy.tech/badge/pygad)](https://pepy.tech/project/pygad) [![Conda Downloads](https://img.shields.io/conda/dn/conda-forge/pygad.svg?label=Conda%20Downloads)](
https://anaconda.org/conda-forge/PyGAD) [![PyPI version](https://badge.fury.io/py/pygad.svg)](https://badge.fury.io/py/pygad)![Docs](https://readthedocs.org/projects/pygad/badge)[![PyGAD PyTest / Python 3.13](https://github.com/ahmedfgad/GeneticAlgorithmPython/actions/workflows/main_py313.yml/badge.svg)](https://github.com/ahmedfgad/GeneticAlgorithmPython/actions/workflows/main_py313.yml) [![PyGAD PyTest / Python 3.12](https://github.com/ahmedfgad/GeneticAlgorithmPython/actions/workflows/main_py312.yml/badge.svg)](https://github.com/ahmedfgad/GeneticAlgorithmPython/actions/workflows/main_py312.yml) [![PyGAD PyTest / Python 3.11](https://github.com/ahmedfgad/GeneticAlgorithmPython/actions/workflows/main_py311.yml/badge.svg)](https://github.com/ahmedfgad/GeneticAlgorithmPython/actions/workflows/main_py311.yml) [![PyGAD PyTest / Python 3.10](https://github.com/ahmedfgad/GeneticAlgorithmPython/actions/workflows/main_py310.yml/badge.svg)](https://github.com/ahmedfgad/GeneticAlgorithmPython/actions/workflows/main_py310.yml) [![PyGAD PyTest / Python 3.9](https://github.com/ahmedfgad/GeneticAlgorithmPython/actions/workflows/main_py39.yml/badge.svg)](https://github.com/ahmedfgad/GeneticAlgorithmPython/actions/workflows/main_py39.yml) [![PyGAD PyTest / Python 3.8](https://github.com/ahmedfgad/GeneticAlgorithmPython/actions/workflows/main_py38.yml/badge.svg)](https://github.com/ahmedfgad/GeneticAlgorithmPython/actions/workflows/main_py38.yml) [![License](https://img.shields.io/badge/License-BSD_3--Clause-blue.svg)](https://opensource.org/licenses/BSD-3-Clause) [![Translation](https://hosted.weblate.org/widgets/weblate/-/svg-badge.svg)](https://hosted.weblate.org/engage/weblate/) [![REUSE](https://api.reuse.software/badge/github.com/WeblateOrg/weblate)](https://api.reuse.software/info/github.com/WeblateOrg/weblate) [![Stack Overflow](https://img.shields.io/badge/stackoverflow-Ask%20questions-blue.svg)](
https://anaconda.org/conda-forge/PyGAD) [![PyPI version](https://badge.fury.io/py/pygad.svg)](https://badge.fury.io/py/pygad)![Docs](https://readthedocs.org/projects/pygad/badge)[![PyGAD PyTest / Python 3.13](https://github.com/ahmedfgad/GeneticAlgorithmPython/actions/workflows/main.yml/badge.svg)](https://github.com/ahmedfgad/GeneticAlgorithmPython/actions/workflows/main.yml) [![PyGAD PyTest / Python 3.12](https://github.com/ahmedfgad/GeneticAlgorithmPython/actions/workflows/release.yml/badge.svg)](https://github.com/ahmedfgad/GeneticAlgorithmPython/actions/workflows/release.yml) [![PyGAD PyTest / Python 3.11](https://github.com/ahmedfgad/GeneticAlgorithmPython/actions/workflows/scorecard.yml/badge.svg)](https://github.com/ahmedfgad/GeneticAlgorithmPython/actions/workflows/scorecard.yml) [![License](https://img.shields.io/badge/License-BSD_3--Clause-blue.svg)](https://opensource.org/licenses/BSD-3-Clause) [![Translation](https://hosted.weblate.org/widgets/weblate/-/svg-badge.svg)](https://hosted.weblate.org/engage/weblate/) [![REUSE](https://api.reuse.software/badge/github.com/WeblateOrg/weblate)](https://api.reuse.software/info/github.com/WeblateOrg/weblate) [![Stack Overflow](https://img.shields.io/badge/stackoverflow-Ask%20questions-blue.svg)](
https://stackoverflow.com/questions/tagged/pygad) [![OpenSSF Scorecard](https://api.securityscorecards.dev/projects/github.com/ahmedfgad/GeneticAlgorithmPython/badge)](https://securityscorecards.dev/viewer/?uri=github.com/ahmedfgad/GeneticAlgorithmPython) [![DOI](https://zenodo.org/badge/DOI/10.1007/s11042-023-17167-y.svg)](https://doi.org/10.1007/s11042-023-17167-y)

![PYGAD-LOGO](https://user-images.githubusercontent.com/16560492/101267295-c74c0180-375f-11eb-9ad0-f8e37bd796ce.png)
Expand All @@ -18,7 +18,6 @@ The library is under active development and more features are added regularly. I

# Donation

* [Credit/Debit Card](https://donate.stripe.com/eVa5kO866elKgM0144): https://donate.stripe.com/eVa5kO866elKgM0144
* [Open Collective](https://opencollective.com/pygad): [opencollective.com/pygad](https://opencollective.com/pygad)
* PayPal: Use either this link: [paypal.me/ahmedfgad](https://paypal.me/ahmedfgad) or the e-mail address ahmed.f.gad@gmail.com
* Interac e-Transfer: Use e-mail address ahmed.f.gad@gmail.com
Expand All @@ -45,18 +44,6 @@ pip install pygad[deep_learning]

To get started with PyGAD, read the documentation at [Read the Docs](https://pygad.readthedocs.io).

# PyGAD Source Code

The source code of the PyGAD modules is in the following GitHub projects:

- [pygad](https://github.com/ahmedfgad/GeneticAlgorithmPython): (https://github.com/ahmedfgad/GeneticAlgorithmPython)
- [pygad.nn](https://github.com/ahmedfgad/NumPyANN): https://github.com/ahmedfgad/NumPyANN
- [pygad.gann](https://github.com/ahmedfgad/NeuralGenetic): https://github.com/ahmedfgad/NeuralGenetic
- [pygad.cnn](https://github.com/ahmedfgad/NumPyCNN): https://github.com/ahmedfgad/NumPyCNN
- [pygad.gacnn](https://github.com/ahmedfgad/CNNGenetic): https://github.com/ahmedfgad/CNNGenetic
- [pygad.kerasga](https://github.com/ahmedfgad/KerasGA): https://github.com/ahmedfgad/KerasGA
- [pygad.torchga](https://github.com/ahmedfgad/TorchGA): https://github.com/ahmedfgad/TorchGA

# PyGAD Documentation

The PyGAD documentation is available at [Read the Docs](https://pygad.readthedocs.io) at this link: https://pygad.readthedocs.io. It explains the modules supported by PyGAD and all its classes, methods, attributes, and functions. For each module, several examples are given.
Expand Down Expand Up @@ -304,7 +291,4 @@ If you used PyGAD, please consider adding a citation to the following paper abou

* E-mail: ahmed.f.gad@gmail.com
* [LinkedIn](https://www.linkedin.com/in/ahmedfgad)
* [Paperspace](https://blog.paperspace.com/author/ahmed)
* [KDnuggets](https://kdnuggets.com/author/ahmed-gad)
* [TowardsDataScience](https://towardsdatascience.com/@ahmedfgad)
* [GitHub](https://github.com/ahmedfgad)
163 changes: 163 additions & 0 deletions docs/source/benchmarks.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,163 @@
# Benchmark Problems

PyGAD bundles common benchmark problems under `pygad.benchmarks`. Each problem is a class callable with `(ga, solution, sol_idx)` and returns a fitness in PyGAD's maximisation format. Minimisation values are negated.

Class attributes for setting up the GA:

- `num_genes`: number of decision variables.
- `num_objectives`: number of objectives (`1` for single-objective).
- `bounds`: `(low, high)` tuple of variable bounds.

ZDT classes also have a `pareto_front(num_points)` method that returns true-front reference points. Pass these to the IGD or GD indicators as `reference_front`.

A runnable example per benchmark lives under `examples/benchmarks/`.

## Single-Objective Problems

Available in `pygad.benchmarks.classic`:

| Class | Global minimum | Bounds |
|---|---|---|
| `Sphere` | f(0, ..., 0) = 0 | `(-5.12, 5.12)` |
| `Rastrigin` | f(0, ..., 0) = 0 | `(-5.12, 5.12)` |
| `Rosenbrock` | f(1, ..., 1) = 0 | `(-5.0, 10.0)` |
| `Griewank` | f(0, ..., 0) = 0 | `(-600.0, 600.0)` |
| `Schwefel` | f(420.97, ..., 420.97) ≈ 0 | `(-500.0, 500.0)` |
| `Ackley` | f(0, ..., 0) = 0 | `(-32.768, 32.768)` |
| `Himmelblau` | four equal minima at f = 0 (2D only) | `(-5.0, 5.0)` |

## Multi-Objective Problems (ZDT family)

In `pygad.benchmarks.zdt`. Two objectives, variables in `[0, 1]` (ZDT4 uses `[-5, 5]` for the rest).

| Class | Pareto front shape |
|---|---|
| `ZDT1` | convex |
| `ZDT2` | non-convex |
| `ZDT3` | disconnected (five pieces) |
| `ZDT4` | convex, many local minima in the search space |
| `ZDT6` | non-uniform |

## Many-Objective Problems (DTLZ family)

In `pygad.benchmarks.dtlz`. Any number of objectives `M`. Decision variables: `M + k - 1`, where `k` is the distance-variable count.

| Class | Default M | Pareto front shape |
|---|---|---|
| `DTLZ1` | 3 | linear hyperplane (`sum(f_i) = 0.5`) |
| `DTLZ2` | 3 | unit sphere first orthant |
| `DTLZ3` | 3 | unit sphere with hard multimodal g-function |
| `DTLZ4` | 3 | unit sphere with strong bias toward one corner |

## Combinatorial Problems

Two combinatorial benchmarks: 0/1 `Knapsack` and `TSP`.

### Knapsack

In `pygad.benchmarks.knapsack`. `Knapsack` takes three arguments: 1D arrays of `weights` and `values`, and a numeric `capacity`. A solution is a binary vector (1 = pick the item). Fitness is the total value within capacity, or a negative penalty scaled by the overweight amount.

Class attributes `gene_space=[0, 1]` and `gene_type=int` plug into PyGAD as is:

```python
import pygad
from pygad.benchmarks.knapsack import Knapsack

problem = Knapsack(weights=[2, 3, 4, 5],
values=[3, 4, 5, 6],
capacity=5)

ga = pygad.GA(
num_generations=50,
num_parents_mating=10,
fitness_func=problem,
sol_per_pop=30,
num_genes=problem.num_genes,
gene_space=problem.gene_space,
gene_type=problem.gene_type,
)
ga.run()
```

### Travelling Salesman Problem

In `pygad.benchmarks.tsp`. Build `TSP` from either a 2D `coordinates` array or a square `distance_matrix`. A solution is a permutation of city indices and the fitness is the negative tour length (the tour closes back to the start). Non-permutation candidates get a large negative penalty.

Class attributes `gene_space=list(range(num_cities))`, `gene_type=int`, and `allow_duplicate_genes=False` keep the permutation constraint:

```python
import pygad
from pygad.benchmarks.tsp import TSP

problem = TSP(coordinates=[[0.0, 0.0],
[1.0, 0.0],
[1.0, 1.0],
[0.0, 1.0]])

ga = pygad.GA(
num_generations=200,
num_parents_mating=10,
fitness_func=problem,
sol_per_pop=30,
num_genes=problem.num_genes,
gene_space=problem.gene_space,
gene_type=problem.gene_type,
allow_duplicate_genes=problem.allow_duplicate_genes,
)
ga.run()
```

## Example: SOO

```python
import pygad
from pygad.benchmarks.classic import Sphere

problem = Sphere(num_genes=10)

ga = pygad.GA(
num_generations=100,
num_parents_mating=10,
fitness_func=problem,
sol_per_pop=20,
num_genes=problem.num_genes,
init_range_low=problem.bounds[0],
init_range_high=problem.bounds[1],
crossover_type='sbx',
sbx_crossover_eta=30,
mutation_type='polynomial',
polynomial_mutation_eta=20,
)
ga.run()
```

## Example: MOO

```python
import pygad
from pygad.benchmarks.zdt import ZDT1
from pygad.utils.quality_indicators import inverted_generational_distance

problem = ZDT1(num_genes=10)

ga = pygad.GA(
num_generations=200,
num_parents_mating=20,
fitness_func=problem,
sol_per_pop=30,
num_genes=problem.num_genes,
init_range_low=problem.bounds[0],
init_range_high=problem.bounds[1],
parent_selection_type='nsga2',
crossover_type='sbx',
sbx_crossover_eta=30,
mutation_type='polynomial',
polynomial_mutation_eta=20,
)
ga.run()

# IGD against the true front.
true_front = problem.pareto_front(num_points=100)
igd = inverted_generational_distance(ga.last_generation_fitness, true_front)
print(f'IGD = {igd}')
```
Binary file added docs/source/figures/plot_fitness.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added docs/source/figures/plot_fitness_band.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added docs/source/figures/plot_genes.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added docs/source/figures/plot_new_solution_rate.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added docs/source/figures/plot_pareto_front_heatmap.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added docs/source/figures/plot_pareto_front_pcp.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added docs/source/figures/plot_population_diversity.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
13 changes: 13 additions & 0 deletions docs/source/gene_values.md
Original file line number Diff line number Diff line change
Expand Up @@ -174,6 +174,19 @@ lambda solution,values: [val for val in values if val<5]

The first parameter is the solution where the target gene exists. It is passed just in case you would like to compare the gene value with other genes. The second parameter is the list of candidate values for the gene. The objective of the lambda function is to filter the values and return only the valid values that are less than 5.

#### What does the `solution` parameter hold?

The `solution` passed to the callable is **not** a fixed snapshot taken before the operation started. PyGAD processes the genes one at a time and writes each gene's chosen value back into the solution *in place* before moving on to the next gene. So the `solution` is updated incrementally, and the state it is in when a given gene's constraint runs depends on which genes were already processed in the current step:

* The genes that were **already processed** in the current step hold their **updated** values (i.e. the value just selected for that gene).
* The genes that were **not processed yet** still hold their **previous** values: the values inherited from crossover (when mutating offspring) or the values originally sampled (when creating the initial population).

When the genes are processed in index order (this is the case while creating the initial population and when using probability-based mutation via `mutation_probability`), this means that for the gene at index `i`, the entries `solution[:i]` already hold their updated values while `solution[i:]` still hold their previous values.

This is exactly why dependent genes must be ordered so that a gene appears **after** the genes it depends on: by the time a later gene's constraint runs, the earlier genes it reads have already been finalized. See the note at the end of this section.

> **Note:** The callable receives a copy of the solution, so modifying it inside the callable has no effect on the actual solution. Only the values returned from the callable are used.

A lambda function is used in this case but we can use a regular function:

```python
Expand Down
2 changes: 1 addition & 1 deletion docs/source/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -144,7 +144,7 @@ There is much more you can do with PyGAD. Read the documentation to explore its
6. The `kerasga` module trains [Keras](https://keras.io) models using the genetic algorithm.
7. The `torchga` module trains [PyTorch](https://pytorch.org) models using the genetic algorithm.
8. The `visualize` module visualizes the results.
9. The `utils` module holds the operators (crossover, mutation, and parent selection) and the NSGA-II code.
9. The `utils` module holds the operators (crossover, mutation, and parent selection) and the NSGA-II and NSGA-III code.
10. The `helper` module has some helper functions.

The documentation explains these modules.
Expand Down
Loading