Skip to content

NLopt_mod

opt(p0, data, model_func, pts, multinom=True, lower_bound=None, upper_bound=None, fixed_params=None, ineq_constraints=[], eq_constraints=[], algorithm=nlopt.LN_BOBYQA, ftol_abs=1e-06, xtol_abs=1e-06, maxeval=int(1000000000.0), maxtime=np.inf, stopval=0, log_opt=False, local_optimizer=nlopt.LN_BOBYQA, verbose=0, func_args=[], func_kwargs={})

Perform optimization using NLopt.

Parameters:

Name Type Description Default
p0 list

Initial parameters.

required
data Spectrum

Spectrum with data.

required
model_func function

Function to evaluate model spectrum. Should take arguments (params, (n1, n2...), pts).

required
pts list

Grid points list for evaluating likelihoods.

required
multinom bool

If True, do a multinomial fit where the model is optimally scaled to data at each step. If False, assume theta is a parameter and do no scaling. Defaults to True.

True
lower_bound list

Lower bound on parameter values. If not None, must be of the same length as p0. Defaults to None.

None
upper_bound list

Upper bound on parameter values. If not None, must be of the same length as p0. Defaults to None.

None
fixed_params list

List used to fix model parameters at particular values. For example, if the model parameters are (nu1, nu2, T, m), then fixed_params = [0.5, None, None, 2] will hold nu1=0.5 and m=2. The optimizer will only change T and m. Note that the bounds lists must include all parameters. Optimization will fail if the fixed values lie outside their bounds. A full-length p0 should be passed in; values corresponding to fixed parameters are ignored. Defaults to None.

None
ineq_constraints list

List of functions defining inequality constraints, specifying quantities that should be less than zero, along with tolerances. Each function should take arguments func(params, grad), where params is the current vector of parameter values. grad is not typically used in dadi. Defaults to an empty list. For example, def func1(p, grad): (p[0]+p[1])-1 specifies that the total of p[0]+[1] should be less than 1. This would be passed into opt as ineq_constraints = [(func1, 1e-6)]. Here the 1e-6 is the tolerance on the constraint, which is > 0 to deal with numerical rounding issues. Only some algorithms support constraints. We suggest using nlopt.LN_COBYLA.

[]
eq_constraints list

List of functions defining equality constraints, specifying quantities that should be equal to zero, along with tolerances. Each function should take arguments func(params, grad), where params is the current vector of parameter values. grad is not typically used in dadi. For example, def func1(p, grad): 1 - (p[0]+p[1]) specifies that the total of p[0]+[1] should be equal to 1. This would be passed into opt as ineq_constraints = [(func1, 1e-6)]. Here the 1e-6 is the tolerance on the constraint, which is > 0 to deal with numerical rounding issues. Only some algorithms support constraints. We suggest using nlopt.LN_COBYLA.

[]
algorithm nlopt algorithm

Optimization algorithm to employ. See https://nlopt.readthedocs.io/en/latest/NLopt_Algorithms/ for possibilities. Defaults to nlopt.LN_BOBYQA.

LN_BOBYQA
ftol_abs float

Absolute tolerance on log-likelihood. Defaults to 1e-6.

1e-06
xtol_abs float

Absolute tolerance in parameter values. Both these tolerances should be set more stringently than your actual desire, because algorithms cannot generally guarantee convergence. Defaults to 1e-6.

1e-06
maxeval int

Maximum number of function evaluations. Defaults to 1e9.

int(1000000000.0)
maxtime float

Maximum optimization time, in seconds. Defaults to np.inf.

inf
stopval float

Algorithm will stop when a log-likelihood of at least stopval is found. This is primarily useful for testing. Defaults to 0.

0
log_opt bool

If True, optimization algorithm will run in terms of logs of parameters. Defaults to False.

False
local_optimizer nlopt algorithm

If using a global algorithm, this specifies the local algorithm to be used for refinement. Defaults to nlopt.LN_BOBYQA.

LN_BOBYQA
verbose int

If > 0, print optimization status every model evaluations. Defaults to 0.

0
func_args list

Additional arguments to model_func. It is assumed that model_func's first argument is an array of parameters to optimize, that its second argument is an array of sample sizes for the sfs, and that its last argument is the list of grid points to use in evaluation. Defaults to an empty list.

[]
func_kwargs dict

Additional keyword arguments to model_func. Defaults to an empty dictionary.

{}

Returns:

Name Type Description
xopt float

Optimized log-likelihood value.

opt_val list

Optimized parameters.

Source code in dadi/NLopt_mod.py
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
def opt(p0, data, model_func, pts, multinom=True,
        lower_bound=None, upper_bound=None, fixed_params=None,
        ineq_constraints=[], eq_constraints=[], 
        algorithm=nlopt.LN_BOBYQA,
        ftol_abs=1e-6, xtol_abs=1e-6,
        maxeval=int(1e9), maxtime=np.inf,
        stopval=0, log_opt=False,
        local_optimizer=nlopt.LN_BOBYQA,
        verbose=0, func_args=[], func_kwargs={},
        ):
    """
    Perform optimization using NLopt.

    Parameters:
        p0 (list): Initial parameters.
        data (Spectrum): Spectrum with data.
        model_func (function): Function to evaluate model spectrum. Should take arguments
            (params, (n1, n2...), pts).
        pts (list): Grid points list for evaluating likelihoods.
        multinom (bool, optional): If True, do a multinomial fit where the model is optimally scaled to
            data at each step. If False, assume theta is a parameter and do no scaling. Defaults to True.
        lower_bound (list, optional): Lower bound on parameter values. If not None, must be of the same
            length as p0. Defaults to None.
        upper_bound (list, optional): Upper bound on parameter values. If not None, must be of the same
            length as p0. Defaults to None.
        fixed_params (list, optional): List used to fix model parameters at particular values. For example,
            if the model parameters are (nu1, nu2, T, m), then fixed_params = [0.5, None, None, 2]
            will hold nu1=0.5 and m=2. The optimizer will only change T and m. Note that the bounds lists
            must include all parameters. Optimization will fail if the fixed values lie outside their bounds.
            A full-length p0 should be passed in; values corresponding to fixed parameters are ignored.
            Defaults to None.
        ineq_constraints (list, optional): List of functions defining inequality constraints, specifying
            quantities that should be less than zero, along with tolerances. Each function should take
            arguments func(params, grad), where params is the current vector of parameter values. grad is
            not typically used in dadi. Defaults to an empty list.
            For example, def func1(p, grad): (p[0]+p[1])-1 specifies that the total of
            p[0]+[1] should be less than 1.
            This would be passed into opt as ineq_constraints = [(func1, 1e-6)].
            Here the 1e-6 is the tolerance on the constraint, which is > 0 to deal with numerical
            rounding issues.
            Only some algorithms support constraints. We suggest using nlopt.LN_COBYLA.
        eq_constraints (list, optional): List of functions defining equality constraints, specifying
            quantities that should be equal to zero, along with tolerances. Each function should take
            arguments func(params, grad), where params is the current vector of parameter values. grad is
            not typically used in dadi.
            For example, def func1(p, grad): 1 - (p[0]+p[1]) specifies that the total of
            p[0]+[1] should be equal to 1.
            This would be passed into opt as ineq_constraints = [(func1, 1e-6)].
            Here the 1e-6 is the tolerance on the constraint, which is > 0 to deal with numerical
            rounding issues.
            Only some algorithms support constraints. We suggest using nlopt.LN_COBYLA.
        algorithm (nlopt algorithm, optional): Optimization algorithm to employ. See
            https://nlopt.readthedocs.io/en/latest/NLopt_Algorithms/ for possibilities. Defaults to nlopt.LN_BOBYQA.
        ftol_abs (float, optional): Absolute tolerance on log-likelihood. Defaults to 1e-6.
        xtol_abs (float, optional): Absolute tolerance in parameter values. Both these tolerances should
            be set more stringently than your actual desire, because algorithms cannot generally guarantee
            convergence. Defaults to 1e-6.
        maxeval (int, optional): Maximum number of function evaluations. Defaults to 1e9.
        maxtime (float, optional): Maximum optimization time, in seconds. Defaults to np.inf.
        stopval (float, optional): Algorithm will stop when a log-likelihood of at least stopval is found.
            This is primarily useful for testing. Defaults to 0.
        log_opt (bool, optional): If True, optimization algorithm will run in terms of logs of parameters.
            Defaults to False.
        local_optimizer (nlopt algorithm, optional): If using a global algorithm, this specifies the local
            algorithm to be used for refinement. Defaults to nlopt.LN_BOBYQA.
        verbose (int, optional): If > 0, print optimization status every <verbose> model evaluations.
            Defaults to 0.
        func_args (list, optional): Additional arguments to model_func. It is assumed that model_func's
            first argument is an array of parameters to optimize, that its second argument is an array of
            sample sizes for the sfs, and that its last argument is the list of grid points to use in
            evaluation. Defaults to an empty list.
        func_kwargs (dict, optional): Additional keyword arguments to model_func. Defaults to an empty dictionary.

    Returns:
        xopt (float): Optimized log-likelihood value.
        opt_val (list): Optimized parameters.
    """
    if lower_bound is None:
            lower_bound = [-np.inf] * len(p0)
    lower_bound = _project_params_down(lower_bound, fixed_params)
    # Replace None in bounds with infinity
    if upper_bound is None:
            upper_bound = [np.inf] * len(p0)
    upper_bound = _project_params_down(upper_bound, fixed_params)
    # Replace None in bounds with infinities
    lower_bound = [_ if _ is not None else -np.inf for _ in lower_bound]
    upper_bound = [_ if _ is not None else np.inf for _ in upper_bound]

    if log_opt:
        lower_bound, upper_bound = np.log(lower_bound), np.log(upper_bound)

    p0 = _project_params_down(p0, fixed_params)

    opt = nlopt.opt(algorithm, len(p0))

    opt.set_lower_bounds(lower_bound)
    opt.set_upper_bounds(upper_bound)

    for cons, tol in ineq_constraints:
        opt.add_inequality_constraint(cons, tol)
    for cons, tol in eq_constraints:
        opt.add_equality_constraint(cons, tol)

    opt.set_stopval(stopval)
    opt.set_ftol_abs(ftol_abs)
    opt.set_xtol_abs(xtol_abs)
    opt.set_maxeval(maxeval)
    opt.set_maxtime(maxtime)

    # For some global optimizers, need to set local optimizer parameters.
    local_opt = nlopt.opt(local_optimizer, len(p0))
    local_opt.set_stopval(stopval)
    local_opt.set_ftol_abs(ftol_abs)
    local_opt.set_xtol_abs(xtol_abs)
    local_opt.set_maxeval(maxeval)
    local_opt.set_maxtime(maxtime)
    opt.set_local_optimizer(local_opt)

    def f(x, grad):
        if grad.size:
            raise ValueError("Cannot use optimization algorithms that require a derivative function.")
        if log_opt: # Convert back from log parameters
            x = np.exp(x)
        return -_object_func(x, data, model_func, pts, 
                             verbose=verbose, multinom=multinom,
                             func_args=func_args, func_kwargs=func_kwargs, fixed_params=fixed_params)

    # NLopt can run into a roundoff error on rare occassion.
    # To account for this we put in an exception for nlopt.RoundoffLimited
    # and return -inf log-likelihood and nan parameter values.
    try:
        opt.set_max_objective(f)

        if log_opt:
            p0 = np.log(p0)
        xopt = opt.optimize(p0)
        if log_opt:
            xopt = np.exp(p0)

        opt_val = opt.last_optimum_value()
        result = opt.last_optimize_result()

        xopt = _project_params_up(xopt, fixed_params)

    except nlopt.RoundoffLimited:
        print('nlopt.RoundoffLimited occured, other jobs still running. Users might want to adjust their boundaries or starting parameters if this message occures many times.')
        opt_val = -np.inf
        xopt = [np.nan] * len(p0)

    return xopt, opt_val