From 24c1cb5ad788655ca963771c6ffc650d5fae2dbf Mon Sep 17 00:00:00 2001 From: Christoph Hansknecht Date: Fri, 24 May 2024 16:50:14 +0200 Subject: [PATCH 1/4] Discard unreliable nonlinearity measures --- pygradflow/iterate.py | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/pygradflow/iterate.py b/pygradflow/iterate.py index 2754bbf..e634cfb 100644 --- a/pygradflow/iterate.py +++ b/pygradflow/iterate.py @@ -183,9 +183,16 @@ def total_res(self) -> float: def obj_nonlin(self, other: "Iterate") -> float: dx = other.x - self.x next_obj = self.obj + np.dot(dx, self.obj_grad) - return abs(other.obj - next_obj) / np.dot(dx, dx) + dx_dot = np.dot(dx, dx) + if np.isclose(dx_dot, 0.0): + return 0.0 + return abs(other.obj - next_obj) / dx_dot def cons_nonlin(self, other: "Iterate") -> np.ndarray: dx = other.x - self.x next_cons = self.cons + self.cons_jac.dot(dx) - return (other.cons - next_cons) / np.dot(dx, dx) + dx_dot = np.dot(dx, dx) + if np.isclose(dx_dot, 0.0): + problem = self.problem + return np.zeros((problem.num_cons,)) + return (other.cons - next_cons) / dx_dot From 608ced1f75f9052e3418400cb6cc0f367654d3d2 Mon Sep 17 00:00:00 2001 From: Christoph Hansknecht Date: Fri, 24 May 2024 16:50:49 +0200 Subject: [PATCH 2/4] Move sparse zero function to utility file --- pygradflow/cons_problem.py | 5 +---- pygradflow/util.py | 9 +++++++++ 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/pygradflow/cons_problem.py b/pygradflow/cons_problem.py index f78f2bd..c45ce1c 100644 --- a/pygradflow/cons_problem.py +++ b/pygradflow/cons_problem.py @@ -2,10 +2,7 @@ import scipy as sp from pygradflow.problem import Problem - - -def sparse_zero(shape): - return sp.sparse.coo_matrix(([], ([], [])), shape) +from pygradflow.util import sparse_zero class ConstrainedProblem(Problem): diff --git a/pygradflow/util.py b/pygradflow/util.py index 4bee2e2..48e507e 100644 --- a/pygradflow/util.py +++ b/pygradflow/util.py @@ -3,6 +3,15 @@ from numpy import ndarray +def sparse_zero(shape, format=None): + zero_mat = sp.sparse.coo_matrix(([], ([], [])), shape) + + if format not in [None, "coo"]: + return zero_mat.asformat(format) + + return zero_mat + + def norm_sq(x: ndarray) -> float: return np.dot(x, x) From ae77174e6c2d1d7e69ba2953487cd64d2d7cdb66 Mon Sep 17 00:00:00 2001 From: Christoph Hansknecht Date: Fri, 24 May 2024 16:52:22 +0200 Subject: [PATCH 3/4] Refactor initial solutions of runners --- pygradflow/runners/cutest_runner.py | 21 ++------------------- pygradflow/runners/instance.py | 12 ++++++++++-- pygradflow/runners/qplib_runner.py | 18 +++++++----------- 3 files changed, 19 insertions(+), 32 deletions(-) diff --git a/pygradflow/runners/cutest_runner.py b/pygradflow/runners/cutest_runner.py index 3bc7b29..a06ef16 100644 --- a/pygradflow/runners/cutest_runner.py +++ b/pygradflow/runners/cutest_runner.py @@ -1,16 +1,13 @@ -import logging from functools import cached_property import numpy as np import pycutest -from pygradflow.solver import Problem, Solver +from pygradflow.problem import Problem from .instance import Instance from .runner import Runner -formatter = logging.Formatter("%(asctime)s:%(name)s:%(levelname)s:%(message)s") - def cutest_is_ne_prob(name): return name.endswith("NE") @@ -48,14 +45,9 @@ def cons_jac(self, x): def lag_hess(self, x, y): return self.instance.sphess(x, v=None) - @property def x0(self): return self.instance.x0 - @property - def y0(self): - return np.zeros((self.num_cons,)) - class ConstrainedCUTEstProblem(Problem): def __init__(self, instance): @@ -86,11 +78,7 @@ def lag_hess(self, x, y): @property def x0(self): - return self.instance.x0 - - @property - def y0(self): - return self.instance.v0 + return self.instance.x0() # Nonlinear equations: Goal is to minimize the violation @@ -162,11 +150,6 @@ def problem(self): else: return ConstrainedCUTEstProblem(cutest_problem) - def solve(self, params): - problem = self.problem() - solver = Solver(problem, params) - return solver.solve(problem.x0, problem.y0) - class CUTestRunner(Runner): def __init__(self): diff --git a/pygradflow/runners/instance.py b/pygradflow/runners/instance.py index d4355c9..6d4eeb0 100644 --- a/pygradflow/runners/instance.py +++ b/pygradflow/runners/instance.py @@ -1,5 +1,9 @@ from abc import ABC, abstractmethod +import numpy as np + +from pygradflow.solver import Solver + class Instance(ABC): def __init__(self, name, num_vars, num_cons): @@ -11,9 +15,10 @@ def __init__(self, name, num_vars, num_cons): def size(self): return self.num_vars + self.num_cons - @abstractmethod def solve(self, params): - raise NotImplementedError() + problem = self.problem() + solver = Solver(problem, params) + return solver.solve(self.x0(), self.y0()) @abstractmethod def problem(self): @@ -22,3 +27,6 @@ def problem(self): @abstractmethod def x0(self): raise NotImplementedError() + + def y0(self): + return np.zeros((self.num_cons,)) diff --git a/pygradflow/runners/qplib_runner.py b/pygradflow/runners/qplib_runner.py index ebfce2e..fd30453 100644 --- a/pygradflow/runners/qplib_runner.py +++ b/pygradflow/runners/qplib_runner.py @@ -2,7 +2,7 @@ import pyqplib -from pygradflow.solver import Problem, Solver +from pygradflow.solver import Problem from .instance import Instance from .runner import Runner @@ -34,13 +34,11 @@ def cons_jac(self, x): def lag_hess(self, x, y): return self.problem.lag_hess(x, y) - @property def x0(self): - return self.problem.x0 + return self.problem.x0() - @property def y0(self): - return self.problem.y0 + return self.problem.y0() class QPLIBInstance(Instance): @@ -53,17 +51,15 @@ def __init__(self, description): def filename(self): return self.description.filename - def solve(self, params): - problem = self.problem() - solver = Solver(problem, params) - return solver.solve(problem.x0, problem.y0) - def problem(self): qproblem = pyqplib.read_problem(self.filename) return QPLIBProblem(qproblem) def x0(self): - return self.problem().x0 + return self.problem().x0() + + def y0(self): + return self.problem().y0() class QPLIBRunner(Runner): From 60000c07963ccd5f2d1fae0fc86b885677f756b0 Mon Sep 17 00:00:00 2001 From: Christoph Hansknecht Date: Fri, 24 May 2024 16:53:50 +0200 Subject: [PATCH 4/4] Bump version --- docs/conf.py | 2 +- pyproject.toml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/conf.py b/docs/conf.py index 291f500..ca3c02e 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -14,7 +14,7 @@ project = "pygradflow" copyright = "2023, Christoph Hansknecht" author = "Christoph Hansknecht" -release = "0.5.0" +release = "0.5.1" # -- General configuration --------------------------------------------------- # https://www.sphinx-doc.org/en/master/usage/configuration.html#general-configuration diff --git a/pyproject.toml b/pyproject.toml index 1b073c6..744a329 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [tool.poetry] name = "pygradflow" -version = "0.5.0" +version = "0.5.1" description = "PyGradFlow is a simple implementation of the sequential homotopy method to be used to solve general nonlinear programs." authors = ["Christoph Hansknecht "] readme = "README.md"