# Path: Optimizers/Optimizer.py
# class Optimizer(object):
#     __metaclass__ = abc.ABCMeta
# 
#     @abc.abstractmethod
#     def __init__(self, problem, parameters):
#         """
#         This method initialized the Optimizer with an objective function and a set of parameters
#         :param problem: this is the problem being optimized
#         :param parameters: set of algorithm control parameters
#         """
#         self.problem = problem
#         self.parameters = parameters
#         return
# 
#     @abc.abstractmethod
#     def optimize(self, iterations=1000, stopping=True):
#         """
#         This is the generic optimization method to be overloaded by each optimizer
#         :param stopping: whether or not the algorithm should use early stopping
#         :param iterations: the number of iterations to optimize for, default is 1000
#         """
#         return
# 
#     def fitness(self, candidate):
#         """
#         This is the generic optimization method to be overloaded by each optimizer
#         :param candidate:
#         """
#         assert isinstance(self.problem, Problems.Function)
#         assert isinstance(candidate, Solution)
#         return self.problem.evaluate(candidate)
# 
# Path: Optimizers/Solution.py
# class Solution(object):
#     solution = []
# 
#     def __init__(self, solution, problem):
#         """
#         Abstract initialization method for a solution to some optimization function
#         :param solution: a numpy array (much faster than lists)
#         """
#         self.solution = solution
#         self.problem = problem
#         return
# 
#     def __len__(self):
#         """
#         Overload of the len operator for the Solution class
#         :rtype : Sized?
#         """
#         return len(self.solution)
# 
#     def update(self, solution):
#         """
#         This method is used for updating a solution
#         """
#         self.solution = solution
# 
#     def get(self):
#         """
#         This method is used to retrieve the numpy array for direct manipulation
#         """
#         return self.solution
# 
#     def evaluate(self):
#         return self.problem.evaluate(self.solution)
# 
#     def __gt__(self, other):
#         assert isinstance(other, Solution)
#         if self.problem.optimization is "min":
#             return self.evaluate() < other.evaluate()
#         elif self.problem.optimization is "max":
#             return self.evaluate() > other.evaluate()
# 
#     def deep_copy(self):
#         copy = Solution(None, self.problem)
#         copy.solution = []
#         for i in range(len(self.solution)):
#             copy.solution.append(self.solution[i])
#         return copy


import random
from Optimizers.Optimizer import Optimizer
from Optimizers.Solution import Solution
        :param problem:
        :param parameters[0]: Crossover rate (% of the population which is used in crossover)
        :param parameters[1]: Crossover strategy e.g. sexual, asexual
        :param parameters[2]: Mutation rate (% of the population which is mutated)
        :param parameters[3]: Mutator strategy e.g. Brownian Individuals
        :param parameters[4]: Selection rate (% of the population to be culled)
        :param parameters[5]: Selection strategy e.g. Rank Selection vs. Random Selection
        :param parameters[6]: Population size # individuals.
        """
        if parameters is None:
            parameters = [0.5, "sexual", 0.05, "brownian", 0.5, "rank", 50]
        super(GeneticAlgorithm, self).__init__(problem, parameters)
        self.population = []
        for i in range(parameters[6]):
            random_solution = random.sample(xrange(problem.lower_bound, problem.upper_bound), problem.dimension)
            self.population.append(Individual(random_solution, problem))

    def optimize(self, iterations=1000, stopping=True):
        pass

    def select(self):
        pass

    def crossover(self):
        pass

    def mutate(self):
        pass



# Path: Optimizers/Optimizer.py
# class Optimizer(object):
#     __metaclass__ = abc.ABCMeta
# 
#     @abc.abstractmethod
#     def __init__(self, problem, parameters):
#         """
#         This method initialized the Optimizer with an objective function and a set of parameters
#         :param problem: this is the problem being optimized
#         :param parameters: set of algorithm control parameters
#         """
#         self.problem = problem
#         self.parameters = parameters
#         return
# 
#     @abc.abstractmethod
#     def optimize(self, iterations=1000, stopping=True):
#         """
#         This is the generic optimization method to be overloaded by each optimizer
#         :param stopping: whether or not the algorithm should use early stopping
#         :param iterations: the number of iterations to optimize for, default is 1000
#         """
#         return
# 
#     def fitness(self, candidate):
#         """
#         This is the generic optimization method to be overloaded by each optimizer
#         :param candidate:
#         """
#         assert isinstance(self.problem, Problems.Function)
#         assert isinstance(candidate, Solution)
#         return self.problem.evaluate(candidate)
# 
# Path: Optimizers/Solution.py
# class Solution(object):
#     solution = []
# 
#     def __init__(self, solution, problem):
#         """
#         Abstract initialization method for a solution to some optimization function
#         :param solution: a numpy array (much faster than lists)
#         """
#         self.solution = solution
#         self.problem = problem
#         return
# 
#     def __len__(self):
#         """
#         Overload of the len operator for the Solution class
#         :rtype : Sized?
#         """
#         return len(self.solution)
# 
#     def update(self, solution):
#         """
#         This method is used for updating a solution
#         """
#         self.solution = solution
# 
#     def get(self):
#         """
#         This method is used to retrieve the numpy array for direct manipulation
#         """
#         return self.solution
# 
#     def evaluate(self):
#         return self.problem.evaluate(self.solution)
# 
#     def __gt__(self, other):
#         assert isinstance(other, Solution)
#         if self.problem.optimization is "min":
#             return self.evaluate() < other.evaluate()
#         elif self.problem.optimization is "max":
#             return self.evaluate() > other.evaluate()
# 
#     def deep_copy(self):
#         copy = Solution(None, self.problem)
#         copy.solution = []
#         for i in range(len(self.solution)):
#             copy.solution.append(self.solution[i])
#         return copy


# Path: Optimizers/GeneticAlgorithm.py
import random
from Optimizers.Optimizer import Optimizer
from Optimizers.Solution import Solution

        :param problem:
        :param parameters[0]: Crossover rate (% of the population which is used in crossover)
        :param parameters[1]: Crossover strategy e.g. sexual, asexual
        :param parameters[2]: Mutation rate (% of the population which is mutated)
        :param parameters[3]: Mutator strategy e.g. Brownian Individuals
        :param parameters[4]: Selection rate (% of the population to be culled)
        :param parameters[5]: Selection strategy e.g. Rank Selection vs. Random Selection
        :param parameters[6]: Population size # individuals.
        """
        if parameters is None:
            parameters = [0.5, "sexual", 0.05, "brownian", 0.5, "rank", 50]
        super(GeneticAlgorithm, self).__init__(problem, parameters)
        self.population = []
        for i in range(parameters[6]):
            random_solution = random.sample(xrange(problem.lower_bound, problem.upper_bound), problem.dimension)
            self.population.append(Individual(random_solution, problem))

    def optimize(self, iterations=1000, stopping=True):
        pass

    def select(self):
        pass

    def crossover(self):
        pass

    def mutate(self):
        pass



class Individual(Solution):