asd
This commit is contained in:
@ -0,0 +1,20 @@
|
||||
from .main import minimize
|
||||
from .utils import show_versions
|
||||
|
||||
# PEP0440 compatible formatted version, see:
|
||||
# https://www.python.org/dev/peps/pep-0440/
|
||||
#
|
||||
# Final release markers:
|
||||
# X.Y.0 # For first release after an increment in Y
|
||||
# X.Y.Z # For bugfix releases
|
||||
#
|
||||
# Admissible pre-release markers:
|
||||
# X.YaN # Alpha release
|
||||
# X.YbN # Beta release
|
||||
# X.YrcN # Release Candidate
|
||||
#
|
||||
# Dev branch marker is: 'X.Y.dev' or 'X.Y.devN' where N is an integer.
|
||||
# 'X.Y.dev0' is the canonical version of 'X.Y.dev'.
|
||||
__version__ = "1.1.1"
|
||||
|
||||
__all__ = ["minimize", "show_versions"]
|
||||
1240
venv/lib/python3.12/site-packages/scipy/_lib/cobyqa/framework.py
Normal file
1240
venv/lib/python3.12/site-packages/scipy/_lib/cobyqa/framework.py
Normal file
File diff suppressed because it is too large
Load Diff
1488
venv/lib/python3.12/site-packages/scipy/_lib/cobyqa/main.py
Normal file
1488
venv/lib/python3.12/site-packages/scipy/_lib/cobyqa/main.py
Normal file
File diff suppressed because it is too large
Load Diff
1525
venv/lib/python3.12/site-packages/scipy/_lib/cobyqa/models.py
Normal file
1525
venv/lib/python3.12/site-packages/scipy/_lib/cobyqa/models.py
Normal file
File diff suppressed because it is too large
Load Diff
1287
venv/lib/python3.12/site-packages/scipy/_lib/cobyqa/problem.py
Normal file
1287
venv/lib/python3.12/site-packages/scipy/_lib/cobyqa/problem.py
Normal file
File diff suppressed because it is too large
Load Diff
132
venv/lib/python3.12/site-packages/scipy/_lib/cobyqa/settings.py
Normal file
132
venv/lib/python3.12/site-packages/scipy/_lib/cobyqa/settings.py
Normal file
@ -0,0 +1,132 @@
|
||||
import sys
|
||||
from enum import Enum
|
||||
|
||||
import numpy as np
|
||||
|
||||
|
||||
# Exit status.
|
||||
class ExitStatus(Enum):
|
||||
"""
|
||||
Exit statuses.
|
||||
"""
|
||||
|
||||
RADIUS_SUCCESS = 0
|
||||
TARGET_SUCCESS = 1
|
||||
FIXED_SUCCESS = 2
|
||||
CALLBACK_SUCCESS = 3
|
||||
FEASIBLE_SUCCESS = 4
|
||||
MAX_EVAL_WARNING = 5
|
||||
MAX_ITER_WARNING = 6
|
||||
INFEASIBLE_ERROR = -1
|
||||
LINALG_ERROR = -2
|
||||
|
||||
|
||||
class Options(str, Enum):
|
||||
"""
|
||||
Options.
|
||||
"""
|
||||
|
||||
DEBUG = "debug"
|
||||
FEASIBILITY_TOL = "feasibility_tol"
|
||||
FILTER_SIZE = "filter_size"
|
||||
HISTORY_SIZE = "history_size"
|
||||
MAX_EVAL = "maxfev"
|
||||
MAX_ITER = "maxiter"
|
||||
NPT = "nb_points"
|
||||
RHOBEG = "radius_init"
|
||||
RHOEND = "radius_final"
|
||||
SCALE = "scale"
|
||||
STORE_HISTORY = "store_history"
|
||||
TARGET = "target"
|
||||
VERBOSE = "disp"
|
||||
|
||||
|
||||
class Constants(str, Enum):
|
||||
"""
|
||||
Constants.
|
||||
"""
|
||||
|
||||
DECREASE_RADIUS_FACTOR = "decrease_radius_factor"
|
||||
INCREASE_RADIUS_FACTOR = "increase_radius_factor"
|
||||
INCREASE_RADIUS_THRESHOLD = "increase_radius_threshold"
|
||||
DECREASE_RADIUS_THRESHOLD = "decrease_radius_threshold"
|
||||
DECREASE_RESOLUTION_FACTOR = "decrease_resolution_factor"
|
||||
LARGE_RESOLUTION_THRESHOLD = "large_resolution_threshold"
|
||||
MODERATE_RESOLUTION_THRESHOLD = "moderate_resolution_threshold"
|
||||
LOW_RATIO = "low_ratio"
|
||||
HIGH_RATIO = "high_ratio"
|
||||
VERY_LOW_RATIO = "very_low_ratio"
|
||||
PENALTY_INCREASE_THRESHOLD = "penalty_increase_threshold"
|
||||
PENALTY_INCREASE_FACTOR = "penalty_increase_factor"
|
||||
SHORT_STEP_THRESHOLD = "short_step_threshold"
|
||||
LOW_RADIUS_FACTOR = "low_radius_factor"
|
||||
BYRD_OMOJOKUN_FACTOR = "byrd_omojokun_factor"
|
||||
THRESHOLD_RATIO_CONSTRAINTS = "threshold_ratio_constraints"
|
||||
LARGE_SHIFT_FACTOR = "large_shift_factor"
|
||||
LARGE_GRADIENT_FACTOR = "large_gradient_factor"
|
||||
RESOLUTION_FACTOR = "resolution_factor"
|
||||
IMPROVE_TCG = "improve_tcg"
|
||||
|
||||
|
||||
# Default options.
|
||||
DEFAULT_OPTIONS = {
|
||||
Options.DEBUG.value: False,
|
||||
Options.FEASIBILITY_TOL.value: np.sqrt(np.finfo(float).eps),
|
||||
Options.FILTER_SIZE.value: sys.maxsize,
|
||||
Options.HISTORY_SIZE.value: sys.maxsize,
|
||||
Options.MAX_EVAL.value: lambda n: 500 * n,
|
||||
Options.MAX_ITER.value: lambda n: 1000 * n,
|
||||
Options.NPT.value: lambda n: 2 * n + 1,
|
||||
Options.RHOBEG.value: 1.0,
|
||||
Options.RHOEND.value: 1e-6,
|
||||
Options.SCALE.value: False,
|
||||
Options.STORE_HISTORY.value: False,
|
||||
Options.TARGET.value: -np.inf,
|
||||
Options.VERBOSE.value: False,
|
||||
}
|
||||
|
||||
# Default constants.
|
||||
DEFAULT_CONSTANTS = {
|
||||
Constants.DECREASE_RADIUS_FACTOR.value: 0.5,
|
||||
Constants.INCREASE_RADIUS_FACTOR.value: np.sqrt(2.0),
|
||||
Constants.INCREASE_RADIUS_THRESHOLD.value: 2.0,
|
||||
Constants.DECREASE_RADIUS_THRESHOLD.value: 1.4,
|
||||
Constants.DECREASE_RESOLUTION_FACTOR.value: 0.1,
|
||||
Constants.LARGE_RESOLUTION_THRESHOLD.value: 250.0,
|
||||
Constants.MODERATE_RESOLUTION_THRESHOLD.value: 16.0,
|
||||
Constants.LOW_RATIO.value: 0.1,
|
||||
Constants.HIGH_RATIO.value: 0.7,
|
||||
Constants.VERY_LOW_RATIO.value: 0.01,
|
||||
Constants.PENALTY_INCREASE_THRESHOLD.value: 1.5,
|
||||
Constants.PENALTY_INCREASE_FACTOR.value: 2.0,
|
||||
Constants.SHORT_STEP_THRESHOLD.value: 0.5,
|
||||
Constants.LOW_RADIUS_FACTOR.value: 0.1,
|
||||
Constants.BYRD_OMOJOKUN_FACTOR.value: 0.8,
|
||||
Constants.THRESHOLD_RATIO_CONSTRAINTS.value: 2.0,
|
||||
Constants.LARGE_SHIFT_FACTOR.value: 10.0,
|
||||
Constants.LARGE_GRADIENT_FACTOR.value: 10.0,
|
||||
Constants.RESOLUTION_FACTOR.value: 2.0,
|
||||
Constants.IMPROVE_TCG.value: True,
|
||||
}
|
||||
|
||||
# Printing options.
|
||||
PRINT_OPTIONS = {
|
||||
"threshold": 6,
|
||||
"edgeitems": 2,
|
||||
"linewidth": sys.maxsize,
|
||||
"formatter": {
|
||||
"float_kind": lambda x: np.format_float_scientific(
|
||||
x,
|
||||
precision=3,
|
||||
unique=False,
|
||||
pad_left=2,
|
||||
)
|
||||
},
|
||||
}
|
||||
|
||||
# Constants.
|
||||
BARRIER = 2.0 ** min(
|
||||
100,
|
||||
np.finfo(float).maxexp // 2,
|
||||
-np.finfo(float).minexp // 2,
|
||||
)
|
||||
@ -0,0 +1,14 @@
|
||||
from .geometry import cauchy_geometry, spider_geometry
|
||||
from .optim import (
|
||||
tangential_byrd_omojokun,
|
||||
constrained_tangential_byrd_omojokun,
|
||||
normal_byrd_omojokun,
|
||||
)
|
||||
|
||||
__all__ = [
|
||||
"cauchy_geometry",
|
||||
"spider_geometry",
|
||||
"tangential_byrd_omojokun",
|
||||
"constrained_tangential_byrd_omojokun",
|
||||
"normal_byrd_omojokun",
|
||||
]
|
||||
@ -0,0 +1,387 @@
|
||||
import inspect
|
||||
|
||||
import numpy as np
|
||||
|
||||
from ..utils import get_arrays_tol
|
||||
|
||||
|
||||
TINY = np.finfo(float).tiny
|
||||
|
||||
|
||||
def cauchy_geometry(const, grad, curv, xl, xu, delta, debug):
|
||||
r"""
|
||||
Maximize approximately the absolute value of a quadratic function subject
|
||||
to bound constraints in a trust region.
|
||||
|
||||
This function solves approximately
|
||||
|
||||
.. math::
|
||||
|
||||
\max_{s \in \mathbb{R}^n} \quad \bigg\lvert c + g^{\mathsf{T}} s +
|
||||
\frac{1}{2} s^{\mathsf{T}} H s \bigg\rvert \quad \text{s.t.} \quad
|
||||
\left\{ \begin{array}{l}
|
||||
l \le s \le u,\\
|
||||
\lVert s \rVert \le \Delta,
|
||||
\end{array} \right.
|
||||
|
||||
by maximizing the objective function along the constrained Cauchy
|
||||
direction.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
const : float
|
||||
Constant :math:`c` as shown above.
|
||||
grad : `numpy.ndarray`, shape (n,)
|
||||
Gradient :math:`g` as shown above.
|
||||
curv : callable
|
||||
Curvature of :math:`H` along any vector.
|
||||
|
||||
``curv(s) -> float``
|
||||
|
||||
returns :math:`s^{\mathsf{T}} H s`.
|
||||
xl : `numpy.ndarray`, shape (n,)
|
||||
Lower bounds :math:`l` as shown above.
|
||||
xu : `numpy.ndarray`, shape (n,)
|
||||
Upper bounds :math:`u` as shown above.
|
||||
delta : float
|
||||
Trust-region radius :math:`\Delta` as shown above.
|
||||
debug : bool
|
||||
Whether to make debugging tests during the execution.
|
||||
|
||||
Returns
|
||||
-------
|
||||
`numpy.ndarray`, shape (n,)
|
||||
Approximate solution :math:`s`.
|
||||
|
||||
Notes
|
||||
-----
|
||||
This function is described as the first alternative in Section 6.5 of [1]_.
|
||||
It is assumed that the origin is feasible with respect to the bound
|
||||
constraints and that `delta` is finite and positive.
|
||||
|
||||
References
|
||||
----------
|
||||
.. [1] T. M. Ragonneau. *Model-Based Derivative-Free Optimization Methods
|
||||
and Software*. PhD thesis, Department of Applied Mathematics, The Hong
|
||||
Kong Polytechnic University, Hong Kong, China, 2022. URL:
|
||||
https://theses.lib.polyu.edu.hk/handle/200/12294.
|
||||
"""
|
||||
if debug:
|
||||
assert isinstance(const, float)
|
||||
assert isinstance(grad, np.ndarray) and grad.ndim == 1
|
||||
assert inspect.signature(curv).bind(grad)
|
||||
assert isinstance(xl, np.ndarray) and xl.shape == grad.shape
|
||||
assert isinstance(xu, np.ndarray) and xu.shape == grad.shape
|
||||
assert isinstance(delta, float)
|
||||
assert isinstance(debug, bool)
|
||||
tol = get_arrays_tol(xl, xu)
|
||||
assert np.all(xl <= tol)
|
||||
assert np.all(xu >= -tol)
|
||||
assert np.isfinite(delta) and delta > 0.0
|
||||
xl = np.minimum(xl, 0.0)
|
||||
xu = np.maximum(xu, 0.0)
|
||||
|
||||
# To maximize the absolute value of a quadratic function, we maximize the
|
||||
# function itself or its negative, and we choose the solution that provides
|
||||
# the largest function value.
|
||||
step1, q_val1 = _cauchy_geom(const, grad, curv, xl, xu, delta, debug)
|
||||
step2, q_val2 = _cauchy_geom(
|
||||
-const,
|
||||
-grad,
|
||||
lambda x: -curv(x),
|
||||
xl,
|
||||
xu,
|
||||
delta,
|
||||
debug,
|
||||
)
|
||||
step = step1 if abs(q_val1) >= abs(q_val2) else step2
|
||||
|
||||
if debug:
|
||||
assert np.all(xl <= step)
|
||||
assert np.all(step <= xu)
|
||||
assert np.linalg.norm(step) < 1.1 * delta
|
||||
return step
|
||||
|
||||
|
||||
def spider_geometry(const, grad, curv, xpt, xl, xu, delta, debug):
|
||||
r"""
|
||||
Maximize approximately the absolute value of a quadratic function subject
|
||||
to bound constraints in a trust region.
|
||||
|
||||
This function solves approximately
|
||||
|
||||
.. math::
|
||||
|
||||
\max_{s \in \mathbb{R}^n} \quad \bigg\lvert c + g^{\mathsf{T}} s +
|
||||
\frac{1}{2} s^{\mathsf{T}} H s \bigg\rvert \quad \text{s.t.} \quad
|
||||
\left\{ \begin{array}{l}
|
||||
l \le s \le u,\\
|
||||
\lVert s \rVert \le \Delta,
|
||||
\end{array} \right.
|
||||
|
||||
by maximizing the objective function along given straight lines.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
const : float
|
||||
Constant :math:`c` as shown above.
|
||||
grad : `numpy.ndarray`, shape (n,)
|
||||
Gradient :math:`g` as shown above.
|
||||
curv : callable
|
||||
Curvature of :math:`H` along any vector.
|
||||
|
||||
``curv(s) -> float``
|
||||
|
||||
returns :math:`s^{\mathsf{T}} H s`.
|
||||
xpt : `numpy.ndarray`, shape (n, npt)
|
||||
Points defining the straight lines. The straight lines considered are
|
||||
the ones passing through the origin and the points in `xpt`.
|
||||
xl : `numpy.ndarray`, shape (n,)
|
||||
Lower bounds :math:`l` as shown above.
|
||||
xu : `numpy.ndarray`, shape (n,)
|
||||
Upper bounds :math:`u` as shown above.
|
||||
delta : float
|
||||
Trust-region radius :math:`\Delta` as shown above.
|
||||
debug : bool
|
||||
Whether to make debugging tests during the execution.
|
||||
|
||||
Returns
|
||||
-------
|
||||
`numpy.ndarray`, shape (n,)
|
||||
Approximate solution :math:`s`.
|
||||
|
||||
Notes
|
||||
-----
|
||||
This function is described as the second alternative in Section 6.5 of
|
||||
[1]_. It is assumed that the origin is feasible with respect to the bound
|
||||
constraints and that `delta` is finite and positive.
|
||||
|
||||
References
|
||||
----------
|
||||
.. [1] T. M. Ragonneau. *Model-Based Derivative-Free Optimization Methods
|
||||
and Software*. PhD thesis, Department of Applied Mathematics, The Hong
|
||||
Kong Polytechnic University, Hong Kong, China, 2022. URL:
|
||||
https://theses.lib.polyu.edu.hk/handle/200/12294.
|
||||
"""
|
||||
if debug:
|
||||
assert isinstance(const, float)
|
||||
assert isinstance(grad, np.ndarray) and grad.ndim == 1
|
||||
assert inspect.signature(curv).bind(grad)
|
||||
assert (
|
||||
isinstance(xpt, np.ndarray)
|
||||
and xpt.ndim == 2
|
||||
and xpt.shape[0] == grad.size
|
||||
)
|
||||
assert isinstance(xl, np.ndarray) and xl.shape == grad.shape
|
||||
assert isinstance(xu, np.ndarray) and xu.shape == grad.shape
|
||||
assert isinstance(delta, float)
|
||||
assert isinstance(debug, bool)
|
||||
tol = get_arrays_tol(xl, xu)
|
||||
assert np.all(xl <= tol)
|
||||
assert np.all(xu >= -tol)
|
||||
assert np.isfinite(delta) and delta > 0.0
|
||||
xl = np.minimum(xl, 0.0)
|
||||
xu = np.maximum(xu, 0.0)
|
||||
|
||||
# Iterate through the straight lines.
|
||||
step = np.zeros_like(grad)
|
||||
q_val = const
|
||||
s_norm = np.linalg.norm(xpt, axis=0)
|
||||
|
||||
# Set alpha_xl to the step size for the lower-bound constraint and
|
||||
# alpha_xu to the step size for the upper-bound constraint.
|
||||
|
||||
# xl.shape = (N,)
|
||||
# xpt.shape = (N, M)
|
||||
# i_xl_pos.shape = (M, N)
|
||||
i_xl_pos = (xl > -np.inf) & (xpt.T > -TINY * xl)
|
||||
i_xl_neg = (xl > -np.inf) & (xpt.T < TINY * xl)
|
||||
i_xu_pos = (xu < np.inf) & (xpt.T > TINY * xu)
|
||||
i_xu_neg = (xu < np.inf) & (xpt.T < -TINY * xu)
|
||||
|
||||
# (M, N)
|
||||
alpha_xl_pos = np.atleast_2d(
|
||||
np.broadcast_to(xl, i_xl_pos.shape)[i_xl_pos] / xpt.T[i_xl_pos]
|
||||
)
|
||||
# (M,)
|
||||
alpha_xl_pos = np.max(alpha_xl_pos, axis=1, initial=-np.inf)
|
||||
# make sure it's (M,)
|
||||
alpha_xl_pos = np.broadcast_to(np.atleast_1d(alpha_xl_pos), xpt.shape[1])
|
||||
|
||||
alpha_xl_neg = np.atleast_2d(
|
||||
np.broadcast_to(xl, i_xl_neg.shape)[i_xl_neg] / xpt.T[i_xl_neg]
|
||||
)
|
||||
alpha_xl_neg = np.max(alpha_xl_neg, axis=1, initial=np.inf)
|
||||
alpha_xl_neg = np.broadcast_to(np.atleast_1d(alpha_xl_neg), xpt.shape[1])
|
||||
|
||||
alpha_xu_neg = np.atleast_2d(
|
||||
np.broadcast_to(xu, i_xu_neg.shape)[i_xu_neg] / xpt.T[i_xu_neg]
|
||||
)
|
||||
alpha_xu_neg = np.max(alpha_xu_neg, axis=1, initial=-np.inf)
|
||||
alpha_xu_neg = np.broadcast_to(np.atleast_1d(alpha_xu_neg), xpt.shape[1])
|
||||
|
||||
alpha_xu_pos = np.atleast_2d(
|
||||
np.broadcast_to(xu, i_xu_pos.shape)[i_xu_pos] / xpt.T[i_xu_pos]
|
||||
)
|
||||
alpha_xu_pos = np.max(alpha_xu_pos, axis=1, initial=np.inf)
|
||||
alpha_xu_pos = np.broadcast_to(np.atleast_1d(alpha_xu_pos), xpt.shape[1])
|
||||
|
||||
for k in range(xpt.shape[1]):
|
||||
# Set alpha_tr to the step size for the trust-region constraint.
|
||||
if s_norm[k] > TINY * delta:
|
||||
alpha_tr = max(delta / s_norm[k], 0.0)
|
||||
else:
|
||||
# The current straight line is basically zero.
|
||||
continue
|
||||
|
||||
alpha_bd_pos = max(min(alpha_xu_pos[k], alpha_xl_neg[k]), 0.0)
|
||||
alpha_bd_neg = min(max(alpha_xl_pos[k], alpha_xu_neg[k]), 0.0)
|
||||
|
||||
# Set alpha_quad_pos and alpha_quad_neg to the step size to the extrema
|
||||
# of the quadratic function along the positive and negative directions.
|
||||
grad_step = grad @ xpt[:, k]
|
||||
curv_step = curv(xpt[:, k])
|
||||
if (
|
||||
grad_step >= 0.0
|
||||
and curv_step < -TINY * grad_step
|
||||
or grad_step <= 0.0
|
||||
and curv_step > -TINY * grad_step
|
||||
):
|
||||
alpha_quad_pos = max(-grad_step / curv_step, 0.0)
|
||||
else:
|
||||
alpha_quad_pos = np.inf
|
||||
if (
|
||||
grad_step >= 0.0
|
||||
and curv_step > TINY * grad_step
|
||||
or grad_step <= 0.0
|
||||
and curv_step < TINY * grad_step
|
||||
):
|
||||
alpha_quad_neg = min(-grad_step / curv_step, 0.0)
|
||||
else:
|
||||
alpha_quad_neg = -np.inf
|
||||
|
||||
# Select the step that provides the largest value of the objective
|
||||
# function if it improves the current best. The best positive step is
|
||||
# either the one that reaches the constraints or the one that reaches
|
||||
# the extremum of the objective function along the current direction
|
||||
# (only possible if the resulting step is feasible). We test both, and
|
||||
# we perform similar calculations along the negative step.
|
||||
# N.B.: we select the largest possible step among all the ones that
|
||||
# maximize the objective function. This is to avoid returning the zero
|
||||
# step in some extreme cases.
|
||||
alpha_pos = min(alpha_tr, alpha_bd_pos)
|
||||
alpha_neg = max(-alpha_tr, alpha_bd_neg)
|
||||
q_val_pos = (
|
||||
const + alpha_pos * grad_step + 0.5 * alpha_pos**2.0 * curv_step
|
||||
)
|
||||
q_val_neg = (
|
||||
const + alpha_neg * grad_step + 0.5 * alpha_neg**2.0 * curv_step
|
||||
)
|
||||
if alpha_quad_pos < alpha_pos:
|
||||
q_val_quad_pos = (
|
||||
const
|
||||
+ alpha_quad_pos * grad_step
|
||||
+ 0.5 * alpha_quad_pos**2.0 * curv_step
|
||||
)
|
||||
if abs(q_val_quad_pos) > abs(q_val_pos):
|
||||
alpha_pos = alpha_quad_pos
|
||||
q_val_pos = q_val_quad_pos
|
||||
if alpha_quad_neg > alpha_neg:
|
||||
q_val_quad_neg = (
|
||||
const
|
||||
+ alpha_quad_neg * grad_step
|
||||
+ 0.5 * alpha_quad_neg**2.0 * curv_step
|
||||
)
|
||||
if abs(q_val_quad_neg) > abs(q_val_neg):
|
||||
alpha_neg = alpha_quad_neg
|
||||
q_val_neg = q_val_quad_neg
|
||||
if abs(q_val_pos) >= abs(q_val_neg) and abs(q_val_pos) > abs(q_val):
|
||||
step = np.clip(alpha_pos * xpt[:, k], xl, xu)
|
||||
q_val = q_val_pos
|
||||
elif abs(q_val_neg) > abs(q_val_pos) and abs(q_val_neg) > abs(q_val):
|
||||
step = np.clip(alpha_neg * xpt[:, k], xl, xu)
|
||||
q_val = q_val_neg
|
||||
|
||||
if debug:
|
||||
assert np.all(xl <= step)
|
||||
assert np.all(step <= xu)
|
||||
assert np.linalg.norm(step) < 1.1 * delta
|
||||
return step
|
||||
|
||||
|
||||
def _cauchy_geom(const, grad, curv, xl, xu, delta, debug):
|
||||
"""
|
||||
Same as `bound_constrained_cauchy_step` without the absolute value.
|
||||
"""
|
||||
# Calculate the initial active set.
|
||||
fixed_xl = (xl < 0.0) & (grad > 0.0)
|
||||
fixed_xu = (xu > 0.0) & (grad < 0.0)
|
||||
|
||||
# Calculate the Cauchy step.
|
||||
cauchy_step = np.zeros_like(grad)
|
||||
cauchy_step[fixed_xl] = xl[fixed_xl]
|
||||
cauchy_step[fixed_xu] = xu[fixed_xu]
|
||||
if np.linalg.norm(cauchy_step) > delta:
|
||||
working = fixed_xl | fixed_xu
|
||||
while True:
|
||||
# Calculate the Cauchy step for the directions in the working set.
|
||||
g_norm = np.linalg.norm(grad[working])
|
||||
delta_reduced = np.sqrt(
|
||||
delta**2.0 - cauchy_step[~working] @ cauchy_step[~working]
|
||||
)
|
||||
if g_norm > TINY * abs(delta_reduced):
|
||||
mu = max(delta_reduced / g_norm, 0.0)
|
||||
else:
|
||||
break
|
||||
cauchy_step[working] = mu * grad[working]
|
||||
|
||||
# Update the working set.
|
||||
fixed_xl = working & (cauchy_step < xl)
|
||||
fixed_xu = working & (cauchy_step > xu)
|
||||
if not np.any(fixed_xl) and not np.any(fixed_xu):
|
||||
# Stop the calculations as the Cauchy step is now feasible.
|
||||
break
|
||||
cauchy_step[fixed_xl] = xl[fixed_xl]
|
||||
cauchy_step[fixed_xu] = xu[fixed_xu]
|
||||
working = working & ~(fixed_xl | fixed_xu)
|
||||
|
||||
# Calculate the step that maximizes the quadratic along the Cauchy step.
|
||||
grad_step = grad @ cauchy_step
|
||||
if grad_step >= 0.0:
|
||||
# Set alpha_tr to the step size for the trust-region constraint.
|
||||
s_norm = np.linalg.norm(cauchy_step)
|
||||
if s_norm > TINY * delta:
|
||||
alpha_tr = max(delta / s_norm, 0.0)
|
||||
else:
|
||||
# The Cauchy step is basically zero.
|
||||
alpha_tr = 0.0
|
||||
|
||||
# Set alpha_quad to the step size for the maximization problem.
|
||||
curv_step = curv(cauchy_step)
|
||||
if curv_step < -TINY * grad_step:
|
||||
alpha_quad = max(-grad_step / curv_step, 0.0)
|
||||
else:
|
||||
alpha_quad = np.inf
|
||||
|
||||
# Set alpha_bd to the step size for the bound constraints.
|
||||
i_xl = (xl > -np.inf) & (cauchy_step < TINY * xl)
|
||||
i_xu = (xu < np.inf) & (cauchy_step > TINY * xu)
|
||||
alpha_xl = np.min(xl[i_xl] / cauchy_step[i_xl], initial=np.inf)
|
||||
alpha_xu = np.min(xu[i_xu] / cauchy_step[i_xu], initial=np.inf)
|
||||
alpha_bd = min(alpha_xl, alpha_xu)
|
||||
|
||||
# Calculate the solution and the corresponding function value.
|
||||
alpha = min(alpha_tr, alpha_quad, alpha_bd)
|
||||
step = np.clip(alpha * cauchy_step, xl, xu)
|
||||
q_val = const + alpha * grad_step + 0.5 * alpha**2.0 * curv_step
|
||||
else:
|
||||
# This case is never reached in exact arithmetic. It prevents this
|
||||
# function to return a step that decreases the objective function.
|
||||
step = np.zeros_like(grad)
|
||||
q_val = const
|
||||
|
||||
if debug:
|
||||
assert np.all(xl <= step)
|
||||
assert np.all(step <= xu)
|
||||
assert np.linalg.norm(step) < 1.1 * delta
|
||||
return step, q_val
|
||||
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,18 @@
|
||||
from .exceptions import (
|
||||
MaxEvalError,
|
||||
TargetSuccess,
|
||||
CallbackSuccess,
|
||||
FeasibleSuccess,
|
||||
)
|
||||
from .math import get_arrays_tol, exact_1d_array
|
||||
from .versions import show_versions
|
||||
|
||||
__all__ = [
|
||||
"MaxEvalError",
|
||||
"TargetSuccess",
|
||||
"CallbackSuccess",
|
||||
"FeasibleSuccess",
|
||||
"get_arrays_tol",
|
||||
"exact_1d_array",
|
||||
"show_versions",
|
||||
]
|
||||
@ -0,0 +1,22 @@
|
||||
class MaxEvalError(Exception):
|
||||
"""
|
||||
Exception raised when the maximum number of evaluations is reached.
|
||||
"""
|
||||
|
||||
|
||||
class TargetSuccess(Exception):
|
||||
"""
|
||||
Exception raised when the target value is reached.
|
||||
"""
|
||||
|
||||
|
||||
class CallbackSuccess(StopIteration):
|
||||
"""
|
||||
Exception raised when the callback function raises a ``StopIteration``.
|
||||
"""
|
||||
|
||||
|
||||
class FeasibleSuccess(Exception):
|
||||
"""
|
||||
Exception raised when a feasible point of a feasible problem is found.
|
||||
"""
|
||||
@ -0,0 +1,77 @@
|
||||
import numpy as np
|
||||
|
||||
|
||||
EPS = np.finfo(float).eps
|
||||
|
||||
|
||||
def get_arrays_tol(*arrays):
|
||||
"""
|
||||
Get a relative tolerance for a set of arrays.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
*arrays: tuple
|
||||
Set of `numpy.ndarray` to get the tolerance for.
|
||||
|
||||
Returns
|
||||
-------
|
||||
float
|
||||
Relative tolerance for the set of arrays.
|
||||
|
||||
Raises
|
||||
------
|
||||
ValueError
|
||||
If no array is provided.
|
||||
"""
|
||||
if len(arrays) == 0:
|
||||
raise ValueError("At least one array must be provided.")
|
||||
size = max(array.size for array in arrays)
|
||||
weight = max(
|
||||
np.max(np.abs(array[np.isfinite(array)]), initial=1.0)
|
||||
for array in arrays
|
||||
)
|
||||
return 10.0 * EPS * max(size, 1.0) * weight
|
||||
|
||||
|
||||
def exact_1d_array(x, message):
|
||||
"""
|
||||
Preprocess a 1-dimensional array.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
x : array_like
|
||||
Array to be preprocessed.
|
||||
message : str
|
||||
Error message if `x` cannot be interpreter as a 1-dimensional array.
|
||||
|
||||
Returns
|
||||
-------
|
||||
`numpy.ndarray`
|
||||
Preprocessed array.
|
||||
"""
|
||||
x = np.atleast_1d(np.squeeze(x)).astype(float)
|
||||
if x.ndim != 1:
|
||||
raise ValueError(message)
|
||||
return x
|
||||
|
||||
|
||||
def exact_2d_array(x, message):
|
||||
"""
|
||||
Preprocess a 2-dimensional array.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
x : array_like
|
||||
Array to be preprocessed.
|
||||
message : str
|
||||
Error message if `x` cannot be interpreter as a 2-dimensional array.
|
||||
|
||||
Returns
|
||||
-------
|
||||
`numpy.ndarray`
|
||||
Preprocessed array.
|
||||
"""
|
||||
x = np.atleast_2d(x).astype(float)
|
||||
if x.ndim != 2:
|
||||
raise ValueError(message)
|
||||
return x
|
||||
@ -0,0 +1,67 @@
|
||||
import os
|
||||
import platform
|
||||
import sys
|
||||
from importlib.metadata import PackageNotFoundError, version
|
||||
|
||||
|
||||
def _get_sys_info():
|
||||
"""
|
||||
Get useful system information.
|
||||
|
||||
Returns
|
||||
-------
|
||||
dict
|
||||
Useful system information.
|
||||
"""
|
||||
return {
|
||||
"python": sys.version.replace(os.linesep, " "),
|
||||
"executable": sys.executable,
|
||||
"machine": platform.platform(),
|
||||
}
|
||||
|
||||
|
||||
def _get_deps_info():
|
||||
"""
|
||||
Get the versions of the dependencies.
|
||||
|
||||
Returns
|
||||
-------
|
||||
dict
|
||||
Versions of the dependencies.
|
||||
"""
|
||||
deps = ["cobyqa", "numpy", "scipy", "setuptools", "pip"]
|
||||
deps_info = {}
|
||||
for module in deps:
|
||||
try:
|
||||
deps_info[module] = version(module)
|
||||
except PackageNotFoundError:
|
||||
deps_info[module] = None
|
||||
return deps_info
|
||||
|
||||
|
||||
def show_versions():
|
||||
"""
|
||||
Display useful system and dependencies information.
|
||||
|
||||
When reporting issues, please include this information.
|
||||
"""
|
||||
print("System settings")
|
||||
print("---------------")
|
||||
sys_info = _get_sys_info()
|
||||
print(
|
||||
"\n".join(
|
||||
f"{k:>{max(map(len, sys_info.keys())) + 1}}: {v}"
|
||||
for k, v in sys_info.items()
|
||||
)
|
||||
)
|
||||
|
||||
print()
|
||||
print("Python dependencies")
|
||||
print("-------------------")
|
||||
deps_info = _get_deps_info()
|
||||
print(
|
||||
"\n".join(
|
||||
f"{k:>{max(map(len, deps_info.keys())) + 1}}: {v}"
|
||||
for k, v in deps_info.items()
|
||||
)
|
||||
)
|
||||
Reference in New Issue
Block a user