diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..01ceca1 --- /dev/null +++ b/.gitignore @@ -0,0 +1,4 @@ +venv +build +dist +*.egg-info \ No newline at end of file diff --git a/appveyor.yml b/appveyor.yml index e7b0ca0..1cf08ce 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -28,7 +28,7 @@ for: PYPI_USERNAME: __token__ PYPI_SERVER: https://upload.pypi.org/legacy/ PYPI_PASSWORD: - secure: BlFonvNFzspp5kZ6nsJTjSJfWqviD0DDAiCgMtKVbyspHPCu+PR/fS++fUCt6hM3X03oTdvzX0wYGbZiZwPr09SO4lblS0Qyilm8rnHpICzuCDn+KBBNrIFYdvU4WYndcQ9fNniPw1QiWxmMJsbxsSc7io3thIt+fG8L9OJxFQmjzDj2Az0oXOUswSVjKmq8aoOD2agdcS+JI6uyEq9Ve5kQYdY4Bgn3FNWSsL8QxnHW8MQxuNrpaWvhV22BGqGk0NQVNlnlEyCuiPVatPKsUA== + secure: BlFonvNFzspp5kZ6nsJTjZhe70GzsNHPjsCw+6xTyPiQE2eZg4hbf2o3SPwVsdObLnSwsiNUtsfTvstjwj5SZrTJj6P7pXCAr55T4cE3o6PCP8Z3/3C6l9nvFDw3CoQMrFPDWDKu9hwItO4Yndu46DQoz+uSlDZBvJF1wCzw20hGzeTDPnfPnELpa3fFC3SZTEPYx6kzRpSizJoT9Y+8IhIRo7Nm9mu6QiZJqRSDRVtT9vk6Ra44XSJ52J/+t+Z4GthRixxKTnGDtB9Ywt06Ug== install: - sh: | diff --git a/pygosolnp/evaluation_functions.py b/pygosolnp/evaluation_functions.py index c804682..c660ffa 100644 --- a/pygosolnp/evaluation_functions.py +++ b/pygosolnp/evaluation_functions.py @@ -25,7 +25,8 @@ def initialize_worker_process_resources(obj_func, evaluation_type, number_of_parameters, eval_results, - restart_results): + restart_results, + restart_convergence): """ This function is used to provide the functions in this file access to shared resources when running pygosolnp. In multiprocess-mode it will pass multiprocess-safe types for each process, in single-processing it will simply have regular Python types. @@ -48,6 +49,7 @@ def initialize_worker_process_resources(obj_func, :param number_of_parameters: An int / multiprocessing.Value (int) representing the number of parameters for this problem (a.k.a len(par_lower_limit)) :param eval_results: An List / multiprocessing.Array (float) for storing the evaluation function results :param restart_results: An List / multiprocessing.Array (float) for storing the pysolnp calculation parameter results + :param restart_convergence: An List / multiprocessing.Array (bool) for storing the pysolnp calculation convergence results """ resources.obj_func = obj_func resources.par_lower_limit = par_lower_limit @@ -68,6 +70,7 @@ def initialize_worker_process_resources(obj_func, resources.number_of_parameters = number_of_parameters resources.eval_results = eval_results resources.restart_results = restart_results + resources.restart_convergence = restart_convergence def __resource_value(resource: Any): @@ -168,6 +171,7 @@ def pysolnp_solve(solve_index: int, guess_index: int): resources.restart_results[(solve_index * number_of_parameters): ( (solve_index + 1) * number_of_parameters)] = solve_result.optimum + resources.restart_convergence[solve_index] = solve_result.converged except ValueError as value_error: if debug: print(f"Error happened when running pysolnp for guess with index {guess_index}, ignoring this result. Error message: {value_error}") diff --git a/pygosolnp/model.py b/pygosolnp/model.py index 9aea642..f98548f 100644 --- a/pygosolnp/model.py +++ b/pygosolnp/model.py @@ -230,24 +230,3 @@ def validate(self): if type(self.__debug) is not bool: raise ValueError("debug needs to be a boolean value") - def check_solution_feasibility(self, par_found_solution): - if any(value < self.__par_lower_limit[index] - self.__tolerance or self.__par_upper_limit[ - index] + self.__tolerance < value for index, value in - enumerate(par_found_solution)): - return False - - if self.__eq_func is not None: - equality_function_values = self.__eq_func(par_found_solution) - if any(value < self.__eq_values[index] - self.__tolerance or self.__eq_values[ - index] + self.__tolerance < value for index, value in - enumerate(equality_function_values)): - return False - - if self.__ineq_func is not None: - inequality_function_values = self.__ineq_func(par_found_solution) - if any(value < self.__ineq_lower_bounds[index] - self.__tolerance or self.__ineq_upper_bounds[ - index] + self.__tolerance < value for - index, value in enumerate(inequality_function_values)): - return False - - return True diff --git a/pygosolnp/pygosolnp.py b/pygosolnp/pygosolnp.py index 2e85aa5..186716f 100644 --- a/pygosolnp/pygosolnp.py +++ b/pygosolnp/pygosolnp.py @@ -139,7 +139,7 @@ def solve(obj_func: Callable, eval_results = Array(c_double, model.number_of_evaluations) # Results from the eval function restart_results = Array(c_double, model.number_of_restarts * model.number_of_parameters) # Results from pysolnp restarts - + restart_convergence = Array(c_bool, model.number_of_restarts) initargs = ( obj_func, par_lower_limit, @@ -159,7 +159,8 @@ def solve(obj_func: Callable, evaluation_type, number_of_parameters, eval_results, - restart_results + restart_results, + restart_convergence ) with Pool(processes=number_of_processes, initializer=initialize_worker_process_resources, @@ -178,6 +179,7 @@ def solve(obj_func: Callable, else: eval_results = [None] * model.number_of_evaluations restart_results = [None] * model.number_of_restarts * model.number_of_parameters + restart_convergence = [None] * model.number_of_restarts initialize_worker_process_resources( obj_func=obj_func, @@ -198,7 +200,8 @@ def solve(obj_func: Callable, evaluation_type=model.evaluation_type.value, number_of_parameters=model.number_of_parameters, eval_results=eval_results, - restart_results=restart_results + restart_results=restart_results, + restart_convergence=restart_convergence ) for index in range(model.number_of_evaluations): @@ -214,13 +217,13 @@ def solve(obj_func: Callable, pysolnp_solve(solve_index=solve_index, guess_index=guess_index) # For each restart, get the resulting parameters - solutions = [restart_results[index * model.number_of_parameters: (index + 1) * model.number_of_parameters] for - index in range(model.number_of_restarts)] + solutions = [(restart_results[index * model.number_of_parameters: (index + 1) * model.number_of_parameters], + restart_convergence[index]) for index in range(model.number_of_restarts)] # Each Result represents a solution to the restart (might have not converged) all_results = [ - Result(parameters=solution, obj_value=obj_func(solution), converged=model.check_solution_feasibility(solution)) - for solution in solutions] + Result(parameters=solution, obj_value=obj_func(solution), converged=converged) + for solution, converged in solutions] # pysolnp might have not converged for some solution, if no converging solutions exist, print an warning message. if len([solution for solution in all_results if solution.converged]) == 0: diff --git a/pygosolnp/resources.py b/pygosolnp/resources.py index 2ae2fcb..e558d02 100644 --- a/pygosolnp/resources.py +++ b/pygosolnp/resources.py @@ -26,3 +26,4 @@ number_of_parameters = None eval_results = None restart_results = None +restart_convergence = None diff --git a/requirements.txt b/requirements.txt index 58e749f..bf8e8a9 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1 +1 @@ -pysolnp +pysolnp>=2021.4.30 diff --git a/setup.py b/setup.py index ac37841..4cd5f14 100644 --- a/setup.py +++ b/setup.py @@ -2,7 +2,7 @@ import setuptools from datetime import datetime -__version__ = datetime.today().strftime('%Y.%m.%d').replace(".0", ".") # Remove initial 0 from date, ex: 01 -> 1 +__version__ = "2021.5.1" here = os.path.abspath(os.path.dirname(__file__)) with open(os.path.join(here, 'README.md')) as file: