Skip to content

Commit

Permalink
finished initial tests
Browse files Browse the repository at this point in the history
  • Loading branch information
100 committed Jun 19, 2017
1 parent e2f8667 commit 9b0ea8b
Show file tree
Hide file tree
Showing 8 changed files with 138 additions and 38 deletions.
45 changes: 23 additions & 22 deletions library/ParticleSwarm.py
Original file line number Diff line number Diff line change
Expand Up @@ -53,19 +53,19 @@ def __init__(self, swarm_size, member_size, lower_bound, upper_bound, c1, c2, c3
else:
raise ValueError('Member size must be a positive integer')

if isinstance(lower_bound, (int, float)):
self.lower_bound = float(lower_bound)
if all([isinstance(x, (int, float)) for x in lower_bound]):
self.lower_bound = array([float(x) for x in lower_bound])
else:
raise ValueError()
raise ValueError('Lower bounds must be numeric types')

if isinstance(upper_bound, (int, float)):
self.upper_bound = float(upper_bound)
if all([isinstance(x, (int, float)) for x in upper_bound]):
self.upper_bound = array([float(x) for x in upper_bound])
else:
raise ValueError()
raise ValueError('Upper bounds must be numeric types')

self.pos = uniform(lower_bound, upper_bound, size=(swarm_size, member_size))
self.pos = uniform(self.lower_bound, self.upper_bound, size=(swarm_size, member_size))

self.vel = uniform(upper_bound - lower_bound, lower_bound - upper_bound, size=(swarm_size, member_size))
self.vel = uniform(self.lower_bound - self.upper_bound, self.upper_bound - self.lower_bound, size=(swarm_size, member_size))

self.best = copy(self.pos)

Expand All @@ -92,7 +92,7 @@ def __str__(self):
'CURRENT STEPS: %d \n' +
'BEST FITNESS: %f \n' +
'BEST MEMBER: %s \n\n') % \
(self.cur_steps, self._score(self.global_best[0]), str(self.global_best[0]))
(self.cur_steps, self._objective(self.global_best[0]), str(self.global_best[0]))

def __repr__(self):
return self.__str__()
Expand All @@ -104,10 +104,11 @@ def _clear(self):
:return: None
"""
self.pos = uniform(self.lower_bound, self.upper_bound, size=(self.swarm_size, self.member_size))
self.vel = uniform(self.upper_bound - self.lower_bound, self.lower_bound - self.upper_bound, size=(self.swarm_size, self.member_size))
self.vel = uniform(self.lower_bound - self.upper_bound, self.upper_bound - self.lower_bound, size=(self.swarm_size, self.member_size))
self.scores = self._score(self.pos)
self.best = copy(self.pos)
self.cur_steps = 0
self._global_best()

@abstractmethod
def _objective(self, member):
Expand All @@ -122,10 +123,10 @@ def _objective(self, member):

def _score(self, pos):
"""
Applies objective function to a member of swarm
Applies objective function to all members of swarm
:param pos:
:return:
:param pos: position matrix
:return: score vector
"""
return apply_along_axis(self._objective, 1, pos)

Expand All @@ -137,11 +138,11 @@ def _best(self, old, new):
:param new: new values
:return: None
"""
old_score = self._score(old)
new_score = self._score(new)
old_scores = self._score(old)
new_scores = self._score(new)
best = []
for i in range(len(old_score)):
if old_score > new_score:
for i in range(len(old_scores)):
if old_scores[i] < new_scores[i]:
best.append(old[i])
else:
best.append(new[i])
Expand All @@ -153,7 +154,7 @@ def _global_best(self):
:return: None
"""
if min(self.scores) < self.global_best[0][0]:
if self.global_best is None or min(self.scores) < self._objective(self.global_best[0]):
self.global_best = array([self.pos[argmin(self.scores)],] * self.swarm_size)

def run(self, verbose=True):
Expand All @@ -167,7 +168,7 @@ def run(self, verbose=True):
for i in range(self.max_steps):
self.cur_steps += 1

if (i % 100 == 0) and verbose:
if ((i + 1) % 100 == 0) and verbose:
print self

u1 = zeros((self.swarm_size, self.swarm_size))
Expand All @@ -186,8 +187,8 @@ def run(self, verbose=True):
self.scores = self._score(self.pos)
self._global_best()

if self._score(self.global_best[0]) < self.min_objective:
if self._objective(self.global_best[0]) < self.min_objective:
print "TERMINATING - REACHED MINIMUM OBJECTIVE"
return self.global_best[0], self._score(self.global_best[0])
return self.global_best[0], self._objective(self.global_best[0])
print "TERMINATING - REACHED MAXIMUM STEPS"
return self.global_best[0], self._score(self.global_best[0])
return self.global_best[0], self._objective(self.global_best[0])
23 changes: 17 additions & 6 deletions library/SimulatedAnnealing.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,10 +26,14 @@ class SimulatedAnnealing:
adjust_temp = None

def _exponential(self, schedule_constant):
self.current_temp *= schedule_constant
def f():
self.current_temp *= schedule_constant
return f

def _linear(self, schedule_constant):
self.current_temp -= schedule_constant
def f():
self.current_temp -= schedule_constant
return f

def _get_schedule(self, schedule_str, schedule_constant):
if schedule_str == 'exponential':
Expand All @@ -39,7 +43,7 @@ def _get_schedule(self, schedule_str, schedule_constant):
else:
raise ValueError('Annealing schedule must be either "exponential" or "linear"')

def __init__(self, initial_state, max_steps, temp_begin, schedule_constant,
def __init__(self, initial_state, temp_begin, schedule_constant, max_steps,
min_energy=None, schedule='exponential'):
"""
Expand Down Expand Up @@ -119,7 +123,10 @@ def _accept_neighbor(self, neighbor):
:param neighbor: a state
:return: boolean indicating whether or not transition is accepted
"""
p = exp(self._energy(self.current_state) - self._energy(neighbor)) / self.current_temp
try:
p = exp(-(self._energy(neighbor) - self._energy(self.current_state)) / self.current_temp)
except OverflowError:
return True
return True if p >= 1 else p >= random()

def run(self, verbose=True):
Expand All @@ -132,10 +139,11 @@ def run(self, verbose=True):
self._clear()
self.current_state = self.initial_state
self.current_temp = self.start_temp
self.best_energy = self._energy(self.current_state)
for i in range(self.max_steps):
self.cur_steps += 1

if (i % 100 == 0) and verbose:
if ((i + 1) % 100 == 0) and verbose:
print self

neighbor = self._neighbor()
Expand All @@ -152,6 +160,9 @@ def run(self, verbose=True):
print "TERMINATING - REACHED MINIMUM ENERGY"
return self.best_state, self.best_energy

self.current_temp = self.adjust_temp()
self.adjust_temp()
if self.current_temp < 0.000001:
print "TERMINATING - REACHED TEMPERATURE OF 0"
return self.best_state, self.best_energy
print "TERMINATING - REACHED MAXIMUM STEPS"
return self.best_state, self.best_energy
9 changes: 6 additions & 3 deletions library/StochasticHillClimb.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ class StochasticHillClimb:

temp = None

def __init__(self, initial_state, max_steps, temp, max_objective=None):
def __init__(self, initial_state, temp, max_steps, max_objective=None):
"""
:param initial_state: initial state of hill climbing
Expand Down Expand Up @@ -95,7 +95,10 @@ def _accept_neighbor(self, neighbor):
:param neighbor: a state
:return: boolean indicating whether or not transition was accepted
"""
p = 1. / (1 + (exp(self._objective(self.current_state) - self._objective(neighbor)) / self.temp))
try:
p = 1. / (1 + (exp((self._objective(self.current_state) - self._objective(neighbor)) / self.temp)))
except OverflowError:
return True
return True if p >= 1 else p >= random()

def run(self, verbose=True):
Expand All @@ -110,7 +113,7 @@ def run(self, verbose=True):
for i in range(self.max_steps):
self.cur_steps += 1

if (i % 100 == 0) and verbose:
if ((i + 1) % 100 == 0) and verbose:
print self

neighbor = self._neighbor()
Expand Down
20 changes: 13 additions & 7 deletions library/TabuSearch.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,19 +15,23 @@ class TabuSearch:
tabu_size = None
tabu_list = None

initial_state = None
current = None
best = None

max_steps = None
max_score = None

def __init__(self, tabu_size, max_steps, max_score=None):
def __init__(self, initial_state, tabu_size, max_steps, max_score=None):
"""
:param initial_state: initial state
:param tabu_size: number of states to keep in tabu list
:param max_steps: maximum number of steps to run algorithm for
:param max_score: score to stop algorithm once reached
"""
self.initial_state = initial_state

if isinstance(tabu_size, int) and tabu_size > 0:
self.tabu_size = tabu_size
else:
Expand Down Expand Up @@ -62,8 +66,8 @@ def _clear(self):
"""
self.cur_steps = 0
self.tabu_list = deque(maxlen=self.tabu_size)
self.current = None
self.best = None
self.current = self.initial_state
self.best = self.initial_state

@abstractmethod
def _score(self, state):
Expand All @@ -78,7 +82,7 @@ def _score(self, state):
@abstractmethod
def _neighborhood(self):
"""
Returns list of all members of neighborhood of current state
Returns list of all members of neighborhood of current state, given self.current
:return: list of members of neighborhood
"""
Expand All @@ -104,7 +108,7 @@ def run(self, verbose=True):
for i in range(self.max_steps):
self.cur_steps += 1

if (i % 100 == 0) and verbose:
if ((i + 1) % 100 == 0) and verbose:
print self

neighborhood = self._neighborhood()
Expand All @@ -117,14 +121,16 @@ def run(self, verbose=True):
if neighborhood_best in self.tabu_list:
if self._score(neighborhood_best) > self._score(self.best):
self.tabu_list.append(neighborhood_best)
self.best = neighborhood_best
self.best = deepcopy(neighborhood_best)
break
else:
neighborhood.remove(neighborhood_best)
neighborhood_best = self._best(neighborhood)
else:
self.tabu_list.append(neighborhood_best)
self.best = neighborhood_best
self.current = neighborhood_best
if self._score(self.current) > self._score(self.best):
self.best = deepcopy(self.current)
break

if self.max_score is not None and self._score(self.best) > self.max_score:
Expand Down
14 changes: 14 additions & 0 deletions tests/test_particle_swarm.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
from library.ParticleSwarm import ParticleSwarm


class Algorithm(ParticleSwarm):
"""
Tries to get a randomly-generated list to match [.1, .2, .3, .2, .1]
"""
def _objective(self, member):
return sum(abs(member[i] - [.1, .2, .3, .2, .1][i]) if (member[i] > 0 or member[i] < 0) else 1 for i in range(5))


def test_algorithm():
algorithm = Algorithm(50, 5, [0.,0.,0.,0.,0.], [1.,1.,1.,1.,1.], 1., 2., 2., 500, min_objective=None)
algorithm.run()
19 changes: 19 additions & 0 deletions tests/test_simulated_annealing.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
from random import uniform
from library.SimulatedAnnealing import SimulatedAnnealing
from numpy import array


class Algorithm(SimulatedAnnealing):
"""
Tries to get a randomly-generated list to match [.1, .2, .3, .2, .1]
"""
def _neighbor(self):
return list(array(self.current_state) + array([uniform(-.02, .02) for _ in range(5)]))

def _energy(self, member):
return sum(abs(member[i] - [.1, .2, .3, .2, .1][i]) if (member[i] > 0 or member[i] < 0) else 1 for i in range(5))


def test_algorithm():
algorithm = Algorithm(list([uniform(0, 1) for _ in range(5)]), 5, .99, 5000)
algorithm.run()
19 changes: 19 additions & 0 deletions tests/test_stochastic_hill_climb.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
from random import uniform
from library.StochasticHillClimb import StochasticHillClimb
from numpy import array


class Algorithm(StochasticHillClimb):
"""
Tries to get a randomly-generated list to match [.1, .2, .3, .2, .1]
"""
def _neighbor(self):
return list(array(self.current_state) + array([uniform(-.02, .02) for _ in range(5)]))

def _objective(self, state):
return 1. / sum(abs(state[i] - [.1, .2, .3, .2, .1][i]) if (state[i] > 0 or state[i] < 0) else 1 for i in range(5))


def test_algorithm():
algorithm = Algorithm(list([uniform(0, 1) for _ in range(5)]), .01, 1000)
algorithm.run()
27 changes: 27 additions & 0 deletions tests/test_tabu_search.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
from random import choice, randint, random
from string import lowercase
from library.TabuSearch import TabuSearch
from copy import deepcopy


class Algorithm(TabuSearch):
"""
Tries to get a randomly-generated string to match string "clout"
"""
def _neighborhood(self):
member = list(self.current)
neighborhood = []
for _ in range(10):
neighbor = deepcopy(member)
neighbor[randint(0,4)] = choice(lowercase)
neighbor = ''.join(neighbor)
neighborhood.append(neighbor)
return neighborhood

def _score(self, state):
return float(sum(state[i] == "clout"[i] for i in range(5)))


def test_algorithm():
algorithm = Algorithm('abcde', 50, 500, max_score=None)
algorithm.run()

0 comments on commit 9b0ea8b

Please sign in to comment.