diff --git a/.gitignore b/.gitignore index 9bbde01f..cf0563cd 100644 --- a/.gitignore +++ b/.gitignore @@ -2,4 +2,4 @@ *.jl.mem docs/build docs/site -Manifest.toml +Manifest*.toml diff --git a/docs/make.jl b/docs/make.jl index fccdca6c..c66a0cca 100644 --- a/docs/make.jl +++ b/docs/make.jl @@ -16,6 +16,7 @@ makedocs( "Guidelines" => "guidelines.md", "Tools" => "tools.md", "API" => "api.md", + "Batch API" => "batch_api.md", "Internals" => "internals.md", "Reference" => "reference.md", ], diff --git a/docs/src/batch_api.md b/docs/src/batch_api.md new file mode 100644 index 00000000..27366335 --- /dev/null +++ b/docs/src/batch_api.md @@ -0,0 +1,103 @@ +# Batch API + +This section documents the batch API of `NLPModels.jl`. +The batch API reuses the same symbols as the standard (non-batch) API. +The only new in-place function is `obj!`, which returns a vector of all objectives. + +--- + +## Abstract types + +- [`AbstractBatchNLPModel`](@ref) +- [`AbstractBatchNLPModelMeta`](@ref) + +--- + +## Batch metadata + +- [`BatchNLPModelMeta`](@ref) + +--- + +## Objectives + +| Function | Signature | +|:--------:|:---------:| +| `obj` | `obj(bnlp::AbstractBatchNLPModel, bx::AbstractMatrix)` | +| `obj!` | `obj!(bnlp::AbstractBatchNLPModel, bx::AbstractMatrix, bf::AbstractVector)` | + +--- + +## Gradients + +| Function | Signature | +|:--------:|:---------:| +| `grad` | `grad(bnlp::AbstractBatchNLPModel, bx::AbstractMatrix)` | +| `grad!` | `grad!(bnlp::AbstractBatchNLPModel, bx::AbstractMatrix, bg::AbstractMatrix)` | + +--- + +## Constraints + +| Function | Signature | +|:--------:|:---------:| +| `cons` | `cons(bnlp::AbstractBatchNLPModel, bx::AbstractMatrix)` | +| `cons!` | `cons!(bnlp::AbstractBatchNLPModel, bx::AbstractMatrix, bc::AbstractMatrix)` | + +--- + +## Sparse jacobians + +| Function | Signature | +|:--------:|:---------:| +| `jac_structure` | `(jrows, jcols) = jac_structure(bnlp::AbstractBatchNLPModel)` | +| `jac_structure!` | `(jrows, jcols) = jac_structure!(bnlp::AbstractBatchNLPModel, jrows::AbstractVector, jcols::AbstractVector)` | +| `jac_coord` | `bjvals = jac_coord(bnlp::AbstractBatchNLPModel, bx::AbstractMatrix)` | +| `jac_coord!` | `bjvals = jac_coord!(bnlp::AbstractBatchNLPModel, bx::AbstractMatrix, bjvals::AbstractMatrix)` | + +--- + +## Dense Jacobians + +| Function | Signature | +|:--------:|:---------:| +| `jac_dense!` | `bJx = jac_dense!(bnlp::AbstractBatchNLPModel, bx::AbstractMatrix, bJx::AbstractArray)` | + +--- + +## Jacobian-vector products + +| Function | Signature | +|:--------:|:---------:| +| `jprod` | `bJv = jprod(bnlp::AbstractBatchNLPModel, bx::AbstractMatrix, bv::AbstractMatrix)` | +| `jprod!` | `bJv = jprod!(bnlp::AbstractBatchNLPModel, bx::AbstractMatrix, bv::AbstractMatrix, bJv::AbstractMatrix)` | +| `jtprod` | `bJtv = jtprod(bnlp::AbstractBatchNLPModel, bx::AbstractMatrix, bv::AbstractMatrix)` | +| `jtprod!` | `bJtv = jtprod!(bnlp::AbstractBatchNLPModel, bx::AbstractMatrix, bv::AbstractMatrix, bJtv::AbstractMatrix)` | + +--- + +## Sparse Hessians of the Lagrangian + +| Function | Signature | +|:--------:|:---------:| +| `hess_structure` | `(hrows, hcols) = hess_structure(bnlp::AbstractBatchNLPModel)` | +| `hess_structure!` | `(hrows, hcols) = hess_structure!(bnlp::AbstractBatchNLPModel, hrows::AbstractVector, hcols::AbstractVector)` | +| `hess_coord` | `bhvals = hess_coord(bnlp::AbstractBatchNLPModel, bx::AbstractMatrix, by::AbstractMatrix, bobj_weight::AbstractVector)` | +| `hess_coord!` | `bhvals = hess_coord!(bnlp::AbstractBatchNLPModel, bx::AbstractMatrix, by::AbstractMatrix, bobj_weight::AbstractVector, bhvals::AbstractMatrix)` | + +--- + +## Dense Hessians of the Lagrangian + +| Function | Signature | +|:--------:|:---------:| +| `hess_dense!` | `bHx = hess_dense!(bnlp::AbstractBatchNLPModel, bx::AbstractMatrix, by::AbstractMatrix, bobj_weight::AbstractVector, bHx::AbstractArray)` | + +--- + +## Hessian-vector products + +| Function | Signature | +|:--------:|:---------:| +| `hprod` | `bHv = hprod(bnlp::AbstractBatchNLPModel, bx::AbstractMatrix, by::AbstractMatrix, bv::AbstractMatrix, bobj_weight::AbstractVector)` | +| `hprod!` | `bHv = hprod!(bnlp::AbstractBatchNLPModel, bx::AbstractMatrix, by::AbstractMatrix, bv::AbstractMatrix, bobj_weight::AbstractVector, bHv::AbstractMatrix)` | diff --git a/docs/src/reference.md b/docs/src/reference.md index 45ffa759..ef9a50ca 100644 --- a/docs/src/reference.md +++ b/docs/src/reference.md @@ -1,17 +1,17 @@ # Reference -​ + ## Contents -​ + ```@contents Pages = ["reference.md"] ``` -​ + ## Index -​ + ```@index Pages = ["reference.md"] ``` -​ + ```@autodocs Modules = [NLPModels] -``` \ No newline at end of file +``` diff --git a/src/NLPModels.jl b/src/NLPModels.jl index 17299f9b..4d60317d 100644 --- a/src/NLPModels.jl +++ b/src/NLPModels.jl @@ -41,5 +41,7 @@ for f in ["utils", "api", "counters", "meta", "show", "tools"] include("nlp/$f.jl") include("nls/$f.jl") end +include("nlp/batch_api.jl") +include("nlp/batch_meta.jl") end # module diff --git a/src/nlp/batch_api.jl b/src/nlp/batch_api.jl new file mode 100644 index 00000000..851e877c --- /dev/null +++ b/src/nlp/batch_api.jl @@ -0,0 +1,90 @@ +export AbstractBatchNLPModel +export obj! + +""" + AbstractBatchNLPModel + +Abstract base type for batched nonlinear optimization models. + +Each model in the batch has the same number of variables and constraints, +and the sparsity patterns of the Jacobian and the Hessian of the Lagrangian are identical across the batch. +""" +abstract type AbstractBatchNLPModel{T, S} end + +function obj(bnlp::AbstractBatchNLPModel{T, S}, bx::AbstractMatrix) where {T, S} + bf = S(undef, 1, bnlp.meta.nbatch) |> vec + obj!(bnlp, bx, bf) + return bf +end + +""" + bf = obj!(bnlp, bx) +""" +function obj! end + +function grad(bnlp::AbstractBatchNLPModel{T, S}, bx::AbstractMatrix) where {T, S} + bg = S(undef, bnlp.meta.nvar, bnlp.meta.nbatch) + grad!(bnlp, bx, bg) + return bg +end + +function cons(bnlp::AbstractBatchNLPModel{T, S}, bx::AbstractMatrix) where {T, S} + bc = S(undef, bnlp.meta.ncon, bnlp.meta.nbatch) + cons!(bnlp, bx, bc) + return bc +end + +function jac_structure(bnlp::AbstractBatchNLPModel) + jrows = Vector{Int}(undef, bnlp.meta.nnzj) + jcols = Vector{Int}(undef, bnlp.meta.nnzj) + jac_structure!(bnlp, jrows, jcols) + return (jrows, jcols) +end + +function jac_coord(bnlp::AbstractBatchNLPModel{T, S}, bx::AbstractMatrix) where {T, S} + bjvals = S(undef, bnlp.meta.nnzj, bnlp.meta.nbatch) + jac_coord!(bnlp, bx, bjvals) + return bjvals +end + +function jprod(bnlp::AbstractBatchNLPModel{T, S}, bx::AbstractMatrix, bv::AbstractMatrix) where {T, S} + bJv = S(undef, bnlp.meta.ncon, bnlp.meta.nbatch) + jprod!(bnlp, bx, bv, bJv) + return bJv +end + +function jtprod(bnlp::AbstractBatchNLPModel{T, S}, bx::AbstractMatrix, bv::AbstractMatrix) where {T, S} + bJtv = S(undef, bnlp.meta.nvar, bnlp.meta.nbatch) + jtprod!(bnlp, bx, bv, bJtv) + return bJtv +end + +function hess_structure(bnlp::AbstractBatchNLPModel) + hrows = Vector{Int}(undef, bnlp.meta.nnzh) + hcols = Vector{Int}(undef, bnlp.meta.nnzh) + hess_structure!(bnlp, hrows, hcols) + return hrows, hcols +end + +function hess_coord( + bnlp::AbstractBatchNLPModel{T, S}, + bx::AbstractMatrix, + by::AbstractMatrix, + bobj_weight::AbstractVector, +) where {T, S} + bhvals = S(undef, bnlp.meta.nnzh, bnlp.meta.nbatch) + hess_coord!(bnlp, bx, by, bobj_weight, bhvals) + return bhvals +end + +function hprod( + bnlp::AbstractBatchNLPModel{T, S}, + bx::AbstractMatrix, + by::AbstractMatrix, + bv::AbstractMatrix, + bobj_weight::AbstractVector, +) where {T, S} + bHv = S(undef, bnlp.meta.nvar, bnlp.meta.nbatch) + hprod!(bnlp, bx, by, bv, bobj_weight, bHv) + return bHv +end diff --git a/src/nlp/batch_meta.jl b/src/nlp/batch_meta.jl new file mode 100644 index 00000000..4d035735 --- /dev/null +++ b/src/nlp/batch_meta.jl @@ -0,0 +1,145 @@ +export AbstractBatchNLPModelMeta, BatchNLPModelMeta + +""" + AbstractBatchNLPModelMeta + +Abstract base type for metadata related to batched nonlinear optimization models. +""" +abstract type AbstractBatchNLPModelMeta{T, S} end + +""" + BatchNLPModelMeta <: AbstractBatchNLPModelMeta + +A composite type that represents the main features of a batch of +nonlinear optimization problems sharing the same structure. + +Each batch contains `nbatch` independent NLP models of the form: + + optimize objᵢ(x) + subject to lvarᵢ ≤ x ≤ uvarᵢ + lconᵢ ≤ consᵢ(x) ≤ uconᵢ + +for i = 1, ..., nbatch. + +Each model variable vector `x` has dimension `nvar`, and constraint vector +`consᵢ(x)` has dimension `ncon`. + +All batch data are stored in matrices of size: + +- `(nvar, nbatch)` for variables and bounds (`x0`, `lvar`, `uvar`) +- `(ncon, nbatch)` for constraints and multipliers (`y0`, `lcon`, `ucon`) + +--- + + BatchNLPModelMeta(nbatch::Int, nvar::Int; kwargs...) + +Create a `BatchNLPModelMeta` with `nbatch` models, each having `nvar` variables. +The following keyword arguments are accepted: +- `x0`: initial guess +- `lvar`: matrix of lower bounds +- `uvar`: matrix of upper bounds +- `ncon`: number of general constraints +- `y0`: initial Lagrange multipliers +- `lcon`: matrix of constraint lower bounds +- `ucon`: matrix of constraint upper bounds +- `nnzj`: number of elements needed to store the nonzeros in the sparse Jacobian +- `nnzh`: number of elements needed to store the nonzeros in the sparse Hessian +- `minimize`: true if optimize == minimize +- `islp`: true if the problems are linear programs +- `name`: problem name for the batch +- `sparse_jacobian`: indicates whether the Jacobian of the constraints is sparse +- `sparse_hessian`: indicates whether the Hessian of the Lagrangian is sparse +- `grad_available`: indicates whether the gradient of the objective is available +- `jac_available`: indicates whether the Jacobian of the constraints is available +- `hess_available`: indicates whether the Hessian of the Lagrangian is available +- `jprod_available`: indicates whether the Jacobian-vector product `J * v` is available +- `jtprod_available`: indicates whether the transpose Jacobian-vector product `J' * v` is available +- `hprod_available`: indicates whether the Hessian-vector product of the Lagrangian `H * v` is available +""" +struct BatchNLPModelMeta{T, S} <: AbstractBatchNLPModelMeta{T, S} + nbatch::Int + nvar::Int + x0::S + lvar::S + uvar::S + ncon::Int + y0::S + lcon::S + ucon::S + nnzj::Int + nnzh::Int + minimize::Bool + islp::Bool + name::String + sparse_jacobian::Bool + sparse_hessian::Bool + grad_available::Bool + jac_available::Bool + hess_available::Bool + jprod_available::Bool + jtprod_available::Bool + hprod_available::Bool +end + +for field in fieldnames(BatchNLPModelMeta) + meth = Symbol("get_", field) + @eval begin + $meth(meta::AbstractBatchNLPModelMeta) = getproperty(meta, $(QuoteNode(field))) + end + @eval $meth(bnlp::AbstractBatchNLPModel) = $meth(bnlp.meta) + @eval export $meth +end + +function BatchNLPModelMeta{T, S}( + nbatch::Int, + nvar::Int; + x0::S = fill!(S(undef, nvar, nbatch), zero(T)), + lvar::S = fill!(S(undef, nvar, nbatch), T(-Inf)), + uvar::S = fill!(S(undef, nvar, nbatch), T(Inf)), + ncon::Int = 0, + y0::S = fill!(S(undef, ncon, nbatch), zero(T)), + lcon::S = fill!(S(undef, ncon, nbatch), T(-Inf)), + ucon::S = fill!(S(undef, ncon, nbatch), T(Inf)), + nnzj::Int = nvar * ncon, + nnzh::Int = nvar * (nvar + 1) ÷ 2, + minimize::Bool = true, + islp::Bool = false, + name::String = "Batch NLP", + sparse_jacobian::Bool = true, + sparse_hessian::Bool = true, + grad_available::Bool = true, + jac_available::Bool = (ncon > 0), + hess_available::Bool = true, + jprod_available::Bool = (ncon > 0), + jtprod_available::Bool = (ncon > 0), + hprod_available::Bool = true, +) where {T, S} + if (nbatch < 1) || (nvar < 1) || (ncon < 0) || (nnzj < 0) || (nnzh < 0) + error("Nonsensical dimensions") + end + + BatchNLPModelMeta{T, S}( + nbatch, + nvar, + x0, + lvar, + uvar, + ncon, + y0, + lcon, + ucon, + nnzj, + nnzh, + minimize, + islp, + name, + sparse_jacobian, + sparse_hessian, + grad_available, + jac_available, + hess_available, + jprod_available, + jtprod_available, + hprod_available, + ) +end diff --git a/test/nlp/batch_api.jl b/test/nlp/batch_api.jl new file mode 100644 index 00000000..ea2ef951 --- /dev/null +++ b/test/nlp/batch_api.jl @@ -0,0 +1,56 @@ +@testset "Batch API" begin + bnlp = BatchSimpleNLPModel([1.0, 2.0, 3.0]) + models = [ + SimpleNLPModel(; p = 1.0) + SimpleNLPModel(; p = 2.0) + SimpleNLPModel(; p = 3.0) + ] + + @test bnlp.meta.nbatch == 3 + + bx = [ + 1.0 3.0 5.0; + 2.0 4.0 6.0; + ] + by = [ + -1.0 -3.0 -5.0; + -2.0 -4.0 -6.0; + ] + xs = [ + 1.0 3.0 5.0; + 2.0 4.0 6.0; + ] + ys = [ + -1.0 -3.0 -5.0; + -2.0 -4.0 -6.0; + ] + bobj_weight = [1.0, 1.0, 1.0] + + bf = obj(bnlp, bx) + bg = grad(bnlp, bx) + bc = cons(bnlp, bx) + bjvals = jac_coord(bnlp, bx) + bhvals = hess_coord(bnlp, bx, by, bobj_weight) + bJv = jprod(bnlp, bx, bx) + bJtv = jtprod(bnlp, bx, by) + bHv = hprod(bnlp, bx, by, bx, bobj_weight) + jrows, jcols = jac_structure(bnlp) + hrows, hcols = hess_structure(bnlp) + + for i in 1:3 + @test bf[i] == obj(models[i], xs[:,i]) + @test bg[:,i] == grad(models[i], xs[:,i]) + @test bc[:,i] == cons(models[i], xs[:,i]) + @test bjvals[:,i] == jac_coord(models[i], xs[:,i]) + @test bhvals[:,i] == hess_coord(models[i], xs[:,i], ys[:,i]) + @test bJv[:,i] == jprod(models[i], xs[:,i], xs[:,i]) + @test bJtv[:,i] == jtprod(models[i], xs[:,i], ys[:,i]) + @test bHv[:,i] == hprod(models[i], xs[:,i], ys[:,i], xs[:,i]) + jrowsi, jcolsi = jac_structure(models[i]) + @test jrows == jrowsi + @test jcols == jcolsi + hrowsi, hcolsi = hess_structure(models[i]) + @test hrows == hrowsi + @test hcols == hcolsi + end +end diff --git a/test/nlp/simple-model.jl b/test/nlp/simple-model.jl index 7f61c626..ce5d3674 100644 --- a/test/nlp/simple-model.jl +++ b/test/nlp/simple-model.jl @@ -14,9 +14,10 @@ x₀ = [2.0, 2.0]. mutable struct SimpleNLPModel{T, S} <: AbstractNLPModel{T, S} meta::NLPModelMeta{T, S} counters::Counters + p::T end -function SimpleNLPModel(::Type{T}) where {T} +function SimpleNLPModel(::Type{T}; p = T(4)) where {T} meta = NLPModelMeta( 2, nnzh = 2, @@ -32,10 +33,10 @@ function SimpleNLPModel(::Type{T}) where {T} nln_nnzj = 2, ) - return SimpleNLPModel(meta, Counters()) + return SimpleNLPModel(meta, Counters(), T(p)) end -SimpleNLPModel() = SimpleNLPModel(Float64) +SimpleNLPModel(; p = 4.0) = SimpleNLPModel(Float64; p = p) function NLPModels.obj(nlp::SimpleNLPModel, x::AbstractVector) @lencheck 2 x @@ -73,7 +74,7 @@ function NLPModels.hess_coord!( @lencheck 2 x y vals increment!(nlp, :neval_hess) vals .= 2obj_weight - vals[1] -= y[2] / 2 + vals[1] -= 2y[2] / nlp.p vals[2] -= 2y[2] return vals end @@ -89,7 +90,7 @@ function NLPModels.hprod!( @lencheck 2 x y v Hv increment!(nlp, :neval_hprod) Hv .= 2obj_weight * v - Hv[1] -= y[2] * v[1] / 2 + Hv[1] -= (2y[2] / nlp.p) * v[1] Hv[2] -= 2y[2] * v[2] return Hv end @@ -98,7 +99,7 @@ function NLPModels.cons_nln!(nlp::SimpleNLPModel, x::AbstractVector, cx::Abstrac @lencheck 2 x @lencheck 1 cx increment!(nlp, :neval_cons_nln) - cx .= [-x[1]^2 / 4 - x[2]^2 + 1] + cx .= [-x[1]^2 / nlp.p - x[2]^2 + 1] return cx end @@ -135,7 +136,7 @@ end function NLPModels.jac_nln_coord!(nlp::SimpleNLPModel, x::AbstractVector, vals::AbstractVector) @lencheck 2 x vals increment!(nlp, :neval_jac_nln) - vals .= [-x[1] / 2, -2 * x[2]] + vals .= [-2 * x[1] / nlp.p, -2 * x[2]] return vals end @@ -155,7 +156,7 @@ function NLPModels.jprod_nln!( @lencheck 2 x v @lencheck 1 Jv increment!(nlp, :neval_jprod_nln) - Jv .= [-x[1] * v[1] / 2 - 2 * x[2] * v[2]] + Jv .= [-(2 * x[1] / nlp.p) * v[1] - 2 * x[2] * v[2]] return Jv end @@ -181,7 +182,7 @@ function NLPModels.jtprod_nln!( @lencheck 2 x Jtv @lencheck 1 v increment!(nlp, :neval_jtprod_nln) - Jtv .= [-x[1] * v[1] / 2; -2 * x[2] * v[1]] + Jtv .= [-(2 * x[1] / nlp.p) * v[1]; -2 * x[2] * v[1]] return Jtv end @@ -209,7 +210,7 @@ function NLPModels.jth_hess_coord!( if j == 1 vals .= 0 elseif j == 2 - vals[1] = -1 / 2 + vals[1] = -2 / nlp.p vals[2] = -2 end return vals @@ -227,7 +228,7 @@ function NLPModels.jth_hprod!( if j == 1 Hv .= 0 elseif j == 2 - Hv[1] = -v[1] / 2 + Hv[1] = -(2 / nlp.p) * v[1] Hv[2] = -2v[2] end return Hv @@ -243,6 +244,91 @@ function NLPModels.ghjvprod!( @lencheck nlp.meta.nvar x g v @lencheck nlp.meta.ncon gHv increment!(nlp, :neval_hprod) - gHv .= [T(0); -g[1] * v[1] / 2 - 2 * g[2] * v[2]] + gHv .= [T(0); -(2 * g[1] / nlp.p) * v[1] - 2 * g[2] * v[2]] return gHv end + +mutable struct BatchSimpleNLPModel{T,M,S} <: AbstractBatchNLPModel{T,M} + meta::BatchNLPModelMeta{T,M} + models::Vector{SimpleNLPModel{T,S}} +end + +function BatchSimpleNLPModel(ps::Vector{T}) where T + return BatchSimpleNLPModel( + BatchNLPModelMeta{T, Matrix{T}}( + length(ps), + 2; + nnzh = 2, + ncon = 2, + lvar = zeros(T, 1, 2), + uvar = ones(T, 1, 2), + x0 = [T(2.0) T(2.0);], + lcon = [zero(T) zero(T);], + ucon = [zero(T) T(Inf);], + name = "Batch simple NLP Model", + nnzj = 4, + ), + [SimpleNLPModel(; p = p) for p in ps] + ) +end + +function NLPModels.obj!(bnlp::BatchSimpleNLPModel, bx, bf) + for (i, nlp) in enumerate(bnlp.models) + bf[i] = NLPModels.obj(nlp, view(bx,:,i)) + end + return bf +end + +function NLPModels.grad!(bnlp::BatchSimpleNLPModel, bx, bg) + for (i, nlp) in enumerate(bnlp.models) + NLPModels.grad!(nlp, view(bx,:,i), view(bg,:,i)) + end + return bg +end + +function NLPModels.cons!(bnlp::BatchSimpleNLPModel, bx, bc) + for (i, nlp) in enumerate(bnlp.models) + NLPModels.cons!(nlp, view(bx,:,i), view(bc,:,i)) + end + return bc +end + +NLPModels.jac_structure!(bnlp::BatchSimpleNLPModel, jrows, jcols) = NLPModels.jac_structure!(bnlp.models[1], jrows, jcols) + +function NLPModels.jac_coord!(bnlp::BatchSimpleNLPModel, bx, bjvals) + for (i, nlp) in enumerate(bnlp.models) + NLPModels.jac_coord!(nlp, view(bx,:,i), view(bjvals,:,i)) + end + return bjvals +end + +function NLPModels.jprod!(bnlp::BatchSimpleNLPModel, bx, bv, bJv) + for (i, nlp) in enumerate(bnlp.models) + NLPModels.jprod!(nlp, view(bx,:,i), view(bv,:,i), view(bJv,:,i)) + end + return bJv +end + +function NLPModels.jtprod!(bnlp::BatchSimpleNLPModel, bx, bv, bJtv) + for (i, nlp) in enumerate(bnlp.models) + NLPModels.jtprod!(nlp, view(bx,:,i), view(bv,:,i), view(bJtv,:,i)) + end + return bJtv +end + +NLPModels.hess_structure!(bnlp::BatchSimpleNLPModel, jrows, jcols) = NLPModels.hess_structure!(bnlp.models[1], jrows, jcols) + + +function NLPModels.hess_coord!(bnlp::BatchSimpleNLPModel, bx, by, bobj_weight, bhvals) + for (i, nlp) in enumerate(bnlp.models) + NLPModels.hess_coord!(nlp, view(bx,:,i), view(by,:,i), view(bhvals,:,i); obj_weight = bobj_weight[i]) + end + return bhvals +end + +function NLPModels.hprod!(bnlp::BatchSimpleNLPModel, bx, by, bv, bobj_weight, bHv) + for (i, nlp) in enumerate(bnlp.models) + NLPModels.hprod!(nlp, view(bx,:,i), view(by,:,i), view(bv,:,i), view(bHv,:,i); obj_weight = bobj_weight[i]) + end + return bHv +end diff --git a/test/nlp/utils.jl b/test/nlp/utils.jl index 7d8b5ef8..d78bd967 100644 --- a/test/nlp/utils.jl +++ b/test/nlp/utils.jl @@ -2,7 +2,7 @@ mutable struct SuperNLPModel{T, S} <: AbstractNLPModel{T, S} model end -@testset "Testing @lencheck e @rangecheck" begin +@testset "Testing @lencheck and @rangecheck" begin x = zeros(2) @lencheck 2 x @test_throws DimensionError @lencheck 1 x diff --git a/test/runtests.jl b/test/runtests.jl index 06639cf7..3b3ad64b 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -4,6 +4,7 @@ include("nlp/simple-model.jl") include("nlp/dummy-model.jl") include("nlp/api.jl") +include("nlp/batch_api.jl") include("nlp/counters.jl") include("nlp/meta.jl") include("nlp/show.jl")