Skip to content

Commit

Permalink
add the S back to the Hessian for DpN
Browse files Browse the repository at this point in the history
  • Loading branch information
wangronin committed Sep 6, 2024
1 parent 6b4d7cc commit 8b35ab7
Show file tree
Hide file tree
Showing 2 changed files with 31 additions and 16 deletions.
6 changes: 6 additions & 0 deletions examples/DpN/2D_example_convex.py
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,11 @@ def h_Jacobian(x):
return 2 * x


def h_Hessian(x):
x = np.array(x)
return 2 * np.eye(2)


theta = np.linspace(-np.pi * 3 / 4, np.pi / 4, 100)
ref_x = np.array([[np.cos(a) * 0.99, np.sin(a) * 0.99] for a in theta])
ref = np.array([MOP1(_) for _ in ref_x])
Expand Down Expand Up @@ -86,6 +91,7 @@ def h_Jacobian(x):
hessian=MOP1_Hessian,
h=h,
h_jac=h_Jacobian,
h_hessian=h_Hessian,
N=len(x0),
x0=x0,
xl=-2,
Expand Down
41 changes: 25 additions & 16 deletions hvd/newton.py
Original file line number Diff line number Diff line change
Expand Up @@ -357,15 +357,18 @@ def __init__(
N: int = 5,
h: Callable = None,
h_jac: callable = None,
h_hessian: callable = None,
g: Callable = None,
g_jac: Callable = None,
g_hessian: callable = None,
x0: np.ndarray = None,
max_iters: Union[int, str] = np.inf,
xtol: float = 0,
verbose: bool = True,
pareto_front: Union[List[float], np.ndarray] = None,
eta=None,
Y_label=None,
preconditioning: bool = False,
):
"""
Args:
Expand Down Expand Up @@ -404,8 +407,11 @@ def __init__(
self.N = N
self.xl = xl
self.xu = xu
self.preconditioning: bool = preconditioning
self._check_constraints(h, g)
self.state = State(self.dim_p, self.n_eq, self.n_ieq, func, jac, h=h, h_jac=h_jac, g=g, g_jac=g_jac)
self.state = State(
self.dim_p, self.n_eq, self.n_ieq, func, jac, h, h_jac, h_hessian, g, g_jac, g_hessian
)
self._initialize(x0)
self._set_indicator(ref, func, jac, hessian)
self._set_logging(verbose)
Expand Down Expand Up @@ -526,7 +532,7 @@ def newton_iteration(self):
# shift the reference set if needed
self._shift_reference_set()
# compute the Newton step
self.step, self.R = self._compute_netwon_step()
self.step, self.R = self._compute_netwon_step(self.state)
# prevent the decision points from moving out of the decision space. Needed for CF7 with NSGA-III
self.step, max_step_size = self._handle_box_constraint(self.step)
# backtracking line search for the step size
Expand Down Expand Up @@ -586,39 +592,42 @@ def _compute_R(
X=primal_vars, Y=state.Y, Y_label=self.Y_label, compute_hessian=False, Jacobian=state.J
)
R = grad # the unconstrained case
dH, idx = None, None
dH, active_indices = None, np.array([[True] * state.n_var] * self.N)
if self._constrained:
func = lambda g, dual, h: g + np.einsum("j,jk->k", dual, h)
v, idx, dH = state.cstr_value, state.active_indices, state.cstr_grad
dH = [dH[i][idx, :] for i, idx in enumerate(idx)]
R = [np.r_[func(grad[i], dual_vars[i, k], dH[i]), v[i, k]] for i, k in enumerate(idx)]
return R, dH, idx
active_indices = np.c_[active_indices, idx]
return R, dH, active_indices

def _compute_netwon_step(self) -> Tuple[np.ndarray, np.ndarray]:
primal_vars = self.state.primal
def _compute_netwon_step(self, state: State) -> Tuple[np.ndarray, np.ndarray]:
newton_step = np.zeros((self.N, self.dim)) # Netwon steps
R = np.zeros((self.N, self.dim)) # the root-finding problem
# gradient and Hessian of the incumbent indicator
grad, Hessian = self.active_indicator.compute_derivatives(
X=primal_vars,
Y=self.state.Y,
Jacobian=self.state.J,
X=state.primal,
Y=state.Y,
Jacobian=state.J,
Y_label=self.Y_label,
)
# the root-finding problem and the gradient of the active constraints
R_list, dH, active_indices = self._compute_R(self.state, grad=grad)
idx = np.array([[True] * self.dim_p] * self.N)
if active_indices is not None:
idx = np.c_[idx, active_indices]
R_list, dH, active_indices = self._compute_R(state, grad=grad)
idx = active_indices[:, self.dim_p :]
if state.cstr_hess.size != 0:
S = [np.einsum("i...,i", state.cstr_hess[i, k], state.dual[i, k]) for i, k in enumerate(idx)]
else:
S = [np.zeros((self.dim_p, self.dim_p))] * self.N
# compute the Newton step for each approximation point - lower computation costs
for r in range(self.N):
c = idx[r]
c = active_indices[r]
dh = np.array([]) if dH is None else dH[r]
Z = np.zeros((len(dh), len(dh)))
# pre-condition indicator's Hessian if needed, e.g., on ZDT6, CF1, CF7
# Hessian[r] = precondition_hessian(Hessian[r])
if self.preconditioning:
Hessian[r] = precondition_hessian(Hessian[r])
# derivative of the root-finding problem
DR = np.r_[np.c_[Hessian[r], dh.T], np.c_[dh, Z]] if self._constrained else Hessian[r]
DR = np.r_[np.c_[Hessian[r] + S[r], dh.T], np.c_[dh, Z]] if self._constrained else Hessian[r]
R[r, c] = R_list[r]
with warnings.catch_warnings():
warnings.filterwarnings("error")
Expand Down

0 comments on commit 8b35ab7

Please sign in to comment.