Skip to content

Add VectorNonlinearOracle support for Grey-Box Models - #48

Open
wenwen0231 wants to merge 2 commits into
infiniteopt:mainfrom
wenwen0231:embedML
Open

wenwen0231 wants to merge 2 commits into
infiniteopt:mainfrom
wenwen0231:embedML

Conversation

@wenwen0231

Copy link
Copy Markdown
Contributor

Support for embedding grey-box ML formulations in ExaModels by adding support for VectorNonlinearOracle.

@codecov-commenter

codecov-commenter commented Sep 4, 2026 •

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 1.12360% with 88 lines in your changes missing coverage. Please review.
✅ Project coverage is 77.06%. Comparing base (782b4c3) to head (b58cd53).

Files with missing lines Patch % Lines
src/transform.jl 1.12% 88 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main      #48      +/-   ##
==========================================
- Coverage   85.99%   77.06%   -8.93%     
==========================================
  Files           6        6              
  Lines         757      846      +89     
==========================================
+ Hits          651      652       +1     
- Misses        106      194      +88     

☔ View full report in Codecov by Harness.
📢 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.

@wenwen0231

Copy link
Copy Markdown
Contributor Author

@pulsipher thought I'd bump this in case you might've missed it.

@pulsipher pulsipher left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Thanks for this, we just need to make this a little safer against edge cases and I think we can make it more performant on GPUs by more carefully allocating arrays. Also tests will be needed.

Comment thread src/transform.jl
Comment on lines +502 to +507
function _add_oracle(
core::ExaModels.ExaCore,
vrefs::Vector{InfiniteOpt.GeneralVariableRef},
set::_MOI.VectorNonlinearOracle,
inf_model::InfiniteOpt.InfiniteModel
)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

this should take the mapping data as an input

Comment thread src/transform.jl
Comment on lines +518 to +520
push!(invars, InfiniteOpt.transformation_variable(vrefs[i]))
elseif i in moi_out_idxs
push!(outvars, InfiniteOpt.transformation_variable(vrefs[i]))

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

This is not a save way to access the variables as everything is being made, the mapping data should be used instead

Comment thread src/transform.jl
Comment on lines +525 to +527
nsupps = unique([length(InfiniteOpt.supports(v, label = InfiniteOpt.All)) for v in vrefs])
@assert length(nsupps) == 1 "All input/output variable references must have the same number of supports, found $(nsupps) different numbers."
nsupps = only(nsupps)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Again this should be handled with the mapping data and/or it would be safer to check via calling parameter_refs to make sure each variable has the same dependencies. Though I wonder if this is a necessary assumption.

Comment thread src/transform.jl
Comment on lines +530 to +533
for t in 1:nsupps
# Extract indices of relevant input/output variables at this transcription point
in_idxs = [v[t].i for v in invars]
out_idxs = [v[t].i for v in outvars]

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Instead of iterating over the supports and making an oracle for each, what if we made a single oracle that pieced all of the discretized constraints together?

Comment thread src/transform.jl
hvp! = _hvp!,
# From the ExaModels docs: "Use `adapt=Val(true)` to have arrays
# automatically copied to CPU before each callback invocation.
adapt = Val(true),

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

We probably want to make Val(false) work such that we can try to propagate CUDA arrays through and keep everything on the GPU

Comment thread src/transform.jl
_f! = let x_idx = in_idxs, z_idx = out_idxs
(c, xv) -> begin
# MOI callback func takes a vector of size input_dim + output_dim
in_vec = Float32.(vcat(view(xv, x_idx), zeros(set.output_dimension)))

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

This will only make a CPU array, but should be generalized to make a GPU array if that is being passed through

Comment thread src/transform.jl

_jvp! = let x_idx = in_idxs, z_idx = out_idxs
(Jv, xv, v) -> begin
in_vec = Float32.(vcat(view(xv, x_idx), zeros(set.output_dimension)))

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

This will only make a CPU array, but should be generalized to make a GPU array if that is being passed through

Comment thread src/transform.jl
_jvp! = let x_idx = in_idxs, z_idx = out_idxs
(Jv, xv, v) -> begin
in_vec = Float32.(vcat(view(xv, x_idx), zeros(set.output_dimension)))
J_vals = zeros(Float32, length(set.jacobian_structure))

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

This will only make a CPU array, but should be generalized to make a GPU array if that is being passed through

Comment thread src/transform.jl
Comment on lines +569 to +570
in_vec = Float32.(vcat(view(xv, x_idx), zeros(set.output_dimension)))
J_vals = zeros(Float32, length(set.jacobian_structure))

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

This will only make a CPU array, but should be generalized to make a GPU array if that is being passed through

Comment thread src/transform.jl
Comment on lines +587 to +588
in_vec = Float32.(vcat(view(xv, x_idx), zeros(set.output_dimension)))
H_vals = zeros(Float32, length(set.hessian_lagrangian_structure))

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

This will only make a CPU array, but should be generalized to make a GPU array if that is being passed through

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.

3 participants