Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 12 additions & 3 deletions pypesto/profile/options.py
Original file line number Diff line number Diff line change
Expand Up @@ -52,8 +52,13 @@ class ProfileOptions(dict):
Number of profile points used for regression in regression based
adaptive profile points proposal.
reg_order:
Maximum degree of regression polynomial used in regression based
adaptive profile points proposal.
Polynomial degree for regression-based extrapolation.
Higher values may cause extrapolation instability.
correlation_threshold:
Minimum absolute correlation coefficient for extrapolating a parameter
in regression-based methods. Parameters whose absolute correlation is
below this threshold will be kept at their current values instead of
extrapolated.
adaptive_target_scaling_factor:
The scaling factor of the next_obj_target in next guess generation.
Larger values result in larger next_guess step size (must be > 1).
Expand Down Expand Up @@ -88,7 +93,8 @@ def __init__(
delta_ratio_max: float = 0.1,
ratio_min: float = 0.145,
reg_points: int = 10,
reg_order: int = 4,
reg_order: int = 1,
correlation_threshold: float = 0.7,
adaptive_target_scaling_factor: float = 1.5,
whole_path: bool = False,
profile_n_starts: int = 6,
Expand Down Expand Up @@ -138,6 +144,7 @@ def __init__(
self.delta_ratio_max = delta_ratio_max
self.reg_points = reg_points
self.reg_order = reg_order
self.correlation_threshold = correlation_threshold
self.adaptive_target_scaling_factor = adaptive_target_scaling_factor
self.whole_path = whole_path
self.profile_n_starts = profile_n_starts
Expand Down Expand Up @@ -222,6 +229,8 @@ def validate_step_size_family(family: str) -> bool:

if self.adaptive_target_scaling_factor < 1:
raise ValueError("adaptive_target_scaling_factor must be > 1.")
if self.correlation_threshold < 0 or self.correlation_threshold > 1:
raise ValueError("correlation_threshold must be in [0, 1].")
if self.profile_n_starts < 1:
raise ValueError("profile_n_starts must be >= 1.")
if self.profile_sampling_sigma <= 0:
Expand Down
7 changes: 6 additions & 1 deletion pypesto/profile/profile.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ def parameter_profile(
profile_index: Iterable[int] = None,
profile_list: int = None,
result_index: int = 0,
next_guess_method: Callable | str = "adaptive_step_order_1",
next_guess_method: Callable | str = "adaptive_step_order_0",
profile_options: ProfileOptions = None,
progress_bar: bool = None,
filename: str | Callable | None = None,
Expand Down Expand Up @@ -66,6 +66,11 @@ def parameter_profile(
Method that creates the next starting point for optimization in profiling.
One of the ``update_type`` options supported by
:func:`pypesto.profile.profile_next_guess.next_guess`.
Default: ``"adaptive_step_order_0"`` (adaptive step size, no extrapolation
of other parameters). ``"adaptive_step_order_1"`` is a two-point
extrapolation based only on the last profile step and is not the same
as regression-based extrapolation. More robust than regression-based
methods for complex models.
profile_options:
Various options applied to the profile optimization.
See :class:`pypesto.profile.options.ProfileOptions`.
Expand Down
58 changes: 43 additions & 15 deletions pypesto/profile/profile_next_guess.py
Original file line number Diff line number Diff line change
Expand Up @@ -52,9 +52,14 @@ def next_guess(
Type of update for next profile point. Available options are:

* ``fixed_step`` (see :func:`fixed_step`)
* ``adaptive_step_order_0`` (see :func:`adaptive_step`).
* ``adaptive_step_order_1`` (see :func:`adaptive_step`).
* ``adaptive_step_regression`` (see :func:`adaptive_step`).
* ``adaptive_step_order_0``: adaptive step size without extrapolating
the other parameters (see :func:`adaptive_step`).
* ``adaptive_step_order_1``: adaptive step size with two-point
extrapolation based only on the last profile step
(see :func:`adaptive_step`).
* ``adaptive_step_regression``: adaptive step size with regression-based
extrapolation using several recent profile points
(see :func:`adaptive_step`).
current_profile:
The profile which should be computed.
problem:
Expand Down Expand Up @@ -204,10 +209,12 @@ def adaptive_step(
Specifies the precise algorithm for extrapolation.
Available options are:

* ``0``: just one parameter is updated
* ``1``: the last two points are used to extrapolate all parameters
* ``np.nan``: indicates that a more complex regression should be used
as determined by :attr:`pypesto.profile.ProfileOptions.reg_order`.
* ``0``: just the profiled parameter is updated
* ``1``: the last two profile points are used to extrapolate all
parameters, i.e. only the last profile step direction is reused
* ``np.nan``: indicates that a regression over several recent profile
points should be used, as determined by
:attr:`pypesto.profile.ProfileOptions.reg_order`.
min_step_increase_factor:
Factor to increase the minimal step size bound.
max_step_reduce_factor:
Expand Down Expand Up @@ -477,28 +484,49 @@ def get_reg_polynomial(

# set up matrix of regression parameters
reg_par = []
x_prof = current_profile.x_path[par_index, -reg_points:]
x_prof_std = np.std(x_prof)
for i_par in range(problem.dim_full):
if i_par in problem.x_fixed_indices:
# if we meet the current profiling parameter or a fixed parameter,
# there is nothing to do, so pass a np.nan
reg_par.append(np.nan)
else:
y_par = current_profile.x_path[i_par, -reg_points:]
par_reg_order = reg_order

# Only extrapolate a free parameter if it is sufficiently
# correlated with the profiled parameter over the recent
# profile history. Otherwise keep it at its current value.
if x_prof_std == 0 or np.std(y_par) == 0:
correlation = 0.0
else:
correlation = np.corrcoef(x_prof, y_par)[0, 1]
if np.isnan(correlation):
correlation = 0.0

if abs(correlation) <= options.correlation_threshold:
reg_par.append(
np.array([0.0, current_profile.x_path[i_par, -1]])
)
continue

# Do polynomial interpolation of profile path
# Determine rank of polynomial interpolation
regression_tmp = np.polyfit(
current_profile.x_path[par_index, -reg_points:],
current_profile.x_path[i_par, -reg_points:],
reg_order,
x_prof,
y_par,
par_reg_order,
full=True,
)

# Decrease rank if interpolation problem is ill-conditioned
if regression_tmp[2] < reg_order:
reg_order = regression_tmp[2]
if regression_tmp[2] < par_reg_order:
par_reg_order = regression_tmp[2]
regression_tmp = np.polyfit(
current_profile.x_path[par_index, -reg_points:],
current_profile.x_path[i_par, -reg_points:],
int(reg_order),
x_prof,
y_par,
int(par_reg_order),
full=True,
)

Expand Down
2 changes: 2 additions & 0 deletions test/profile/test_profile.py
Original file line number Diff line number Diff line change
Expand Up @@ -478,6 +478,8 @@ def test_options_valid():
"default_step_size_relative": 0.03,
"max_step_size_relative": 0.02,
},
{"correlation_threshold": -0.1},
{"correlation_threshold": 1.1},
{"profile_n_starts": 0},
{"profile_sampling_sigma": 0},
{
Expand Down
Loading