Skip to content
Closed
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
48 changes: 8 additions & 40 deletions src/nlp/api.jl
Original file line number Diff line number Diff line change
Expand Up @@ -61,20 +61,8 @@ function cons!(nlp::AbstractNLPModel, x::AbstractVector, cx::AbstractVector)
@lencheck get_nvar(nlp.meta) x
@lencheck get_ncon(nlp.meta) cx
increment!(nlp, :neval_cons)
if get_nlin(nlp.meta) > 0
if get_nnln(nlp.meta) == 0
cons_lin!(nlp, x, cx)
else
cons_lin!(nlp, x, view(cx, get_lin(nlp.meta)))
end
end
if get_nnln(nlp.meta) > 0
if get_nlin(nlp.meta) == 0
cons_nln!(nlp, x, cx)
else
cons_nln!(nlp, x, view(cx, get_nln(nlp.meta)))
end
end
get_nlin(nlp.meta) > 0 && cons_lin!(nlp, x, view(cx, get_lin(nlp.meta)))
get_nnln(nlp.meta) > 0 && cons_nln!(nlp, x, view(cx, get_nln(nlp.meta)))
Comment on lines +64 to +65

Copilot AI Apr 17, 2026

Copy link

Choose a reason for hiding this comment

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

cons! now always forwards cx to cons_lin!/cons_nln! as view(cx, meta.lin/meta.nln). When the problem is purely linear or purely nonlinear, this changes the argument type from the original cx (often a Vector/StridedVector) to a SubArray with index-vector indirection, which can break downstream model implementations that dispatch on Vector/StridedVector or use BLAS/external kernels requiring strided storage, and can add avoidable overhead. Consider restoring the fast-path branches for get_nnln(meta)==0 / get_nlin(meta)==0 (pass cx directly) and only using indexed views when both linear and nonlinear constraints are present.

Suggested change
get_nlin(nlp.meta) > 0 && cons_lin!(nlp, x, view(cx, get_lin(nlp.meta)))
get_nnln(nlp.meta) > 0 && cons_nln!(nlp, x, view(cx, get_nln(nlp.meta)))
nlin = get_nlin(nlp.meta)
nnln = get_nnln(nlp.meta)
if nnln == 0
cons_lin!(nlp, x, cx)
elseif nlin == 0
cons_nln!(nlp, x, cx)
else
cons_lin!(nlp, x, view(cx, get_lin(nlp.meta)))
cons_nln!(nlp, x, view(cx, get_nln(nlp.meta)))
end

Copilot uses AI. Check for mistakes.
return cx
end

Expand Down Expand Up @@ -275,20 +263,12 @@ function jac_coord!(nlp::AbstractNLPModel, x::AbstractVector, vals::AbstractVect
@lencheck get_nnzj(nlp.meta) vals
increment!(nlp, :neval_jac)
if get_nlin(nlp.meta) > 0
if get_nnln(nlp.meta) == 0
jac_lin_coord!(nlp, x, vals)
else
lin_ind = 1:(get_lin_nnzj(nlp.meta))
jac_lin_coord!(nlp, x, view(vals, lin_ind))
end
lin_ind = 1:(get_lin_nnzj(nlp.meta))
jac_lin_coord!(nlp, x, view(vals, lin_ind))
end
if get_nnln(nlp.meta) > 0
if get_nlin(nlp.meta) == 0
jac_nln_coord!(nlp, x, vals)
else
nln_ind = (get_lin_nnzj(nlp.meta) + 1):(get_lin_nnzj(nlp.meta) + get_nln_nnzj(nlp.meta))
jac_nln_coord!(nlp, x, view(vals, nln_ind))
end
nln_ind = (get_lin_nnzj(nlp.meta) + 1):(get_lin_nnzj(nlp.meta) + get_nln_nnzj(nlp.meta))
jac_nln_coord!(nlp, x, view(vals, nln_ind))
Comment on lines 265 to +271

Copilot AI Apr 17, 2026

Copy link

Choose a reason for hiding this comment

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

jac_coord! now always passes view(vals, lin_ind/nln_ind) into jac_lin_coord!/jac_nln_coord! even when the Jacobian is entirely linear or entirely nonlinear. This changes the concrete type seen by model implementations from the original vals (commonly a Vector) to a SubArray, which may break downstream methods that dispatch on Vector/StridedVector or call routines requiring strided storage. Suggest keeping the previous single-block fast paths (call jac_*_coord! with vals directly when the other block is empty) and using views only for the mixed case.

Copilot uses AI. Check for mistakes.
end
return vals
end
Expand Down Expand Up @@ -414,20 +394,8 @@ function jprod!(nlp::AbstractNLPModel, x::AbstractVector, v::AbstractVector, Jv:
@lencheck get_nvar(nlp.meta) x v
@lencheck get_ncon(nlp.meta) Jv
increment!(nlp, :neval_jprod)
if get_nlin(nlp.meta) > 0
if get_nnln(nlp.meta) == 0
jprod_lin!(nlp, x, v, Jv)
else
jprod_lin!(nlp, x, v, view(Jv, get_lin(nlp.meta)))
end
end
if get_nnln(nlp.meta) > 0
if get_nlin(nlp.meta) == 0
jprod_nln!(nlp, x, v, Jv)
else
jprod_nln!(nlp, x, v, view(Jv, get_nln(nlp.meta)))
end
end
get_nlin(nlp.meta) > 0 && jprod_lin!(nlp, x, v, view(Jv, get_lin(nlp.meta)))
get_nnln(nlp.meta) > 0 && jprod_nln!(nlp, x, v, view(Jv, get_nln(nlp.meta)))
Comment on lines +397 to +398

Copilot AI Apr 17, 2026

Copy link

Choose a reason for hiding this comment

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

jprod! now always calls jprod_lin!/jprod_nln! with view(Jv, ...). This removes the previous fast paths for the all-linear (get_nnln(meta)==0) and all-nonlinear (get_nlin(meta)==0) cases, and changes the type of the destination passed to downstream implementations from a plain Vector to a SubArray even when no remapping is needed. That can be a breaking change for model implementations that specialized jprod_lin!/jprod_nln! on concrete vectors (and it introduces extra indirection for the common contiguous/full-range case). Consider restoring the old branching (as done in cons! / jac_coord!) or conditionally passing Jv directly when the constraint set is purely linear or purely nonlinear.

Suggested change
get_nlin(nlp.meta) > 0 && jprod_lin!(nlp, x, v, view(Jv, get_lin(nlp.meta)))
get_nnln(nlp.meta) > 0 && jprod_nln!(nlp, x, v, view(Jv, get_nln(nlp.meta)))
if get_nnln(nlp.meta) == 0
jprod_lin!(nlp, x, v, Jv)
elseif get_nlin(nlp.meta) == 0
jprod_nln!(nlp, x, v, Jv)
else
jprod_lin!(nlp, x, v, view(Jv, get_lin(nlp.meta)))
jprod_nln!(nlp, x, v, view(Jv, get_nln(nlp.meta)))
end

Copilot uses AI. Check for mistakes.
Comment on lines +397 to +398

Copilot AI Apr 17, 2026

Copy link

Choose a reason for hiding this comment

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

There are no tests covering the edge cases where all constraints are linear (nnln==0) or all constraints are nonlinear (nlin==0). Since this change alters how jprod! dispatches (passing views vs the full vector), adding targeted tests for those two scenarios would help prevent regressions and catch downstream dispatch/type issues.

Suggested change
get_nlin(nlp.meta) > 0 && jprod_lin!(nlp, x, v, view(Jv, get_lin(nlp.meta)))
get_nnln(nlp.meta) > 0 && jprod_nln!(nlp, x, v, view(Jv, get_nln(nlp.meta)))
ncon = get_ncon(nlp.meta)
nlin = get_nlin(nlp.meta)
nnln = get_nnln(nlp.meta)
if nlin > 0
if nlin == ncon
jprod_lin!(nlp, x, v, Jv)
else
jprod_lin!(nlp, x, v, view(Jv, get_lin(nlp.meta)))
end
end
if nnln > 0
if nnln == ncon
jprod_nln!(nlp, x, v, Jv)
else
jprod_nln!(nlp, x, v, view(Jv, get_nln(nlp.meta)))
end
end

Copilot uses AI. Check for mistakes.
Comment on lines +397 to +398

Copilot AI Apr 17, 2026

Copy link

Choose a reason for hiding this comment

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

jprod! now always calls jprod_lin!/jprod_nln! with view(Jv, meta.lin/meta.nln). For purely linear or purely nonlinear problems this changes the Jv argument from the original array (often a Vector/StridedVector) to an indexed SubArray, which can break downstream implementations that dispatch on Vector/StridedVector or use BLAS/external kernels, and may add overhead compared to the previous direct call. Consider reinstating the get_nnln(meta)==0 / get_nlin(meta)==0 fast paths (pass Jv directly) and only using indexed views when both constraint types are present.

Suggested change
get_nlin(nlp.meta) > 0 && jprod_lin!(nlp, x, v, view(Jv, get_lin(nlp.meta)))
get_nnln(nlp.meta) > 0 && jprod_nln!(nlp, x, v, view(Jv, get_nln(nlp.meta)))
if get_nnln(nlp.meta) == 0
jprod_lin!(nlp, x, v, Jv)
elseif get_nlin(nlp.meta) == 0
jprod_nln!(nlp, x, v, Jv)
else
jprod_lin!(nlp, x, v, view(Jv, get_lin(nlp.meta)))
jprod_nln!(nlp, x, v, view(Jv, get_nln(nlp.meta)))
end

Copilot uses AI. Check for mistakes.
return Jv
end

Expand Down
Loading