Skip to content

Commit

Permalink
added docstring comments
Browse files Browse the repository at this point in the history
  • Loading branch information
100 committed Jun 18, 2017
1 parent bafabd7 commit e5a130e
Show file tree
Hide file tree
Showing 7 changed files with 353 additions and 5 deletions.
62 changes: 62 additions & 0 deletions library/EvolutionaryAlgorithm.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,9 @@


class EvolutionaryAlgorithm:
"""
Conducts evolutionary algorithm
"""
__metaclass__ = ABCMeta

population = None
Expand All @@ -21,6 +24,13 @@ class EvolutionaryAlgorithm:
max_fitness = None

def __init__(self, crossover_rate, mutation_rate, max_steps, max_fitness=None):
"""
:param crossover_rate: probability of crossover
:param mutation_rate: probability of mutation
:param max_steps: maximum steps to run genetic algorithm for
:param max_fitness: fitness value to stop algorithm once reached
"""
if isinstance(crossover_rate, float):
if crossover_rate >= 0 and crossover_rate <= 1:
self.crossover_rate = crossover_rate
Expand Down Expand Up @@ -59,6 +69,11 @@ def __repr__(self):
return self.__str__()

def _clear(self):
"""
Resets the variables that are altered on a per-run basis of the algorithm
:return: None
"""
self.cur_steps = 0
self.population = None
self.fitnesses = None
Expand All @@ -67,16 +82,37 @@ def _clear(self):

@abstractmethod
def _initial_population(self):
"""
Generates initial population
:return: list of members of population
"""
pass

@abstractmethod
def _fitness(self, member):
"""
Evaluates fitness of a given member
:param member: a member
:return: fitness of member
"""
pass

def _populate_fitness(self):
"""
Calculates fitness of all members of current population
:return: None
"""
self.fitnesses = list([self._fitness(x) for x in self.population])

def _most_fit(self):
"""
Finds most fit member of current population
:return: most fit member and most fit member's fitness
"""
best_idx = 0
cur_idx = 0
for x in self.fitnesses:
Expand All @@ -86,6 +122,13 @@ def _most_fit(self):
return self.population[best_idx], self.fitnesses[best_idx]

def _select_n(self, n):
"""
Probabilistically selects n members from current population using
roulette-wheel selection
:param n: number of members to select
:return: n members
"""
shuffle(self.population)
total_fitness = sum(self.fitnesses)
probs = list([self._fitness(x) / total_fitness for x in self.population])
Expand All @@ -101,13 +144,32 @@ def _select_n(self, n):

@abstractmethod
def _crossover(self, parent1, parent2):
"""
Creates new member of population by combining two parent members
:param parent1: a member
:param parent2: a member
:return: member made by combining elements of both parents
"""
pass

@abstractmethod
def _mutate(self, member):
"""
Randomly mutates a member
:param member: a member
:return: mutated member
"""
pass

def evolutionary_algorithm(self, verbose=True):
"""
Conducts evolutionary algorithm
:param verbose: indicates whether or not to print progress regularly
:return: best state and best objective function value
"""
num_copy = int((1 - self.crossover_rate) * len(self.population))
num_crossover = len(self.population) - num_copy
self._clear()
Expand Down
63 changes: 63 additions & 0 deletions library/GeneticAlgorithm.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,9 @@


class GeneticAlgorithm:
"""
Conducts genetic algorithm
"""
__metaclass__ = ABCMeta

population = None
Expand All @@ -21,6 +24,13 @@ class GeneticAlgorithm:
max_fitness = None

def __init__(self, crossover_rate, mutation_rate, max_steps, max_fitness=None):
"""
:param crossover_rate: probability of crossover
:param mutation_rate: probability of mutation
:param max_steps: maximum steps to run genetic algorithm for
:param max_fitness: fitness value to stop algorithm once reached
"""
if isinstance(crossover_rate, float):
if crossover_rate >= 0 and crossover_rate <= 1:
self.crossover_rate = crossover_rate
Expand Down Expand Up @@ -59,6 +69,11 @@ def __repr__(self):
return self.__str__()

def _clear(self):
"""
Resets the variables that are altered on a per-run basis of the algorithm
:return: None
"""
self.cur_steps = 0
self.population = None
self.fitnesses = None
Expand All @@ -67,16 +82,38 @@ def _clear(self):

@abstractmethod
def _initial_population(self):
"""
Generates initial population -
members must be represented by a list of binary-values integers
:return: list of members of population
"""
pass

@abstractmethod
def _fitness(self, member):
"""
Evaluates fitness of a given member
:param member: a member
:return: fitness of member
"""
pass

def _populate_fitness(self):
"""
Calculates fitness of all members of current population
:return: None
"""
self.fitnesses = list([self._fitness(x) for x in self.population])

def _most_fit(self):
"""
Finds most fit member of current population
:return: most fit member and most fit member's fitness
"""
best_idx = 0
cur_idx = 0
for x in self.fitnesses:
Expand All @@ -86,6 +123,13 @@ def _most_fit(self):
return self.population[best_idx], self.fitnesses[best_idx]

def _select_n(self, n):
"""
Probabilistically selects n members from current population using
roulette-wheel selection
:param n: number of members to select
:return: n members
"""
shuffle(self.population)
total_fitness = sum(self.fitnesses)
probs = list([self._fitness(x) / total_fitness for x in self.population])
Expand All @@ -100,15 +144,34 @@ def _select_n(self, n):
return res

def _crossover(self, parent1, parent2):
"""
Creates new member of population by combining two parent members
:param parent1: a member
:param parent2: a member
:return: member made by combining elements of both parents
"""
partition = randint(0, len(self.population[0] - 1))
return parent1[0:partition] + parent2[partition:]

def _mutate(self, member):
"""
Randomly mutates a member
:param member: a member
:return: mutated member
"""
if self.mutation_rate >= random():
idx = randint(0, len(member) - 1)
member[idx] = 1 if member[idx] == 0 else 1

def genetic_algorithm(self, verbose=True):
"""
Conducts genetic algorithm
:param verbose: indicates whether or not to print progress regularly
:return: best state and best objective function value
"""
num_copy = int((1 - self.crossover_rate) * len(self.population))
num_crossover = len(self.population) - num_copy
self._clear()
Expand Down
49 changes: 49 additions & 0 deletions library/HarmonySearch.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,9 @@


class HarmonySearch:
"""
Conducts harmony search
"""
__metaclass__ = ABCMeta

cur_steps = None
Expand All @@ -21,6 +24,15 @@ class HarmonySearch:
max_score = None

def __init__(self, hms, hmcr, par, fw, max_steps, max_score=None):
"""
:param hms: harmony memory size
:param hmcr: harmony memory considering rate
:param par: pitch adjustment rate
:param fw: fret width
:param max_steps: maximum number of steps to run algorithm for
:param max_score: objective function value to stop algorithm once reached
"""
if isinstance(hms, int) and hms > 0:
self.hms = hms
else:
Expand Down Expand Up @@ -63,28 +75,65 @@ def __repr__(self):
return self.__str__()

def _clear(self):
"""
Resets the variables that are altered on a per-run basis of the algorithm
:return: None
"""
self.cur_steps = 0
self.memory = list([self._random_harmony() for _ in range(self.hms)])
self.scores = None

@abstractmethod
def _random_harmony(self):
"""
Generates a list of random harmonies, each represented as a list of floats
:return: list of harmonies
"""
pass

@abstractmethod
def _score(self, harmony):
"""
Returns score of a harmony
:param harmony: a harmony
:return: score of harmony
"""
pass

def _score_all(self):
"""
Finds score of all current harmonies in memory
:return: None
"""
self.scores = list([self._score(x) for x in self.memory])

def _worst_score(self):
"""
Returns index of worst harmony in memory
:return: index of worst harmony in memory
"""
return argmin(self.scores)

def _best_score(self):
"""
Returns index of best harmony in memory
:return: index of best harmony in memory
"""
return argmax(self.scores)

def harmony_search(self, verbose=True):
"""
Conducts harmony search
:param verbose: indicates whether or not to print progress regularly
:return: best state and objective function value of best state
"""
self._clear()
for i in range(self.max_steps):
self.cur_steps += 1
Expand Down
Loading

0 comments on commit e5a130e

Please sign in to comment.