Skip to content

Getting proximal to work with augmented Lagrangian optimizers - #2298

Draft
singh-jaydeep wants to merge 6 commits into
masterfrom
js/proximal-auglag
Draft

Getting proximal to work with augmented Lagrangian optimizers#2298
singh-jaydeep wants to merge 6 commits into
masterfrom
js/proximal-auglag

Conversation

@singh-jaydeep

Copy link
Copy Markdown
Collaborator

One way of addressing #873. Right now, the only nonlinear constraints which proximal methods accept are force balance related ones. ProximalProjection already 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.

@github-actions

github-actions Bot commented Aug 19, 2026

Copy link
Copy Markdown
Contributor

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 Memory Benchmarks workflow and download the artifact.

@codecov

codecov Bot commented Aug 19, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 98.28326% with 4 lines in your changes missing coverage. Please review.
✅ Project coverage is 94.35%. Comparing base (7582fb3) to head (c411830).

Files with missing lines Patch % Lines
desc/optimize/_constraint_wrappers.py 98.53% 3 Missing ⚠️
desc/optimize/optimizer.py 95.45% 1 Missing ⚠️
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     
Files with missing lines Coverage Δ
desc/objectives/utils.py 100.00% <100.00%> (ø)
desc/optimize/aug_lagrangian_ls.py 95.98% <100.00%> (-0.02%) ⬇️
desc/optimize/optimizer.py 96.09% <95.45%> (-0.15%) ⬇️
desc/optimize/_constraint_wrappers.py 96.98% <98.53%> (+0.07%) ⬆️

... and 2 files with indirect coverage changes

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

del J
J = lagjac(z, y, mu, *args)
njev += 1
J = J.at[f.size :].multiply((jnp.sqrt(mu) / jnp.sqrt(mu_old))[:, None])

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This change is not strictly necessary for the PR, but saves a Jacobian calculation.

objective = ProximalProjection(
objective,
constraint=_combine_constraints(nonlinear_constraints),
state = ProximalState(

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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"):

@singh-jaydeep singh-jaydeep Aug 20, 2026

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added a vjp for use with auglag

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant