Skip to content

Conversation

JoseALermaIII
Copy link
Owner

@JoseALermaIII JoseALermaIII commented Oct 11, 2019

Summary

Initialize chapter 7 with a genetic algorithm simulator.

Description

Simulates a genetic algorithm by breeding rats until they reach an average weight of 50000 grams. The challenge here is modifying the code to allow for a variable number of males and females in the population rather than equal numbers for matched pairs.

This version keeps the population in a dictionary, pseudo-randomly assigns gender to the litters of pups (the test data for this is very interesting, I might add), and pseudo-randomly selects males to breed with more than one female.

The litters of pups are then added to the general population based on gender and become part of the selection process for the largest weight per gender.

This method uses the same population size as the one detailed in the book, but because of gender separation and selection, shaves off about 10 years from reaching the target weight.

So, why am I not merging? Pylint doesn't like functions to have more than 5 arguments nor 15 variable names. To get around that, I had to use tuples, but tuples as arguments don't allow for specifying what is in them. That creates this clunky function:

def breed_rats(population: dict, limits: tuple, pop_stats: tuple,
mut_stats: tuple) -> tuple:
"""Simulate genetic algorithm by breeding rats.
Using **population**, repeat cycle of measure, select, crossover,
and mutate until either of **limits** are met.
Args:
population (dict): Dictionary of lists with ``males`` and ``females``
as keys and specimen weight in grams as values.
limits (tuple): Tuple of integers representing target weight
(in grams) and generational cutoff to stop breeding program.
pop_stats (tuple): Tuple of integers representing number of male
rats in population, number of female rats in population, and
number of pups per pair of breeding rats.
mut_stats (tuple): Tuple of floats representing probability of a
mutation occurring in a pup, scalar on pup weight of least
beneficial mutation, and scalar on pup weight of most
beneficial mutation.

I'd like to clean this up as much as possible. After some research and pondering, I can either use module constants directly in the function or make the whole module a class.

So, I'll be spending time converting this module into a proper class.

Team Notifications

Me, myself, and I

@JoseALermaIII
Copy link
Owner Author

Now that was a refactor session. RIP coverage from not testing setters.

I'll add setter tests and review sphinx docs next time.

@JoseALermaIII JoseALermaIII marked this pull request as ready for review October 12, 2019 22:31
@JoseALermaIII
Copy link
Owner Author

Never needed to make ROUSs, like in Princess Bride, but now I know how they may have gotten there.

Comment on lines +55 to +65
@property
def min_wt(self):
"""int: Minimum weight of adult rat in initial population.

Default is ``200``.
"""
return self._min_wt

@min_wt.setter
def min_wt(self, value: int):
self._min_wt = value
Copy link
Owner Author

@JoseALermaIII JoseALermaIII Oct 12, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I considered making the properties mixedCase, like I've seen in other packages, but PEP8 advises to follow function naming rules for method names. Furthermore, PEP8 advises function names should be lowercase with underscores.

Technically, minWt has one fewer key press than min_wt. This will keep me up at night.

Comment on lines +30 to +35
# pylint: disable=too-many-instance-attributes,too-many-public-methods
# Limit is for instance attributes and public methods are 7 and 20,
# but analysis like this requires many constants.
# I am opting to make them modifiable in something that is isn't a
# dictionary.
# If there is a better way, please submit an issue for discussion.
Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

pylint is a wise sage that tries to warn you when you're doing too much at once. Turning this module into a class helped with usability and readability, but there are a lot of variables at work here.

While I may look into dictionaries or namedtuples again, I like that each variable can be controlled independently for testing small variances.

Testing at what point each variable stops being beneficial is an interesting pastime.

@JoseALermaIII JoseALermaIII merged commit 1e41daf into master Oct 12, 2019
@JoseALermaIII JoseALermaIII deleted the breed-rats branch October 12, 2019 23:16
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request
Projects
None yet
Development

Successfully merging this pull request may close these issues.

1 participant