diff --git a/pypesto/profile/walk_along_profile.py b/pypesto/profile/walk_along_profile.py index 909863cd8..729bb2c35 100644 --- a/pypesto/profile/walk_along_profile.py +++ b/pypesto/profile/walk_along_profile.py @@ -62,14 +62,15 @@ def walk_along_profile( x_now = current_profile.x_path[:, -1] # check if the next profile point needs to be computed - if options.whole_path: - stop_profile = ( - x_now[i_par] * par_direction >= problem.ub_full[[i_par]] - ) + # ... check bounds + if par_direction == -1: + stop_profile = x_now[i_par] <= problem.lb_full[[i_par]] + elif par_direction == 1: + stop_profile = x_now[i_par] >= problem.ub_full[[i_par]] else: - stop_profile = ( - x_now[i_par] * par_direction >= problem.ub_full[[i_par]] - ) or (current_profile.ratio_path[-1] < options.ratio_min) + raise AssertionError("par_direction must be -1 or 1") + if not options.whole_path: + stop_profile |= current_profile.ratio_path[-1] < options.ratio_min if stop_profile: break diff --git a/test/profile/test_profile.py b/test/profile/test_profile.py index 133c2f3ab..a1371c948 100644 --- a/test/profile/test_profile.py +++ b/test/profile/test_profile.py @@ -435,3 +435,51 @@ def test_options_valid(): min_step_size=2, max_step_size=1, ) + + +@pytest.mark.parametrize( + "lb,ub", + [(6 * np.ones(5), 10 * np.ones(5)), (-4 * np.ones(5), 1 * np.ones(5))], +) +def test_gh1165(lb, ub): + """Regression test for https://github.com/ICB-DCM/pyPESTO/issues/1165 + + Check profiles with non-symmetric bounds and whole_path=True span the full parameter domain. + """ + obj = rosen_for_sensi(max_sensi_order=1)['obj'] + + problem = pypesto.Problem( + objective=obj, + lb=lb, + ub=ub, + ) + + optimizer = optimize.ScipyOptimizer(options={'maxiter': 10}) + result = optimize.minimize( + problem=problem, + optimizer=optimizer, + n_starts=2, + progress_bar=False, + ) + # just any parameter + par_idx = 1 + profile.parameter_profile( + problem=problem, + result=result, + optimizer=optimizer, + next_guess_method='fixed_step', + profile_index=[par_idx], + progress_bar=False, + profile_options=profile.ProfileOptions( + min_step_size=0.1, + delta_ratio_max=0.05, + default_step_size=0.5, + ratio_min=0.01, + whole_path=True, + ), + ) + # parameter value of the profiled parameter + x_path = result.profile_result.list[0][par_idx]['x_path'][par_idx, :] + # ensure we cover lb..ub + assert x_path[0] == lb[par_idx], (x_path.min(), lb[par_idx]) + assert x_path[-1] == ub[par_idx], (x_path.max(), ub[par_idx])