Skip to content

Commit 8cbb307

Browse files
committed
Update docs and NSGA edits
1 parent 655fd15 commit 8cbb307

File tree

8 files changed

+2506
-2312
lines changed

8 files changed

+2506
-2312
lines changed

docs/source/helper.rst

+20-2
Original file line numberDiff line numberDiff line change
@@ -7,5 +7,23 @@ This section of the PyGAD's library documentation discusses the
77
**pygad.helper** module.
88

99
Yet, this module has a submodule called ``unique`` that has a class
10-
named ``Unique`` with some helper methods. Such methods help to check
11-
and fix duplicate values in the genes of a solution.
10+
named ``Unique`` with the following helper methods. Such methods help to
11+
check and fix duplicate values in the genes of a solution.
12+
13+
- ``solve_duplicate_genes_randomly()``: Solves the duplicates in a
14+
solution by randomly selecting new values for the duplicating genes.
15+
16+
- ``solve_duplicate_genes_by_space()``: Solves the duplicates in a
17+
solution by selecting values for the duplicating genes from the gene
18+
space
19+
20+
- ``unique_int_gene_from_range()``: Finds a unique integer value for
21+
the gene.
22+
23+
- ``unique_genes_by_space()``: Loops through all the duplicating genes
24+
to find unique values that from their gene spaces to solve the
25+
duplicates. For each duplicating gene, a call to the
26+
``unique_gene_by_space()`` is made.
27+
28+
- ``unique_gene_by_space()``: Returns a unique gene value for a single
29+
gene based on its value space to solve the duplicates.

docs/source/pygad.rst

+104-101
Original file line numberDiff line numberDiff line change
@@ -595,24 +595,6 @@ Other Methods
595595
- ``adaptive_mutation_population_fitness()``: Returns the average
596596
fitness value used in the adaptive mutation to filter the solutions.
597597

598-
- ``solve_duplicate_genes_randomly()``: Solves the duplicates in a
599-
solution by randomly selecting new values for the duplicating genes.
600-
601-
- ``solve_duplicate_genes_by_space()``: Solves the duplicates in a
602-
solution by selecting values for the duplicating genes from the gene
603-
space
604-
605-
- ``unique_int_gene_from_range()``: Finds a unique integer value for
606-
the gene.
607-
608-
- ``unique_genes_by_space()``: Loops through all the duplicating genes
609-
to find unique values that from their gene spaces to solve the
610-
duplicates. For each duplicating gene, a call to the
611-
``unique_gene_by_space()`` is made.
612-
613-
- ``unique_gene_by_space()``: Returns a unique gene value for a single
614-
gene based on its value space to solve the duplicates.
615-
616598
- ``summary()``: Prints a Keras-like summary of the PyGAD lifecycle.
617599
This helps to have an overview of the architecture. Supported in
618600
`PyGAD
@@ -961,31 +943,6 @@ generation.
961943
It works only after completing at least 1 generation. If no generation
962944
is completed (at least 1), an exception is raised.
963945

964-
This method accepts the following parameters:
965-
966-
1. ``title``: Title of the figure.
967-
968-
2. ``xlabel``: X-axis label.
969-
970-
3. ``ylabel``: Y-axis label.
971-
972-
4. ``linewidth``: Line width of the plot. Defaults to ``3``.
973-
974-
5. ``font_size``: Font size for the labels and title. Defaults to
975-
``14``.
976-
977-
6. ``plot_type``: Type of the plot which can be either ``"plot"``
978-
(default), ``"scatter"``, or ``"bar"``.
979-
980-
7. ``color``: Color of the plot which defaults to the greenish color
981-
``"#64f20c"``.
982-
983-
8. ``label``: The label used for the legend in the figures of
984-
multi-objective problems. It is not used for single-objective
985-
problems. It defaults to ``None`` which means no labels used.
986-
987-
9. ``save_dir``: Directory to save the figure.
988-
989946
.. _plotnewsolutionrate:
990947

991948
``plot_new_solution_rate()``
@@ -999,26 +956,6 @@ constructor of the ``pygad.GA`` class.
999956
It works only after completing at least 1 generation. If no generation
1000957
is completed (at least 1), an exception is raised.
1001958

1002-
This method accepts the following parameters:
1003-
1004-
1. ``title``: Title of the figure.
1005-
1006-
2. ``xlabel``: X-axis label.
1007-
1008-
3. ``ylabel``: Y-axis label.
1009-
1010-
4. ``linewidth``: Line width of the plot. Defaults to ``3``.
1011-
1012-
5. ``font_size``: Font size for the labels and title. Defaults to
1013-
``14``.
1014-
1015-
6. ``plot_type``: Type of the plot which can be either ``"plot"``
1016-
(default), ``"scatter"``, or ``"bar"``.
1017-
1018-
7. ``color``: Color of the plot which defaults to ``"#3870FF"``.
1019-
1020-
8. ``save_dir``: Directory to save the figure.
1021-
1022959
.. _plotgenes:
1023960

1024961
``plot_genes()``
@@ -1039,43 +976,6 @@ This is controlled by the ``graph_type`` parameter.
1039976
It works only after completing at least 1 generation. If no generation
1040977
is completed (at least 1), an exception is raised.
1041978

1042-
This method accepts the following parameters:
1043-
1044-
1. ``title``: Title of the figure.
1045-
1046-
2. ``xlabel``: X-axis label.
1047-
1048-
3. ``ylabel``: Y-axis label.
1049-
1050-
4. ``linewidth``: Line width of the plot. Defaults to ``3``.
1051-
1052-
5. ``font_size``: Font size for the labels and title. Defaults to
1053-
``14``.
1054-
1055-
6. ``plot_type``: Type of the plot which can be either ``"plot"``
1056-
(default), ``"scatter"``, or ``"bar"``.
1057-
1058-
7. ``graph_type``: Type of the graph which can be either ``"plot"``
1059-
(default), ``"boxplot"``, or ``"histogram"``.
1060-
1061-
8. ``fill_color``: Fill color of the graph which defaults to
1062-
``"#3870FF"``. This has no effect if ``graph_type="plot"``.
1063-
1064-
9. ``color``: Color of the plot which defaults to ``"#3870FF"``.
1065-
1066-
10. ``solutions``: Defaults to ``"all"`` which means use all solutions.
1067-
If ``"best"`` then only the best solutions are used.
1068-
1069-
11. ``save_dir``: Directory to save the figure.
1070-
1071-
An exception is raised if:
1072-
1073-
- ``solutions="all"`` while ``save_solutions=False`` in the constructor
1074-
of the ``pygad.GA`` class. .
1075-
1076-
- ``solutions="best"`` while ``save_best_solutions=False`` in the
1077-
constructor of the ``pygad.GA`` class. .
1078-
1079979
``save()``
1080980
----------
1081981

@@ -1160,7 +1060,8 @@ optimization problem is single-objective or multi-objective.
11601060
- If the fitness function returns a ``list``, ``tuple``, or
11611061
``numpy.ndarray``, then the problem is single-objective. Even if
11621062
there is only one element, the problem is still considered
1163-
multi-objective.
1063+
multi-objective. Each element represents the fitness value of its
1064+
corresponding objective.
11641065

11651066
Using a user-defined fitness function allows the user to freely use
11661067
PyGAD to solve any problem by passing the appropriate fitness
@@ -1580,6 +1481,108 @@ below.
15801481
loaded_ga_instance = pygad.load(filename=filename)
15811482
loaded_ga_instance.plot_fitness()
15821483
1484+
Linear Model Optimization - Multi-Objective
1485+
-------------------------------------------
1486+
1487+
This is a multi-objective optimization example that optimizes these 2
1488+
functions:
1489+
1490+
1. ``y1 = f(w1:w6) = w1x1 + w2x2 + w3x3 + w4x4 + w5x5 + 6wx6``
1491+
1492+
2. ``y2 = f(w1:w6) = w1x7 + w2x8 + w3x9 + w4x10 + w5x11 + 6wx12``
1493+
1494+
Where:
1495+
1496+
1. ``(x1,x2,x3,x4,x5,x6)=(4,-2,3.5,5,-11,-4.7)`` and ``y=50``
1497+
1498+
2. ``(x7,x8,x9,x10,x11,x12)=(-2,0.7,-9,1.4,3,5)`` and ``y=30``
1499+
1500+
The 2 functions use the same parameters (weights) ``w1`` to ``w6``.
1501+
1502+
The goal is to use PyGAD to find the optimal values for such weights
1503+
that satisfy the 2 functions ``y1`` and ``y2``.
1504+
1505+
To use PyGAD to solve multi-objective problems, the only adjustment is
1506+
to return a ``list``, ``tuple``, or ``numpy.ndarray`` from the fitness
1507+
function. Each element represents the fitness of an objective in order.
1508+
That is the first element is the fitness of the first objective, the
1509+
second element is the fitness for the second objective, and so on.
1510+
1511+
.. code:: python
1512+
1513+
import pygad
1514+
import numpy
1515+
1516+
"""
1517+
Given these 2 functions:
1518+
y1 = f(w1:w6) = w1x1 + w2x2 + w3x3 + w4x4 + w5x5 + 6wx6
1519+
y2 = f(w1:w6) = w1x7 + w2x8 + w3x9 + w4x10 + w5x11 + 6wx12
1520+
where (x1,x2,x3,x4,x5,x6)=(4,-2,3.5,5,-11,-4.7) and y=50
1521+
and (x7,x8,x9,x10,x11,x12)=(-2,0.7,-9,1.4,3,5) and y=30
1522+
What are the best values for the 6 weights (w1 to w6)? We are going to use the genetic algorithm to optimize these 2 functions.
1523+
This is a multi-objective optimization problem.
1524+
1525+
PyGAD considers the problem as multi-objective if the fitness function returns:
1526+
1) List.
1527+
2) Or tuple.
1528+
3) Or numpy.ndarray.
1529+
"""
1530+
1531+
function_inputs1 = [4,-2,3.5,5,-11,-4.7] # Function 1 inputs.
1532+
function_inputs2 = [-2,0.7,-9,1.4,3,5] # Function 2 inputs.
1533+
desired_output1 = 50 # Function 1 output.
1534+
desired_output2 = 30 # Function 2 output.
1535+
1536+
def fitness_func(ga_instance, solution, solution_idx):
1537+
output1 = numpy.sum(solution*function_inputs1)
1538+
output2 = numpy.sum(solution*function_inputs2)
1539+
fitness1 = 1.0 / (numpy.abs(output1 - desired_output1) + 0.000001)
1540+
fitness2 = 1.0 / (numpy.abs(output2 - desired_output2) + 0.000001)
1541+
return [fitness1, fitness2]
1542+
1543+
num_generations = 100
1544+
num_parents_mating = 10
1545+
1546+
sol_per_pop = 20
1547+
num_genes = len(function_inputs1)
1548+
1549+
ga_instance = pygad.GA(num_generations=num_generations,
1550+
num_parents_mating=num_parents_mating,
1551+
sol_per_pop=sol_per_pop,
1552+
num_genes=num_genes,
1553+
fitness_func=fitness_func,
1554+
parent_selection_type='nsga2')
1555+
1556+
ga_instance.run()
1557+
1558+
ga_instance.plot_fitness(label=['Obj 1', 'Obj 2'])
1559+
1560+
solution, solution_fitness, solution_idx = ga_instance.best_solution(ga_instance.last_generation_fitness)
1561+
print(f"Parameters of the best solution : {solution}")
1562+
print(f"Fitness value of the best solution = {solution_fitness}")
1563+
1564+
prediction = numpy.sum(numpy.array(function_inputs1)*solution)
1565+
print(f"Predicted output 1 based on the best solution : {prediction}")
1566+
prediction = numpy.sum(numpy.array(function_inputs2)*solution)
1567+
print(f"Predicted output 2 based on the best solution : {prediction}")
1568+
1569+
This is the result of the print statements. The predicted outputs are
1570+
close to the desired outputs.
1571+
1572+
.. code::
1573+
1574+
Parameters of the best solution : [ 0.79676439 -2.98823386 -4.12677662 5.70539445 -2.02797016 -1.07243922]
1575+
Fitness value of the best solution = [ 1.68090829 349.8591915 ]
1576+
Predicted output 1 based on the best solution : 50.59491545442283
1577+
Predicted output 2 based on the best solution : 29.99714270722312
1578+
1579+
This is the figure created by the ``plot_fitness()`` method. The fitness
1580+
of the first objective has the green color. The blue color is used for
1581+
the second objective fitness.
1582+
1583+
.. image:: https://github.com/ahmedfgad/GeneticAlgorithmPython/assets/16560492/7896f8d8-01c5-4ff9-8d15-52191c309b63
1584+
:alt:
1585+
15831586
Reproducing Images
15841587
------------------
15851588

0 commit comments

Comments
 (0)