Skip to content

Commit 65ca5f7

Browse files
committed
Merge branch 'bugfix/termination'
Closes #54. See Merge Request !60.
2 parents b12c403 + b5e7889 commit 65ca5f7

2 files changed

Lines changed: 42 additions & 4 deletions

File tree

adaptive/learner/learner1D.py

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,9 @@ def __init__(self, function, bounds, loss_per_interval=None):
107107
self._scale = [bounds[1] - bounds[0], 0]
108108
self._oldscale = deepcopy(self._scale)
109109

110+
# The precision in 'x' below which we set losses to 0.
111+
self._dx_eps = max(np.abs(bounds)) * np.finfo(float).eps
112+
110113
self.bounds = list(bounds)
111114

112115
self._vdim = None
@@ -132,12 +135,19 @@ def loss(self, real=True):
132135

133136
def update_losses(self, x, data, neighbors, losses):
134137
x_lower, x_upper = neighbors[x]
138+
139+
def _update(interval):
140+
a, b = interval
141+
if abs(a - b) > self._dx_eps:
142+
losses[interval] = self.loss_per_interval(interval,
143+
self._scale, data)
144+
else:
145+
losses[interval] = 0
146+
135147
if x_lower is not None:
136-
losses[x_lower, x] = self.loss_per_interval((x_lower, x),
137-
self._scale, data)
148+
_update((x_lower, x))
138149
if x_upper is not None:
139-
losses[x, x_upper] = self.loss_per_interval((x, x_upper),
140-
self._scale, data)
150+
_update((x, x_upper))
141151
try:
142152
del losses[x_lower, x_upper]
143153
except KeyError:

adaptive/tests/test_learner.py

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -345,6 +345,34 @@ def test_learner1d_first_iteration():
345345
assert set(points) == set(to_see)
346346

347347

348+
def _run_on_discontinuity(x_0, bounds):
349+
350+
def f(x):
351+
return -1 if x < x_0 else +1
352+
353+
learner = Learner1D(f, bounds)
354+
while learner.loss() > 0.1:
355+
(x,), _ = learner.choose_points(1)
356+
learner.add_point(x, learner.function(x))
357+
358+
return learner
359+
360+
361+
def test_termination_on_discontinuities():
362+
363+
learner = _run_on_discontinuity(0, (-1, 1))
364+
smallest_interval = min(abs(a - b) for a, b in learner.losses.keys())
365+
assert smallest_interval >= np.finfo(float).eps
366+
367+
learner = _run_on_discontinuity(1, (-2, 2))
368+
smallest_interval = min(abs(a - b) for a, b in learner.losses.keys())
369+
assert smallest_interval >= np.finfo(float).eps
370+
371+
learner = _run_on_discontinuity(0.5E3, (-1E3, 1E3))
372+
smallest_interval = min(abs(a - b) for a, b in learner.losses.keys())
373+
assert smallest_interval >= 0.5E3 * np.finfo(float).eps
374+
375+
348376
@pytest.mark.xfail
349377
@run_with(Learner1D, Learner2D)
350378
def test_convergence_for_arbitrary_ordering(learner_type, f, learner_kwargs):

0 commit comments

Comments
 (0)