From 4a80e07fe35e6b71905e4e5d18aeb07e6bed4e43 Mon Sep 17 00:00:00 2001 From: Ahmed Gad Date: Tue, 21 Apr 2026 06:27:09 -0400 Subject: [PATCH 1/2] gene_space example --- examples/example_gene_space.py | 88 ++++++++++++++++++++++++++++++++++ 1 file changed, 88 insertions(+) create mode 100644 examples/example_gene_space.py diff --git a/examples/example_gene_space.py b/examples/example_gene_space.py new file mode 100644 index 0000000..2c27590 --- /dev/null +++ b/examples/example_gene_space.py @@ -0,0 +1,88 @@ +""" +PyGAD Example: Using the gene_space Parameter +============================================== + +The `gene_space` parameter controls the set of valid values that each gene +can take. This example demonstrates all major forms of `gene_space`. + +Documentation: + https://pygad.readthedocs.io/en/latest/pygad_more.html#more-about-the-gene-space-parameter + +Dependencies: + pip install pygad numpy +""" + +import numpy +import pygad + + +def fitness_func(ga_instance, solution, solution_idx): + """Return the sum of all gene values as the fitness score.""" + return numpy.sum(solution) + + +# =========================================================================== +# 1. Single flat list or NumPy array (shared across all genes) +# =========================================================================== +# Every gene independently draws its value from the same list. +# Using None in the list means that gene value is unconstrained (random float). + +# gene_space = [1, 2, 3, 4, 5] +# gene_space = [1, 2, None] +# gene_space = numpy.array([10, 20, 30, 40, 50]) + +# =========================================================================== +# 2. A range or NumPy sequence (shared across all genes) +# =========================================================================== + +# gene_space = range(1, 11) # integers 1 through 10 +# gene_space = numpy.arange(0.0, 1.1, 0.1) # [0.0, 0.1, ..., 1.0] +# gene_space = numpy.linspace(1, 5, num=9) # 9 evenly-spaced floats in [1, 5] + +# =========================================================================== +# 3. Per-gene list (each gene has its own independent space) +# =========================================================================== +# When gene_space is a list with length equal to num_genes, each element +# defines the space for the corresponding gene. Elements can be a list, +# a NumPy array, a range, or None (unconstrained). + +# gene_space = [range(1, 5), range(5, 11), range(10, 21)] +# gene_space = [[1, 2, 3], None, range(10, 21)] +# gene_space = [[1, 2, 3], numpy.linspace(5, 10, num=6), [10, 12, 14, 16, 18, 20]] + +# =========================================================================== +# 4. Dictionary – continuous range (shared across all genes) +# =========================================================================== +# A dict with "low" and "high" makes every gene sample from a continuous +# uniform distribution. An optional "step" key discretises the range. + +# gene_space = {"low": 0.0, "high": 10.0} +# gene_space = {"low": 0.0, "high": 10.0, "step": 0.5} + +# =========================================================================== +# 5. Per-gene list of dictionaries (each gene has its own continuous range) +# =========================================================================== +# Each gene gets its own dict-based range. This is the most expressive form +# and is useful when each gene lives in a different numerical domain. + +gene_space = [ + [1, 2, 3, 4, 5], # gene 0 + {"low": 5, "high": 10}, # gene 1 + range(10, 15), # gene 2 + None, # gene 3 +] + +ga_instance = pygad.GA( + num_generations=50, + num_parents_mating=4, + sol_per_pop=8, + num_genes=4, + fitness_func=fitness_func, + gene_space=gene_space, +) + +ga_instance.run() + +best_solution, best_fitness, _ = ga_instance.best_solution() +print(f"Best solution : {best_solution}") +print(f"Best fitness : {best_fitness:.4f}") \ No newline at end of file From 0246a8057c87e2aee7df0e1921406d88d703da6b Mon Sep 17 00:00:00 2001 From: Ahmed Gad Date: Wed, 29 Apr 2026 17:19:39 -0400 Subject: [PATCH 2/2] Fix a bug in Matplotlib parameter --- .gitignore | 10 ++++++++++ pygad/visualize/plot.py | 16 +++++++++++++--- 2 files changed, 23 insertions(+), 3 deletions(-) create mode 100644 .gitignore diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..4a84706 --- /dev/null +++ b/.gitignore @@ -0,0 +1,10 @@ +# ============================================================================= +# Python Compiled Files: Machine-generated bytecode that speeds up execution. +# These vary by OS and Python version, so they should never be committed. +# ============================================================================= +# Folders containing .pyc files (e.g., views.cpython-312.pyc) +# Matches .pyc (compiled), .pyo (optimized), and .pyd (Windows DLLs) +# Compiled Java class files generated by Jython +__pycache__/ +*.py[cod] +*$py.class diff --git a/pygad/visualize/plot.py b/pygad/visualize/plot.py index b1aa9aa..3341c84 100644 --- a/pygad/visualize/plot.py +++ b/pygad/visualize/plot.py @@ -322,9 +322,19 @@ def plot_genes(self, # Create an axes instance ax = fig.add_subplot(111) - boxeplots = ax.boxplot(solutions_to_plot, - labels=range(self.num_genes), - patch_artist=True) + # Matplotlib 3.9 renamed the boxplot `labels=` kwarg to + # `tick_labels=` and will drop the old name in 3.11. Use whichever + # name this matplotlib supports so we work on either side of the + # rename without forcing users to upgrade matplotlib. + import inspect + _tick_kw = ( + "tick_labels" + if "tick_labels" in inspect.signature(ax.boxplot).parameters + else "labels" + ) + boxeplots = ax.boxplot(solutions_to_plot, + patch_artist=True, + **{_tick_kw: range(self.num_genes)}) # adding horizontal grid lines ax.yaxis.grid(True)