# Path: platypus/core.py
# class Solution(object):
#     """Class representing a solution to a problem.
#     
#     Attributes
#     ----------
#     problem: Problem
#         The problem.
#     variables: FixedLengthArray of objects
#         The values of the variables.
#     objectives: FixedLengthArray of float
#         The values of the objectives.  These values will only be assigned after
#         the solution is evaluated.
#     constraints: FixedLengthArray of float
#         The values of the constraints.  These values will only be assigned
#         after the solution is evaluated.
#     constraint_violation: float
#         The magnitude of the constraint violation.
#     feasible: bool
#         True if the solution does not violate any constraints; False otherwise.
#     evaluated: bool
#         True if the solution is evaluated; False otherwise.
#     """
#     
#     def __init__(self, problem):
#         """Creates a new solution for the given problem."""
#         super(Solution, self).__init__()
#         self.problem = problem
#         self.variables = FixedLengthArray(problem.nvars)
#         self.objectives = FixedLengthArray(problem.nobjs)
#         self.constraints = FixedLengthArray(problem.nconstrs)
#         self.constraint_violation = 0.0
#         self.evaluated = False
#         
#     def evaluate(self):
#         """Evaluates this solution."""
#         self.problem(self)
#         
#     def __repr__(self):
#         return self.__str__()
#         
#     def __str__(self):
#         return "Solution[" + ",".join(list(map(str, self.variables))) + "|" + ",".join(list(map(str, self.objectives))) + "|" + str(self.constraint_violation) + "]"
#     
#     def __deepcopy__(self, memo):
#         """Overridden to avoid cloning the problem definition."""
#         result = Solution(self.problem)
#         memo[id(self)] = result
#         
#         for k, v in self.__dict__.items():
#             if k != "problem":
#                 setattr(result, k, copy.deepcopy(v, memo))
#                 
#         return result
# 
# POSITIVE_INFINITY = float("inf")
# 
# EPSILON = sys.float_info.epsilon
# 
# class PlatypusError(Exception):
#     pass


import sys
import math
import random
import inspect
import operator
import functools
from functools import reduce
from .core import Solution, POSITIVE_INFINITY, EPSILON, PlatypusError
def random_vector(n, rng=functools.partial(random.gauss, 0.0, 1.0)):
    return [rng() for _ in range(n)]

def zeros(m, n):
    return [[0.0]*n for _ in range(m)]

class SingularError(PlatypusError):
    pass
    
def lsolve(A, b):
    """Gaussian elimination with partial pivoting.
    
    This is implemented here to avoid a dependency on numpy.  This could be
    replaced by :code:`(x, _, _, _) = lstsq(A, b)`, but we prefer the pure
    Python implementation here.
    """
    N = len(b)
     
    for p in range(N):
        # find pivot row and swap
        max = p
         
        for i in range(p+1, N):
            if abs(A[i][p]) > abs(A[max][p]):
                max = i
                 
        A[p], A[max] = A[max], A[p]
        b[p], b[max] = b[max], b[p]
        
        # singular or nearly singular

# Path: platypus/core.py
# class Solution(object):
#     """Class representing a solution to a problem.
#     
#     Attributes
#     ----------
#     problem: Problem
#         The problem.
#     variables: FixedLengthArray of objects
#         The values of the variables.
#     objectives: FixedLengthArray of float
#         The values of the objectives.  These values will only be assigned after
#         the solution is evaluated.
#     constraints: FixedLengthArray of float
#         The values of the constraints.  These values will only be assigned
#         after the solution is evaluated.
#     constraint_violation: float
#         The magnitude of the constraint violation.
#     feasible: bool
#         True if the solution does not violate any constraints; False otherwise.
#     evaluated: bool
#         True if the solution is evaluated; False otherwise.
#     """
#     
#     def __init__(self, problem):
#         """Creates a new solution for the given problem."""
#         super(Solution, self).__init__()
#         self.problem = problem
#         self.variables = FixedLengthArray(problem.nvars)
#         self.objectives = FixedLengthArray(problem.nobjs)
#         self.constraints = FixedLengthArray(problem.nconstrs)
#         self.constraint_violation = 0.0
#         self.evaluated = False
#         
#     def evaluate(self):
#         """Evaluates this solution."""
#         self.problem(self)
#         
#     def __repr__(self):
#         return self.__str__()
#         
#     def __str__(self):
#         return "Solution[" + ",".join(list(map(str, self.variables))) + "|" + ",".join(list(map(str, self.objectives))) + "|" + str(self.constraint_violation) + "]"
#     
#     def __deepcopy__(self, memo):
#         """Overridden to avoid cloning the problem definition."""
#         result = Solution(self.problem)
#         memo[id(self)] = result
#         
#         for k, v in self.__dict__.items():
#             if k != "problem":
#                 setattr(result, k, copy.deepcopy(v, memo))
#                 
#         return result
# 
# POSITIVE_INFINITY = float("inf")
# 
# EPSILON = sys.float_info.epsilon
# 
# class PlatypusError(Exception):
#     pass


# Path: platypus/tools.py
import sys
import math
import random
import inspect
import operator
import functools
from functools import reduce
from .core import Solution, POSITIVE_INFINITY, EPSILON, PlatypusError

def random_vector(n, rng=functools.partial(random.gauss, 0.0, 1.0)):
    return [rng() for _ in range(n)]

def zeros(m, n):
    return [[0.0]*n for _ in range(m)]

class SingularError(PlatypusError):
    pass
    
def lsolve(A, b):
    """Gaussian elimination with partial pivoting.
    
    This is implemented here to avoid a dependency on numpy.  This could be
    replaced by :code:`(x, _, _, _) = lstsq(A, b)`, but we prefer the pure
    Python implementation here.
    """
    N = len(b)
     
    for p in range(N):
        # find pivot row and swap
        max = p
         
        for i in range(p+1, N):
            if abs(A[i][p]) > abs(A[max][p]):
                max = i
                 
        A[p], A[max] = A[max], A[p]
        b[p], b[max] = b[max], b[p]
        
        # singular or nearly singular

        if abs(A[p][p]) <= EPSILON: