Getting proximal to work with augmented Lagrangian optimizers - #2298
Getting proximal to work with augmented Lagrangian optimizers#2298singh-jaydeep wants to merge 6 commits into
Conversation
Memory benchmark result| Test Name | %Δ | Master (MB) | PR (MB) | Δ (MB) | Time PR (s) | Time Master (s) |
| -------------------------------------- | ------------ | ------------------ | ------------------ | ------------ | ------------------ | ------------------ |
test_objective_jac_w7x | 0.18 % | 4.241e+03 | 4.248e+03 | 7.51 | 32.00 | 27.60 |
test_proximal_jac_w7x_with_eq_update | -3.87 % | 6.828e+03 | 6.564e+03 | -263.95 | 154.26 | 149.26 |
test_proximal_freeb_jac | -0.67 % | 1.353e+04 | 1.344e+04 | -90.63 | 77.18 | 77.40 |
test_proximal_freeb_jac_blocked | -1.02 % | 7.892e+03 | 7.811e+03 | -80.61 | 66.35 | 67.33 |
test_proximal_freeb_jac_batched | -0.82 % | 7.879e+03 | 7.815e+03 | -64.25 | 65.20 | 66.87 |
+ test_proximal_jac_ripple | -12.85 % | 3.821e+03 | 3.330e+03 | -490.99 | 44.48 | 51.29 |
+ test_proximal_jac_ripple_bounce1d | -18.50 % | 4.002e+03 | 3.262e+03 | -740.39 | 56.41 | 65.04 |
test_eq_solve | 0.23 % | 1.821e+03 | 1.825e+03 | 4.28 | 51.91 | 50.77 |
test_objective_quadratic_flux_jac | -0.15 % | 1.902e+03 | 1.900e+03 | -2.86 | 34.22 | 33.35 |For the memory plots, go to the summary of |
Codecov Report❌ Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## master #2298 +/- ##
=======================================
Coverage 94.35% 94.35%
=======================================
Files 101 101
Lines 29036 29127 +91
=======================================
+ Hits 27396 27483 +87
- Misses 1640 1644 +4
🚀 New features to boost your workflow:
|
| del J | ||
| J = lagjac(z, y, mu, *args) | ||
| njev += 1 | ||
| J = J.at[f.size :].multiply((jnp.sqrt(mu) / jnp.sqrt(mu_old))[:, None]) |
There was a problem hiding this comment.
This change is not strictly necessary for the PR, but saves a Jacobian calculation.
| objective = ProximalProjection( | ||
| objective, | ||
| constraint=_combine_constraints(nonlinear_constraints), | ||
| state = ProximalState( |
There was a problem hiding this comment.
The ProximalState object is created here, outside of any particular ProximalProjection wrapper. This allows both the objective and nonlinear_constraints to see this state.
| if nonlinear_constraint is not None: | ||
| nonlinear_constraint = LinearConstraintProjection( | ||
| nonlinear_constraint, linear_constraint | ||
| nonlinear_constraint, linear_constraint, **linear_constraint_options |
There was a problem hiding this comment.
This change is unrelated to the PR, but linear_constraint_options was not being passed here.
| def _get_tangent(self, v, xf, constants, op): | ||
| # Note: This function is vectorized over v. So, v is expected to be 1D array | ||
| # of size self.dim_x. | ||
| def _vjp(self, v, x, constants=None, op="scaled"): |
There was a problem hiding this comment.
Added a vjp for use with auglag
One way of addressing #873. Right now, the only nonlinear constraints which proximal methods accept are force balance related ones.
ProximalProjectionalready handles the process of translating between the full set of state variables (including R_lmn, Z_lmn, L_lmn) and the reduced set of optimization variables, and ensures that an objective wrapped in proximal gets the proper tangents. For augmented lagrangian methods, the nonlinear constraints need those same tangents.This adds a class,
ProximalState, which is responsible for managing all properties of the equilibrium subproblem. Any proximal wrapped objective, e.g. the objective or a nonlinear constraint, can access the up-to-date equilibrium this way. The state also stores the equilibrium tangents for the present equilibrium, so multiple calls to grad start to just read the cache. It seems to work for the few cases I have tried.Since this is an issue others have thought about more, there may be better ways of getting this to work. Lmk and I can refactor.
Also some of the diff is due to changes from #2239, which will disappear once that is merged.