Skip to content

Commit

Permalink
make tournament create new objects for chromosomes + tests
Browse files Browse the repository at this point in the history
as we want to create new population and because all of out methods are by reference, creating new instances from tournament is the best way to handle any further misuse.

Took 1 hour 21 minutes
  • Loading branch information
Nikronic committed Oct 14, 2019
1 parent b28a8f7 commit d13443a
Show file tree
Hide file tree
Showing 2 changed files with 66 additions and 10 deletions.
45 changes: 41 additions & 4 deletions tests/test_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -318,16 +318,53 @@ def test_fittest_chromosome(supply_population):
def test_tournament(supply_population):
parents = F.tournament(supply_population)
assert parents.len() == 2
assert supply_population.contains(parents[0]) == True
assert supply_population.contains(parents[1]) == True

f = 0
idcs = [-1, -1]
for idx, ch in enumerate(supply_population):
if ch.id == parents[0].id and ch.fitness_value() == parents[0].fitness_value():
f += 1
idcs[0] = idx
if ch.id == parents[1].id and ch.fitness_value() == parents[1].fitness_value():
f += 1
idcs[1] = idx
assert f >= 2
assert parents[0] != parents[1]

for p, ch in zip([p for p in parents], [supply_population[idcs[0]], supply_population[idcs[1]]]):
assert p.id == ch.id

assert parents[0].chromosome[0].x == supply_population[idcs[0]].chromosome[0].x
assert parents[0].chromosome[0].y == supply_population[idcs[0]].chromosome[0].y

assert parents[1].chromosome[0].x == supply_population[idcs[1]].chromosome[0].x
assert parents[1].chromosome[0].y == supply_population[idcs[1]].chromosome[0].y

parents = F.tournament(supply_population, 0.0) # force to use random parents not fittest ('else' condition)
assert parents.len() == 2
assert supply_population.contains(parents[0]) == True
assert supply_population.contains(parents[1]) == True
assert parents[0] != parents[1]

f = 0
idcs = [-1, -1]
for idx, ch in enumerate(supply_population):
if ch.id == parents[0].id and ch.fitness_value() == parents[0].fitness_value():
f += 1
idcs[0] = idx
if ch.id == parents[1].id and ch.fitness_value() == parents[1].fitness_value():
f += 1
idcs[1] = idx
assert f >= 2
assert parents[0] != parents[1]

for p, ch in zip([p for p in parents], [supply_population[idcs[0]], supply_population[idcs[1]]]):
assert p.id == ch.id

assert parents[0].chromosome[0].x == supply_population[idcs[0]].chromosome[0].x
assert parents[0].chromosome[0].y == supply_population[idcs[0]].chromosome[0].y

assert parents[1].chromosome[0].x == supply_population[idcs[1]].chromosome[0].x
assert parents[1].chromosome[0].y == supply_population[idcs[1]].chromosome[0].y


def test_routes_ending_indices_attr(supply_depot: Depot):
F.initial_routing(supply_depot)
Expand Down
31 changes: 25 additions & 6 deletions utils/functional.py
Original file line number Diff line number Diff line change
Expand Up @@ -122,24 +122,43 @@ def tournament(population: Population, tournament_probability: float = 0.8, size
3. Select another random unique sample from the population
4. Find fittest chromosomes from each sampled populations and return them as new population.
5. Randomly choose two chromosomes and return them as a new population.
Note: if samples be same, then fittest `chromosome` of the samples both will be same `Chromosome`s. So as we want to
pass the result of `tournament` to `cross_over`, the cross over operation is asexual or single-parent.
:param population: An instance of `Population` class
:param tournament_probability: The probability of using fittest or random sample (=0.8)
:param size: The size of population to be sampled. By default, we use Binary tournament (size = 2).
:param size: The size of population to be sampled. By default, we use Binary tournament.
:return: A `Population` with size of `size`
"""

# we create new objects to make sure asexual can happen too. (all methods are by reference)
first_fittest = Chromosome(7770, -1)
second_fittest = Chromosome(7771, -1)

first_sample = extract_population(population, size)
if random.random() <= tournament_probability:
second_sample = extract_population(population, size)
first_fittest = fittest_chromosome(first_sample)
second_fittest = fittest_chromosome(second_sample)
while first_sample == second_fittest:
second_fittest = fittest_chromosome(second_sample)
first = fittest_chromosome(first_sample)
second = fittest_chromosome(second_sample)
for new, found in zip([first_fittest, second_fittest], [first, second]):
new.chromosome = found.get_all()
new.id = found.id
new.fitness = found.fitness
new.capacity = found.capacity
new.size = found.size

return Population(0, [first_fittest, second_fittest])
else:
indices = random.sample(range(0, first_sample.len()), 2)
return Population(0, [first_sample[indices[0]], first_sample[indices[1]]])
first = first_sample[indices[0]]
second = first_sample[indices[1]]
for new, found in zip([first_fittest, second_fittest], [first, second]):
new.chromosome = found.get_all()
new.id = found.id
new.fitness = found.fitness
new.capacity = found.capacity
new.size = found.size
return Population(0, [first_fittest, second_fittest])


def extract_random_route(chromosome: Chromosome, delete=True) -> (List[Customer], int, int, int):
Expand Down

0 comments on commit d13443a

Please sign in to comment.