3.6.4. Adaptive Rate MC

class ARMCOptimizer(phi: float = 1.0, gamma: float = 2.0, a_target: float = 0.25, super_iter_len: int = 1000, sub_iter_len: int = 100, move_range: Union[float, Sequence[float]] = array([0.9 , 0.905, 0.91 , 0.915, 0.92 , 0.925, 0.93 , 0.935, 0.94 , 0.945, 0.95 , 0.955, 0.96 , 0.965, 0.97 , 0.975, 0.98 , 0.985, 0.99 , 0.995, 1.005, 1.01 , 1.015, 1.02 , 1.025, 1.03 , 1.035, 1.04 , 1.045, 1.05 , 1.055, 1.06 , 1.065, 1.07 , 1.075, 1.08 , 1.085, 1.09 , 1.095, 1.1 ]), move_func: Callable[[float, float], float] = <ufunc 'multiply'>)

An optimzer using the Addaptive Rate Monte Carlo (ARMC) algorithm.

  1. A trial state, \(S_{\omega}\), is generated by moving a random parameter retrieved from a user-specified parameter set (e.g. atomic charge). By default, parameters moves are applied in a multiplicative manner.
  2. The move is accepted if the new set of parameters, \(S_{\omega}\), lowers the auxiliary error (\(\Delta \varepsilon_{QM-MM}\)) with respect to the previous set of accepted parameters \(S_{\omega-i}\) (\(i > 0\); see (3.2)). The auxiliary error is calculated with a user-specified cost function.
(3.2)\[p(\omega \leftarrow \omega-i) = \Biggl \lbrace { 1, \quad \Delta \varepsilon_{QM-MM} ( S_{\omega} ) \; \lt \; \Delta \varepsilon_{QM-MM} ( S_{\omega-i} ) \atop 0, \quad \Delta \varepsilon_{QM-MM} ( S_{\omega} ) \; \gt \; \Delta \varepsilon_{QM-MM} ( S_{\omega-i} ) }\]
  1. The parameter history is updated. Either \(S_{\omega}\) or \(S_{\omega-i}\) is increased by the variable \(\phi\) (see (3.3)) if, respectivelly, the new parameters are accepted or rejected. In this manner the underlying PES is continuously modified, preventing the optimizer from getting permanently stuck in a (local) parameter space minima.
(3.3)\[\Delta \varepsilon_{QM-MM} ( S_{\omega} ) + \phi \quad \text{if} \quad \Delta \varepsilon_{QM-MM} ( S_{\omega} ) \; \lt \; \Delta \varepsilon_{QM-MM} ( S_{\omega-i} ) \atop \Delta \varepsilon_{QM-MM} ( S_{\omega-i} ) + \phi \quad \text{if} \quad \Delta \varepsilon_{QM-MM} ( S_{\omega} ) \; \gt \; \Delta \varepsilon_{QM-MM} ( S_{\omega-i} )\]
  1. The parameter \(\phi\) is updated at regular intervals in order to maintain a constant acceptance rate \(\alpha_{t}\). This is illustrated in (3.4), where \(\phi\) is updated the begining of every super-iteration \(\kappa\). In this example the total number of iterations, \(\kappa \omega\), is divided into \(\kappa\) super- and \(\omega\) sub-iterations.
(3.4)\[\phi_{\kappa \omega} = \phi_{ ( \kappa - 1 ) \omega} * \gamma^{ \text{sgn} ( \alpha_{t} - \overline{\alpha}_{ ( \kappa - 1 ) }) } \quad \kappa = 1, 2, 3, ..., N\]

Attributes:

phi : float
The variable \(\phi\).
gamma : float
The constant \(\gamma\).
a_target : float
The target acceptance rate \(\alpha_{t}\).
super_iter : range
A range object with the total number of each super-iterations \(\kappa\). Total number of iterations: \(\kappa \omega\).
sub_iter : range
A range object with the the length of each ARMC sub-iteration \(\omega\). Total number of iterations: \(\kappa \omega\).
move_range : numpy.ndarray[float]
An array-like object containing all allowed move sizes.
move_func : Callable[[float, float], float]
A callable for performing the moves. The callable should take 2 floats (i.e. a single value from the parameter set S_{omega-i} and the move size) and return 1 float (i.e. an updated value for the parameter set S_{omega}).
run : Callable
The (bound) ParameterOptimization.run() method. See the function parameter in ARMCOptimizer.minimize().
bounds : numpy.ndarray or (None, None)
An 2D array (or 2-tuple filled with None) denoting minimum and maximum values for each to-be moved parameter. See the bounds parameter in ARMCOptimizer.minimize().
x_best : numpy.ndarray[float]
The parameter set which minimizes the user-specified error function.
fx_best : float
The error associated with ARMCOptimizer.x_best.
fx_old : float
The error of the last set of accepted parameters.

See Also:

Paper
The paper describing the original ARMC implementation: Salvatore Cosseddu et al, J. Chem. Theory Comput., 2017, 13, 297–308 10.1021/acs.jctc.6b01089.
Code
The Python-based implementation of ARMC this class is based on: Automated Forcefield Optimization Extension github.com/nlesc-nano/auto-FOX.
__init__(phi: float = 1.0, gamma: float = 2.0, a_target: float = 0.25, super_iter_len: int = 1000, sub_iter_len: int = 100, move_range: Union[float, Sequence[float]] = array([0.9 , 0.905, 0.91 , 0.915, 0.92 , 0.925, 0.93 , 0.935, 0.94 , 0.945, 0.95 , 0.955, 0.96 , 0.965, 0.97 , 0.975, 0.98 , 0.985, 0.99 , 0.995, 1.005, 1.01 , 1.015, 1.02 , 1.025, 1.03 , 1.035, 1.04 , 1.045, 1.05 , 1.055, 1.06 , 1.065, 1.07 , 1.075, 1.08 , 1.085, 1.09 , 1.095, 1.1 ]), move_func: Callable[[float, float], float] = <ufunc 'multiply'>) → None

Initialize a ARMCOptimizer instance.

Parameters:

phi : float
The variable \(\phi\).
gamma : float
The constant \(\gamma\).
a_target : float
The target acceptance rate \(\alpha_{t}\).
super_iter_len : int
The total number of each super-iterations \(\kappa\). Total number of iterations: \(\kappa \omega\).
sub_iter_len : int
The length of each ARMC sub-iteration \(\omega\). Total number of iterations: \(\kappa \omega\).
move_range : array-like[float]
An array-like object containing all allowed move sizes.
move_func : Callable[[float, float], float]
A callable for performing the moves. The callable should take 2 floats (i.e. a single value from the parameter set S_{omega-i} and the move size) and return 1 float (i.e. an updated value for the parameter set S_{omega}).
bounds

Get or set the bounds parameter of ARMCOptimizer.minimize().

minimize(function: Callable, x0: Union[float, Sequence[float]], bounds: Optional[Sequence[Tuple[float, float]]] = None, workers: int = 1) → scm.params.optimizers.base.MinimizeResult

Start the minimization process.

Parameters:

function : Callable
The (bound) ParameterOptimization.run() method.
x0 : array-like[float]
A 1D array-like object representing the set of to-be optimized parameters \(S\).
bounds : array-like[float], optional
An (optional) 2D array-like object denoting minimum and maximum values for each to-be moved parameter. The sequence should be of the same length as x0.
callbacks : Callable, optional
A callable which allows for Optimization specific callbacks such as early stopping.
_inner(x0_old: numpy.ndarray, omega: int, acceptance: numpy.ndarray) → numpy.ndarray

Run the inner loop of ARMCOptimizer.minimize().

Parameters:

x0_old : numpy.ndarray[float]
The last set of accepted parameters \(S_{\omega-i}\).
omega : int
The ARMC sub-iteration \(\omega\).
acceptance : numpy.ndarray[bool]
A boolean array for keeping track of accepted moves during the current sub-iteration.

Returns:

numpy.ndarray[float]:
The accepted parameters \(S_{\omega}\) or \(S_{\omega-i}\). Equivalent to x0_old if the new parameter set is not accepted.
static callstop(reason: Any = None)

Signal to terminate the minimize() loop while still returning MinimizeResult.

move(x0: numpy.ndarray, x0_min: Optional[numpy.ndarray] = None, x0_max: Optional[numpy.ndarray] = None) → numpy.ndarray

Create a copy of x0 and apply a random move to it.

The move will be applied with ARMCOptimizer.move_func (multiplication by default) using a random value from ARMCOptimizer.move_range.

Parameters:

x0 : numpy.ndarray[float]
A 1D array of parameters \(S_{\omega-i}\).
value_min : numpy.ndarray[float], optional
A 1D array minimum values for each to-be moved parameter. The array should be of the same length as x0.
value_max : numpy.ndarray[float], optional
A 1D array maximum values for each to-be moved parameter. The array should be of the same length as x0.

Returns:

numpy.ndarray[float]
A copy of x0 \(S_{\omega}\). A single value is moved within this parameter set.
phi_apply(aux_err: float) → float

Apply ARMCOptimizer.phi to the supplied auxiliary error: \(\Delta \varepsilon_{QM-MM} + \phi\).

phi_update(acceptance: numpy.ndarray) → None

Update the variable \(\phi\) (ARMCOptimizer.phi).

\(\phi\) is updated based on the target accepatance rate, \(\alpha_{t}\) (ARMCOptimizer.a_target), and the acceptance rate, acceptance, of the current super-iteration:

\[\phi_{\kappa \omega} = \phi_{ ( \kappa - 1 ) \omega} * \gamma^{ \text{sgn} ( \alpha_{t} - \overline{\alpha}_{ ( \kappa - 1 ) }) }\]

Parameters:

acceptance : numpy.ndarray[bool]
A boolean array for keeping track of accepted moves over the course of the current sub-iteration of \(\kappa\).

The Adaptive Rate MC optimizer was contributed by Bas van Beek.