Source code for modopt.core.merit_functions.augmented_lagrangian_ineq

import numpy as np
from modopt import MeritFunction


# Note: Augmented Lagrangian is a function of  x, lag_mult and slack variables
# Note: This Merit function is for problems in all-inequality form, i.e., c(x) >= 0
[docs]class AugmentedLagrangianIneq(MeritFunction): """ Augmented Lagrangian merit function for pure inequality-constraints of the form c(x) >= 0. Parameters ---------- f : callable Objective function. c : callable Constraint function representing the inequality constraints c(x) >= 0. g : callable Objective gradient. j : callable Constraint Jacobian. nx : int Number of optimization/design variables. nc : int Number of inequality constraints. Attributes ---------- rho : np.ndarray Vector of penalty parameters corresponding to each inequality constraint. cache : dict Dictionary to store the latest function evaluations for 'f', 'c', 'g' and 'j'. Keys are the function names 'f', 'c', 'g' and 'j', and values are tuples of the form (x, f(x)). eval_count : dict Dictionary to store the number of times each function has been evaluated. Keys are the function names 'f', 'c', 'g' and 'j', and values are the number of evaluations. """
[docs] def setup(self): """ Set up the merit function by initializing `rho` as a vector of zeros. """ nc = self.options['nc'] self.rho = np.zeros(nc)
[docs] def set_rho(self, rho): """ Set the penalty parameters `rho` for the inequality constraints. Parameters ---------- rho : np.ndarray Penalty parameter vector for the inequality constraints. Must be a 1D numpy array of length `nc`. """ self.rho[:] = rho
[docs] def compute_function(self, v): """ Compute the value of the augmented Lagrangian function at the point `v`. Parameters ---------- v : np.ndarray Point at which to evaluate the augmented Lagrangian function. The point `v` is a concatenation of the design variables `x`, Lagrange multipliers `lag_mult` and slack variables `slacks`. The point `v` has the form [x, lag_mult, slacks]. Returns ------- float Value of the augmented Lagrangian function at the point `v`. """ nx = self.options['nx'] nc = self.options['nc'] rho = self.rho x = v[:nx] lag_mult = v[nx:(nx + nc)] slacks = v[(nx + nc):] self.update_functions_in_cache(['f', 'c'], x) obj = self.cache['f'][1] con = self.cache['c'][1] # obj = self.options['f'](x) # con = self.options['c'](x) return obj - np.dot(lag_mult, (con - slacks)) + 0.5 * np.inner(rho, (con - slacks)**2)
[docs] def evaluate_function(self, x, lag_mult, s, f, c): """ Evaluate the augmented Lagrangian function at the point [`x`, `lag_mult`, `s`], given the objective function value `f` and constraint function values `c` at the point `x`. Parameters ---------- x : np.ndarray Design variables. lag_mult : np.ndarray Lagrange multipliers. s : np.ndarray Slack variables. f : float Objective function value at the point `x`. c : np.ndarray Constraint function values at the point `x`. Returns ------- float Value of the augmented Lagrangian function at the point `x`. """ rho = self.rho return f - np.dot(lag_mult,(c - s)) + 0.5 * np.inner(rho, (c - s)**2)
# Note: Gradient is evaluated with respect to x, lag_mult and slack variables
[docs] def compute_gradient(self, v): """ Compute the gradient of the augmented Lagrangian function at the point `v`. Parameters ---------- v : np.ndarray Point at which to evaluate the gradient of the augmented Lagrangian function. The point `v` is a concatenation of the design variables `x`, Lagrange multipliers `lag_mult` and slack variables `slacks`. The point `v` has the form [x, lag_mult, slacks]. Returns ------- np.ndarray Gradient of the augmented Lagrangian function at the point `v`. """ nx = self.options['nx'] nc = self.options['nc'] rho = self.rho x = v[:nx] lag_mult = v[nx:(nx + nc)] slacks = v[(nx + nc):] self.update_functions_in_cache(['c', 'g', 'j'], x) con = self.cache['c'][1] grad = self.cache['g'][1] jac = self.cache['j'][1] # con = self.options['c'](x) # grad = self.options['g'](x) # jac = self.options['j'](x) # grad_x = grad - np.matmul(jac.T, lag_mult - (rho * (con - slacks))) grad_x = grad - jac.T @ (lag_mult - (rho * (con - slacks))) grad_lag_mult = -(con - slacks) grad_slacks = lag_mult - rho * (con - slacks) return np.concatenate((grad_x, grad_lag_mult, grad_slacks))
[docs] def evaluate_gradient(self, x, lag_mult, s, f, c, g, j): """ Evaluate the gradient of the augmented Lagrangian function at the point [`x`, `lag_mult`, `s`], given the objective function `f`, constraint function `c`, objective gradient `g`, and constraint Jacobian `j` at the point `x`. Parameters ---------- x : np.ndarray Design variables. lag_mult : np.ndarray Lagrange multipliers. s : np.ndarray Slack variables. f : float Objective function value at the point `x`. c : np.ndarray Constraint function values at the point `x`. g : np.ndarray Objective gradient at the point `x`. j : np.ndarray Constraint Jacobian at the point `x`. Returns ------- np.ndarray Gradient of the augmented Lagrangian function at the point `x`. """ rho = self.rho # grad_x = g - np.matmul(j.T, lag_mult - (rho * (c - s))) grad_x = g - j.T @ (lag_mult - (rho * (c - s))) grad_lag_mult = -(c - s) grad_slacks = lag_mult - rho * (c - s) return np.concatenate((grad_x, grad_lag_mult, grad_slacks))