Skip to content

Commit 1452dd4

Browse files
committed
Allow 1-sided bounds, deterministic initialisation, keep any feasible x0, remove warnings in tests
1 parent a073cc1 commit 1452dd4

File tree

4 files changed

+12
-18
lines changed

4 files changed

+12
-18
lines changed

pybobyqa/model.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -106,7 +106,7 @@ def fopt(self):
106106
def xpt(self, k, abs_coordinates=False):
107107
assert 0 <= k < self.npt(), "Invalid index %g" % k
108108
if not abs_coordinates:
109-
return self.points[k, :].copy()
109+
return np.minimum(np.maximum(self.sl, self.points[k, :].copy()), self.su)
110110
else:
111111
# Apply bounds and convert back to absolute coordinates
112112
return self.xbase + np.minimum(np.maximum(self.sl, self.points[k, :]), self.su)

pybobyqa/params.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ def __init__(self, n, npt, maxfun, objfun_has_noise=False, seek_global_minimum=F
3939
self.params["general.safety_step_thresh"] = 0.5 # safety step called if ||d|| <= thresh * rho
4040
self.params["general.check_objfun_for_overflow"] = True
4141
# Initialisation
42-
self.params["init.random_initial_directions"] = True
42+
self.params["init.random_initial_directions"] = False
4343
self.params["init.run_in_parallel"] = False # only available for random directions at the moment
4444
self.params["init.random_directions_make_orthogonal"] = True # although random > orthogonal, avoid for init
4545
# Interpolation

pybobyqa/solver.py

Lines changed: 8 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -654,14 +654,18 @@ def solve(objfun, x0, args=(), bounds=None, npt=None, rhobeg=None, rhoend=1e-8,
654654
assert len(bounds) == 2, "bounds must be a 2-tuple of (lower, upper), where both are arrays of size(x0)"
655655
xl = bounds[0]
656656
if type(xl) == list:
657-
xl = np.array(xl, dtype=np.float)
657+
xl = np.array(xl, dtype=np.float) if xl is not None else None
658658
else:
659-
xl = xl.astype(np.float)
659+
xl = xl.astype(np.float) if xl is not None else None
660660
xu = bounds[1]
661661
if type(xu) == list:
662-
xu = np.array(xu, dtype=np.float)
662+
xu = np.array(xu, dtype=np.float) if xu is not None else None
663663
else:
664-
xu = xu.astype(np.float)
664+
xu = xu.astype(np.float) if xu is not None else None
665+
666+
if (xl is None or xu is None) and scaling_within_bounds:
667+
scaling_within_bounds = False
668+
warnings.warn("Ignoring scaling_within_bounds=True for unconstrained problem/1-sided bounds", RuntimeWarning)
665669

666670
exit_info = None
667671
if seek_global_minimum and (xl is None or xu is None):
@@ -760,21 +764,11 @@ def solve(objfun, x0, args=(), bounds=None, npt=None, rhobeg=None, rhoend=1e-8,
760764
return results
761765

762766
# Enforce lower & upper bounds on x0
763-
idx = (xl < x0) & (x0 <= xl + rhobeg)
764-
if np.any(idx):
765-
warnings.warn("x0 too close to lower bound, adjusting", RuntimeWarning)
766-
x0[idx] = xl[idx] + rhobeg
767-
768767
idx = (x0 <= xl)
769768
if np.any(idx):
770769
warnings.warn("x0 below lower bound, adjusting", RuntimeWarning)
771770
x0[idx] = xl[idx]
772771

773-
idx = (xu - rhobeg <= x0) & (x0 < xu)
774-
if np.any(idx):
775-
warnings.warn("x0 too close to upper bound, adjusting", RuntimeWarning)
776-
x0[idx] = xu[idx] - rhobeg
777-
778772
idx = (x0 >= xu)
779773
if np.any(idx):
780774
warnings.warn("x0 above upper bound, adjusting", RuntimeWarning)

pybobyqa/tests/test_solver.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -114,7 +114,7 @@ def runTest(self):
114114
objfun = lambda x: sumsq(np.dot(A, x) - b)
115115
gradfun = lambda x: 2.0 * np.dot(A.T, np.dot(A,x)) - 2.0 * np.dot(A.T, b)
116116
hessfun = 2.0 * np.dot(A.T, A) # constant Hessian
117-
xmin = np.linalg.lstsq(A, b)[0]
117+
xmin = np.linalg.lstsq(A, b, rcond=None)[0]
118118
fmin = objfun(xmin)
119119
x0 = np.zeros((n,))
120120
np.random.seed(0)
@@ -135,7 +135,7 @@ def runTest(self):
135135
objfun = lambda x: sumsq(np.dot(A, x) - b)
136136
gradfun = lambda x: 2.0 * np.dot(A.T, np.dot(A,x)) - 2.0 * np.dot(A.T, b)
137137
hessfun = 2.0 * np.dot(A.T, A) # constant Hessian
138-
xmin = np.linalg.lstsq(A, b)[0]
138+
xmin = np.linalg.lstsq(A, b, rcond=None)[0]
139139
fmin = objfun(xmin)
140140
x0 = np.zeros((n,))
141141
np.random.seed(0)

0 commit comments

Comments
 (0)