Skip to content
Open
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
23 changes: 14 additions & 9 deletions pygad/utils/crossover.py
Original file line number Diff line number Diff line change
Expand Up @@ -114,17 +114,22 @@ def two_points_crossover(self, parents, offspring_size):
else:
offspring = numpy.empty(offspring_size, dtype=object)

# Randomly generate all the first K points at which crossover takes place between each two parents.
# This saves time by calling the numpy.random.randint() function only once.
if (parents.shape[1] == 1): # If the chromosome has only a single gene. In this case, this gene is copied from the second parent.
crossover_points_1 = numpy.zeros(offspring_size[0])
else:
crossover_points_1 = numpy.random.randint(low=0,
high=numpy.ceil(parents.shape[1]/2 + 1),
size=offspring_size[0])
# Randomly generate all the K pairs of points at which crossover takes place between each two parents.
# This saves time by calling the numpy.random.randint() function only twice.
# The 2 points of a pair are different values in [0, num_genes], and every such pair is equally likely.
# If the chromosome has only a single gene, the points are 0 and 1: the gene is copied from the second parent.
points_a = numpy.random.randint(low=0,
high=parents.shape[1] + 1,
size=offspring_size[0])
points_b = numpy.random.randint(low=0,
high=parents.shape[1],
size=offspring_size[0])
# Skip the value of the first point so that the 2 points differ.
points_b[points_b >= points_a] += 1

# The second point must always be greater than the first point.
crossover_points_2 = crossover_points_1 + int(parents.shape[1]/2)
crossover_points_1 = numpy.minimum(points_a, points_b)
crossover_points_2 = numpy.maximum(points_a, points_b)

for k in range(offspring_size[0]):

Expand Down
29 changes: 29 additions & 0 deletions tests/test_crossover_mutation.py
Original file line number Diff line number Diff line change
Expand Up @@ -241,6 +241,32 @@ def test_random_mutation_manual_call4():
for value in comp_sorted:
assert value in value_space

def test_two_points_crossover_manual_call():
# Both points are random: the genes between them form 1 segment of any length from 1 to num_genes.
num_genes = 10
num_offspring = 1000
result, ga_instance = output_crossover_mutation(gene_type=int,
crossover_type="two_points")

parents = numpy.array([[0] * num_genes,
[1] * num_genes])
offspring = ga_instance.two_points_crossover(parents=parents,
offspring_size=(num_offspring, num_genes))

# Without crossover_probability, the first parent of offspring k is parents[k % 2].
# Mark the genes that come from the second parent with 1.
from_second_parent = numpy.array([child if k % 2 == 0 else 1 - child for k, child in enumerate(offspring)])

segment_lengths = set()
for child in from_second_parent:
segment = numpy.flatnonzero(child)
# The genes from the second parent are consecutive.
assert len(segment) > 0
assert segment[-1] - segment[0] + 1 == len(segment)
segment_lengths.add(len(segment))

assert segment_lengths == set(range(1, num_genes + 1))

if __name__ == "__main__":
#### Single-objective
print()
Expand Down Expand Up @@ -285,3 +311,6 @@ def test_random_mutation_manual_call4():

test_random_mutation_manual_call4()
print()

test_two_points_crossover_manual_call()
print()