Skip to content

Reverse mode and exact hessians#22

Open
rafaqz wants to merge 8 commits into
IPOPT-implementationfrom
reverse_mode
Open

Reverse mode and exact hessians#22
rafaqz wants to merge 8 commits into
IPOPT-implementationfrom
reverse_mode

Conversation

@rafaqz
Copy link
Copy Markdown
Member

@rafaqz rafaqz commented May 14, 2026

This PR adds proper reverse mode in Enzyme and exact hessians, and does some perfreoamance optimisation. Should be 4-5x faster.

We remove the OptimiastionIpopt package and just use Ipopt.jl directly, as OptimisationIpopt kind of just gets in the way.

rafaqz and others added 2 commits May 12, 2026 15:22
- Drop Optimization.jl / OptimizationIpopt.jl / SciMLBase in favour of
  the direct Ipopt.jl C interface. Gives access to the primal+dual
  warm-start API (IpoptProblem.x / mult_g) that the SciMLBase wrappers
  do not expose, so consecutive solves at similar parameter settings
  reuse the previous solution as the new initial guess.
- Export IPOPTSolverCache so callers can construct the cache once and
  pass it across sweeps.
- ipopt.jl rewritten end-to-end: cached buffers for primals, duals,
  bounds, constraint values, and Enzyme.forward-over-reverse Hessian
  (replaces FiniteDiff).
- Adopt HeatExchange Air/Water Fluid singletons in examples and test
  data: example_environment_pars defaults to Air(); endotherm test now
  maps the FLTYPE input flag to Water()/Air().
- Add bench_ipopt_sweep.jl and hessian_validation.jl examples for
  benchmarking warm-start speedup and Hessian correctness.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@rafaqz rafaqz requested a review from mrke May 14, 2026 01:47
Copy link
Copy Markdown
Contributor

@mrke mrke left a comment

Choose a reason for hiding this comment

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

Heavy stuff - I looked at all the code but probably need to spend a full week digesting how all this works.

@rafaqz
Copy link
Copy Markdown
Member Author

rafaqz commented May 18, 2026

I can probably split it up if that makes it easier to read?

Comment thread src/endotherm/thermoregulation/ipopt.jl Outdated
log_heat_flow_max,
flesh_conductivity_max, panting_rate_max, skin_wetness_max,
insulation_depth_max, aspect_ratio_max]
lb[1] = core_temperature_min; lb[2] = skin_temperature_min; lb[3] = skin_temperature_min
Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Note that this code is pretty bad. We only need it because we dont have the generalised (e.g. ModelParameters) way to get these thing into a vector.

This is a hack to get it working because its pretty hard to do that!

Later we can generalise it.

Comment thread src/endotherm/thermoregulation/ipopt.jl Outdated
# through `_*_inputs!` to fill `cache.x_scaling`. Worth doing the next time
# we touch the trait schema.
# ──────────────────────────────────────────────────────────────────────────
function _scaling_weighted()
Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Again, as the comment mentions, this code sucks

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Now that the trait examples are shifted into HeatExchange.jl we might be closer to revisiting the trait schema. I've been thinking about the whole trait database to parameters set up too - have some ideas.

@mrke
Copy link
Copy Markdown
Contributor

mrke commented May 18, 2026

I can probably split it up if that makes it easier to read?
No it's fine, just lots of new terms and concepts for me

rafaqz and others added 3 commits May 18, 2026 23:14
Spell out short identifiers in the IPOPT thermoregulation code: lb/ub/u0,
lcons/ucons, metab_pars/int_cond/evap_pars/opt_pars/nlp_pars, M/sT/iT
init shorthand, jac_*/hess_*/lag_* AD buffers, eval_f/eval_g/eval_grad_f/
eval_jac_g/eval_h closures, and the corresponding type parameters.

Drop the mutable-struct on IPOPTSolverCache: the only mutating field was
the warm-start flag, now stored as Base.RefValue{Bool}.
…o functors

- `thermoregulate` and `IPOPTSolverCache` take a single `init` NamedTuple
  (`metabolic_heat_flow`, `skin_temperature`, `insulation_temperature`) instead
  of three loose positional args, threaded through the rule-based loop, IPOPT
  builder, `_inputs!`, and `_refresh!`.
- Rename `_IPOPTState` to `IPOPTParameters` and its instance field to
  `ipopt_parameters` — what it holds is per-solve problem parameters, not
  optimizer state. The mutable cell is just so the callbacks can be reused
  across solves.
- Replace the anonymous Ipopt callback closures with six named functor structs
  (`EvaluateObjective`, `EvaluateConstraints`, `EvaluateObjectiveGradient`,
  `EvaluateConstraintJacobian`, `EvaluateHessian`, `LagrangianGradient`), all
  subtypes of `Function` so `Ipopt.IpoptProblem`'s typed callback fields accept
  them.
- Collapse `_build_cache` into two layered `IPOPTSolverCache` constructors and
  factor out `_problem_size` / `_constraint_bounds` so the strategy-specific
  dimensions live in one place.
- Deduplicate `_inputs!`: one shared body computes all scalars and parameter
  NamedTuples; the strategy-specific index layout is delegated to a small
  `_write_layout!` dispatched on packed type.
- Drop the `effectors[i]` magic numbers in `_objective_value` — name only the
  variables each method actually uses.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
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.

2 participants