Skip to content

Rework FH problem: reduce allocations and improve efficiency#92

Open
MaxenceGollier wants to merge 10 commits intoJuliaSmoothOptimizers:mainfrom
MaxenceGollier:pde_fh
Open

Rework FH problem: reduce allocations and improve efficiency#92
MaxenceGollier wants to merge 10 commits intoJuliaSmoothOptimizers:mainfrom
MaxenceGollier:pde_fh

Conversation

@MaxenceGollier
Copy link
Copy Markdown
Collaborator

@MaxenceGollier MaxenceGollier commented Feb 25, 2026

@dpo, @MohamedLaghdafHABIBOULLAH

closes #91
partially closes #90 by adding the OrdinaryDiffEqVerner dep instead of the much much much larger DifferentialEquations dep.
I will use this for the last problem of #88, with NLPModelsModifiers.jl.
I removed the MLDataSet from the dep because I had compat issues. I am waiting for chengchingwen/Pickle.jl#47 to add it back.

I think nonetheless that having to download a large dataset on each CI run is not a good idea and should be avoided (50 minutes of CI for a package of this scale is ridiculous).

@MohamedLaghdafHABIBOULLAH, this is breaking i would like to see your review on this one and make sure that this does not destroy to much code. Can we meet at GERAD sometime ?

@codecov
Copy link
Copy Markdown

codecov bot commented Feb 25, 2026

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 67.29%. Comparing base (85de184) to head (c0b1cbc).
⚠️ Report is 21 commits behind head on main.

Additional details and impacted files
@@             Coverage Diff             @@
##             main      #92       +/-   ##
===========================================
- Coverage   99.18%   67.29%   -31.90%     
===========================================
  Files          11       19        +8     
  Lines         369      480      +111     
===========================================
- Hits          366      323       -43     
- Misses          3      157      +154     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

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

@MaxenceGollier
Copy link
Copy Markdown
Collaborator Author

For example, with this version

julia> model, _, _ = fh_model()
julia> @benchmark grad!(model, gx, model.meta.x0)
BenchmarkTools.Trial: 232 samples with 1 evaluation per sample.
 Range (min … max):  20.801 ms …  25.364 ms  ┊ GC (min … max): 0.00% … 0.00%
 Time  (median):     21.283 ms               ┊ GC (median):    0.00%
 Time  (mean ± σ):   21.518 ms ± 737.232 μs  ┊ GC (mean ± σ):  0.00% ± 0.00%

      ▄██▁▂▁▄▃
  ▃▅▇▅████████▅▆▅▅▃▃▄▄▃▄▁▃▃▁▁▃▃▁▁▃▃▁▃▁▁▃▁▁▃▃▁▃▃▃▃▃▃▁▁▃▃▁▃▁▁▁▃▃ ▃
  20.8 ms         Histogram: frequency by time         24.1 ms <

 Memory estimate: 624 bytes, allocs estimate: 3.

I am trying to get results with the older version but i am running in a ton of problems, it seems that the previous version was not even compatible with ADNLPModels@v0.8.

@MohamedLaghdafHABIBOULLAH
Copy link
Copy Markdown
Collaborator

@MaxenceGollier this seems to be extraordinary, I will review it ASAP, yes sure we can meet!

@dpo
Copy link
Copy Markdown
Member

dpo commented Mar 5, 2026

@MaxenceGollier Could you please check that objective, gradients, etc., match the old implementation?

@MaxenceGollier MaxenceGollier marked this pull request as ready for review April 10, 2026 18:15
Copilot AI review requested due to automatic review settings April 10, 2026 18:15
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

This PR refactors the Fitzhugh–Nagumo (FH) problem implementation to reduce allocations and dependency weight by switching from DifferentialEquations to OrdinaryDiffEqVerner, and by using ReverseDiff-based AD backends.

Changes:

  • Replace DifferentialEquations usage with OrdinaryDiffEqVerner and introduce ReverseDiff for FH objective/residual evaluation.
  • Rework FH residual/objective to use in-place ODE solves with preallocated buffers.
  • Update dependencies/compat and documentation to reflect the new required packages for FH.

Reviewed changes

Copilot reviewed 4 out of 5 changed files in this pull request and generated 5 comments.

Show a summary per file
File Description
test/runtests.jl Switch test deps to OrdinaryDiffEqVerner; SVM test blocks are currently wrapped in a triple-quoted string (disabled).
src/RegularizedProblems.jl Gate FH model loading behind Requires on OrdinaryDiffEqVerner + ReverseDiff.
src/fh_model.jl Major FH rewrite: integrator reuse, in-place residual, ReverseDiff backends.
Project.toml Remove DifferentialEquations from test extras/targets; add OrdinaryDiffEqVerner + ReverseDiff.
docs/src/index.md Document updated imports required for fh_model().

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines 6 to 9
NLPModels,
NLPModelsModifiers,
OrdinaryDiffEqVerner,
QuadraticModels
Copy link

Copilot AI Apr 10, 2026

Choose a reason for hiding this comment

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

fh_model is only included via @require ReverseDiff (see src/RegularizedProblems.jl), but ReverseDiff is not imported in this test file. As a result, fh_model() is likely undefined when the "FH" testset runs. Import ReverseDiff (or otherwise ensure it is Base.required) before calling fh_model() so the Requires hook fires.

Copilot uses AI. Check for mistakes.
test/runtests.jl Outdated
Comment on lines 113 to 115
"""
@testset "SVM-Train" begin
ENV["DATADEPS_ALWAYS_ACCEPT"] = true
Copy link

Copilot AI Apr 10, 2026

Choose a reason for hiding this comment

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

The triple-quoted string starting here turns the entire SVM testsets into a string literal, so these tests no longer run. If the goal is to avoid large dataset downloads on CI, consider guarding the testsets behind an env flag (and/or using a small local fixture) rather than silently disabling them.

Copilot uses AI. Check for mistakes.
Comment on lines +28 to +31
noise = 0.1 * randn(length(integrator.sol.u), 2)
noise = collect(eachrow(noise))
data = noise + integrator.sol.u
temp = zeros(eltype(data[1]), length(data) * 2)
Copy link

Copilot AI Apr 10, 2026

Choose a reason for hiding this comment

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

data = noise + integrator.sol.u will throw a MethodError in Julia because + is not defined for Vector/Vector containers (you likely want elementwise/broadcasted addition). Use broadcasting (e.g., noise .+ integrator.sol.u) or explicitly build data element-by-element so data[i] remains a 2-vector.

Copilot uses AI. Check for mistakes.
Comment on lines +35 to +39
function residual!(F, x :: AbstractVector{T}) where{T <: Real}
if integrator.p != x
OrdinaryDiffEqVerner.reinit!(integrator, u0)
integrator.p .= x
OrdinaryDiffEqVerner.solve!(integrator)
Copy link

Copilot AI Apr 10, 2026

Choose a reason for hiding this comment

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

The cache check if integrator.p != x is not safe when callers reuse and mutate the same x vector between evaluations (common in optimization). In that case integrator.p can alias x, the comparison stays false, and the ODE solve is skipped even though parameters changed, returning a stale residual. Prefer always re-solving, or compare against a non-aliasing cached copy of the last parameters.

Copilot uses AI. Check for mistakes.
Comment on lines 95 to +99
function fh_model(; kwargs...)
data, simulate, resid, misfit, x0 = FH_smooth_term()
data, resid!, misfit, x0 = FH_smooth_term()
nequ = 202
ADNLPModels.ADNLPModel(misfit, ones(5); kwargs...),
ADNLPModels.ADNLSModel(resid, ones(5), nequ; kwargs...),
x0
end
nlp = ADNLPModels.ADNLPModel(misfit, ones(5);
hessian_backend = ADNLPModels.ReverseDiffADHessian,
Copy link

Copilot AI Apr 10, 2026

Choose a reason for hiding this comment

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

fh_model(; kwargs...) no longer forwards kwargs... to ADNLPModel/ADNLSModel!, even though the docstring says all keyword arguments are passed through (and callers like setup_fh_l0/l1 forward kwargs). This is a breaking API change and prevents users from overriding AD backends/options. Consider keeping the ReverseDiff backends as defaults but still merging/forwarding kwargs... so callers can customize behavior.

Copilot uses AI. Check for mistakes.
@github-actions
Copy link
Copy Markdown
Contributor

Package name latest stable
RegularizedOptimization

@github-actions
Copy link
Copy Markdown
Contributor

Package name latest stable
RegularizedOptimization

@github-actions
Copy link
Copy Markdown
Contributor

Package name latest stable
RegularizedOptimization

@github-actions
Copy link
Copy Markdown
Contributor

Package name latest stable
RegularizedOptimization

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.

Make FH allocation-free Reduce precompilation time

4 participants